From ad5152b85e8bc7dacb1e6e237553fbe779c938e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Jun 2023 15:09:40 +0300 Subject: [PATCH 01/40] 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(-) 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); } From 66c5e98bbf7b7b2ba0a095ef25bf55c7230e846e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 23 Jun 2023 17:22:29 +0200 Subject: [PATCH 02/40] 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(+) 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 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: [PATCH 03/40] 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(-) 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, }; From 7a72f33b6771d37aafe1d396f8d49e5886e6262e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 4 Jul 2023 17:47:45 +0800 Subject: [PATCH 04/40] 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(-) 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"; From 713899c0627c440851a543b36b0ffe36fade2622 Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Mon, 3 Jul 2023 15:03:12 +0200 Subject: [PATCH 05/40] dt-bindings: leds: Read max-brightness from device tree 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. Signed-off-by: Astrid Rost Reviewed-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Acked-by: Jacek Anaszewski Link: https://lore.kernel.org/r/20230703130313.548519-2-astrid.rost@axis.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/common.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 58b492d00246..1c425eb5bec9 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -158,6 +158,18 @@ properties: For flash LED controllers with configurable current this property is mandatory for the LEDs in the non-flash modes (e.g. torch or indicator). + max-brightness: + description: + 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. + $ref: /schemas/types.yaml#definitions/uint32 + panic-indicator: description: This property specifies that the LED should be used, if at all possible, From 7cd7a2995ecde065a486e077deb002426975fa40 Mon Sep 17 00:00:00 2001 From: Astrid Rost Date: Mon, 3 Jul 2023 15:03:13 +0200 Subject: [PATCH 06/40] 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(+) 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; From 51c8be0c58a73ac243515516f349d44090c54e9b Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 4 Jul 2023 22:29:29 +0200 Subject: [PATCH 07/40] dt-bindings: leds: bd2606mvv: Fix maximum register value Since the chip can drive up to 6 lines, the maximum register number should be only 5, not 6. Signed-off-by: Marek Vasut Acked-by: Rob Herring Reviewed-by: Andreas Kemnade Link: https://lore.kernel.org/r/20230704202929.91962-1-marex@denx.de Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml index 14700a2e5fea..44dd91aa239d 100644 --- a/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml +++ b/Documentation/devicetree/bindings/leds/rohm,bd2606mvv.yaml @@ -35,7 +35,7 @@ properties: description: GPIO pin to enable/disable the device. patternProperties: - "^led@[0-6]$": + "^led@[0-5]$": type: object $ref: common.yaml# unevaluatedProperties: false @@ -43,7 +43,7 @@ patternProperties: properties: reg: minimum: 0 - maximum: 6 + maximum: 5 required: - reg From cadb2de2a7fd9e955381307de3eddfcc386c208e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Jul 2023 09:13:34 +0300 Subject: [PATCH 08/40] 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(-) 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; } From 07cdd959d62ee87eb29aa9a40b2e41bb11ecf4ec Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 6 Jul 2023 18:10:40 +0200 Subject: [PATCH 09/40] 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(-) 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 * From a4789089b7dea561c2750710065edb8df441648a Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 13 Jul 2023 18:35:15 +0200 Subject: [PATCH 10/40] dt-bindings: leds: pca995x: Add binding document 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. Add binding document. Signed-off-by: Marek Vasut Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230713163516.21644-1-marex@denx.de Signed-off-by: Lee Jones --- .../devicetree/bindings/leds/nxp,pca995x.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/nxp,pca995x.yaml diff --git a/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml new file mode 100644 index 000000000000..654915c1f687 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/nxp,pca995x.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/nxp,pca995x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PCA995x LED controllers + +maintainers: + - Isai Gaspar + - Marek Vasut + +description: + The NXP PCA9952/PCA9955B are programmable LED controllers connected via I2C + that can drive 16 separate lines. Each of them can be individually switched + on and off, and brightness can be controlled via individual PWM. + + Datasheets are available at + https://www.nxp.com/docs/en/data-sheet/PCA9952_PCA9955.pdf + https://www.nxp.com/docs/en/data-sheet/PCA9955B.pdf + +properties: + compatible: + enum: + - nxp,pca9952 + - nxp,pca9955b + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[0-9a-f]+$": + type: object + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + minimum: 0 + maximum: 15 + + required: + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@1 { + compatible = "nxp,pca9955b"; + reg = <0x01>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0x0>; + color = ; + function = LED_FUNCTION_POWER; + }; + + led@2 { + reg = <0x2>; + color = ; + function = LED_FUNCTION_STATUS; + }; + }; + }; + +... From ee4e80b2962e98faf69afa6230cb0c249fedec9c Mon Sep 17 00:00:00 2001 From: Isai Gaspar Date: Thu, 13 Jul 2023 18:35:16 +0200 Subject: [PATCH 11/40] 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 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"); From 7e6d86e99a5dee6f81e39f1f6d57091503dc7593 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Thu, 13 Jul 2023 13:56:39 +0200 Subject: [PATCH 12/40] 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 + .../leds/simple/simatic-ipc-leds-gpio-core.c | 4 ++ .../simatic-ipc-leds-gpio-elkhartlake.c | 57 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c 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 "); 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: [PATCH 13/40] 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(-) 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 From 3192f141240336dd6d7675ff374757006fed1916 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:46:50 -0600 Subject: [PATCH 14/40] 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(-) 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 From c8a039436525072af7e77f540d21f0d312fc7c38 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 22 Jul 2023 22:26:49 +0200 Subject: [PATCH 15/40] 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(-) 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; From 02a3fa1edeb4fa7bac2cc7f604adf23e34cb2e40 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 24 Jul 2023 17:02:58 -0600 Subject: [PATCH 16/40] dt-bindings: leds: Convert Panasonic AN30259A to DT schema Convert the Panasonic AN30259A 3-channel LED controller binding to DT schema format. Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230724230258.1017258-1-robh@kernel.org Signed-off-by: Lee Jones --- .../bindings/leds/leds-an30259a.txt | 55 ------------ .../bindings/leds/panasonic,an30259a.yaml | 84 +++++++++++++++++++ 2 files changed, 84 insertions(+), 55 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/leds-an30259a.txt create mode 100644 Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml diff --git a/Documentation/devicetree/bindings/leds/leds-an30259a.txt b/Documentation/devicetree/bindings/leds/leds-an30259a.txt deleted file mode 100644 index cbd833906b2b..000000000000 --- a/Documentation/devicetree/bindings/leds/leds-an30259a.txt +++ /dev/null @@ -1,55 +0,0 @@ -* Panasonic AN30259A 3-channel LED driver - -The AN30259A is a LED controller capable of driving three LEDs independently. It supports -constant current output and sloping current output modes. The chip is connected over I2C. - -Required properties: - - compatible: Must be "panasonic,an30259a". - - reg: I2C slave address. - - #address-cells: Must be 1. - - #size-cells: Must be 0. - -Each LED is represented as a sub-node of the panasonic,an30259a node. - -Required sub-node properties: - - reg: Pin that the LED is connected to. Must be 1, 2, or 3. - -Optional sub-node properties: - - function : - see Documentation/devicetree/bindings/leds/common.txt - - color : - see Documentation/devicetree/bindings/leds/common.txt - - label : - see Documentation/devicetree/bindings/leds/common.txt (deprecated) - - linux,default-trigger : - see Documentation/devicetree/bindings/leds/common.txt - -Example: - -#include - -led-controller@30 { - compatible = "panasonic,an30259a"; - reg = <0x30>; - #address-cells = <1>; - #size-cells = <0>; - - led@1 { - reg = <1>; - linux,default-trigger = "heartbeat"; - function = LED_FUNCTION_INDICATOR; - color = ; - }; - - led@2 { - reg = <2>; - function = LED_FUNCTION_INDICATOR; - color = ; - }; - - led@3 { - reg = <3>; - function = LED_FUNCTION_INDICATOR; - color = ; - }; -}; diff --git a/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml b/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml new file mode 100644 index 000000000000..e918dceea082 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/panasonic,an30259a.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/panasonic,an30259a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Panasonic AN30259A 3-channel LED controller + +maintainers: + - Iskren Chernev + +description: + The AN30259A is a LED controller capable of driving three LEDs independently. + It supports constant current output and sloping current output modes. The chip + is connected over I2C. + +properties: + compatible: + const: panasonic,an30259a + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[1-3]$": + $ref: common.yaml# + unevaluatedProperties: false + + properties: + reg: + enum: [ 1, 2, 3 ] + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@30 { + compatible = "panasonic,an30259a"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + + led@2 { + reg = <2>; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + + led@3 { + reg = <3>; + function = LED_FUNCTION_INDICATOR; + color = ; + }; + }; + }; +... From 05a576059ac23355a86e4be058cb43997d83c7fd Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:19 +0800 Subject: [PATCH 17/40] 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(+) 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 From 7c47381c8664d55861036d1d858daf5e9d5d67b8 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:20 +0800 Subject: [PATCH 18/40] 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(+) 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; From 546924102de8327a5b2095d2134faed6de971476 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 25 Jul 2023 17:57:21 +0800 Subject: [PATCH 19/40] 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(+) 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; 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: [PATCH 20/40] 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(-) 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; From 179507fcd5e448eaecae9b69f0fb30965c3c4466 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 9 Aug 2023 14:53:14 +0200 Subject: [PATCH 21/40] 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(-) 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 = { From afb48153220d35f330d0d979792920a31f7d9a81 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:28 +0200 Subject: [PATCH 22/40] 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 +++++++++++++++++++++++++ include/linux/leds.h | 2 ++ 2 files changed, 27 insertions(+) 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) { diff --git a/include/linux/leds.h b/include/linux/leds.h index 7d428100b42b..8740b4e47f88 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -313,6 +313,8 @@ extern struct led_classdev *of_led_get(struct device_node *np, int index); extern void led_put(struct led_classdev *led_cdev); struct led_classdev *__must_check devm_of_led_get(struct device *dev, int index); +struct led_classdev *__must_check devm_of_led_get_optional(struct device *dev, + int index); /** * led_blink_set - set blinking with software fallback From c7d80059b086c4986cd994a1973ec7a5d75f8eea Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:29 +0200 Subject: [PATCH 23/40] 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 --- Documentation/ABI/testing/sysfs-class-led | 9 +++++++++ drivers/leds/led-class.c | 21 +++++++++++++++++++++ include/linux/leds.h | 1 + 3 files changed, 31 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led index 2e24ac3bd7ef..b2ff0012c0f2 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -59,6 +59,15 @@ Description: brightness. Reading this file when no hw brightness change event has happened will return an ENODATA error. +What: /sys/class/leds//color +Date: June 2023 +KernelVersion: 6.5 +Description: + Color of the LED. + + This is a read-only file. Reading this file returns the color + of the LED as a string (e.g: "red", "green", "multicolor"). + What: /sys/class/leds//trigger Date: March 2006 KernelVersion: 2.6.17 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, diff --git a/include/linux/leds.h b/include/linux/leds.h index 8740b4e47f88..aa16dc2a8230 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -100,6 +100,7 @@ struct led_classdev { const char *name; unsigned int brightness; unsigned int max_brightness; + unsigned int color; int flags; /* Lower 16 bits reflect status */ From 099c52d9448c1ca832b4695e982221a521282b94 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:30 +0200 Subject: [PATCH 24/40] dt-bindings: leds: Add binding for a multicolor group of LEDs This allows to group multiple monochromatic LEDs into a multicolor LED, e.g. RGB LEDs. Signed-off-by: Jean-Jacques Hiblot Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230728153731.3742339-4-jjhiblot@traphandler.com Signed-off-by: Lee Jones --- .../bindings/leds/leds-group-multicolor.yaml | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-group-multicolor.yaml diff --git a/Documentation/devicetree/bindings/leds/leds-group-multicolor.yaml b/Documentation/devicetree/bindings/leds/leds-group-multicolor.yaml new file mode 100644 index 000000000000..8ed059a5a724 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-group-multicolor.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/leds-group-multicolor.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Multi-color LED built with monochromatic LEDs + +maintainers: + - Jean-Jacques Hiblot + +description: | + This driver combines several monochromatic LEDs into one multi-color + LED using the multicolor LED class. + +properties: + compatible: + const: leds-group-multicolor + + leds: + description: + An aray of monochromatic leds + $ref: /schemas/types.yaml#/definitions/phandle-array + +required: + - leds + +allOf: + - $ref: leds-class-multicolor.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + + monochromatic-leds { + compatible = "gpio-leds"; + + led0: led-0 { + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; + color = ; + }; + + led1: led-1 { + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; + color = ; + }; + + led2: led-2 { + gpios = <&mcu_pio 2 GPIO_ACTIVE_HIGH>; + color = ; + }; + }; + + multi-led { + compatible = "leds-group-multicolor"; + color = ; + function = LED_FUNCTION_INDICATOR; + leds = <&led0>, <&led1>, <&led2>; + }; + +... From 37d0849ed3927f7c4be6f5ee030730f9aa7439c0 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Fri, 28 Jul 2023 17:37:31 +0200 Subject: [PATCH 25/40] 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 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"); 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: [PATCH 26/40] 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(-) 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; } 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: [PATCH 27/40] 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(-) 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 From f044ae6b5a215df5420705dbaa287c59d8d5ef6b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 28 Jul 2023 19:11:23 +0200 Subject: [PATCH 28/40] dt-bindings: leds: rohm,bd71828: Drop select:false select:false makes the schema basically ignored (not selected for given compatible), unless some other binding references it. It's not really useful nor needed for device bindings, even if they are part of other binding (like MFD). Signed-off-by: Krzysztof Kozlowski Reviewed-by: Matti Vaittinen Reviewed-by: Conor Dooley Link: https://lore.kernel.org/r/20230728171123.110489-1-krzysztof.kozlowski@linaro.org Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml b/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml index 58f0d94c6d71..b7a3ef76cbf4 100644 --- a/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml +++ b/Documentation/devicetree/bindings/leds/rohm,bd71828-leds.yaml @@ -18,8 +18,6 @@ description: | The device has two LED outputs referred as GRNLED and AMBLED in data-sheet. -select: false - properties: compatible: const: rohm,bd71828-leds 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: [PATCH 29/40] 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(-) 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[] = { From 4aa8f7e24f07669d27945149a72903bc032fa6e9 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 24 Jul 2023 08:35:20 +0200 Subject: [PATCH 30/40] dt-bindings: leds: Add gpio-line-names to PCA9532 GPIO This is a gpio-controller, so gpio-line-names should be allowed as well. pca9532 supports up to 16 GPIOs. Signed-off-by: Alexander Stein Reviewed-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230724063520.182888-2-alexander.stein@ew.tq-group.com Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/nxp,pca953x.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml b/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml index edf6f55df685..9610bca57dd5 100644 --- a/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml +++ b/Documentation/devicetree/bindings/leds/nxp,pca953x.yaml @@ -29,6 +29,10 @@ properties: gpio-controller: true + gpio-line-names: + minItems: 1 + maxItems: 16 + '#gpio-cells': const: 2 From 3d590af89b1e61568395ab37e9b5f88fd711f638 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Tue, 8 Aug 2023 19:11:08 +0800 Subject: [PATCH 31/40] 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(-) 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, From 43a707ae58406200597b03a5be782e726b3c175b Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 10 Aug 2023 21:49:05 +0400 Subject: [PATCH 32/40] 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(-) 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); 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: [PATCH 33/40] 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(-) 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, 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: [PATCH 34/40] 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(-) 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); From d3679199f6847061683069d65737a55a8a5c60ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Mon, 14 Aug 2023 18:31:15 +0200 Subject: [PATCH 35/40] dt-bindings: leds: Fix reference to definition of default-state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least since the YAML conversion, the default-state property is described in leds/common.yaml, so there's no need to point to another file for its definition. Signed-off-by: Jonathan Neuschäfer Acked-by: Rob Herring Link: https://lore.kernel.org/r/20230814163116.1696092-1-j.neuschaefer@gmx.net Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/common.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index 1c425eb5bec9..5fb7007f3618 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -83,8 +83,7 @@ properties: - enum: # LED will act as a back-light, controlled by the framebuffer system - backlight - # LED will turn on (but for leds-gpio see "default-state" property in - # Documentation/devicetree/bindings/leds/leds-gpio.yaml) + # LED will turn on (see also "default-state" property) - default-on # LED "double" flashes at a load average based rate - heartbeat From 74cd23e87d7b5ebd5185d3930a7d95fbd859a256 Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 15 Aug 2023 15:59:43 +0800 Subject: [PATCH 36/40] 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(-) 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 "); From a916d720ab5b4facd956fd2ec8332946f763cfbf Mon Sep 17 00:00:00 2001 From: Li Zetao Date: Tue, 15 Aug 2023 15:59:44 +0800 Subject: [PATCH 37/40] 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(-) 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"); From 9422bcf125b94e553c795af4f6c59d8e8fd8affa Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 15 Aug 2023 19:21:04 +0200 Subject: [PATCH 38/40] dt-bindings: leds: aw2013: Document interrupt AW2013 has an optional interrupt pin "INTN" which is used to report completion of started operations (e.g. power up or LED breath effects). The driver does not use it (yet) but it should be described for completeness inside the DT schema. Signed-off-by: Stephan Gerhold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Nikita Travkin Link: https://lore.kernel.org/r/20230815-aw2013-vio-v3-1-2505296b0856@gerhold.net Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/leds-aw2013.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-aw2013.yaml b/Documentation/devicetree/bindings/leds/leds-aw2013.yaml index 08f3e1cfc1b1..a0a0dabcfbf3 100644 --- a/Documentation/devicetree/bindings/leds/leds-aw2013.yaml +++ b/Documentation/devicetree/bindings/leds/leds-aw2013.yaml @@ -20,6 +20,11 @@ properties: reg: maxItems: 1 + interrupts: + maxItems: 1 + description: Open-drain, low active interrupt pin "INTN". + Used to report completion of operations (power up, LED breath effects). + vcc-supply: description: Regulator providing power to the "VCC" pin. @@ -52,6 +57,7 @@ additionalProperties: false examples: - | #include + #include #include i2c { @@ -61,6 +67,7 @@ examples: led-controller@45 { compatible = "awinic,aw2013"; reg = <0x45>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; #address-cells = <1>; #size-cells = <0>; From 2cccb179addedff6a5234e37237fc6b22d9217d4 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Tue, 15 Aug 2023 19:21:05 +0200 Subject: [PATCH 39/40] dt-bindings: leds: Document pull-up supply for interrupt and I2C Since the interrupt and I2C lines of AW2013 operate in open drain low active mode a pull-up supply is needed for correct operation. Unfortunately there is no ideal place to describe it in the DT: The pull-up needed for the I2C lines could be described on the I2C bus. However, the pull-up needed for the interrupt line belongs neither directly to the interrupt controller nor to AW2013. Since the AW2013 driver will be typically in control of the power management and interrupt masking it makes more sense to describe it inside the AW2013 device tree node. Add it to the AW2013 DT schema together with a comment that makes it clear what exactly it represents. Signed-off-by: Stephan Gerhold Acked-by: Krzysztof Kozlowski Reviewed-by: Nikita Travkin Link: https://lore.kernel.org/r/20230815-aw2013-vio-v3-2-2505296b0856@gerhold.net Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/leds/leds-aw2013.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-aw2013.yaml b/Documentation/devicetree/bindings/leds/leds-aw2013.yaml index a0a0dabcfbf3..26238446f2bd 100644 --- a/Documentation/devicetree/bindings/leds/leds-aw2013.yaml +++ b/Documentation/devicetree/bindings/leds/leds-aw2013.yaml @@ -28,6 +28,12 @@ properties: vcc-supply: description: Regulator providing power to the "VCC" pin. + vio-supply: + description: Regulator providing power for pull-up of the I/O lines. + "VIO1" in the typical application circuit example of the datasheet. + Note that this regulator does not directly connect to AW2013, but is + needed for the correct operation of the interrupt and I2C lines. + "#address-cells": const: 1 From baca986e1f2c31f8e4b2a6d99d47c3bc844033e8 Mon Sep 17 00:00:00 2001 From: "Lin, Meng-Bo" Date: Tue, 15 Aug 2023 19:21:06 +0200 Subject: [PATCH 40/40] 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(-) 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);