From ad5152b85e8bc7dacb1e6e237553fbe779c938e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Jun 2023 15:09:40 +0300 Subject: leds: aw200xx: Fix error code in probe() The "ret" variable is zero/success here. Don't return that, return -EINVAL instead. Fixes: 36a87f371b7a ("leds: Add AW20xx driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/4d791b69-01c7-4532-818c-63712d3f63e1@moroto.mountain Signed-off-by: Lee Jones --- drivers/leds/leds-aw200xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 96979b8e09b7..7b996bc01c46 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -368,7 +368,7 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip) if (!chip->display_rows || chip->display_rows > chip->cdef->display_size_rows_max) { - return dev_err_probe(dev, ret, + return dev_err_probe(dev, -EINVAL, "Invalid leds display size %u\n", chip->display_rows); } -- cgit v1.2.3 From 66c5e98bbf7b7b2ba0a095ef25bf55c7230e846e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 23 Jun 2023 17:22:29 +0200 Subject: leds: simatic-ipc-leds-gpio: Restore LEDS_CLASS dependency A recent rework accidentally lost the dependency on LEDS_CLASS, which leads to a link error when LED support is disbled: x86_64-linux-ld: drivers/leds/simple/simatic-ipc-leds.o: in function `simatic_ipc_leds_probe': simatic-ipc-leds.c:(.text+0x10c): undefined reference to `devm_led_classdev_register_ext' Add back the dependency that was there originally. Fixes: a6c80bec3c935 ("leds: simatic-ipc-leds-gpio: Add GPIO version of Siemens driver") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20230623152233.2246285-1-arnd@kernel.org Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/leds') diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index 44fa0f93cb3b..02443e745ff3 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config LEDS_SIEMENS_SIMATIC_IPC tristate "LED driver for Siemens Simatic IPCs" + depends on LEDS_CLASS depends on SIEMENS_SIMATIC_IPC help This option enables support for the LEDs of several Industrial PCs -- cgit v1.2.3 From 07a476e04f3479b4c5e2e027859b496a48836028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 26 Jun 2023 11:02:54 +0200 Subject: leds: aw200xx: Switch back to use struct i2c_driver::probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct i2c_driver::probe_new is about to go away. Switch the driver to use the probe callback with the same prototype. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230626090254.556206-1-u.kleine-koenig@pengutronix.de Signed-off-by: Lee Jones --- drivers/leds/leds-aw200xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 7b996bc01c46..691a743cc9b0 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -583,7 +583,7 @@ static struct i2c_driver aw200xx_driver = { .name = "aw200xx", .of_match_table = aw200xx_match_table, }, - .probe_new = aw200xx_probe, + .probe = aw200xx_probe, .remove = aw200xx_remove, .id_table = aw200xx_id, }; -- cgit v1.2.3 From 7a72f33b6771d37aafe1d396f8d49e5886e6262e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 17:47:45 +0800 Subject: leds: ip30: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Link: https://lore.kernel.org/r/20230704094745.25665-1-frank.li@vivo.com Signed-off-by: Lee Jones --- drivers/leds/leds-ip30.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-ip30.c b/drivers/leds/leds-ip30.c index 1f952bad0fe8..2df24c303366 100644 --- a/drivers/leds/leds-ip30.c +++ b/drivers/leds/leds-ip30.c @@ -27,22 +27,16 @@ static void ip30led_set(struct led_classdev *led_cdev, static int ip30led_create(struct platform_device *pdev, int num) { - struct resource *res; struct ip30_led *data; - res = platform_get_resource(pdev, IORESOURCE_MEM, num); - if (!res) - return -EBUSY; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->reg = devm_ioremap_resource(&pdev->dev, res); + data->reg = devm_platform_ioremap_resource(pdev, num); if (IS_ERR(data->reg)) return PTR_ERR(data->reg); - switch (num) { case IP30_LED_SYSTEM: data->cdev.name = "white:power"; -- cgit v1.2.3 From 7cd7a2995ecde065a486e077deb002426975fa40 Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Mon, 3 Jul 2023 15:03:13 +0200 Subject: led: led-class: Read max-brightness from devicetree Normally, the maximum brightness is determined by the hardware, and this property is not required. This property is used to set a software limit. It could happen that an LED is made so bright that it gets damaged or causes damage due to restrictions in a specific system, such as mounting conditions. Note that this flag is mainly used for PWM-LEDs, where it is not possible to map brightness to current. Drivers for other controllers should use led-max-microamp. Reviewed-by: Andy Shevchenko Signed-off-by: Astrid Rost Acked-by: Jacek Anaszewski Link: https://lore.kernel.org/r/20230703130313.548519-3-astrid.rost@axis.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 6dae56b914fe..4758da2b59cf 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -457,6 +457,10 @@ int led_classdev_register_ext(struct device *parent, if (fwnode_property_present(init_data->fwnode, "retain-state-shutdown")) led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; + + fwnode_property_read_u32(init_data->fwnode, + "max-brightness", + &led_cdev->max_brightness); } } else { proposed_name = led_cdev->name; -- cgit v1.2.3 From cadb2de2a7fd9e955381307de3eddfcc386c208e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Jul 2023 09:13:34 +0300 Subject: leds: pwm: Fix error code in led_pwm_create_fwnode() Negative -EINVAL was intended, not positive EINVAL. Fix it. Fixes: 95138e01275e ("leds: pwm: Make error handling more robust") Signed-off-by: Dan Carpenter Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/a33b981a-b2c4-4dc2-b00a-626a090d2f11@moroto.mountain Signed-off-by: Lee Jones --- drivers/leds/leds-pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 29194cc382af..87c199242f3c 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -146,7 +146,7 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) led.name = to_of_node(fwnode)->name; if (!led.name) { - ret = EINVAL; + ret = -EINVAL; goto err_child_out; } -- cgit v1.2.3 From 07cdd959d62ee87eb29aa9a40b2e41bb11ecf4ec Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 6 Jul 2023 18:10:40 +0200 Subject: leds: simatic-ipc-leds-gpio: Fix comment style in SPDX header This was found with giving the file to checkpatch. Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20230706161040.21152-3-henning.schild@siemens.com Signed-off-by: Lee Jones --- drivers/leds/simple/simatic-ipc-leds-gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio.h b/drivers/leds/simple/simatic-ipc-leds-gpio.h index bf258c32f83d..3d4877aa4e0c 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio.h +++ b/drivers/leds/simple/simatic-ipc-leds-gpio.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Siemens SIMATIC IPC driver for GPIO based LEDs * -- cgit v1.2.3 From ee4e80b2962e98faf69afa6230cb0c249fedec9c Mon Sep 17 00:00:00 2001 From: Isai Gaspar Date: Thu, 13 Jul 2023 18:35:16 +0200 Subject: leds: pca995x: Add support for PCA995X chips The PCA995x chips are I2C controlled LED drivers. Each chip has up to 16 outputs, each one with an individual 8-bit resolution PWM for brightness control. Signed-off-by: Isai Gaspar Signed-off-by: Marek Vasut # Basically rewrite the driver Link: https://lore.kernel.org/r/20230713163516.21644-2-marex@denx.de Signed-off-by: Lee Jones --- drivers/leds/Kconfig | 9 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-pca995x.c | 204 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 drivers/leds/leds-pca995x.c (limited to 'drivers/leds') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6046dfeca16f..b92208eccdea 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -521,6 +521,15 @@ config LEDS_PCA963X LED driver chip accessed via the I2C bus. Supported devices include PCA9633 and PCA9634 +config LEDS_PCA995X + tristate "LED Support for PCA995x I2C chips" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for LEDs connected to PCA995x + LED driver chips accessed via the I2C bus. Supported + devices include PCA9955BTW, PCA9952TW and PCA9955TW. + config LEDS_WM831X_STATUS tristate "LED support for status LEDs on WM831x PMICs" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index d71f1226540c..d7348e8bc019 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_LEDS_OT200) += leds-ot200.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_PCA963X) += leds-pca963x.o +obj-$(CONFIG_LEDS_PCA995X) += leds-pca995x.o obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o obj-$(CONFIG_LEDS_PWM) += leds-pwm.o diff --git a/drivers/leds/leds-pca995x.c b/drivers/leds/leds-pca995x.c new file mode 100644 index 000000000000..3ac99a433fcd --- /dev/null +++ b/drivers/leds/leds-pca995x.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * LED driver for PCA995x I2C LED drivers + * + * Copyright 2011 bct electronic GmbH + * Copyright 2013 Qtechnology/AS + * Copyright 2022 NXP + * Copyright 2023 Marek Vasut + */ + +#include +#include +#include +#include +#include +#include + +/* Register definition */ +#define PCA995X_MODE1 0x00 +#define PCA995X_MODE2 0x01 +#define PCA995X_LEDOUT0 0x02 +#define PCA9955B_PWM0 0x08 +#define PCA9952_PWM0 0x0A +#define PCA9952_IREFALL 0x43 +#define PCA9955B_IREFALL 0x45 + +/* Auto-increment disabled. Normal mode */ +#define PCA995X_MODE1_CFG 0x00 + +/* LED select registers determine the source that drives LED outputs */ +#define PCA995X_LED_OFF 0x0 +#define PCA995X_LED_ON 0x1 +#define PCA995X_LED_PWM_MODE 0x2 +#define PCA995X_LDRX_MASK 0x3 +#define PCA995X_LDRX_BITS 2 + +#define PCA995X_MAX_OUTPUTS 16 +#define PCA995X_OUTPUTS_PER_REG 4 + +#define PCA995X_IREFALL_FULL_CFG 0xFF +#define PCA995X_IREFALL_HALF_CFG (PCA995X_IREFALL_FULL_CFG / 2) + +#define PCA995X_TYPE_NON_B 0 +#define PCA995X_TYPE_B 1 + +#define ldev_to_led(c) container_of(c, struct pca995x_led, ldev) + +struct pca995x_led { + unsigned int led_no; + struct led_classdev ldev; + struct pca995x_chip *chip; +}; + +struct pca995x_chip { + struct regmap *regmap; + struct pca995x_led leds[PCA995X_MAX_OUTPUTS]; + int btype; +}; + +static int pca995x_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct pca995x_led *led = ldev_to_led(led_cdev); + struct pca995x_chip *chip = led->chip; + u8 ledout_addr, pwmout_addr; + int shift, ret; + + pwmout_addr = (chip->btype ? PCA9955B_PWM0 : PCA9952_PWM0) + led->led_no; + ledout_addr = PCA995X_LEDOUT0 + (led->led_no / PCA995X_OUTPUTS_PER_REG); + shift = PCA995X_LDRX_BITS * (led->led_no % PCA995X_OUTPUTS_PER_REG); + + switch (brightness) { + case LED_FULL: + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, + PCA995X_LED_ON << shift); + case LED_OFF: + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, 0); + default: + /* Adjust brightness as per user input by changing individual PWM */ + ret = regmap_write(chip->regmap, pwmout_addr, brightness); + if (ret) + return ret; + + /* + * Change LDRx configuration to individual brightness via PWM. + * LED will stop blinking if it's doing so. + */ + return regmap_update_bits(chip->regmap, ledout_addr, + PCA995X_LDRX_MASK << shift, + PCA995X_LED_PWM_MODE << shift); + } +} + +static const struct regmap_config pca995x_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x49, +}; + +static int pca995x_probe(struct i2c_client *client) +{ + struct fwnode_handle *led_fwnodes[PCA995X_MAX_OUTPUTS] = { 0 }; + struct fwnode_handle *np, *child; + struct device *dev = &client->dev; + struct pca995x_chip *chip; + struct pca995x_led *led; + int i, btype, reg, ret; + + btype = (unsigned long)device_get_match_data(&client->dev); + + np = dev_fwnode(dev); + if (!np) + return -ENODEV; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->btype = btype; + chip->regmap = devm_regmap_init_i2c(client, &pca995x_regmap); + if (IS_ERR(chip->regmap)) + return PTR_ERR(chip->regmap); + + i2c_set_clientdata(client, chip); + + fwnode_for_each_available_child_node(np, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) { + fwnode_handle_put(child); + return ret; + } + + if (reg < 0 || reg >= PCA995X_MAX_OUTPUTS || led_fwnodes[reg]) { + fwnode_handle_put(child); + return -EINVAL; + } + + led = &chip->leds[reg]; + led_fwnodes[reg] = child; + led->chip = chip; + led->led_no = reg; + led->ldev.brightness_set_blocking = pca995x_brightness_set; + led->ldev.max_brightness = 255; + } + + for (i = 0; i < PCA995X_MAX_OUTPUTS; i++) { + struct led_init_data init_data = {}; + + if (!led_fwnodes[i]) + continue; + + init_data.fwnode = led_fwnodes[i]; + + ret = devm_led_classdev_register_ext(dev, + &chip->leds[i].ldev, + &init_data); + if (ret < 0) { + fwnode_handle_put(child); + return dev_err_probe(dev, ret, + "Could not register LED %s\n", + chip->leds[i].ldev.name); + } + } + + /* Disable LED all-call address and set normal mode */ + ret = regmap_write(chip->regmap, PCA995X_MODE1, PCA995X_MODE1_CFG); + if (ret) + return ret; + + /* IREF Output current value for all LEDn outputs */ + return regmap_write(chip->regmap, + btype ? PCA9955B_IREFALL : PCA9952_IREFALL, + PCA995X_IREFALL_HALF_CFG); +} + +static const struct i2c_device_id pca995x_id[] = { + { "pca9952", .driver_data = (kernel_ulong_t)PCA995X_TYPE_NON_B }, + { "pca9955b", .driver_data = (kernel_ulong_t)PCA995X_TYPE_B }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pca995x_id); + +static const struct of_device_id pca995x_of_match[] = { + { .compatible = "nxp,pca9952", .data = (void *)PCA995X_TYPE_NON_B }, + { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, pca995x_of_match); + +static struct i2c_driver pca995x_driver = { + .driver = { + .name = "leds-pca995x", + .of_match_table = pca995x_of_match, + }, + .probe = pca995x_probe, + .id_table = pca995x_id, +}; +module_i2c_driver(pca995x_driver); + +MODULE_AUTHOR("Isai Gaspar "); +MODULE_DESCRIPTION("PCA995x LED driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7e6d86e99a5dee6f81e39f1f6d57091503dc7593 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 13 Jul 2023 13:56:39 +0200 Subject: leds: simatic-ipc-leds-gpio: Add Elkhart Lake version This is used for the Siemens Simatic IPC BX-21A, which has its LEDs connected to GPIOs provided by the Intel Elkhart Lake pinctrl driver. Signed-off-by: Henning Schild Link: https://lore.kernel.org/r/20230713115639.16419-3-henning.schild@siemens.com Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 13 +++++ drivers/leds/simple/Makefile | 1 + drivers/leds/simple/simatic-ipc-leds-gpio-core.c | 4 ++ .../simple/simatic-ipc-leds-gpio-elkhartlake.c | 57 ++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c (limited to 'drivers/leds') diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index 02443e745ff3..4496373bfe24 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -35,3 +35,16 @@ config LEDS_SIEMENS_SIMATIC_IPC_F7188X To compile this driver as a module, choose M here: the module will be called simatic-ipc-leds-gpio-f7188x. + +config LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE + tristate "LED driver for Siemens Simatic IPCs based on Intel Elkhart Lake GPIO" + depends on LEDS_GPIO + depends on PINCTRL_ELKHARTLAKE + depends on SIEMENS_SIMATIC_IPC + default LEDS_SIEMENS_SIMATIC_IPC + help + This option enables support for the LEDs of several Industrial PCs + from Siemens based on Elkhart Lake GPIO i.e. BX-21A. + + To compile this driver as a module, choose M here: the module + will be called simatic-ipc-leds-gpio-elkhartlake. diff --git a/drivers/leds/simple/Makefile b/drivers/leds/simple/Makefile index e3e840cea275..783578f11bb0 100644 --- a/drivers/leds/simple/Makefile +++ b/drivers/leds/simple/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_APOLLOLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-apollolake.o obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_F7188X) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-f7188x.o +obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC_ELKHARTLAKE) += simatic-ipc-leds-gpio-core.o simatic-ipc-leds-gpio-elkhartlake.o diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c index 2a21b663df87..c552ea73ed9d 100644 --- a/drivers/leds/simple/simatic-ipc-leds-gpio-core.c +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-core.c @@ -57,6 +57,7 @@ int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, switch (plat->devmode) { case SIMATIC_IPC_DEVICE_127E: case SIMATIC_IPC_DEVICE_227G: + case SIMATIC_IPC_DEVICE_BX_21A: break; default: return -ENODEV; @@ -72,6 +73,9 @@ int simatic_ipc_leds_gpio_probe(struct platform_device *pdev, goto out; } + if (!table_extra) + return 0; + table_extra->dev_id = dev_name(dev); gpiod_add_lookup_table(table_extra); diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c new file mode 100644 index 000000000000..6ba21dbb3ba0 --- /dev/null +++ b/drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Siemens SIMATIC IPC driver for GPIO based LEDs + * + * Copyright (c) Siemens AG, 2023 + * + * Author: + * Henning Schild + */ + +#include +#include +#include +#include +#include +#include + +#include "simatic-ipc-leds-gpio.h" + +static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX("INTC1020:04", 72, NULL, 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 77, NULL, 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 78, NULL, 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 58, NULL, 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 60, NULL, 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("INTC1020:04", 62, NULL, 5, GPIO_ACTIVE_HIGH), + {} /* Terminating entry */ + }, +}; + +static int simatic_ipc_leds_gpio_elkhartlake_probe(struct platform_device *pdev) +{ + return simatic_ipc_leds_gpio_probe(pdev, &simatic_ipc_led_gpio_table, + NULL); +} + +static int simatic_ipc_leds_gpio_elkhartlake_remove(struct platform_device *pdev) +{ + return simatic_ipc_leds_gpio_remove(pdev, &simatic_ipc_led_gpio_table, + NULL); +} + +static struct platform_driver simatic_ipc_led_gpio_elkhartlake_driver = { + .probe = simatic_ipc_leds_gpio_elkhartlake_probe, + .remove = simatic_ipc_leds_gpio_elkhartlake_remove, + .driver = { + .name = KBUILD_MODNAME, + }, +}; +module_platform_driver(simatic_ipc_led_gpio_elkhartlake_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" KBUILD_MODNAME); +MODULE_SOFTDEP("pre: simatic-ipc-leds-gpio-core platform:elkhartlake-pinctrl"); +MODULE_AUTHOR("Henning Schild "); -- cgit v1.2.3 From 3c19c79146e1522f52918a5d335523e48f669a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 14 Jul 2023 08:32:14 +0200 Subject: leds: bcm63138: Rename dependency symbol ARCH_BCM4908 to ARCH_BCMBCA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symbol ARCH_BCM4908 has been merged/removed without updating leds Kconfig. Fixes: dd5c672d7ca9 ("arm64: bcmbca: Merge ARCH_BCM4908 to ARCH_BCMBCA") Signed-off-by: Rafał Miłecki Reviewed-by: William Zhang Link: https://lore.kernel.org/r/20230714063214.3791-1-zajec5@gmail.com Signed-off-by: Lee Jones --- drivers/leds/blink/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/blink/Kconfig b/drivers/leds/blink/Kconfig index 945c84286a4e..bdcb7377cd4e 100644 --- a/drivers/leds/blink/Kconfig +++ b/drivers/leds/blink/Kconfig @@ -1,10 +1,10 @@ config LEDS_BCM63138 tristate "LED Support for Broadcom BCM63138 SoC" depends on LEDS_CLASS - depends on ARCH_BCM4908 || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST + depends on ARCH_BCMBCA || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST depends on HAS_IOMEM depends on OF - default ARCH_BCM4908 + default ARCH_BCMBCA help This option enables support for LED controller that is part of BCM63138 SoC. The same hardware block is known to be also used -- cgit v1.2.3 From 3192f141240336dd6d7675ff374757006fed1916 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:46:50 -0600 Subject: leds: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230714174651.4058753-1-robh@kernel.org Signed-off-by: Lee Jones --- drivers/leds/leds-ariel.c | 2 +- drivers/leds/leds-cpcap.c | 2 +- drivers/leds/leds-cr0014114.c | 2 +- drivers/leds/leds-is31fl32xx.c | 1 - drivers/leds/leds-mlxreg.c | 1 - drivers/leds/leds-pca9532.c | 1 - drivers/leds/leds-pm8058.c | 1 - drivers/leds/leds-pwm.c | 2 +- drivers/leds/leds-spi-byte.c | 2 +- drivers/leds/leds-syscon.c | 3 +-- drivers/leds/leds-ti-lmu-common.c | 2 +- drivers/leds/leds-tlc591xx.c | 1 - drivers/leds/rgb/leds-qcom-lpg.c | 1 - 13 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-ariel.c b/drivers/leds/leds-ariel.c index 49e1bddaa15e..dd319c7e385f 100644 --- a/drivers/leds/leds-ariel.c +++ b/drivers/leds/leds-ariel.c @@ -7,8 +7,8 @@ #include #include +#include #include -#include enum ec_index { EC_BLUE_LED = 0x01, diff --git a/drivers/leds/leds-cpcap.c b/drivers/leds/leds-cpcap.c index 7d41ce8c9bb1..87354f17644b 100644 --- a/drivers/leds/leds-cpcap.c +++ b/drivers/leds/leds-cpcap.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index c87686bd7c18..b33bca397ea6 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -4,8 +4,8 @@ #include #include +#include #include -#include #include #include diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 72cb56d305c4..b0a0be77bb33 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -15,7 +15,6 @@ #include #include #include -#include /* Used to indicate a device has no such register */ #define IS31FL32XX_REG_NONE 0xFF diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c index b7855c93bd72..39210653acf7 100644 --- a/drivers/leds/leds-mlxreg.c +++ b/drivers/leds/leds-mlxreg.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 8b5c62083e50..bf8bb8fc007c 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -18,7 +18,6 @@ #include #include #include -#include /* m = num_leds*/ #define PCA9532_REG_INPUT(i) ((i) >> 3) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index b9233f14b646..3f49a5181892 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 87c199242f3c..419b710984ab 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index 2c7ffc3c78e6..9d91f21842f2 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index e38abb5e60c1..360a376fa738 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -7,8 +7,7 @@ */ #include #include -#include -#include +#include #include #include #include diff --git a/drivers/leds/leds-ti-lmu-common.c b/drivers/leds/leds-ti-lmu-common.c index d7f10ad721ba..b2491666b5dc 100644 --- a/drivers/leds/leds-ti-lmu-common.c +++ b/drivers/leds/leds-ti-lmu-common.c @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index dfc6fb2b3e52..945e831ef4ac 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 59581b3e25ca..fd7676aa243d 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From c8a039436525072af7e77f540d21f0d312fc7c38 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 Jul 2023 22:26:49 +0200 Subject: leds: ns2: Slightly simplify a memory allocation Use devm_kcalloc() instead of devm_kzalloc()+array_size(). Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/560b8f140c19a7da40f5e9540c3ef312969b0dc4.1690057595.git.christophe.jaillet@wanadoo.fr Signed-off-by: Lee Jones --- drivers/leds/leds-ns2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 1677d66d8b0e..f3010c472bbd 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -247,7 +247,7 @@ static int ns2_led_probe(struct platform_device *pdev) if (!count) return -ENODEV; - leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL); + leds = devm_kcalloc(dev, count, sizeof(*leds), GFP_KERNEL); if (!leds) return -ENOMEM; -- cgit v1.2.3 From 05a576059ac23355a86e4be058cb43997d83c7fd Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:19 +0800 Subject: leds: flash: leds-qcom-flash: Declare the driver as a module Explain in Kconfig that the driver can be compiled as a module. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-1-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig index 4ed2efc65434..4e08dbc05709 100644 --- a/drivers/leds/flash/Kconfig +++ b/drivers/leds/flash/Kconfig @@ -89,6 +89,8 @@ config LEDS_QCOM_FLASH the total LED current will be split symmetrically on each channel and they will be enabled/disabled at the same time. + This driver can be built as a module, it will be called "leds-qcom-flash". + config LEDS_RT4505 tristate "LED support for RT4505 flashlight controller" depends on I2C && OF -- cgit v1.2.3 From 7c47381c8664d55861036d1d858daf5e9d5d67b8 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:20 +0800 Subject: leds: flash: leds-qcom-flash: Turn off LED before setting flash current Strobe off the LED before setting flash current to avoid it's being enabled with an incorrect current if it has been working in torch mode. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-2-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index b089ca1a1901..29cf09479422 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -309,6 +309,10 @@ static int qcom_flash_strobe_set(struct led_classdev_flash *fled_cdev, bool stat struct qcom_flash_led *led = flcdev_to_qcom_fled(fled_cdev); int rc; + rc = set_flash_strobe(led, SW_STROBE, false); + if (rc) + return rc; + rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE); if (rc) return rc; -- cgit v1.2.3 From 546924102de8327a5b2095d2134faed6de971476 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:21 +0800 Subject: leds: flash: leds-qcom-flash: Put child node if registration failed Put the child node if register flash LED device failed. Signed-off-by: Fenglin Wu Link: https://lore.kernel.org/r/20230725-leds-qcom-flash-driver-tiny-fixes-v2-3-0f5cbce5fed0@quicinc.com Signed-off-by: Lee Jones --- drivers/leds/flash/leds-qcom-flash.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/leds') diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c index 29cf09479422..a73d3ea5c97a 100644 --- a/drivers/leds/flash/leds-qcom-flash.c +++ b/drivers/leds/flash/leds-qcom-flash.c @@ -749,6 +749,7 @@ static int qcom_flash_led_probe(struct platform_device *pdev) return 0; release: + fwnode_handle_put(child); while (flash_data->v4l2_flash[flash_data->leds_count] && flash_data->leds_count) v4l2_flash_release(flash_data->v4l2_flash[flash_data->leds_count--]); return rc; -- cgit v1.2.3 From 841165267827955bb3295b066cb6a906ba9265c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 28 Jul 2023 08:57:39 +0200 Subject: leds: qcom-lpg: Drop assignment to struct pwmchip::base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f9a8ee8c8bcd ("pwm: Always allocate PWM chip base ID dynamically") there is no effect any more for assigning this variable. See pwmchip_add() which unconditionally overwrites this member. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230728065739.580281-1-u.kleine-koenig@pengutronix.de Signed-off-by: Lee Jones --- drivers/leds/rgb/leds-qcom-lpg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index fd7676aa243d..df469aaa7e6e 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -1092,7 +1092,6 @@ static int lpg_add_pwm(struct lpg *lpg) { int ret; - lpg->pwm.base = -1; lpg->pwm.dev = lpg->dev; lpg->pwm.npwm = lpg->num_channels; lpg->pwm.ops = &lpg_pwm_ops; -- cgit v1.2.3 From 179507fcd5e448eaecae9b69f0fb30965c3c4466 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 9 Aug 2023 14:53:14 +0200 Subject: leds: pca995x: Fix MODULE_DEVICE_TABLE for OF Fix copy-paste error in MODULE_DEVICE_TABLE() for the OF table, use the 'of' first parameter instead of duplicate 'i2c'. Fixes: ee4e80b2962e ("leds: pca995x: Add support for PCA995X chips") Signed-off-by: Marek Vasut Link: https://lore.kernel.org/r/20230809125314.531806-1-marex@denx.de Signed-off-by: Lee Jones --- drivers/leds/leds-pca995x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-pca995x.c b/drivers/leds/leds-pca995x.c index 3ac99a433fcd..78215dff1499 100644 --- a/drivers/leds/leds-pca995x.c +++ b/drivers/leds/leds-pca995x.c @@ -187,7 +187,7 @@ static const struct of_device_id pca995x_of_match[] = { { .compatible = "nxp,pca9955b", .data = (void *)PCA995X_TYPE_B }, {}, }; -MODULE_DEVICE_TABLE(i2c, pca995x_of_match); +MODULE_DEVICE_TABLE(of, pca995x_of_match); static struct i2c_driver pca995x_driver = { .driver = { -- cgit v1.2.3 From afb48153220d35f330d0d979792920a31f7d9a81 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:28 +0200 Subject: leds: Provide devm_of_led_get_optional() Add an optional variant of devm_of_led_get(). It behaves the same as devm_of_led_get() except where the LED doesn't exist. In this case, instead of returning -ENOENT, the function returns NULL. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230728153731.3742339-2-jjhiblot@traphandler.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4758da2b59cf..78068b06d009 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -402,6 +402,31 @@ void led_remove_lookup(struct led_lookup_data *led_lookup) } EXPORT_SYMBOL_GPL(led_remove_lookup); +/** + * devm_of_led_get_optional - Resource-managed request of an optional LED device + * @dev: LED consumer + * @index: index of the LED to obtain in the consumer + * + * The device node of the device is parsed to find the requested LED device. + * The LED device returned from this function is automatically released + * on driver detach. + * + * @return a pointer to a LED device, ERR_PTR(errno) on failure and NULL if the + * led was not found. + */ +struct led_classdev *__must_check devm_of_led_get_optional(struct device *dev, + int index) +{ + struct led_classdev *led; + + led = devm_of_led_get(dev, index); + if (IS_ERR(led) && PTR_ERR(led) == -ENOENT) + return NULL; + + return led; +} +EXPORT_SYMBOL_GPL(devm_of_led_get_optional); + static int led_classdev_next_name(const char *init_name, char *name, size_t len) { -- cgit v1.2.3 From c7d80059b086c4986cd994a1973ec7a5d75f8eea Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:29 +0200 Subject: leds: class: Store the color index in struct led_classdev Store the color of the LED so that it is not lost after the LED's name has been composed. This color information can then be exposed to the user space or used by the LED consumer. Signed-off-by: Jean-Jacques Hiblot Link: https://lore.kernel.org/r/20230728153731.3742339-3-jjhiblot@traphandler.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 78068b06d009..4bcbd46ec75a 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -76,6 +76,19 @@ static ssize_t max_brightness_show(struct device *dev, } static DEVICE_ATTR_RO(max_brightness); +static ssize_t color_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const char *color_text = "invalid"; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (led_cdev->color < LED_COLOR_ID_MAX) + color_text = led_colors[led_cdev->color]; + + return sysfs_emit(buf, "%s\n", color_text); +} +static DEVICE_ATTR_RO(color); + #ifdef CONFIG_LEDS_TRIGGERS static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0); static struct bin_attribute *led_trigger_bin_attrs[] = { @@ -90,6 +103,7 @@ static const struct attribute_group led_trigger_group = { static struct attribute *led_class_attrs[] = { &dev_attr_brightness.attr, &dev_attr_max_brightness.attr, + &dev_attr_color.attr, NULL, }; @@ -486,6 +500,10 @@ int led_classdev_register_ext(struct device *parent, fwnode_property_read_u32(init_data->fwnode, "max-brightness", &led_cdev->max_brightness); + + if (fwnode_property_present(init_data->fwnode, "color")) + fwnode_property_read_u32(init_data->fwnode, "color", + &led_cdev->color); } } else { proposed_name = led_cdev->name; @@ -495,6 +513,9 @@ int led_classdev_register_ext(struct device *parent, if (ret < 0) return ret; + if (led_cdev->color >= LED_COLOR_ID_MAX) + dev_warn(parent, "LED %s color identifier out of range\n", final_name); + mutex_init(&led_cdev->led_access); mutex_lock(&led_cdev->led_access); led_cdev->dev = device_create_with_groups(leds_class, parent, 0, -- cgit v1.2.3 From 37d0849ed3927f7c4be6f5ee030730f9aa7439c0 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:31 +0200 Subject: leds: rgb: Add a multicolor LED driver to group monochromatic LEDs Grouping multiple monochrome LEDs into a multicolor LED device has a few benefits over handling the group in user-space: - The state of the LEDs relative to each other is consistent. In other words, if 2 threads competes to set the LED to green and red, the end-result cannot be black or yellow. - The multicolor LED as a whole can be driven through the sysfs LED interface. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Lee Jones Link: https://lore.kernel.org/r/20230728153731.3742339-5-jjhiblot@traphandler.com Signed-off-by: Lee Jones --- drivers/leds/rgb/Kconfig | 12 +++ drivers/leds/rgb/Makefile | 1 + drivers/leds/rgb/leds-group-multicolor.c | 169 +++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 drivers/leds/rgb/leds-group-multicolor.c (limited to 'drivers/leds') diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig index 360c8679c6e2..183bccc06cf3 100644 --- a/drivers/leds/rgb/Kconfig +++ b/drivers/leds/rgb/Kconfig @@ -2,6 +2,18 @@ if LEDS_CLASS_MULTICOLOR +config LEDS_GROUP_MULTICOLOR + tristate "LEDs group multi-color support" + depends on OF || COMPILE_TEST + help + This option enables support for monochrome LEDs that are grouped + into multicolor LEDs which is useful in the case where LEDs of + different colors are physically grouped in a single multi-color LED + and driven by a controller that doesn't have multi-color support. + + To compile this driver as a module, choose M here: the module + will be called leds-group-multicolor. + config LEDS_PWM_MULTICOLOR tristate "PWM driven multi-color LED Support" depends on PWM diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile index 8c01daf63f61..c11cc56384e7 100644 --- a/drivers/leds/rgb/Makefile +++ b/drivers/leds/rgb/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o diff --git a/drivers/leds/rgb/leds-group-multicolor.c b/drivers/leds/rgb/leds-group-multicolor.c new file mode 100644 index 000000000000..39f58be32af5 --- /dev/null +++ b/drivers/leds/rgb/leds-group-multicolor.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Multi-color LED built with monochromatic LED devices + * + * This driver groups several monochromatic LED devices in a single multicolor LED device. + * + * Compared to handling this grouping in user-space, the benefits are: + * - The state of the monochromatic LED relative to each other is always consistent. + * - The sysfs interface of the LEDs can be used for the group as a whole. + * + * Copyright 2023 Jean-Jacques Hiblot + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct leds_multicolor { + struct led_classdev_mc mc_cdev; + struct led_classdev **monochromatics; +}; + +static int leds_gmc_set(struct led_classdev *cdev, enum led_brightness brightness) +{ + struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); + struct leds_multicolor *priv = container_of(mc_cdev, struct leds_multicolor, mc_cdev); + const unsigned int group_max_brightness = mc_cdev->led_cdev.max_brightness; + int i; + + for (i = 0; i < mc_cdev->num_colors; i++) { + struct led_classdev *mono = priv->monochromatics[i]; + const unsigned int mono_max_brightness = mono->max_brightness; + unsigned int intensity = mc_cdev->subled_info[i].intensity; + int mono_brightness; + + /* + * Scale the brightness according to relative intensity of the + * color AND the max brightness of the monochromatic LED. + */ + mono_brightness = DIV_ROUND_CLOSEST(brightness * intensity * mono_max_brightness, + group_max_brightness * group_max_brightness); + + led_set_brightness(mono, mono_brightness); + } + + return 0; +} + +static void restore_sysfs_write_access(void *data) +{ + struct led_classdev *led_cdev = data; + + /* Restore the write acccess to the LED */ + mutex_lock(&led_cdev->led_access); + led_sysfs_enable(led_cdev); + mutex_unlock(&led_cdev->led_access); +} + +static int leds_gmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct led_init_data init_data = {}; + struct led_classdev *cdev; + struct mc_subled *subled; + struct leds_multicolor *priv; + unsigned int max_brightness = 0; + int i, ret, count = 0; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + for (;;) { + struct led_classdev *led_cdev; + + led_cdev = devm_of_led_get_optional(dev, count); + if (IS_ERR(led_cdev)) + return dev_err_probe(dev, PTR_ERR(led_cdev), "Unable to get LED #%d", + count); + if (!led_cdev) + break; + + priv->monochromatics = devm_krealloc_array(dev, priv->monochromatics, + count + 1, sizeof(*priv->monochromatics), + GFP_KERNEL); + if (!priv->monochromatics) + return -ENOMEM; + + priv->monochromatics[count] = led_cdev; + + max_brightness = max(max_brightness, led_cdev->max_brightness); + + count++; + } + + subled = devm_kcalloc(dev, count, sizeof(*subled), GFP_KERNEL); + if (!subled) + return -ENOMEM; + priv->mc_cdev.subled_info = subled; + + for (i = 0; i < count; i++) { + struct led_classdev *led_cdev = priv->monochromatics[i]; + + subled[i].color_index = led_cdev->color; + + /* Configure the LED intensity to its maximum */ + subled[i].intensity = max_brightness; + } + + /* Initialise the multicolor's LED class device */ + cdev = &priv->mc_cdev.led_cdev; + cdev->flags = LED_CORE_SUSPENDRESUME; + cdev->brightness_set_blocking = leds_gmc_set; + cdev->max_brightness = max_brightness; + cdev->color = LED_COLOR_ID_MULTI; + priv->mc_cdev.num_colors = count; + + init_data.fwnode = dev_fwnode(dev); + ret = devm_led_classdev_multicolor_register_ext(dev, &priv->mc_cdev, &init_data); + if (ret) + return dev_err_probe(dev, ret, "failed to register multicolor LED for %s.\n", + cdev->name); + + ret = leds_gmc_set(cdev, cdev->brightness); + if (ret) + return dev_err_probe(dev, ret, "failed to set LED value for %s.", cdev->name); + + for (i = 0; i < count; i++) { + struct led_classdev *led_cdev = priv->monochromatics[i]; + + /* + * Make the individual LED sysfs interface read-only to prevent the user + * to change the brightness of the individual LEDs of the group. + */ + mutex_lock(&led_cdev->led_access); + led_sysfs_disable(led_cdev); + mutex_unlock(&led_cdev->led_access); + + /* Restore the write access to the LED sysfs when the group is destroyed */ + devm_add_action_or_reset(dev, restore_sysfs_write_access, led_cdev); + } + + return 0; +} + +static const struct of_device_id of_leds_group_multicolor_match[] = { + { .compatible = "leds-group-multicolor" }, + {} +}; +MODULE_DEVICE_TABLE(of, of_leds_group_multicolor_match); + +static struct platform_driver leds_group_multicolor_driver = { + .probe = leds_gmc_probe, + .driver = { + .name = "leds_group_multicolor", + .of_match_table = of_leds_group_multicolor_match, + } +}; +module_platform_driver(leds_group_multicolor_driver); + +MODULE_AUTHOR("Jean-Jacques Hiblot "); +MODULE_DESCRIPTION("LEDs group multicolor driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:leds-group-multicolor"); -- cgit v1.2.3 From 065d099f1be58187e6629273c50b948a02b7e1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 1 Aug 2023 14:49:31 +0200 Subject: leds: multicolor: Use rounded division when calculating color components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Given channel intensity, LED brightness and max LED brightness, the multicolor LED framework helper led_mc_calc_color_components() computes the color channel brightness as chan_brightness = brightness * chan_intensity / max_brightness Consider the situation when (brightness, intensity, max_brightness) is for example (16, 15, 255), then chan_brightness is computed to 0 although the fractional divison would give 0.94, which should be rounded to 1. Use DIV_ROUND_CLOSEST here for the division to give more realistic component computation: chan_brightness = DIV_ROUND_CLOSEST(brightness * chan_intensity, max_brightness) Fixes: 55d5d3b46b08 ("leds: multicolor: Introduce a multicolor class definition") Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20230801124931.8661-1-kabel@kernel.org Signed-off-by: Lee Jones --- drivers/leds/led-class-multicolor.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c index e317408583df..ec62a4811613 100644 --- a/drivers/leds/led-class-multicolor.c +++ b/drivers/leds/led-class-multicolor.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -19,9 +20,10 @@ int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev, int i; for (i = 0; i < mcled_cdev->num_colors; i++) - mcled_cdev->subled_info[i].brightness = brightness * - mcled_cdev->subled_info[i].intensity / - led_cdev->max_brightness; + mcled_cdev->subled_info[i].brightness = + DIV_ROUND_CLOSEST(brightness * + mcled_cdev->subled_info[i].intensity, + led_cdev->max_brightness); return 0; } -- cgit v1.2.3 From c3f853184bed04105682383c2971798c572226b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 1 Aug 2023 17:16:23 +0200 Subject: leds: Fix BUG_ON check for LED_COLOR_ID_MULTI that is always false MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the time we call BUG_ON(props.color == LED_COLOR_ID_MULTI); the props variable is still initialized to zero. Call the BUG_ON only after we parse fwnode into props. Fixes: 77dce3a22e89 ("leds: disallow /sys/class/leds/*:multi:* for now") Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20230801151623.30387-1-kabel@kernel.org Signed-off-by: Lee Jones --- drivers/leds/led-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index b9b1295833c9..04f9ea675f2c 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -474,15 +474,15 @@ int led_compose_name(struct device *dev, struct led_init_data *init_data, struct fwnode_handle *fwnode = init_data->fwnode; const char *devicename = init_data->devicename; - /* We want to label LEDs that can produce full range of colors - * as RGB, not multicolor */ - BUG_ON(props.color == LED_COLOR_ID_MULTI); - if (!led_classdev_name) return -EINVAL; led_parse_fwnode_props(dev, fwnode, &props); + /* We want to label LEDs that can produce full range of colors + * as RGB, not multicolor */ + BUG_ON(props.color == LED_COLOR_ID_MULTI); + if (props.label) { /* * If init_data.devicename is NULL, then it indicates that -- cgit v1.2.3 From 730094577e0c37e1bc40be37cbd41f71b0a8a2a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 2 Aug 2023 11:07:53 +0200 Subject: leds: trigger: tty: Do not use LED_ON/OFF constants, use led_blink_set_oneshot instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tty LED trigger uses the obsolete LED_ON & LED_OFF constants when setting LED brightness. This is bad because the LED_ON constant is equal to 1, and so when activating the tty LED trigger on a LED class device with max_brightness greater than 1, the LED is dimmer than it can be (when max_brightness is 255, the LED is very dimm indeed; some devices translate 1/255 to 0, so the LED is OFF all the time). Instead of directly setting brightness to a specific value, use the led_blink_set_oneshot() function from LED core to configure the blink. This function takes the current configured brightness as blink brightness if not zero, and max brightness otherwise. This also changes the behavior of the TTY LED trigger. Previously if rx/tx stats kept changing, the LED was ON all the time they kept changing. With this patch the LED will blink on TTY activity. Fixes: fd4a641ac88f ("leds: trigger: implement a tty trigger") Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20230802090753.13611-1-kabel@kernel.org Signed-off-by: Lee Jones --- drivers/leds/trigger/ledtrig-tty.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c index f62db7e520b5..8ae0d2d284af 100644 --- a/drivers/leds/trigger/ledtrig-tty.c +++ b/drivers/leds/trigger/ledtrig-tty.c @@ -7,6 +7,8 @@ #include #include +#define LEDTRIG_TTY_INTERVAL 50 + struct ledtrig_tty_data { struct led_classdev *led_cdev; struct delayed_work dwork; @@ -122,17 +124,19 @@ static void ledtrig_tty_work(struct work_struct *work) if (icount.rx != trigger_data->rx || icount.tx != trigger_data->tx) { - led_set_brightness_sync(trigger_data->led_cdev, LED_ON); + unsigned long interval = LEDTRIG_TTY_INTERVAL; + + led_blink_set_oneshot(trigger_data->led_cdev, &interval, + &interval, 0); trigger_data->rx = icount.rx; trigger_data->tx = icount.tx; - } else { - led_set_brightness_sync(trigger_data->led_cdev, LED_OFF); } out: mutex_unlock(&trigger_data->mutex); - schedule_delayed_work(&trigger_data->dwork, msecs_to_jiffies(100)); + schedule_delayed_work(&trigger_data->dwork, + msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2)); } static struct attribute *ledtrig_tty_attrs[] = { -- cgit v1.2.3 From 3d590af89b1e61568395ab37e9b5f88fd711f638 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 8 Aug 2023 19:11:08 +0800 Subject: leds: Remove redundant of_match_ptr() The driver depends on CONFIG_OF, so it is not necessary to use of_match_ptr() here. We remove both CONFIG_OF and of_match_ptr() here. Signed-off-by: Zhu Wang Link: https://lore.kernel.org/r/20230808111108.24262-1-wangzhu9@huawei.com Signed-off-by: Lee Jones --- drivers/leds/leds-an30259a.c | 2 +- drivers/leds/leds-aw2013.c | 2 +- drivers/leds/leds-lp5521.c | 5 ++--- drivers/leds/leds-lp5523.c | 4 +--- drivers/leds/leds-lp5562.c | 4 +--- drivers/leds/leds-lp8501.c | 4 +--- 6 files changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 24b1041213c2..0216afed3b6e 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -344,7 +344,7 @@ MODULE_DEVICE_TABLE(i2c, an30259a_id); static struct i2c_driver an30259a_driver = { .driver = { .name = "leds-an30259a", - .of_match_table = of_match_ptr(an30259a_match_table), + .of_match_table = an30259a_match_table, }, .probe = an30259a_probe, .remove = an30259a_remove, diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 59765640b70f..a562c01c9775 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -420,7 +420,7 @@ MODULE_DEVICE_TABLE(of, aw2013_match_table); static struct i2c_driver aw2013_driver = { .driver = { .name = "leds-aw2013", - .of_match_table = of_match_ptr(aw2013_match_table), + .of_match_table = aw2013_match_table, }, .probe = aw2013_probe, .remove = aw2013_remove, diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 030c040fdf6d..2ef19ad23b1d 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -594,18 +594,17 @@ static const struct i2c_device_id lp5521_id[] = { }; MODULE_DEVICE_TABLE(i2c, lp5521_id); -#ifdef CONFIG_OF static const struct of_device_id of_lp5521_leds_match[] = { { .compatible = "national,lp5521", }, {}, }; MODULE_DEVICE_TABLE(of, of_lp5521_leds_match); -#endif + static struct i2c_driver lp5521_driver = { .driver = { .name = "lp5521", - .of_match_table = of_match_ptr(of_lp5521_leds_match), + .of_match_table = of_lp5521_leds_match, }, .probe = lp5521_probe, .remove = lp5521_remove, diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index daa6a165fba6..38de853f9939 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -972,7 +972,6 @@ static const struct i2c_device_id lp5523_id[] = { MODULE_DEVICE_TABLE(i2c, lp5523_id); -#ifdef CONFIG_OF static const struct of_device_id of_lp5523_leds_match[] = { { .compatible = "national,lp5523", }, { .compatible = "ti,lp55231", }, @@ -980,12 +979,11 @@ static const struct of_device_id of_lp5523_leds_match[] = { }; MODULE_DEVICE_TABLE(of, of_lp5523_leds_match); -#endif static struct i2c_driver lp5523_driver = { .driver = { .name = "lp5523x", - .of_match_table = of_match_ptr(of_lp5523_leds_match), + .of_match_table = of_lp5523_leds_match, }, .probe = lp5523_probe, .remove = lp5523_remove, diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 4565cc12cea8..39db9aeb67c5 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -589,19 +589,17 @@ static const struct i2c_device_id lp5562_id[] = { }; MODULE_DEVICE_TABLE(i2c, lp5562_id); -#ifdef CONFIG_OF static const struct of_device_id of_lp5562_leds_match[] = { { .compatible = "ti,lp5562", }, {}, }; MODULE_DEVICE_TABLE(of, of_lp5562_leds_match); -#endif static struct i2c_driver lp5562_driver = { .driver = { .name = "lp5562", - .of_match_table = of_match_ptr(of_lp5562_leds_match), + .of_match_table = of_lp5562_leds_match, }, .probe = lp5562_probe, .remove = lp5562_remove, diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index f11886aa8965..ac50aa88939a 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -380,19 +380,17 @@ static const struct i2c_device_id lp8501_id[] = { }; MODULE_DEVICE_TABLE(i2c, lp8501_id); -#ifdef CONFIG_OF static const struct of_device_id of_lp8501_leds_match[] = { { .compatible = "ti,lp8501", }, {}, }; MODULE_DEVICE_TABLE(of, of_lp8501_leds_match); -#endif static struct i2c_driver lp8501_driver = { .driver = { .name = "lp8501", - .of_match_table = of_match_ptr(of_lp8501_leds_match), + .of_match_table = of_lp8501_leds_match, }, .probe = lp8501_probe, .remove = lp8501_remove, -- cgit v1.2.3 From 43a707ae58406200597b03a5be782e726b3c175b Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 10 Aug 2023 21:49:05 +0400 Subject: leds: Make leds_class a static const structure Now that the driver core allows for struct class to be in read-only memory, move the leds_class structure to be declared at build time placing it into read-only memory, instead of having to be dynamically allocated at boot time. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20230810174905.7997-1-ivan.orlov0322@gmail.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4bcbd46ec75a..974b84f6bd6a 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -22,7 +22,6 @@ #include #include "leds.h" -static struct class *leds_class; static DEFINE_MUTEX(leds_lookup_lock); static LIST_HEAD(leds_lookup_list); @@ -248,6 +247,12 @@ static struct led_classdev *led_module_get(struct device *led_dev) return led_cdev; } +static const struct class leds_class = { + .name = "leds", + .dev_groups = led_groups, + .pm = &leds_class_dev_pm_ops, +}; + /** * of_led_get() - request a LED device via the LED framework * @np: device node to get the LED device from @@ -265,7 +270,7 @@ struct led_classdev *of_led_get(struct device_node *np, int index) if (!led_node) return ERR_PTR(-ENOENT); - led_dev = class_find_device_by_of_node(leds_class, led_node); + led_dev = class_find_device_by_of_node(&leds_class, led_node); of_node_put(led_node); put_device(led_dev); @@ -360,7 +365,7 @@ struct led_classdev *led_get(struct device *dev, char *con_id) if (!provider) return ERR_PTR(-ENOENT); - led_dev = class_find_device_by_name(leds_class, provider); + led_dev = class_find_device_by_name(&leds_class, provider); kfree_const(provider); return led_module_get(led_dev); @@ -451,7 +456,7 @@ static int led_classdev_next_name(const char *init_name, char *name, strscpy(name, init_name, len); while ((ret < len) && - (dev = class_find_device_by_name(leds_class, name))) { + (dev = class_find_device_by_name(&leds_class, name))) { put_device(dev); ret = snprintf(name, len, "%s_%u", init_name, ++i); } @@ -518,8 +523,8 @@ int led_classdev_register_ext(struct device *parent, mutex_init(&led_cdev->led_access); mutex_lock(&led_cdev->led_access); - led_cdev->dev = device_create_with_groups(leds_class, parent, 0, - led_cdev, led_cdev->groups, "%s", final_name); + led_cdev->dev = device_create_with_groups(&leds_class, parent, 0, + led_cdev, led_cdev->groups, "%s", final_name); if (IS_ERR(led_cdev->dev)) { mutex_unlock(&led_cdev->led_access); return PTR_ERR(led_cdev->dev); @@ -676,17 +681,12 @@ EXPORT_SYMBOL_GPL(devm_led_classdev_unregister); static int __init leds_init(void) { - leds_class = class_create("leds"); - if (IS_ERR(leds_class)) - return PTR_ERR(leds_class); - leds_class->pm = &leds_class_dev_pm_ops; - leds_class->dev_groups = led_groups; - return 0; + return class_register(&leds_class); } static void __exit leds_exit(void) { - class_destroy(leds_class); + class_unregister(&leds_class); } subsys_initcall(leds_init); -- cgit v1.2.3 From 72a29725b6f2577fa447ca9059cdcd17100043b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 2 Aug 2023 18:07:45 +0200 Subject: leds: turris-omnia: Use sysfs_emit() instead of sprintf() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the dedicated sysfs_emit() function instead of sprintf() in sysfs attribute accessor brightness_show(). Signed-off-by: Marek Behún Link: https://lore.kernel.org/r/20230802160748.11208-4-kabel@kernel.org Signed-off-by: Lee Jones --- drivers/leds/leds-turris-omnia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index 64b2d7b6d3f3..ffcaf228e44a 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -166,7 +166,7 @@ static ssize_t brightness_show(struct device *dev, struct device_attribute *a, if (ret < 0) return ret; - return sprintf(buf, "%d\n", ret); + return sysfs_emit(buf, "%d\n", ret); } static ssize_t brightness_store(struct device *dev, struct device_attribute *a, -- cgit v1.2.3 From 760b6b7925bf09491aafa4727eef74fc6bf738b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Wed, 2 Aug 2023 18:07:43 +0200 Subject: leds: turris-omnia: Drop unnecessary mutex locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not lock driver mutex in the global LED panel brightness sysfs accessors brightness_show() and brightness_store(). The mutex locking is unnecessary here. The I2C transfers are guarded by I2C core locking mechanism, and the LED commands itself do not interfere with other commands. Fixes: 089381b27abe ("leds: initial support for Turris Omnia LEDs") Signed-off-by: Marek Behún Reviewed-by: Lee Jones Link: https://lore.kernel.org/r/20230802160748.11208-2-kabel@kernel.org Signed-off-by: Lee Jones --- drivers/leds/leds-turris-omnia.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index ffcaf228e44a..b8a95a917cfa 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -156,12 +156,9 @@ static ssize_t brightness_show(struct device *dev, struct device_attribute *a, char *buf) { struct i2c_client *client = to_i2c_client(dev); - struct omnia_leds *leds = i2c_get_clientdata(client); int ret; - mutex_lock(&leds->lock); ret = i2c_smbus_read_byte_data(client, CMD_LED_GET_BRIGHTNESS); - mutex_unlock(&leds->lock); if (ret < 0) return ret; @@ -173,7 +170,6 @@ static ssize_t brightness_store(struct device *dev, struct device_attribute *a, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - struct omnia_leds *leds = i2c_get_clientdata(client); unsigned long brightness; int ret; @@ -183,15 +179,10 @@ static ssize_t brightness_store(struct device *dev, struct device_attribute *a, if (brightness > 100) return -EINVAL; - mutex_lock(&leds->lock); ret = i2c_smbus_write_byte_data(client, CMD_LED_SET_BRIGHTNESS, (u8)brightness); - mutex_unlock(&leds->lock); - - if (ret < 0) - return ret; - return count; + return ret < 0 ? ret : count; } static DEVICE_ATTR_RW(brightness); -- cgit v1.2.3 From 74cd23e87d7b5ebd5185d3930a7d95fbd859a256 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 15 Aug 2023 15:59:43 +0800 Subject: leds: trigger: netdev: Use module_led_trigger macro to simplify the code Use the module_led_trigger macro to simplify the code, which is the same as declaring with module_init() and module_exit(). Signed-off-by: Li Zetao Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230815075944.1089298-2-lizetao1@huawei.com Signed-off-by: Lee Jones --- drivers/leds/trigger/ledtrig-netdev.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c index c9bc5a91ec83..a2835f9fed9d 100644 --- a/drivers/leds/trigger/ledtrig-netdev.c +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -605,18 +605,7 @@ static struct led_trigger netdev_led_trigger = { .groups = netdev_trig_groups, }; -static int __init netdev_trig_init(void) -{ - return led_trigger_register(&netdev_led_trigger); -} - -static void __exit netdev_trig_exit(void) -{ - led_trigger_unregister(&netdev_led_trigger); -} - -module_init(netdev_trig_init); -module_exit(netdev_trig_exit); +module_led_trigger(netdev_led_trigger); MODULE_AUTHOR("Ben Whitten "); MODULE_AUTHOR("Oliver Jowett "); -- cgit v1.2.3 From a916d720ab5b4facd956fd2ec8332946f763cfbf Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 15 Aug 2023 15:59:44 +0800 Subject: leds: uleds: Use module_misc_device macro to simplify the code Use the module_misc_device macro to simplify the code, which is the same as declaring with module_init() and module_exit(). Signed-off-by: Li Zetao Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20230815075944.1089298-3-lizetao1@huawei.com Signed-off-by: Lee Jones --- drivers/leds/uleds.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/uleds.c b/drivers/leds/uleds.c index 7320337b22d2..3d361c920030 100644 --- a/drivers/leds/uleds.c +++ b/drivers/leds/uleds.c @@ -209,17 +209,7 @@ static struct miscdevice uleds_misc = { .name = ULEDS_NAME, }; -static int __init uleds_init(void) -{ - return misc_register(&uleds_misc); -} -module_init(uleds_init); - -static void __exit uleds_exit(void) -{ - misc_deregister(&uleds_misc); -} -module_exit(uleds_exit); +module_misc_device(uleds_misc); MODULE_AUTHOR("David Lechner "); MODULE_DESCRIPTION("Userspace driver for the LED subsystem"); -- cgit v1.2.3 From baca986e1f2c31f8e4b2a6d99d47c3bc844033e8 Mon Sep 17 00:00:00 2001 From: "Lin, Meng-Bo" Date: Tue, 15 Aug 2023 19:21:06 +0200 Subject: leds: aw2013: Enable pull-up supply for interrupt and I2C Request and enable the "vio" regulator that represents the power supply that is needed for the pull-up resistors of the interrupt and I2C lines of AW2013. While this regulator is not wired directly to the AW2013 chip it is best managed as part of the AW2013 driver since it decides when AW2013 is powered on and when the interrupt is enabled or disabled. This regulator should always be enabled in conjunction with the main VCC power supply, so use the bulk regulator functions to enable both at the same time. Signed-off-by: Lin, Meng-Bo [rewrite commit message based on discussion] Signed-off-by: Stephan Gerhold Reviewed-by: Nikita Travkin Link: https://lore.kernel.org/r/20230815-aw2013-vio-v3-3-2505296b0856@gerhold.net Signed-off-by: Lee Jones --- drivers/leds/leds-aw2013.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index a562c01c9775..91f44b23cb11 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -62,7 +62,7 @@ struct aw2013_led { struct aw2013 { struct mutex mutex; /* held when writing to registers */ - struct regulator *vcc_regulator; + struct regulator_bulk_data regulators[2]; struct i2c_client *client; struct aw2013_led leds[AW2013_MAX_LEDS]; struct regmap *regmap; @@ -106,10 +106,11 @@ static void aw2013_chip_disable(struct aw2013 *chip) regmap_write(chip->regmap, AW2013_GCR, 0); - ret = regulator_disable(chip->vcc_regulator); + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), + chip->regulators); if (ret) { dev_err(&chip->client->dev, - "Failed to disable regulator: %d\n", ret); + "Failed to disable regulators: %d\n", ret); return; } @@ -123,10 +124,11 @@ static int aw2013_chip_enable(struct aw2013 *chip) if (chip->enabled) return 0; - ret = regulator_enable(chip->vcc_regulator); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), + chip->regulators); if (ret) { dev_err(&chip->client->dev, - "Failed to enable regulator: %d\n", ret); + "Failed to enable regulators: %d\n", ret); return ret; } chip->enabled = true; @@ -348,19 +350,23 @@ static int aw2013_probe(struct i2c_client *client) goto error; } - chip->vcc_regulator = devm_regulator_get(&client->dev, "vcc"); - ret = PTR_ERR_OR_ZERO(chip->vcc_regulator); - if (ret) { + chip->regulators[0].supply = "vcc"; + chip->regulators[1].supply = "vio"; + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(chip->regulators), + chip->regulators); + if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(&client->dev, - "Failed to request regulator: %d\n", ret); + "Failed to request regulators: %d\n", ret); goto error; } - ret = regulator_enable(chip->vcc_regulator); + ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), + chip->regulators); if (ret) { dev_err(&client->dev, - "Failed to enable regulator: %d\n", ret); + "Failed to enable regulators: %d\n", ret); goto error; } @@ -382,10 +388,11 @@ static int aw2013_probe(struct i2c_client *client) if (ret < 0) goto error_reg; - ret = regulator_disable(chip->vcc_regulator); + ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), + chip->regulators); if (ret) { dev_err(&client->dev, - "Failed to disable regulator: %d\n", ret); + "Failed to disable regulators: %d\n", ret); goto error; } @@ -394,7 +401,8 @@ static int aw2013_probe(struct i2c_client *client) return 0; error_reg: - regulator_disable(chip->vcc_regulator); + regulator_bulk_disable(ARRAY_SIZE(chip->regulators), + chip->regulators); error: mutex_destroy(&chip->mutex); -- cgit v1.2.3