From 2d26684a4af6d0829fa9ff637ff56160d571148f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 3 Aug 2020 11:19:36 +0200 Subject: [PATCH 01/84] leds: s3c24xx: Remove unused machine header include The driver includes machine header for GPIO registers but actually does not use them. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Pavel Machek --- drivers/leds/leds-s3c24xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 9b5e67664ba3..3c0c7aa63b8c 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -16,8 +16,6 @@ #include #include -#include - /* our context */ struct s3c24xx_gpio_led { From fa31311c31634e5e900d61b1eb24df4c8555b5f8 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 9 Aug 2020 09:32:21 -0700 Subject: [PATCH 02/84] leds: mt6323: move period calculation clang static analysis reports this problem leds-mt6323.c:275:12: warning: Division by zero duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is because period can be 0. period = *delay_on + *delay_off; There is a later check that *delay_on/off are valid. if (!*delay_on && !*delay_off) { *delay_on = 500; *delay_off = 500; } Setting the delay_on/off means period needs to be recalculated anyway. So move the period statements after this check. Fixes: 216ec6cc4c19 ("leds: Add LED support for MT6323 PMIC") Signed-off-by: Tom Rix Signed-off-by: Pavel Machek --- drivers/leds/leds-mt6323.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index 2a13e3161bf4..7b240771e45b 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -248,15 +248,6 @@ static int mt6323_led_set_blink(struct led_classdev *cdev, u8 duty_hw; int ret; - /* - * Units are in ms, if over the hardware able - * to support, fallback into software blink - */ - period = *delay_on + *delay_off; - - if (period > MT6323_MAX_PERIOD) - return -EINVAL; - /* * LED subsystem requires a default user * friendly blink pattern for the LED so using @@ -268,6 +259,15 @@ static int mt6323_led_set_blink(struct led_classdev *cdev, *delay_off = 500; } + /* + * Units are in ms, if over the hardware able + * to support, fallback into software blink + */ + period = *delay_on + *delay_off; + + if (period > MT6323_MAX_PERIOD) + return -EINVAL; + /* * Calculate duty_hw based on the percentage of period during * which the led is ON. From a2f8e2b4f1817d9438b281d96ca45ca455707f95 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 11 Aug 2020 15:48:13 +0200 Subject: [PATCH 03/84] leds: we don't want people to use LED subsystem for vibrations Remove notes about vibrations, as that is better done using input subsystem. Signed-off-by: Pavel Machek --- Documentation/leds/ledtrig-transient.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Documentation/leds/ledtrig-transient.rst b/Documentation/leds/ledtrig-transient.rst index eedfa1626e8a..63072f310660 100644 --- a/Documentation/leds/ledtrig-transient.rst +++ b/Documentation/leds/ledtrig-transient.rst @@ -17,12 +17,6 @@ set a timer to hold a state, however when user space application crashes or goes away without deactivating the timer, the hardware will be left in that state permanently. -As a specific example of this use-case, let's look at vibrate feature on -phones. Vibrate function on phones is implemented using PWM pins on SoC or -PMIC. There is a need to activate one shot timer to control the vibrate -feature, to prevent user space crashes leaving the phone in vibrate mode -permanently causing the battery to drain. - Transient trigger addresses the need for one shot timer activation. The transient trigger can be enabled and disabled just like the other leds triggers. @@ -159,7 +153,6 @@ repeat the following step as needed:: This trigger is intended to be used for the following example use cases: - - Control of vibrate (phones, tablets etc.) hardware by user space app. - Use of LED by user space app as activity indicator. - Use of LED by user space app as a kind of watchdog indicator -- as long as the app is alive, it can keep the LED illuminated, if it dies From deae5de3340fc1b967f3d868d55104f2c8f5c517 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Mon, 17 Aug 2020 18:02:55 +0200 Subject: [PATCH 04/84] leds: sgm3140: fix led->LED for consistency Signed-off-by: Pavel Machek --- drivers/leds/leds-sgm3140.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-sgm3140.c b/drivers/leds/leds-sgm3140.c index c494b934ae09..28c8b31fa952 100644 --- a/drivers/leds/leds-sgm3140.c +++ b/drivers/leds/leds-sgm3140.c @@ -316,5 +316,5 @@ static struct platform_driver sgm3140_driver = { module_platform_driver(sgm3140_driver); MODULE_AUTHOR("Luca Weiss "); -MODULE_DESCRIPTION("SG Micro SGM3140 charge pump led driver"); +MODULE_DESCRIPTION("SG Micro SGM3140 charge pump LED driver"); MODULE_LICENSE("GPL v2"); From 8ebe6d29a3f163f9fe9fc71e15073913e0ee8ad6 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Mon, 3 Aug 2020 09:50:54 -0500 Subject: [PATCH 05/84] dt-bindings: leds: pca955x: Add IBM implementation compatible string IBM created an implementation of the PCA9552 on a PIC16F microcontroller. Document the new compatible string for this device. Signed-off-by: Eddie James Acked-by: Rob Herring Signed-off-by: Pavel Machek --- Documentation/devicetree/bindings/leds/leds-pca955x.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/leds-pca955x.txt b/Documentation/devicetree/bindings/leds/leds-pca955x.txt index 7a5830f8d5ab..817f460f3a72 100644 --- a/Documentation/devicetree/bindings/leds/leds-pca955x.txt +++ b/Documentation/devicetree/bindings/leds/leds-pca955x.txt @@ -9,6 +9,7 @@ Required properties: "nxp,pca9550" "nxp,pca9551" "nxp,pca9552" + "ibm,pca9552" "nxp,pca9553" - #address-cells: must be 1 - #size-cells: must be 0 From 46de3adb5240f33b6dbf89ca0dc4ba5c86abebb1 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Mon, 3 Aug 2020 09:50:55 -0500 Subject: [PATCH 06/84] leds: pca955x: Add an IBM software implementation of the PCA9552 chip IBM created an implementation of the PCA9552 on a PIC16F microcontroller. The I2C device addresses are different from the hardware PCA9552, so add a new compatible string and associated platform data to be able to probe this device. Signed-off-by: Eddie James Reviewed-by: Vishwanatha Subbanna Signed-off-by: Pavel Machek --- drivers/leds/leds-pca955x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 131f8e922ade..7087ca4592fc 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -65,6 +65,7 @@ enum pca955x_type { pca9550, pca9551, pca9552, + ibm_pca9552, pca9553, }; @@ -90,6 +91,11 @@ static struct pca955x_chipdef pca955x_chipdefs[] = { .slv_addr = /* 1100xxx */ 0x60, .slv_addr_shift = 3, }, + [ibm_pca9552] = { + .bits = 16, + .slv_addr = /* 0110xxx */ 0x30, + .slv_addr_shift = 3, + }, [pca9553] = { .bits = 4, .slv_addr = /* 110001x */ 0x62, @@ -101,6 +107,7 @@ static const struct i2c_device_id pca955x_id[] = { { "pca9550", pca9550 }, { "pca9551", pca9551 }, { "pca9552", pca9552 }, + { "ibm-pca9552", ibm_pca9552 }, { "pca9553", pca9553 }, { } }; @@ -412,6 +419,7 @@ static const struct of_device_id of_pca955x_match[] = { { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, + { .compatible = "ibm,pca9552", .data = (void *)ibm_pca9552 }, { .compatible = "nxp,pca9553", .data = (void *)pca9553 }, {}, }; From 87e236845a3415eb7a7bc6600657c494abe41390 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 17 Aug 2020 12:11:29 -0700 Subject: [PATCH 07/84] leds: LP55XX_COMMON needs to depend on LEDS_CLASS With these kernel configs: CONFIG_LEDS_CLASS=m # CONFIG_LEDS_CLASS_MULTICOLOR is not set CONFIG_LEDS_LP55XX_COMMON=y CONFIG_LEDS_LP5521=m CONFIG_LEDS_LP5562=m leds-lp55xx-common.c has a build error because it is builtin and calls an interface that is built as a loadable module (due to LEDS_CLASS=m). By making LEDS_LP55XX_COMMON depend on LEDS_CLASS, this config combination cannot happen, thus preventing the build error. ld: drivers/leds/leds-lp55xx-common.o: in function `lp55xx_register_leds': leds-lp55xx-common.c:(.text+0xc5f): undefined reference to `devm_led_classdev_register_ext' Fixes: 33b3a561f417 ("leds: support new LP8501 device - another LP55xx common") Signed-off-by: Randy Dunlap Cc: Pavel Machek Cc: Dan Murphy Cc: Milo Kim Cc: linux-leds@vger.kernel.org Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 1c181df24eae..3c54debfc432 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -397,6 +397,7 @@ config LEDS_LP3952 config LEDS_LP55XX_COMMON tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" + depends on LEDS_CLASS depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR depends on OF depends on I2C From dce1452301e7899468a2d46c826f23eba1e1dd28 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 12 Aug 2020 14:50:15 -0500 Subject: [PATCH 08/84] dt: bindings: lp50xx: Introduce the lp50xx family of RGB drivers Introduce the bindings for the Texas Instruments LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 RGB LED device driver. The LP5036/30/24/18/12/9 can control RGB LEDs individually or as part of a control bank group. These devices have the ability to adjust the mixing control for the RGB LEDs to obtain different colors independent of the overall brightness of the LED grouping. Datasheet: http://www.ti.com/lit/ds/symlink/lp5012.pdf http://www.ti.com/lit/ds/symlink/lp5024.pdf http://www.ti.com/lit/ds/symlink/lp5036.pdf Reviewed-by: Rob Herring Acked-by: Jacek Anaszewski Acked-by: Pavel Machek Signed-off-by: Dan Murphy Signed-off-by: Pavel Machek --- .../devicetree/bindings/leds/leds-lp50xx.yaml | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/leds-lp50xx.yaml diff --git a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml new file mode 100644 index 000000000000..947542a253ec --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/leds-lp50xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LED driver for LP50XX RGB LED from Texas Instruments. + +maintainers: + - Dan Murphy + +description: | + The LP50XX is multi-channel, I2C RGB LED Drivers that can group RGB LEDs into + a LED group or control them individually. + + The difference in these RGB LED drivers is the number of supported RGB + modules. + + For more product information please see the link below: + https://www.ti.com/lit/ds/symlink/lp5012.pdf + https://www.ti.com/lit/ds/symlink/lp5024.pdf + https://www.ti.com/lit/ds/symlink/lp5036.pdf + +properties: + compatible: + enum: + - ti,lp5009 + - ti,lp5012 + - ti,lp5018 + - ti,lp5024 + - ti,lp5030 + - ti,lp5036 + + reg: + maxItems: 1 + description: + I2C slave address + lp5009/12 - 0x14, 0x15, 0x16, 0x17 + lp5018/24 - 0x28, 0x29, 0x2a, 0x2b + lp5030/36 - 0x30, 0x31, 0x32, 0x33 + + enable-gpios: + maxItems: 1 + description: GPIO pin to enable/disable the device. + + vled-supply: + description: LED supply. + +patternProperties: + '^multi-led@[0-9a-f]$': + type: object + allOf: + - $ref: leds-class-multicolor.yaml# + properties: + reg: + minItems: 1 + maxItems: 12 + description: + This property denotes the LED module number(s) that is used on the + for the child node. The LED modules can either be used stand alone + or grouped into a module bank. + + patternProperties: + "(^led-[0-9a-f]$|led)": + type: object + $ref: common.yaml# + +required: + - compatible + - reg + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@14 { + compatible = "ti,lp5009"; + reg = <0x14>; + #address-cells = <1>; + #size-cells = <0>; + enable-gpios = <&gpio1 16>; + + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = ; + function = LED_FUNCTION_CHARGING; + + led-0 { + color = ; + }; + + led-1 { + color = ; + }; + + led-2 { + color = ; + }; + }; + + multi-led@2 { + #address-cells = <1>; + #size-cells = <2>; + reg = <0x2 0x3 0x5>; + color = ; + function = LED_FUNCTION_STANDBY; + + led-6 { + color = ; + }; + + led-7 { + color = ; + }; + + led-8 { + color = ; + }; + }; + }; + }; + +... From 242b81170fb8a4a9d84ae183a8e0b1aaf2554d89 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 12 Aug 2020 14:50:16 -0500 Subject: [PATCH 09/84] leds: lp50xx: Add the LP50XX family of the RGB LED driver Introduce the LP5036/30/24/18/12/9 RGB LED driver. The difference in these parts are the number of LED outputs where the: LP5036 can control 36 LEDs LP5030 can control 30 LEDs LP5024 can control 24 LEDs LP5018 can control 18 LEDs LP5012 can control 12 LEDs LP5009 can control 9 LEDs The device has the ability to group LED outputs into control banks so that multiple LED banks can be controlled with the same mixing and brightness. Or the LED outputs can also be controlled independently. Acked-by: Jacek Anaszewski Signed-off-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 11 + drivers/leds/Makefile | 1 + drivers/leds/leds-lp50xx.c | 634 +++++++++++++++++++++++++++++++++++++ 3 files changed, 646 insertions(+) create mode 100644 drivers/leds/leds-lp50xx.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 3c54debfc432..4f6464a169d5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -395,6 +395,17 @@ config LEDS_LP3952 To compile this driver as a module, choose M here: the module will be called leds-lp3952. +config LEDS_LP50XX + tristate "LED Support for TI LP5036/30/24/18/12/9 LED driver chip" + depends on LEDS_CLASS && REGMAP_I2C + depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR + help + If you say yes here you get support for the Texas Instruments + LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 LED driver. + + To compile this driver as a module, choose M here: the + module will be called leds-lp50xx. + config LEDS_LP55XX_COMMON tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index c2c7d7ade0d0..778cb4bb8c52 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_LEDS_LM3697) += leds-lm3697.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o obj-$(CONFIG_LEDS_LP3952) += leds-lp3952.o +obj-$(CONFIG_LEDS_LP50XX) += leds-lp50xx.o obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o obj-$(CONFIG_LEDS_LP5562) += leds-lp5562.o diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c new file mode 100644 index 000000000000..47144a37cb94 --- /dev/null +++ b/drivers/leds/leds-lp50xx.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0 +// TI LP50XX LED chip family driver +// Copyright (C) 2018-20 Texas Instruments Incorporated - https://www.ti.com/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "leds.h" + +#define LP50XX_DEV_CFG0 0x00 +#define LP50XX_DEV_CFG1 0x01 +#define LP50XX_LED_CFG0 0x02 + +/* LP5009 and LP5012 registers */ +#define LP5012_BNK_BRT 0x03 +#define LP5012_BNKA_CLR 0x04 +#define LP5012_BNKB_CLR 0x05 +#define LP5012_BNKC_CLR 0x06 +#define LP5012_LED0_BRT 0x07 +#define LP5012_OUT0_CLR 0x0b +#define LP5012_RESET 0x17 + +/* LP5018 and LP5024 registers */ +#define LP5024_BNK_BRT 0x03 +#define LP5024_BNKA_CLR 0x04 +#define LP5024_BNKB_CLR 0x05 +#define LP5024_BNKC_CLR 0x06 +#define LP5024_LED0_BRT 0x07 +#define LP5024_OUT0_CLR 0x0f +#define LP5024_RESET 0x27 + +/* LP5030 and LP5036 registers */ +#define LP5036_LED_CFG1 0x03 +#define LP5036_BNK_BRT 0x04 +#define LP5036_BNKA_CLR 0x05 +#define LP5036_BNKB_CLR 0x06 +#define LP5036_BNKC_CLR 0x07 +#define LP5036_LED0_BRT 0x08 +#define LP5036_OUT0_CLR 0x14 +#define LP5036_RESET 0x38 + +#define LP50XX_SW_RESET 0xff +#define LP50XX_CHIP_EN BIT(6) + +/* There are 3 LED outputs per bank */ +#define LP50XX_LEDS_PER_MODULE 3 + +#define LP5009_MAX_LED_MODULES 2 +#define LP5012_MAX_LED_MODULES 4 +#define LP5018_MAX_LED_MODULES 6 +#define LP5024_MAX_LED_MODULES 8 +#define LP5030_MAX_LED_MODULES 10 +#define LP5036_MAX_LED_MODULES 12 + +static const struct reg_default lp5012_reg_defs[] = { + {LP50XX_DEV_CFG0, 0x0}, + {LP50XX_DEV_CFG1, 0x3c}, + {LP50XX_LED_CFG0, 0x0}, + {LP5012_BNK_BRT, 0xff}, + {LP5012_BNKA_CLR, 0x0f}, + {LP5012_BNKB_CLR, 0x0f}, + {LP5012_BNKC_CLR, 0x0f}, + {LP5012_LED0_BRT, 0x0f}, + /* LEDX_BRT registers are all 0xff for defaults */ + {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, + {LP5012_OUT0_CLR, 0x0f}, + /* OUTX_CLR registers are all 0x0 for defaults */ + {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00}, {0x10, 0x00}, + {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00}, {0x15, 0x00}, + {0x16, 0x00}, + {LP5012_RESET, 0x00} +}; + +static const struct reg_default lp5024_reg_defs[] = { + {LP50XX_DEV_CFG0, 0x0}, + {LP50XX_DEV_CFG1, 0x3c}, + {LP50XX_LED_CFG0, 0x0}, + {LP5024_BNK_BRT, 0xff}, + {LP5024_BNKA_CLR, 0x0f}, + {LP5024_BNKB_CLR, 0x0f}, + {LP5024_BNKC_CLR, 0x0f}, + {LP5024_LED0_BRT, 0x0f}, + /* LEDX_BRT registers are all 0xff for defaults */ + {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff}, + {0x0d, 0xff}, {0x0e, 0xff}, + {LP5024_OUT0_CLR, 0x0f}, + /* OUTX_CLR registers are all 0x0 for defaults */ + {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00}, {0x14, 0x00}, + {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00}, + {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, + {0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, + {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, + {LP5024_RESET, 0x00} +}; + +static const struct reg_default lp5036_reg_defs[] = { + {LP50XX_DEV_CFG0, 0x0}, + {LP50XX_DEV_CFG1, 0x3c}, + {LP50XX_LED_CFG0, 0x0}, + {LP5036_LED_CFG1, 0x0}, + {LP5036_BNK_BRT, 0xff}, + {LP5036_BNKA_CLR, 0x0f}, + {LP5036_BNKB_CLR, 0x0f}, + {LP5036_BNKC_CLR, 0x0f}, + {LP5036_LED0_BRT, 0x0f}, + /* LEDX_BRT registers are all 0xff for defaults */ + {0x08, 0xff}, {0x09, 0xff}, {0x0a, 0xff}, {0x0b, 0xff}, {0x0c, 0xff}, + {0x0d, 0xff}, {0x0e, 0xff}, {0x0f, 0xff}, {0x10, 0xff}, {0x11, 0xff}, + {0x12, 0xff}, {0x13, 0xff}, + {LP5036_OUT0_CLR, 0x0f}, + /* OUTX_CLR registers are all 0x0 for defaults */ + {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00}, {0x18, 0x00}, {0x19, 0x00}, + {0x1a, 0x00}, {0x1b, 0x00}, {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, + {0x1f, 0x00}, {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00}, + {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00}, + {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x00}, + {0x2e, 0x00}, {0x2f, 0x00}, {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, + {0x33, 0x00}, {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00}, + {LP5036_RESET, 0x00} +}; + +static const struct regmap_config lp5012_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LP5012_RESET, + .reg_defaults = lp5012_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lp5012_reg_defs), + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config lp5024_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LP5024_RESET, + .reg_defaults = lp5024_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lp5024_reg_defs), + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config lp5036_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LP5036_RESET, + .reg_defaults = lp5036_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lp5036_reg_defs), + .cache_type = REGCACHE_FLAT, +}; + +enum lp50xx_model { + LP5009, + LP5012, + LP5018, + LP5024, + LP5030, + LP5036, +}; + +/** + * struct lp50xx_chip_info - + * @lp50xx_regmap_config: regmap register configuration + * @model_id: LED device model + * @max_modules: total number of supported LED modules + * @num_leds: number of LED outputs available on the device + * @led_brightness0_reg: first brightness register of the device + * @mix_out0_reg: first color mix register of the device + * @bank_brt_reg: bank brightness register + * @bank_mix_reg: color mix register + * @reset_reg: device reset register + */ +struct lp50xx_chip_info { + const struct regmap_config *lp50xx_regmap_config; + int model_id; + u8 max_modules; + u8 num_leds; + u8 led_brightness0_reg; + u8 mix_out0_reg; + u8 bank_brt_reg; + u8 bank_mix_reg; + u8 reset_reg; +}; + +static const struct lp50xx_chip_info lp50xx_chip_info_tbl[] = { + [LP5009] = { + .model_id = LP5009, + .max_modules = LP5009_MAX_LED_MODULES, + .num_leds = LP5009_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5012_LED0_BRT, + .mix_out0_reg = LP5012_OUT0_CLR, + .bank_brt_reg = LP5012_BNK_BRT, + .bank_mix_reg = LP5012_BNKA_CLR, + .reset_reg = LP5012_RESET, + .lp50xx_regmap_config = &lp5012_regmap_config, + }, + [LP5012] = { + .model_id = LP5012, + .max_modules = LP5012_MAX_LED_MODULES, + .num_leds = LP5012_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5012_LED0_BRT, + .mix_out0_reg = LP5012_OUT0_CLR, + .bank_brt_reg = LP5012_BNK_BRT, + .bank_mix_reg = LP5012_BNKA_CLR, + .reset_reg = LP5012_RESET, + .lp50xx_regmap_config = &lp5012_regmap_config, + }, + [LP5018] = { + .model_id = LP5018, + .max_modules = LP5018_MAX_LED_MODULES, + .num_leds = LP5018_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5024_LED0_BRT, + .mix_out0_reg = LP5024_OUT0_CLR, + .bank_brt_reg = LP5024_BNK_BRT, + .bank_mix_reg = LP5024_BNKA_CLR, + .reset_reg = LP5024_RESET, + .lp50xx_regmap_config = &lp5024_regmap_config, + }, + [LP5024] = { + .model_id = LP5024, + .max_modules = LP5024_MAX_LED_MODULES, + .num_leds = LP5024_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5024_LED0_BRT, + .mix_out0_reg = LP5024_OUT0_CLR, + .bank_brt_reg = LP5024_BNK_BRT, + .bank_mix_reg = LP5024_BNKA_CLR, + .reset_reg = LP5024_RESET, + .lp50xx_regmap_config = &lp5024_regmap_config, + }, + [LP5030] = { + .model_id = LP5030, + .max_modules = LP5030_MAX_LED_MODULES, + .num_leds = LP5030_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5036_LED0_BRT, + .mix_out0_reg = LP5036_OUT0_CLR, + .bank_brt_reg = LP5036_BNK_BRT, + .bank_mix_reg = LP5036_BNKA_CLR, + .reset_reg = LP5036_RESET, + .lp50xx_regmap_config = &lp5036_regmap_config, + }, + [LP5036] = { + .model_id = LP5036, + .max_modules = LP5036_MAX_LED_MODULES, + .num_leds = LP5036_MAX_LED_MODULES * LP50XX_LEDS_PER_MODULE, + .led_brightness0_reg = LP5036_LED0_BRT, + .mix_out0_reg = LP5036_OUT0_CLR, + .bank_brt_reg = LP5036_BNK_BRT, + .bank_mix_reg = LP5036_BNKA_CLR, + .reset_reg = LP5036_RESET, + .lp50xx_regmap_config = &lp5036_regmap_config, + }, +}; + +struct lp50xx_led { + struct led_classdev_mc mc_cdev; + struct lp50xx *priv; + unsigned long bank_modules; + int led_intensity[LP50XX_LEDS_PER_MODULE]; + u8 ctrl_bank_enabled; + int led_number; +}; + +/** + * struct lp50xx - + * @enable_gpio: hardware enable gpio + * @regulator: LED supply regulator pointer + * @client: pointer to the I2C client + * @regmap: device register map + * @dev: pointer to the devices device struct + * @lock: lock for reading/writing the device + * @chip_info: chip specific information (ie num_leds) + * @num_of_banked_leds: holds the number of banked LEDs + * @leds: array of LED strings + */ +struct lp50xx { + struct gpio_desc *enable_gpio; + struct regulator *regulator; + struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + struct mutex lock; + const struct lp50xx_chip_info *chip_info; + int num_of_banked_leds; + + /* This needs to be at the end of the struct */ + struct lp50xx_led leds[]; +}; + +static struct lp50xx_led *mcled_cdev_to_led(struct led_classdev_mc *mc_cdev) +{ + return container_of(mc_cdev, struct lp50xx_led, mc_cdev); +} + +static int lp50xx_brightness_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct led_classdev_mc *mc_dev = lcdev_to_mccdev(cdev); + struct lp50xx_led *led = mcled_cdev_to_led(mc_dev); + const struct lp50xx_chip_info *led_chip = led->priv->chip_info; + u8 led_offset, reg_val; + int ret = 0; + int i; + + mutex_lock(&led->priv->lock); + if (led->ctrl_bank_enabled) + reg_val = led_chip->bank_brt_reg; + else + reg_val = led_chip->led_brightness0_reg + + led->led_number; + + ret = regmap_write(led->priv->regmap, reg_val, brightness); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot write brightness value %d\n", ret); + goto out; + } + + for (i = 0; i < led->mc_cdev.num_colors; i++) { + if (led->ctrl_bank_enabled) { + reg_val = led_chip->bank_mix_reg + i; + } else { + led_offset = (led->led_number * 3) + i; + reg_val = led_chip->mix_out0_reg + led_offset; + } + + ret = regmap_write(led->priv->regmap, reg_val, + mc_dev->subled_info[i].intensity); + if (ret) { + dev_err(&led->priv->client->dev, + "Cannot write intensity value %d\n", ret); + goto out; + } + } +out: + mutex_unlock(&led->priv->lock); + return ret; +} + +static int lp50xx_set_banks(struct lp50xx *priv, u32 led_banks[]) +{ + u8 led_config_lo, led_config_hi; + u32 bank_enable_mask = 0; + int ret; + int i; + + for (i = 0; i < priv->chip_info->max_modules; i++) { + if (led_banks[i]) + bank_enable_mask |= (1 << led_banks[i]); + } + + led_config_lo = (u8)(bank_enable_mask & 0xff); + led_config_hi = (u8)(bank_enable_mask >> 8) & 0xff; + + ret = regmap_write(priv->regmap, LP50XX_LED_CFG0, led_config_lo); + if (ret) + return ret; + + if (priv->chip_info->model_id >= LP5030) + ret = regmap_write(priv->regmap, LP5036_LED_CFG1, led_config_hi); + + return ret; +} + +static int lp50xx_reset(struct lp50xx *priv) +{ + return regmap_write(priv->regmap, priv->chip_info->reset_reg, LP50XX_SW_RESET); +} + +static int lp50xx_enable_disable(struct lp50xx *priv, int enable_disable) +{ + int ret; + + if (priv->enable_gpio) { + ret = gpiod_direction_output(priv->enable_gpio, enable_disable); + if (ret) + return ret; + } + + if (enable_disable) + return regmap_write(priv->regmap, LP50XX_DEV_CFG0, LP50XX_CHIP_EN); + else + return regmap_write(priv->regmap, LP50XX_DEV_CFG0, 0); + +} + +static int lp50xx_probe_leds(struct fwnode_handle *child, struct lp50xx *priv, + struct lp50xx_led *led, int num_leds) +{ + u32 led_banks[LP5036_MAX_LED_MODULES] = {0}; + int led_number; + int ret; + + if (num_leds > 1) { + if (num_leds > priv->chip_info->max_modules) { + dev_err(&priv->client->dev, "reg property is invalid\n"); + return -EINVAL; + } + + priv->num_of_banked_leds = num_leds; + + ret = fwnode_property_read_u32_array(child, "reg", led_banks, num_leds); + if (ret) { + dev_err(&priv->client->dev, "reg property is missing\n"); + return ret; + } + + ret = lp50xx_set_banks(priv, led_banks); + if (ret) { + dev_err(&priv->client->dev, "Cannot setup banked LEDs\n"); + return ret; + } + + led->ctrl_bank_enabled = 1; + } else { + ret = fwnode_property_read_u32(child, "reg", &led_number); + if (ret) { + dev_err(&priv->client->dev, "led reg property missing\n"); + return ret; + } + + if (led_number > priv->chip_info->num_leds) { + dev_err(&priv->client->dev, "led-sources property is invalid\n"); + return -EINVAL; + } + + led->led_number = led_number; + } + + return 0; +} + +static int lp50xx_probe_dt(struct lp50xx *priv) +{ + struct fwnode_handle *child = NULL; + struct fwnode_handle *led_node = NULL; + struct led_init_data init_data = {}; + struct led_classdev *led_cdev; + struct mc_subled *mc_led_info; + struct lp50xx_led *led; + int ret = -EINVAL; + int num_colors; + u32 color_id; + int i = 0; + + priv->enable_gpio = devm_gpiod_get_optional(priv->dev, "enable", GPIOD_OUT_LOW); + if (IS_ERR(priv->enable_gpio)) { + ret = PTR_ERR(priv->enable_gpio); + dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n", + ret); + return ret; + } + + priv->regulator = devm_regulator_get(priv->dev, "vled"); + if (IS_ERR(priv->regulator)) + priv->regulator = NULL; + + device_for_each_child_node(priv->dev, child) { + led = &priv->leds[i]; + ret = fwnode_property_count_u32(child, "reg"); + if (ret < 0) { + dev_err(&priv->client->dev, "reg property is invalid\n"); + goto child_out; + } + + ret = lp50xx_probe_leds(child, priv, led, ret); + if (ret) + goto child_out; + + init_data.fwnode = child; + num_colors = 0; + + /* + * There are only 3 LEDs per module otherwise they should be + * banked which also is presented as 3 LEDs. + */ + mc_led_info = devm_kcalloc(priv->dev, LP50XX_LEDS_PER_MODULE, + sizeof(*mc_led_info), GFP_KERNEL); + if (!mc_led_info) + return -ENOMEM; + + fwnode_for_each_child_node(child, led_node) { + ret = fwnode_property_read_u32(led_node, "color", + &color_id); + if (ret) { + dev_err(priv->dev, "Cannot read color\n"); + goto child_out; + } + + mc_led_info[num_colors].color_index = color_id; + num_colors++; + } + + led->priv = priv; + led->mc_cdev.num_colors = num_colors; + led->mc_cdev.subled_info = mc_led_info; + led_cdev = &led->mc_cdev.led_cdev; + led_cdev->brightness_set_blocking = lp50xx_brightness_set; + + fwnode_property_read_string(child, "linux,default-trigger", + &led_cdev->default_trigger); + + ret = devm_led_classdev_multicolor_register_ext(&priv->client->dev, + &led->mc_cdev, + &init_data); + if (ret) { + dev_err(&priv->client->dev, "led register err: %d\n", + ret); + goto child_out; + } + i++; + fwnode_handle_put(child); + } + + return 0; + +child_out: + fwnode_handle_put(child); + return ret; +} + +static int lp50xx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lp50xx *led; + int count; + int ret; + + count = device_get_child_node_count(&client->dev); + if (!count) { + dev_err(&client->dev, "LEDs are not defined in device tree!"); + return -ENODEV; + } + + led = devm_kzalloc(&client->dev, struct_size(led, leds, count), + GFP_KERNEL); + if (!led) + return -ENOMEM; + + mutex_init(&led->lock); + led->client = client; + led->dev = &client->dev; + led->chip_info = &lp50xx_chip_info_tbl[id->driver_data]; + i2c_set_clientdata(client, led); + led->regmap = devm_regmap_init_i2c(client, + led->chip_info->lp50xx_regmap_config); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = lp50xx_reset(led); + if (ret) + return ret; + + ret = lp50xx_enable_disable(led, 1); + if (ret) + return ret; + + return lp50xx_probe_dt(led); +} + +static int lp50xx_remove(struct i2c_client *client) +{ + struct lp50xx *led = i2c_get_clientdata(client); + int ret; + + ret = lp50xx_enable_disable(led, 0); + if (ret) { + dev_err(&led->client->dev, "Failed to disable chip\n"); + return ret; + } + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + mutex_destroy(&led->lock); + + return 0; +} + +static const struct i2c_device_id lp50xx_id[] = { + { "lp5009", LP5009 }, + { "lp5012", LP5012 }, + { "lp5018", LP5018 }, + { "lp5024", LP5024 }, + { "lp5030", LP5030 }, + { "lp5036", LP5036 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp50xx_id); + +static const struct of_device_id of_lp50xx_leds_match[] = { + { .compatible = "ti,lp5009", .data = (void *)LP5009 }, + { .compatible = "ti,lp5012", .data = (void *)LP5012 }, + { .compatible = "ti,lp5018", .data = (void *)LP5018 }, + { .compatible = "ti,lp5024", .data = (void *)LP5024 }, + { .compatible = "ti,lp5030", .data = (void *)LP5030 }, + { .compatible = "ti,lp5036", .data = (void *)LP5036 }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lp50xx_leds_match); + +static struct i2c_driver lp50xx_driver = { + .driver = { + .name = "lp50xx", + .of_match_table = of_lp50xx_leds_match, + }, + .probe = lp50xx_probe, + .remove = lp50xx_remove, + .id_table = lp50xx_id, +}; +module_i2c_driver(lp50xx_driver); + +MODULE_DESCRIPTION("Texas Instruments LP50XX LED driver"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL v2"); From 3d93edc77515c6f51fa9bbbe2185e2ec32bad024 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 12 Aug 2020 14:32:48 -0500 Subject: [PATCH 10/84] dt: bindings: lp55xx: Updte yaml examples with new color ID Update the binding examples for the color ID to LED_COLOR_ID_RGB Signed-off-by: Dan Murphy Acked-by: Rob Herring Signed-off-by: Pavel Machek --- Documentation/devicetree/bindings/leds/leds-lp55xx.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml index b1bb3feb0f4d..89f69d62493e 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml @@ -189,7 +189,7 @@ examples: #address-cells = <1>; #size-cells = <0>; reg = <0x2>; - color = ; + color = ; function = LED_FUNCTION_STANDBY; linux,default-trigger = "heartbeat"; From dddb4e38c6ba3f7ff5202d556982a0c82fa9a240 Mon Sep 17 00:00:00 2001 From: Grant Feng Date: Tue, 25 Aug 2020 16:22:05 +0800 Subject: [PATCH 11/84] leds: is31fl319x: Add shutdown pin and generate a 5ms low pulse when startup generate a 5ms low pulse on shutdown pin when startup, then the chip becomes more stable in the complex EM environment. Signed-off-by: Grant Feng Signed-off-by: Pavel Machek --- drivers/leds/leds-is31fl319x.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index ca6634b8683c..54ac50740d43 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include /* register numbers */ #define IS31FL319X_SHUTDOWN 0x00 @@ -61,6 +63,7 @@ struct is31fl319x_chip { const struct is31fl319x_chipdef *cdef; struct i2c_client *client; + struct gpio_desc *shutdown_gpio; struct regmap *regmap; struct mutex lock; u32 audio_gain_db; @@ -207,6 +210,15 @@ static int is31fl319x_parse_dt(struct device *dev, if (!np) return -ENODEV; + is31->shutdown_gpio = devm_gpiod_get_optional(dev, + "shutdown", + GPIOD_OUT_HIGH); + if (IS_ERR(is31->shutdown_gpio)) { + ret = PTR_ERR(is31->shutdown_gpio); + dev_err(dev, "Failed to get shutdown gpio: %d\n", ret); + return ret; + } + of_dev_id = of_match_device(of_is31fl319x_match, dev); if (!of_dev_id) { dev_err(dev, "Failed to match device with supported chips\n"); @@ -350,6 +362,12 @@ static int is31fl319x_probe(struct i2c_client *client, if (err) goto free_mutex; + if (is31->shutdown_gpio) { + gpiod_direction_output(is31->shutdown_gpio, 0); + mdelay(5); + gpiod_direction_output(is31->shutdown_gpio, 1); + } + is31->client = client; is31->regmap = devm_regmap_init_i2c(client, ®map_config); if (IS_ERR(is31->regmap)) { From 23bdfe00424c297051cea73cbdb7ef7398f3cb6e Mon Sep 17 00:00:00 2001 From: Grant Feng Date: Tue, 25 Aug 2020 16:22:06 +0800 Subject: [PATCH 12/84] DT: leds: Add an optional property named 'shutdown-gpios' The chip enters hardware shutdown when the SDB pin is pulled low. The chip releases hardware shutdown when the SDB pin is pulled high. Signed-off-by: Grant Feng Acked-by: Rob Herring Signed-off-by: Pavel Machek --- Documentation/devicetree/bindings/leds/leds-is31fl319x.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt b/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt index fc2603484544..676d43ec8169 100644 --- a/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt +++ b/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt @@ -16,6 +16,7 @@ Optional properties: - audio-gain-db : audio gain selection for external analog modulation input. Valid values: 0 - 21, step by 3 (rounded down) Default: 0 +- shutdown-gpios : Specifier of the GPIO connected to SDB pin of the chip. Each led is represented as a sub-node of the issi,is31fl319x device. There can be less leds subnodes than the chip can support but not more. @@ -44,6 +45,7 @@ fancy_leds: leds@65 { #address-cells = <1>; #size-cells = <0>; reg = <0x65>; + shutdown-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; red_aux: led@1 { label = "red:aux"; From 47eaa8ba12cc77895e2591ec57091bed7b3d9817 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 26 Aug 2020 16:50:10 +0200 Subject: [PATCH 13/84] leds: lm3692x: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Pavel Machek --- drivers/leds/leds-lm3692x.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c index e1e2d2b64a56..1d7ea1b76a12 100644 --- a/drivers/leds/leds-lm3692x.c +++ b/drivers/leds/leds-lm3692x.c @@ -394,13 +394,10 @@ static int lm3692x_probe_dt(struct lm3692x_led *led) led->regulator = devm_regulator_get_optional(&led->client->dev, "vled"); if (IS_ERR(led->regulator)) { ret = PTR_ERR(led->regulator); - if (ret != -ENODEV) { - if (ret != -EPROBE_DEFER) - dev_err(&led->client->dev, - "Failed to get vled regulator: %d\n", - ret); - return ret; - } + if (ret != -ENODEV) + return dev_err_probe(&led->client->dev, ret, + "Failed to get vled regulator\n"); + led->regulator = NULL; } From 7e8da60596b26c40483375f75297f45bd81d4096 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 26 Aug 2020 16:50:11 +0200 Subject: [PATCH 14/84] leds: pwm: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Pavel Machek --- drivers/leds/leds-pwm.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index ef7b91bd2064..e35a97c1d828 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -78,13 +78,10 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL); else led_data->pwm = devm_pwm_get(dev, led->name); - if (IS_ERR(led_data->pwm)) { - ret = PTR_ERR(led_data->pwm); - if (ret != -EPROBE_DEFER) - dev_err(dev, "unable to request PWM for %s: %d\n", - led->name, ret); - return ret; - } + if (IS_ERR(led_data->pwm)) + return dev_err_probe(dev, PTR_ERR(led_data->pwm), + "unable to request PWM for %s\n", + led->name); led_data->cdev.brightness_set_blocking = led_pwm_set; From 4582e783a2f481a813aa61178d77b2a5cb8f1d9e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 26 Aug 2020 16:50:12 +0200 Subject: [PATCH 15/84] leds: sgm3140: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Pavel Machek --- drivers/leds/leds-sgm3140.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/leds/leds-sgm3140.c b/drivers/leds/leds-sgm3140.c index 28c8b31fa952..f4f831570f11 100644 --- a/drivers/leds/leds-sgm3140.c +++ b/drivers/leds/leds-sgm3140.c @@ -195,30 +195,21 @@ static int sgm3140_probe(struct platform_device *pdev) priv->flash_gpio = devm_gpiod_get(&pdev->dev, "flash", GPIOD_OUT_LOW); ret = PTR_ERR_OR_ZERO(priv->flash_gpio); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Failed to request flash gpio: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to request flash gpio\n"); priv->enable_gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); ret = PTR_ERR_OR_ZERO(priv->enable_gpio); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Failed to request enable gpio: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to request enable gpio\n"); priv->vin_regulator = devm_regulator_get(&pdev->dev, "vin"); ret = PTR_ERR_OR_ZERO(priv->vin_regulator); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "Failed to request regulator: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to request regulator\n"); child_node = fwnode_get_next_available_child_node(pdev->dev.fwnode, NULL); From 03eb2ca44a95105d1482d5e7471016cf8b383f97 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 26 Aug 2020 16:50:13 +0200 Subject: [PATCH 16/84] leds: tlc591xx: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Pavel Machek --- drivers/leds/leds-tlc591xx.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index 0929f1275814..1dc14051639c 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -213,12 +213,10 @@ tlc591xx_probe(struct i2c_client *client, led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS; err = devm_led_classdev_register_ext(dev, &led->ldev, &init_data); - if (err < 0) { - if (err != -EPROBE_DEFER) - dev_err(dev, "couldn't register LED %s\n", - led->ldev.name); - return err; - } + if (err < 0) + return dev_err_probe(dev, err, + "couldn't register LED %s\n", + led->ldev.name); } return 0; } From de73f275a059a01c5b514c7762bc80821f8df6d9 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Sat, 19 Sep 2020 07:31:44 +0200 Subject: [PATCH 17/84] leds: pwm: Allow automatic labels for DT based devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If LEDs are configured through device tree and the property 'label' is omitted, the label is supposed to be generated from the properties 'function' and 'color' if present. While this works fine for e.g. the 'leds-gpio' driver, it did not for 'leds-pwm'. The reason is, you get this label naming magic only if you add a LED device through 'devm_led_classdev_register_ext()' and pass a pointer to the current device tree node. For the following node from dts the LED appeared as 'led-5' in sysfs before and as 'red:debug' after this change. pwm_leds { compatible = "pwm-leds"; led-5 { function = LED_FUNCTION_DEBUG; color = ; pwms = <&pwm0 2 10000000 0>; max-brightness = <127>; linux,default-trigger = "heartbeat"; panic-indicator; }; }; Signed-off-by: Alexander Dahl Cc: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/leds-pwm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index e35a97c1d828..4a014d296412 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -65,6 +65,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, struct led_pwm *led, struct fwnode_handle *fwnode) { struct led_pwm_data *led_data = &priv->leds[priv->num_leds]; + struct led_init_data init_data = { .fwnode = fwnode }; int ret; led_data->active_low = led->active_low; @@ -87,7 +88,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, pwm_init_state(led_data->pwm, &led_data->pwmstate); - ret = devm_led_classdev_register(dev, &led_data->cdev); + ret = devm_led_classdev_register_ext(dev, &led_data->cdev, &init_data); if (ret) { dev_err(dev, "failed to register PWM led for %s: %d\n", led->name, ret); From f1b0a43bba3d1ed3fcd13478f8cce24c1275ba92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:49 +0200 Subject: [PATCH 18/84] leds: various: compile if COMPILE_TEST=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These drivers can be compiled without modification when COMPILE_TEST=y: cobalt-qube, cobalt-raq, netxbig, ns2 and s3c24xx Signed-off-by: Marek Behún Cc: Pavel Machek Cc: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 4f6464a169d5..96d54e36e3b5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -274,7 +274,7 @@ config LEDS_MT6323 config LEDS_S3C24XX tristate "LED Support for Samsung S3C24XX GPIO LEDs" depends on LEDS_CLASS - depends on ARCH_S3C24XX + depends on ARCH_S3C24XX || COMPILE_TEST help This option enables support for LEDs connected to GPIO lines on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440. @@ -304,13 +304,13 @@ config LEDS_WRAP config LEDS_COBALT_QUBE tristate "LED Support for the Cobalt Qube series front LED" depends on LEDS_CLASS - depends on MIPS_COBALT + depends on MIPS_COBALT || COMPILE_TEST help This option enables support for the front LED on Cobalt Qube series config LEDS_COBALT_RAQ bool "LED Support for the Cobalt Raq series" - depends on LEDS_CLASS=y && MIPS_COBALT + depends on LEDS_CLASS=y && (MIPS_COBALT || COMPILE_TEST) select LEDS_TRIGGERS help This option enables support for the Cobalt Raq series LEDs. @@ -644,7 +644,7 @@ config LEDS_MC13783 config LEDS_NS2 tristate "LED support for Network Space v2 GPIO LEDs" depends on LEDS_CLASS - depends on MACH_KIRKWOOD || MACH_ARMADA_370 + depends on MACH_KIRKWOOD || MACH_ARMADA_370 || COMPILE_TEST default y help This option enables support for the dual-GPIO LEDs found on the @@ -658,7 +658,7 @@ config LEDS_NS2 config LEDS_NETXBIG tristate "LED support for Big Network series LEDs" depends on LEDS_CLASS - depends on MACH_KIRKWOOD + depends on MACH_KIRKWOOD || COMPILE_TEST depends on OF_GPIO default y help From 2aebb78040e741949ac71f1203f003351061b93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:50 +0200 Subject: [PATCH 19/84] leds: ip30: compile if COMPILE_TEST=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver can be compiled on other platforms with small change if COMPILE_TEST=y. Signed-off-by: Marek Behún Cc: Pavel Machek Cc: Dan Murphy Cc: Thomas Bogendoerfer Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 2 +- drivers/leds/leds-ip30.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 96d54e36e3b5..a008170e73cd 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -905,7 +905,7 @@ config LEDS_TPS6105X config LEDS_IP30 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS - depends on SGI_MFD_IOC3 + depends on SGI_MFD_IOC3 || COMPILE_TEST help This option enables support for the Red and White LEDs of SGI Octane machines. diff --git a/drivers/leds/leds-ip30.c b/drivers/leds/leds-ip30.c index d4ec7361c616..1f952bad0fe8 100644 --- a/drivers/leds/leds-ip30.c +++ b/drivers/leds/leds-ip30.c @@ -3,6 +3,7 @@ * LED Driver for SGI Octane machines */ +#include #include #include #include From 2779f4724b2ff0f296313e5987d10a6ec2c2ebd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:52 +0200 Subject: [PATCH 20/84] leds: various: use device_get_match_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simply use device_get_match_data instead of matching against the match table again. Signed-off-by: Marek Behún Cc: H. Nikolaus Schaller Cc: David Rivshin Cc: Sebastian Reichel Cc: Christian Mauderer Cc: Andrew Lunn Signed-off-by: Pavel Machek --- drivers/leds/leds-cpcap.c | 7 +------ drivers/leds/leds-is31fl319x.c | 12 ++---------- drivers/leds/leds-is31fl32xx.c | 7 +------ drivers/leds/leds-spi-byte.c | 7 +------ drivers/leds/leds-tlc591xx.c | 7 +------ 5 files changed, 6 insertions(+), 34 deletions(-) diff --git a/drivers/leds/leds-cpcap.c b/drivers/leds/leds-cpcap.c index 9f3fa4737213..7d41ce8c9bb1 100644 --- a/drivers/leds/leds-cpcap.c +++ b/drivers/leds/leds-cpcap.c @@ -158,19 +158,14 @@ MODULE_DEVICE_TABLE(of, cpcap_led_of_match); static int cpcap_led_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct cpcap_led *led; int err; - match = of_match_device(of_match_ptr(cpcap_led_of_match), &pdev->dev); - if (!match || !match->data) - return -EINVAL; - led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; platform_set_drvdata(pdev, led); - led->info = match->data; + led->info = device_get_match_data(&pdev->dev); led->dev = &pdev->dev; if (led->info->reg == 0x0000) { diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index 54ac50740d43..b039ffa33559 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -203,7 +203,6 @@ static int is31fl319x_parse_dt(struct device *dev, struct is31fl319x_chip *is31) { struct device_node *np = dev->of_node, *child; - const struct of_device_id *of_dev_id; int count; int ret; @@ -219,18 +218,11 @@ static int is31fl319x_parse_dt(struct device *dev, return ret; } - of_dev_id = of_match_device(of_is31fl319x_match, dev); - if (!of_dev_id) { - dev_err(dev, "Failed to match device with supported chips\n"); - return -EINVAL; - } - - is31->cdef = of_dev_id->data; + is31->cdef = device_get_match_data(dev); count = of_get_child_count(np); - dev_dbg(dev, "probe %s with %d leds defined in DT\n", - of_dev_id->compatible, count); + dev_dbg(dev, "probing with %d leds defined in DT\n", count); if (!count || count > is31->cdef->num_leds) { dev_err(dev, "Number of leds defined must be between 1 and %u\n", diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index cd768f991da1..acf51e17e8df 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -428,17 +428,12 @@ static int is31fl32xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct is31fl32xx_chipdef *cdef; - const struct of_device_id *of_dev_id; struct device *dev = &client->dev; struct is31fl32xx_priv *priv; int count; int ret = 0; - of_dev_id = of_match_device(of_is31fl32xx_match, dev); - if (!of_dev_id) - return -EINVAL; - - cdef = of_dev_id->data; + cdef = device_get_match_data(dev); count = of_get_child_count(dev->of_node); if (!count) diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index b231b563b7bb..9632eb84f8de 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -80,7 +80,6 @@ static int spi_byte_brightness_set_blocking(struct led_classdev *dev, static int spi_byte_probe(struct spi_device *spi) { - const struct of_device_id *of_dev_id; struct device_node *child; struct device *dev = &spi->dev; struct spi_byte_led *led; @@ -88,10 +87,6 @@ static int spi_byte_probe(struct spi_device *spi) const char *state; int ret; - of_dev_id = of_match_device(spi_byte_dt_ids, dev); - if (!of_dev_id) - return -EINVAL; - if (of_get_child_count(dev->of_node) != 1) { dev_err(dev, "Device must have exactly one LED sub-node."); return -EINVAL; @@ -106,7 +101,7 @@ static int spi_byte_probe(struct spi_device *spi) strlcpy(led->name, name, sizeof(led->name)); led->spi = spi; mutex_init(&led->mutex); - led->cdef = of_dev_id->data; + led->cdef = device_get_match_data(dev); led->ldev.name = led->name; led->ldev.brightness = LED_OFF; led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value; diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index 1dc14051639c..aeedf1aa6297 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -150,16 +150,11 @@ tlc591xx_probe(struct i2c_client *client, { struct device_node *np = client->dev.of_node, *child; struct device *dev = &client->dev; - const struct of_device_id *match; const struct tlc591xx *tlc591xx; struct tlc591xx_priv *priv; int err, count, reg; - match = of_match_device(of_tlc591xx_leds_match, dev); - if (!match) - return -ENODEV; - - tlc591xx = match->data; + tlc591xx = device_get_match_data(dev); if (!np) return -ENODEV; From 8853c95e997e0a3621bd8718bdaded81ed37bc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:54 +0200 Subject: [PATCH 21/84] leds: various: use dev_of_node(dev) instead of dev->of_node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dev_of_node function should be preferred. Signed-off-by: Marek Behún Cc: Orson Zhai Cc: Baolin Wang Cc: Chunyan Zhang Cc: Sean Wang Cc: Matthias Brugger Cc: Riku Voipio Signed-off-by: Pavel Machek --- drivers/leds/leds-88pm860x.c | 4 ++-- drivers/leds/leds-aat1290.c | 2 +- drivers/leds/leds-an30259a.c | 2 +- drivers/leds/leds-aw2013.c | 2 +- drivers/leds/leds-bcm6328.c | 2 +- drivers/leds/leds-bcm6358.c | 2 +- drivers/leds/leds-is31fl319x.c | 2 +- drivers/leds/leds-is31fl32xx.c | 4 ++-- drivers/leds/leds-ktd2692.c | 4 ++-- drivers/leds/leds-lp5521.c | 2 +- drivers/leds/leds-lp5523.c | 2 +- drivers/leds/leds-lp5562.c | 2 +- drivers/leds/leds-lp8501.c | 2 +- drivers/leds/leds-lp8860.c | 2 +- drivers/leds/leds-lt3593.c | 2 +- drivers/leds/leds-max77693.c | 2 +- drivers/leds/leds-mc13783.c | 4 ++-- drivers/leds/leds-mt6323.c | 2 +- drivers/leds/leds-netxbig.c | 2 +- drivers/leds/leds-ns2.c | 2 +- drivers/leds/leds-pca9532.c | 2 +- drivers/leds/leds-pm8058.c | 2 +- drivers/leds/leds-sc27xx-bltc.c | 2 +- drivers/leds/leds-spi-byte.c | 4 ++-- drivers/leds/leds-syscon.c | 4 ++-- drivers/leds/leds-tca6507.c | 4 ++-- drivers/leds/leds-tlc591xx.c | 2 +- drivers/leds/leds-turris-omnia.c | 2 +- 28 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 465c3755cf2e..2d1b3269e0f7 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -118,9 +118,9 @@ static int pm860x_led_dt_init(struct platform_device *pdev, struct device_node *nproot, *np; int iset = 0; - if (!pdev->dev.parent->of_node) + if (!dev_of_node(pdev->dev.parent)) return -ENODEV; - nproot = of_get_child_by_name(pdev->dev.parent->of_node, "leds"); + nproot = of_get_child_by_name(dev_of_node(pdev->dev.parent), "leds"); if (!nproot) { dev_err(&pdev->dev, "failed to find leds node\n"); return -ENODEV; diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c index 5a0fe7b7b8bc..589484b22c79 100644 --- a/drivers/leds/leds-aat1290.c +++ b/drivers/leds/leds-aat1290.c @@ -248,7 +248,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led, } #endif - child_node = of_get_next_available_child(dev->of_node, NULL); + child_node = of_get_next_available_child(dev_of_node(dev), NULL); if (!child_node) { dev_err(dev, "No DT child node found for connected LED.\n"); return -EINVAL; diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 82350a28a564..8ec23ccd02d6 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -202,7 +202,7 @@ error: static int an30259a_dt_init(struct i2c_client *client, struct an30259a *chip) { - struct device_node *np = client->dev.of_node, *child; + struct device_node *np = dev_of_node(&client->dev), *child; int count, ret; int i = 0; const char *str; diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index d709cc1f949e..3aeed4f68a8a 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -261,7 +261,7 @@ out: static int aw2013_probe_dt(struct aw2013 *chip) { - struct device_node *np = chip->client->dev.of_node, *child; + struct device_node *np = dev_of_node(&chip->client->dev), *child; int count, ret = 0, i = 0; struct aw2013_led *led; diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index bad7efb75112..73b385d03c0e 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -395,7 +395,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, static int bcm6328_leds_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev_of_node(&pdev->dev); struct device_node *child; void __iomem *mem; spinlock_t *lock; /* memory lock */ diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c index 94fefd456ba0..2f71f4b5b72e 100644 --- a/drivers/leds/leds-bcm6358.c +++ b/drivers/leds/leds-bcm6358.c @@ -149,7 +149,7 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, static int bcm6358_leds_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev_of_node(&pdev->dev); struct device_node *child; void __iomem *mem; spinlock_t *lock; /* memory lock */ diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index b039ffa33559..e6d185ad0b7e 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -202,7 +202,7 @@ static int is31fl319x_parse_child_dt(const struct device *dev, static int is31fl319x_parse_dt(struct device *dev, struct is31fl319x_chip *is31) { - struct device_node *np = dev->of_node, *child; + struct device_node *np = dev_of_node(dev), *child; int count; int ret; diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index acf51e17e8df..82bbf0290ff9 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -372,7 +372,7 @@ static int is31fl32xx_parse_dt(struct device *dev, struct device_node *child; int ret = 0; - for_each_child_of_node(dev->of_node, child) { + for_each_child_of_node(dev_of_node(dev), child) { struct is31fl32xx_led_data *led_data = &priv->leds[priv->num_leds]; const struct is31fl32xx_led_data *other_led_data; @@ -435,7 +435,7 @@ static int is31fl32xx_probe(struct i2c_client *client, cdef = device_get_match_data(dev); - count = of_get_child_count(dev->of_node); + count = of_get_child_count(dev_of_node(dev)); if (!count) return -EINVAL; diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c index 670efee9b131..632f10db4b3f 100644 --- a/drivers/leds/leds-ktd2692.c +++ b/drivers/leds/leds-ktd2692.c @@ -259,11 +259,11 @@ static void ktd2692_setup(struct ktd2692_context *led) static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, struct ktd2692_led_config_data *cfg) { - struct device_node *np = dev->of_node; + struct device_node *np = dev_of_node(dev); struct device_node *child_node; int ret; - if (!dev->of_node) + if (!dev_of_node(dev)) return -ENXIO; led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index ef8c3bfa8f3c..a9e7507c998c 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -523,7 +523,7 @@ static int lp5521_probe(struct i2c_client *client, struct lp55xx_chip *chip; struct lp55xx_led *led; struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index f55d97258d5e..fc433e63b1dc 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -891,7 +891,7 @@ static int lp5523_probe(struct i2c_client *client, struct lp55xx_chip *chip; struct lp55xx_led *led; struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 7ecdd199d7ef..31c14016d289 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -518,7 +518,7 @@ static int lp5562_probe(struct i2c_client *client, struct lp55xx_chip *chip; struct lp55xx_led *led; struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c index ac2c31db4a65..2d2fda2ab104 100644 --- a/drivers/leds/leds-lp8501.c +++ b/drivers/leds/leds-lp8501.c @@ -306,7 +306,7 @@ static int lp8501_probe(struct i2c_client *client, struct lp55xx_chip *chip; struct lp55xx_led *led; struct lp55xx_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index ac2f5d6272dc..e9b16f3358d6 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -380,7 +380,7 @@ static int lp8860_probe(struct i2c_client *client, { int ret; struct lp8860_led *led; - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); struct device_node *child_node; struct led_init_data init_data = {}; diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 9079850e6ea4..c2d7ffebacc5 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -68,7 +68,7 @@ static int lt3593_led_probe(struct platform_device *pdev) struct led_init_data init_data = {}; const char *tmp; - if (!dev->of_node) + if (!dev_of_node(dev)) return -ENODEV; led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL); diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c index fec56090c2ba..5c1faeb55a31 100644 --- a/drivers/leds/leds-max77693.c +++ b/drivers/leds/leds-max77693.c @@ -599,7 +599,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led, { struct device *dev = &led->pdev->dev; struct max77693_sub_led *sub_leds = led->sub_leds; - struct device_node *node = dev->of_node, *child_node; + struct device_node *node = dev_of_node(dev), *child_node; struct property *prop; u32 led_sources[2]; int i, ret, fled_id; diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 5cd810c545f3..ee37f4a2d65b 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -121,7 +121,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( if (!pdata) return ERR_PTR(-ENOMEM); - parent = of_get_child_by_name(dev->parent->of_node, "leds"); + parent = of_get_child_by_name(dev_of_node(dev->parent), "leds"); if (!parent) goto out_node_put; @@ -192,7 +192,7 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev) leds->master = mcdev; platform_set_drvdata(pdev, leds); - if (dev->parent->of_node) { + if (dev_of_node(dev->parent)) { pdata = mc13xxx_led_probe_dt(pdev); if (IS_ERR(pdata)) return PTR_ERR(pdata); diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index 7b240771e45b..88deec9d0ef4 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -369,7 +369,7 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev, static int mt6323_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev_of_node(&pdev->dev); struct device_node *child; struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); struct mt6323_leds *leds; diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index ceceeb6a0e96..9a3b2d15764d 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -419,7 +419,7 @@ static int netxbig_gpio_ext_get(struct device *dev, static int netxbig_leds_get_of_pdata(struct device *dev, struct netxbig_led_platform_data *pdata) { - struct device_node *np = dev->of_node; + struct device_node *np = dev_of_node(dev); struct device_node *gpio_ext_np; struct platform_device *gpio_ext_pdev; struct device *gpio_ext_dev; diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index bd806e7c8017..9cbd2d7251af 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -246,7 +246,7 @@ static void delete_ns2_led(struct ns2_led_data *led_dat) static int ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) { - struct device_node *np = dev->of_node; + struct device_node *np = dev_of_node(dev); struct device_node *child; struct ns2_led *led, *leds; int ret, num_leds = 0; diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 7d515d5e57bd..b1ae34e50958 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -507,7 +507,7 @@ static int pca9532_probe(struct i2c_client *client, struct pca9532_data *data = i2c_get_clientdata(client); struct pca9532_platform_data *pca9532_pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct device_node *np = dev_of_node(&client->dev); if (!pca9532_pdata) { if (np) { diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index 7869ccdf70ce..69a7f7e63ea7 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -88,7 +88,7 @@ static enum led_brightness pm8058_led_get(struct led_classdev *cled) static int pm8058_led_probe(struct platform_device *pdev) { struct pm8058_led *led; - struct device_node *np = pdev->dev.of_node; + struct device_node *np = dev_of_node(&pdev->dev); int ret; struct regmap *map; const char *state; diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c index 0ede87420bfc..f8fe09ecd0d1 100644 --- a/drivers/leds/leds-sc27xx-bltc.c +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -276,7 +276,7 @@ static int sc27xx_led_register(struct device *dev, struct sc27xx_led_priv *priv) static int sc27xx_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node, *child; + struct device_node *np = dev_of_node(dev), *child; struct sc27xx_led_priv *priv; u32 base, count, reg; int err; diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index 9632eb84f8de..ecfd349fa53b 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -87,11 +87,11 @@ static int spi_byte_probe(struct spi_device *spi) const char *state; int ret; - if (of_get_child_count(dev->of_node) != 1) { + if (of_get_child_count(dev_of_node(dev)) != 1) { dev_err(dev, "Device must have exactly one LED sub-node."); return -EINVAL; } - child = of_get_next_child(dev->of_node, NULL); + child = of_get_next_child(dev_of_node(dev), NULL); led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index b58f3cafe16f..d7230da81543 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -56,7 +56,7 @@ static void syscon_led_set(struct led_classdev *led_cdev, static int syscon_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct device_node *np = dev_of_node(dev); struct device *parent; struct regmap *map; struct syscon_led *sled; @@ -68,7 +68,7 @@ static int syscon_led_probe(struct platform_device *pdev) dev_err(dev, "no parent for syscon LED\n"); return -ENODEV; } - map = syscon_node_to_regmap(parent->of_node); + map = syscon_node_to_regmap(dev_of_node(parent)); if (IS_ERR(map)) { dev_err(dev, "no regmap for syscon LED parent\n"); return PTR_ERR(map); diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 1128ac75443c..d44b64af6d6e 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -656,7 +656,7 @@ static int tca6507_probe_gpios(struct i2c_client *client, tca->gpio.set = tca6507_gpio_set_value; tca->gpio.parent = &client->dev; #ifdef CONFIG_OF_GPIO - tca->gpio.of_node = of_node_get(client->dev.of_node); + tca->gpio.of_node = of_node_get(dev_of_node(&client->dev)); #endif err = gpiochip_add_data(&tca->gpio, tca); if (err) { @@ -689,7 +689,7 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) static struct tca6507_platform_data * tca6507_led_dt_init(struct i2c_client *client) { - struct device_node *np = client->dev.of_node, *child; + struct device_node *np = dev_of_node(&client->dev), *child; struct tca6507_platform_data *pdata; struct led_info *tca_leds; int count; diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index aeedf1aa6297..f4d5785f0068 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -148,7 +148,7 @@ static int tlc591xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct device_node *np = client->dev.of_node, *child; + struct device_node *np = dev_of_node(&client->dev), *child; struct device *dev = &client->dev; const struct tlc591xx *tlc591xx; struct tlc591xx_priv *priv; diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index bb23d8e16614..ea7da8517220 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -210,7 +210,7 @@ static int omnia_leds_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct device_node *np = dev->of_node, *child; + struct device_node *np = dev_of_node(dev), *child; struct omnia_leds *leds; struct omnia_led *led; int ret, count; From 05dec742bd20e8284e57559d53d38cffc2054fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:55 +0200 Subject: [PATCH 22/84] leds: lt3593: do not rewrite .of_node of new LED device to wrong value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The devm_led_classdev_register_ext is given init_data with fwnode set, so the LED core sets .of_node of the new LED classdev correctly. Do not rewrite this value to parent of_node. Signed-off-by: Marek Behún Cc: Daniel Mack Signed-off-by: Pavel Machek --- drivers/leds/leds-lt3593.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index c2d7ffebacc5..061f02e3995a 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -107,7 +107,6 @@ static int lt3593_led_probe(struct platform_device *pdev) return ret; } - led_data->cdev.dev->of_node = dev->of_node; platform_set_drvdata(pdev, led_data); return 0; From 99a013c840a05083fd82d220685af7579238bfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:56 +0200 Subject: [PATCH 23/84] leds: various: use only available OF children MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various drivers count and iterate over OF children nodes via of_get_child_count and for_each_child_of_node. Instead they should use of_get_available_child_count and for_each_available_child_of_node, so that if a given node has the `status` property set to `disabled`, the child will be ignored. Signed-off-by: Marek Behún Cc: Andrew Lunn Cc: Andrey Utkin Cc: Baolin Wang Cc: Baolin Wang Cc: Benjamin Herrenschmidt Cc: Christian Mauderer Cc: Chunyan Zhang Cc: Dan Murphy Cc: David Rivshin Cc: Haojian Zhuang Cc: H. Nikolaus Schaller Cc: Michael Ellerman Cc: Milo Kim Cc: NeilBrown Cc: Nikita Travkin Cc: Orson Zhai Cc: Paul Mackerras Cc: Philippe Retornaz Cc: Riku Voipio Cc: Simon Guinot Cc: Simon Shields Cc: Vasant Hegde Cc: Xiaotong Lu Signed-off-by: Pavel Machek --- drivers/leds/leds-88pm860x.c | 2 +- drivers/leds/leds-an30259a.c | 2 +- drivers/leds/leds-aw2013.c | 2 +- drivers/leds/leds-is31fl319x.c | 4 ++-- drivers/leds/leds-is31fl32xx.c | 4 ++-- drivers/leds/leds-lp55xx-common.c | 6 +++--- drivers/leds/leds-mc13783.c | 4 ++-- drivers/leds/leds-netxbig.c | 4 ++-- drivers/leds/leds-ns2.c | 4 ++-- drivers/leds/leds-pca9532.c | 2 +- drivers/leds/leds-powernv.c | 2 +- drivers/leds/leds-sc27xx-bltc.c | 4 ++-- drivers/leds/leds-spi-byte.c | 4 ++-- drivers/leds/leds-tca6507.c | 4 ++-- drivers/leds/leds-tlc591xx.c | 4 ++-- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 2d1b3269e0f7..508d0d859f2e 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -125,7 +125,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev, dev_err(&pdev->dev, "failed to find leds node\n"); return -ENODEV; } - for_each_child_of_node(nproot, np) { + for_each_available_child_of_node(nproot, np) { if (of_node_name_eq(np, data->name)) { of_property_read_u32(np, "marvell,88pm860x-iset", &iset); diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 8ec23ccd02d6..9749f1cc3e15 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -208,7 +208,7 @@ static int an30259a_dt_init(struct i2c_client *client, const char *str; struct an30259a_led *led; - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count || count > AN30259A_MAX_LEDS) return -EINVAL; diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 3aeed4f68a8a..9df7de042bca 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -265,7 +265,7 @@ static int aw2013_probe_dt(struct aw2013 *chip) int count, ret = 0, i = 0; struct aw2013_led *led; - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count || count > AW2013_MAX_LEDS) return -EINVAL; diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index e6d185ad0b7e..4161b9dd7e48 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -220,7 +220,7 @@ static int is31fl319x_parse_dt(struct device *dev, is31->cdef = device_get_match_data(dev); - count = of_get_child_count(np); + count = of_get_available_child_count(np); dev_dbg(dev, "probing with %d leds defined in DT\n", count); @@ -230,7 +230,7 @@ static int is31fl319x_parse_dt(struct device *dev, return -ENODEV; } - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct is31fl319x_led *led; u32 reg; diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index 82bbf0290ff9..b3faf050eece 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -372,7 +372,7 @@ static int is31fl32xx_parse_dt(struct device *dev, struct device_node *child; int ret = 0; - for_each_child_of_node(dev_of_node(dev), child) { + for_each_available_child_of_node(dev_of_node(dev), child) { struct is31fl32xx_led_data *led_data = &priv->leds[priv->num_leds]; const struct is31fl32xx_led_data *other_led_data; @@ -435,7 +435,7 @@ static int is31fl32xx_probe(struct i2c_client *client, cdef = device_get_match_data(dev); - count = of_get_child_count(dev_of_node(dev)); + count = of_get_available_child_count(dev_of_node(dev)); if (!count) return -EINVAL; diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 56210f4ad919..50f7f5b87463 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -611,7 +611,7 @@ static int lp55xx_parse_multi_led(struct device_node *np, struct device_node *child; int num_colors = 0, ret; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { ret = lp55xx_parse_multi_led_child(child, cfg, child_number, num_colors); if (ret) @@ -665,7 +665,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, if (!pdata) return ERR_PTR(-ENOMEM); - num_channels = of_get_child_count(np); + num_channels = of_get_available_child_count(np); if (num_channels == 0) { dev_err(dev, "no LED channels\n"); return ERR_PTR(-EINVAL); @@ -679,7 +679,7 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, pdata->num_channels = num_channels; cfg->max_channel = chip->cfg->max_channel; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { ret = lp55xx_parse_logical_led(child, cfg, i); if (ret) return ERR_PTR(-EINVAL); diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index ee37f4a2d65b..675502c15c2b 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -131,7 +131,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( if (ret) goto out_node_put; - pdata->num_leds = of_get_child_count(parent); + pdata->num_leds = of_get_available_child_count(parent); pdata->led = devm_kcalloc(dev, pdata->num_leds, sizeof(*pdata->led), GFP_KERNEL); @@ -140,7 +140,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt( goto out_node_put; } - for_each_child_of_node(parent, child) { + for_each_available_child_of_node(parent, child) { const char *str; u32 tmp; diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index 9a3b2d15764d..e6fd47365b58 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -485,7 +485,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev, } /* LEDs */ - num_leds = of_get_child_count(np); + num_leds = of_get_available_child_count(np); if (!num_leds) { dev_err(dev, "No LED subnodes found in DT\n"); return -ENODEV; @@ -496,7 +496,7 @@ static int netxbig_leds_get_of_pdata(struct device *dev, return -ENOMEM; led = leds; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { const char *string; int *mode_val; int num_modes; diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 9cbd2d7251af..22d38c83b6dc 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -251,7 +251,7 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) struct ns2_led *led, *leds; int ret, num_leds = 0; - num_leds = of_get_child_count(np); + num_leds = of_get_available_child_count(np); if (!num_leds) return -ENODEV; @@ -261,7 +261,7 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) return -ENOMEM; led = leds; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { const char *string; int i, num_modes; struct ns2_led_modval *modval; diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index b1ae34e50958..f834550999dd 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -478,7 +478,7 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np) if (!pdata) return ERR_PTR(-ENOMEM); - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { if (of_property_read_string(child, "label", &pdata->leds[i].name)) pdata->leds[i].name = child->name; diff --git a/drivers/leds/leds-powernv.c b/drivers/leds/leds-powernv.c index cd43d5dff7f4..743e2cdd0891 100644 --- a/drivers/leds/leds-powernv.c +++ b/drivers/leds/leds-powernv.c @@ -250,7 +250,7 @@ static int powernv_led_classdev(struct platform_device *pdev, struct powernv_led_data *powernv_led; struct device *dev = &pdev->dev; - for_each_child_of_node(led_node, np) { + for_each_available_child_of_node(led_node, np) { p = of_find_property(np, "led-types", NULL); while ((cur = of_prop_next_string(p, cur)) != NULL) { diff --git a/drivers/leds/leds-sc27xx-bltc.c b/drivers/leds/leds-sc27xx-bltc.c index f8fe09ecd0d1..e199ea15e406 100644 --- a/drivers/leds/leds-sc27xx-bltc.c +++ b/drivers/leds/leds-sc27xx-bltc.c @@ -281,7 +281,7 @@ static int sc27xx_led_probe(struct platform_device *pdev) u32 base, count, reg; int err; - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count || count > SC27XX_LEDS_MAX) return -EINVAL; @@ -305,7 +305,7 @@ static int sc27xx_led_probe(struct platform_device *pdev) return err; } - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { err = of_property_read_u32(child, "reg", ®); if (err) { of_node_put(child); diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index ecfd349fa53b..f1964c96fb15 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -87,11 +87,11 @@ static int spi_byte_probe(struct spi_device *spi) const char *state; int ret; - if (of_get_child_count(dev_of_node(dev)) != 1) { + if (of_get_available_child_count(dev_of_node(dev)) != 1) { dev_err(dev, "Device must have exactly one LED sub-node."); return -EINVAL; } - child = of_get_next_child(dev_of_node(dev), NULL); + child = of_get_next_available_child(dev_of_node(dev), NULL); led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index d44b64af6d6e..a7e9fd85b6dd 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -694,7 +694,7 @@ tca6507_led_dt_init(struct i2c_client *client) struct led_info *tca_leds; int count; - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count || count > NUM_LEDS) return ERR_PTR(-ENODEV); @@ -703,7 +703,7 @@ tca6507_led_dt_init(struct i2c_client *client) if (!tca_leds) return ERR_PTR(-ENOMEM); - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct led_info led; u32 reg; int ret; diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index f4d5785f0068..5e84a0c7aacb 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -158,7 +158,7 @@ tlc591xx_probe(struct i2c_client *client, if (!np) return -ENODEV; - count = of_get_child_count(np); + count = of_get_available_child_count(np); if (!count || count > tlc591xx->max_leds) return -EINVAL; @@ -180,7 +180,7 @@ tlc591xx_probe(struct i2c_client *client, if (err < 0) return err; - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { struct tlc591xx_led *led; struct led_init_data init_data = {}; From 2c67756254349d2b4a1af92c846e32f7e15fae89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:57 +0200 Subject: [PATCH 24/84] leds: various: fix OF node leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix OF node leaks by calling of_node_put in for_each_available_child_of_node when the cycle breaks or returns. Signed-off-by: Marek Behún Cc: Nikita Travkin Cc: Milo Kim Cc: Dan Murphy Signed-off-by: Pavel Machek Not-for-stable: untested, theoretical, insignificant leaks --- drivers/leds/leds-aw2013.c | 4 +++- drivers/leds/leds-lp55xx-common.c | 8 ++++++-- drivers/leds/leds-turris-omnia.c | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 9df7de042bca..927c5ba32592 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -305,8 +305,10 @@ static int aw2013_probe_dt(struct aw2013 *chip) ret = devm_led_classdev_register_ext(&chip->client->dev, &led->cdev, &init_data); - if (ret < 0) + if (ret < 0) { + of_node_put(child); return ret; + } i++; } diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c index 50f7f5b87463..81de1346bf5d 100644 --- a/drivers/leds/leds-lp55xx-common.c +++ b/drivers/leds/leds-lp55xx-common.c @@ -614,8 +614,10 @@ static int lp55xx_parse_multi_led(struct device_node *np, for_each_available_child_of_node(np, child) { ret = lp55xx_parse_multi_led_child(child, cfg, child_number, num_colors); - if (ret) + if (ret) { + of_node_put(child); return ret; + } num_colors++; } @@ -681,8 +683,10 @@ struct lp55xx_platform_data *lp55xx_of_populate_pdata(struct device *dev, for_each_available_child_of_node(np, child) { ret = lp55xx_parse_logical_led(child, cfg, i); - if (ret) + if (ret) { + of_node_put(child); return ERR_PTR(-EINVAL); + } i++; } diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index ea7da8517220..117976cf75c8 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -236,8 +236,10 @@ static int omnia_leds_probe(struct i2c_client *client, led = &leds->leds[0]; for_each_available_child_of_node(np, child) { ret = omnia_led_register(client, led, child); - if (ret < 0) + if (ret < 0) { + of_node_put(child); return ret; + } led += ret; } From ff5c89d44453e7ad99502b04bf798a3fc32c758b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:58 +0200 Subject: [PATCH 25/84] leds: bcm6328, bcm6358: use devres LED registering function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These two drivers do not provide remove method and use devres for allocation of other resources, yet they use led_classdev_register instead of the devres variant, devm_led_classdev_register. Fix this. Signed-off-by: Marek Behún Cc: Álvaro Fernández Rojas Cc: Kevin Cernekee Cc: Jaedon Shin Signed-off-by: Pavel Machek Cc: stable@kernel.org --- drivers/leds/leds-bcm6328.c | 2 +- drivers/leds/leds-bcm6358.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index 73b385d03c0e..d590a2d00bfd 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -383,7 +383,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, led->cdev.brightness_set = bcm6328_led_set; led->cdev.blink_set = bcm6328_blink_set; - rc = led_classdev_register(dev, &led->cdev); + rc = devm_led_classdev_register(dev, &led->cdev); if (rc < 0) return rc; diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c index 2f71f4b5b72e..eeec4f9c8fb7 100644 --- a/drivers/leds/leds-bcm6358.c +++ b/drivers/leds/leds-bcm6358.c @@ -137,7 +137,7 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, led->cdev.brightness_set = bcm6358_led_set; - rc = led_classdev_register(dev, &led->cdev); + rc = devm_led_classdev_register(dev, &led->cdev); if (rc < 0) return rc; From e4e912a349b2e194b15163bef5d70fd1e67a7769 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:32:59 +0200 Subject: [PATCH 26/84] leds: bcm6328, bcm6358: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Signed-off-by: Marek Behún Cc: Álvaro Fernández Rojas Cc: Kevin Cernekee Cc: Jaedon Shin Signed-off-by: Pavel Machek --- drivers/leds/leds-bcm6328.c | 5 +++-- drivers/leds/leds-bcm6358.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index d590a2d00bfd..d79aeb956c9b 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -328,6 +328,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, void __iomem *mem, spinlock_t *lock, unsigned long *blink_leds, unsigned long *blink_delay) { + struct led_init_data init_data = {}; struct bcm6328_led *led; const char *state; int rc; @@ -345,7 +346,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, if (of_property_read_bool(nc, "active-low")) led->active_low = true; - led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name; led->cdev.default_trigger = of_get_property(nc, "linux,default-trigger", NULL); @@ -382,8 +382,9 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, led->cdev.brightness_set = bcm6328_led_set; led->cdev.blink_set = bcm6328_blink_set; + init_data.fwnode = of_fwnode_handle(nc); - rc = devm_led_classdev_register(dev, &led->cdev); + rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (rc < 0) return rc; diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c index eeec4f9c8fb7..0fd495103a4d 100644 --- a/drivers/leds/leds-bcm6358.c +++ b/drivers/leds/leds-bcm6358.c @@ -94,6 +94,7 @@ static void bcm6358_led_set(struct led_classdev *led_cdev, static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, void __iomem *mem, spinlock_t *lock) { + struct led_init_data init_data = {}; struct bcm6358_led *led; const char *state; int rc; @@ -109,7 +110,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, if (of_property_read_bool(nc, "active-low")) led->active_low = true; - led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name; led->cdev.default_trigger = of_get_property(nc, "linux,default-trigger", NULL); @@ -136,8 +136,9 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, bcm6358_led_set(&led->cdev, led->cdev.brightness); led->cdev.brightness_set = bcm6358_led_set; + init_data.fwnode = of_fwnode_handle(nc); - rc = devm_led_classdev_register(dev, &led->cdev); + rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (rc < 0) return rc; From 3a953dc330e9ce9c00dc040e59faf66222f0c3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:02 +0200 Subject: [PATCH 27/84] leds: lm3697: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Previously if the `label` DT property was not present, the code composed name for the LED in the form "parent_name::" For backwards compatibility we therefore set init_data->default_label = ":"; so that the LED will not get a different name if `label` property is not present. Signed-off-by: Marek Behún Cc: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm3697.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 024983088d59..623e084c3b53 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -194,7 +194,6 @@ static int lm3697_probe_dt(struct lm3697 *priv) { struct fwnode_handle *child = NULL; struct lm3697_led *led; - const char *name; int control_bank; size_t i = 0; int ret = -EINVAL; @@ -214,6 +213,8 @@ static int lm3697_probe_dt(struct lm3697 *priv) priv->regulator = NULL; device_for_each_child_node(priv->dev, child) { + struct led_init_data init_data = {}; + ret = fwnode_property_read_u32(child, "reg", &control_bank); if (ret) { dev_err(&priv->client->dev, "reg property missing\n"); @@ -271,20 +272,17 @@ static int lm3697_probe_dt(struct lm3697 *priv) fwnode_property_read_string(child, "linux,default-trigger", &led->led_dev.default_trigger); - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(led->label, sizeof(led->label), - "%s::", priv->client->name); - else - snprintf(led->label, sizeof(led->label), - "%s:%s", priv->client->name, name); + init_data.fwnode = child; + init_data.devicename = priv->client->name; + /* for backwards compatibility if `label` is not present */ + init_data.default_label = ":"; led->priv = priv; - led->led_dev.name = led->label; led->led_dev.max_brightness = led->lmu_data.max_brightness; led->led_dev.brightness_set_blocking = lm3697_brightness_set; - ret = devm_led_classdev_register(priv->dev, &led->led_dev); + ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, + &init_data); if (ret) { dev_err(&priv->client->dev, "led register err: %d\n", ret); From 0b9e3572874802f0519e85832d09058fa1c9dcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:03 +0200 Subject: [PATCH 28/84] leds: lm3697: cosmetic change: use helper variable, reverse christmas tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variable dev instead of always writing &client->dev, or &priv->client->dev, or even &led->priv->client->dev. With one more line moved reverse christmas tree is also achieved. Signed-off-by: Marek Behún Reviewed-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm3697.c | 75 ++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 623e084c3b53..a7779ce931ab 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -115,6 +115,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev, struct lm3697_led *led = container_of(led_cdev, struct lm3697_led, led_dev); int ctrl_en_val = (1 << led->control_bank); + struct device *dev = led->priv->dev; int ret; mutex_lock(&led->priv->lock); @@ -123,7 +124,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev, ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE, ctrl_en_val, ~ctrl_en_val); if (ret) { - dev_err(&led->priv->client->dev, "Cannot write ctrl register\n"); + dev_err(dev, "Cannot write ctrl register\n"); goto brightness_out; } @@ -131,8 +132,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev, } else { ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val); if (ret) { - dev_err(&led->priv->client->dev, - "Cannot write brightness\n"); + dev_err(dev, "Cannot write brightness\n"); goto brightness_out; } @@ -141,8 +141,7 @@ static int lm3697_brightness_set(struct led_classdev *led_cdev, LM3697_CTRL_ENABLE, ctrl_en_val, ctrl_en_val); if (ret) { - dev_err(&led->priv->client->dev, - "Cannot enable the device\n"); + dev_err(dev, "Cannot enable the device\n"); goto brightness_out; } @@ -157,6 +156,7 @@ brightness_out: static int lm3697_init(struct lm3697 *priv) { + struct device *dev = priv->dev; struct lm3697_led *led; int i, ret; @@ -165,26 +165,26 @@ static int lm3697_init(struct lm3697 *priv) } else { ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET); if (ret) { - dev_err(&priv->client->dev, "Cannot reset the device\n"); + dev_err(dev, "Cannot reset the device\n"); goto out; } } ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0); if (ret) { - dev_err(&priv->client->dev, "Cannot write ctrl enable\n"); + dev_err(dev, "Cannot write ctrl enable\n"); goto out; } ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg); if (ret) - dev_err(&priv->client->dev, "Cannot write OUTPUT config\n"); + dev_err(dev, "Cannot write OUTPUT config\n"); for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) { led = &priv->leds[i]; ret = ti_lmu_common_set_ramp(&led->lmu_data); if (ret) - dev_err(&priv->client->dev, "Setting the ramp rate failed\n"); + dev_err(dev, "Setting the ramp rate failed\n"); } out: return ret; @@ -193,37 +193,37 @@ out: static int lm3697_probe_dt(struct lm3697 *priv) { struct fwnode_handle *child = NULL; + struct device *dev = priv->dev; struct lm3697_led *led; + int ret = -EINVAL; int control_bank; size_t i = 0; - int ret = -EINVAL; int j; - priv->enable_gpio = devm_gpiod_get_optional(&priv->client->dev, - "enable", GPIOD_OUT_LOW); + priv->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(priv->enable_gpio)) { ret = PTR_ERR(priv->enable_gpio); - dev_err(&priv->client->dev, "Failed to get enable gpio: %d\n", - ret); + dev_err(dev, "Failed to get enable gpio: %d\n", ret); return ret; } - priv->regulator = devm_regulator_get(&priv->client->dev, "vled"); + priv->regulator = devm_regulator_get(dev, "vled"); if (IS_ERR(priv->regulator)) priv->regulator = NULL; - device_for_each_child_node(priv->dev, child) { + device_for_each_child_node(dev, child) { struct led_init_data init_data = {}; ret = fwnode_property_read_u32(child, "reg", &control_bank); if (ret) { - dev_err(&priv->client->dev, "reg property missing\n"); + dev_err(dev, "reg property missing\n"); fwnode_handle_put(child); goto child_out; } if (control_bank > LM3697_CONTROL_B) { - dev_err(&priv->client->dev, "reg property is invalid\n"); + dev_err(dev, "reg property is invalid\n"); ret = -EINVAL; fwnode_handle_put(child); goto child_out; @@ -231,10 +231,10 @@ static int lm3697_probe_dt(struct lm3697 *priv) led = &priv->leds[i]; - ret = ti_lmu_common_get_brt_res(&priv->client->dev, - child, &led->lmu_data); + ret = ti_lmu_common_get_brt_res(dev, child, &led->lmu_data); if (ret) - dev_warn(&priv->client->dev, "brightness resolution property missing\n"); + dev_warn(dev, + "brightness resolution property missing\n"); led->control_bank = control_bank; led->lmu_data.regmap = priv->regmap; @@ -247,7 +247,7 @@ static int lm3697_probe_dt(struct lm3697 *priv) led->num_leds = fwnode_property_count_u32(child, "led-sources"); if (led->num_leds > LM3697_MAX_LED_STRINGS) { - dev_err(&priv->client->dev, "Too many LED strings defined\n"); + dev_err(dev, "Too many LED strings defined\n"); continue; } @@ -255,7 +255,7 @@ static int lm3697_probe_dt(struct lm3697 *priv) led->hvled_strings, led->num_leds); if (ret) { - dev_err(&priv->client->dev, "led-sources property missing\n"); + dev_err(dev, "led-sources property missing\n"); fwnode_handle_put(child); goto child_out; } @@ -264,10 +264,9 @@ static int lm3697_probe_dt(struct lm3697 *priv) priv->bank_cfg |= (led->control_bank << led->hvled_strings[j]); - ret = ti_lmu_common_get_ramp_params(&priv->client->dev, - child, &led->lmu_data); + ret = ti_lmu_common_get_ramp_params(dev, child, &led->lmu_data); if (ret) - dev_warn(&priv->client->dev, "runtime-ramp properties missing\n"); + dev_warn(dev, "runtime-ramp properties missing\n"); fwnode_property_read_string(child, "linux,default-trigger", &led->led_dev.default_trigger); @@ -281,11 +280,10 @@ static int lm3697_probe_dt(struct lm3697 *priv) led->led_dev.max_brightness = led->lmu_data.max_brightness; led->led_dev.brightness_set_blocking = lm3697_brightness_set; - ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, + ret = devm_led_classdev_register_ext(dev, &led->led_dev, &init_data); if (ret) { - dev_err(&priv->client->dev, "led register err: %d\n", - ret); + dev_err(dev, "led register err: %d\n", ret); fwnode_handle_put(child); goto child_out; } @@ -300,18 +298,18 @@ child_out: static int lm3697_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct lm3697 *led; int count; int ret; - count = device_get_child_node_count(&client->dev); + count = device_get_child_node_count(dev); if (!count) { - dev_err(&client->dev, "LEDs are not defined in device tree!"); + dev_err(dev, "LEDs are not defined in device tree!"); return -ENODEV; } - led = devm_kzalloc(&client->dev, struct_size(led, leds, count), - GFP_KERNEL); + led = devm_kzalloc(dev, struct_size(led, leds, count), GFP_KERNEL); if (!led) return -ENOMEM; @@ -319,12 +317,11 @@ static int lm3697_probe(struct i2c_client *client, i2c_set_clientdata(client, led); led->client = client; - led->dev = &client->dev; + led->dev = dev; led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config); if (IS_ERR(led->regmap)) { ret = PTR_ERR(led->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - ret); + dev_err(dev, "Failed to allocate register map: %d\n", ret); return ret; } @@ -338,12 +335,13 @@ static int lm3697_probe(struct i2c_client *client, static int lm3697_remove(struct i2c_client *client) { struct lm3697 *led = i2c_get_clientdata(client); + struct device *dev = &led->client->dev; int ret; ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE, LM3697_CTRL_A_B_EN, 0); if (ret) { - dev_err(&led->client->dev, "Failed to disable the device\n"); + dev_err(dev, "Failed to disable the device\n"); return ret; } @@ -353,8 +351,7 @@ static int lm3697_remove(struct i2c_client *client) if (led->regulator) { ret = regulator_disable(led->regulator); if (ret) - dev_err(&led->client->dev, - "Failed to disable regulator\n"); + dev_err(dev, "Failed to disable regulator\n"); } mutex_destroy(&led->lock); From d7d02b8af5bcaacec9e49993049f57faeb41689c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:04 +0200 Subject: [PATCH 29/84] leds: max77650: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Previously if the `label` DT property was not present, the code composed name for the LED in the form "max77650::" For backwards compatibility we therefore set init_data->default_label = ":"; so that the LED will not get a different name if `label` property is not present. Signed-off-by: Marek Behún Cc: Bartosz Golaszewski Signed-off-by: Pavel Machek --- drivers/leds/leds-max77650.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c index a0d4b725c917..acc1174197c3 100644 --- a/drivers/leds/leds-max77650.c +++ b/drivers/leds/leds-max77650.c @@ -66,7 +66,6 @@ static int max77650_led_probe(struct platform_device *pdev) struct max77650_led *leds, *led; struct device *dev; struct regmap *map; - const char *label; int rv, num_leds; u32 reg; @@ -86,6 +85,8 @@ static int max77650_led_probe(struct platform_device *pdev) return -ENODEV; device_for_each_child_node(dev, child) { + struct led_init_data init_data = {}; + rv = fwnode_property_read_u32(child, "reg", ®); if (rv || reg >= MAX77650_LED_NUM_LEDS) { rv = -EINVAL; @@ -99,22 +100,16 @@ static int max77650_led_probe(struct platform_device *pdev) led->cdev.brightness_set_blocking = max77650_led_brightness_set; led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS; - rv = fwnode_property_read_string(child, "label", &label); - if (rv) { - led->cdev.name = "max77650::"; - } else { - led->cdev.name = devm_kasprintf(dev, GFP_KERNEL, - "max77650:%s", label); - if (!led->cdev.name) { - rv = -ENOMEM; - goto err_node_put; - } - } - fwnode_property_read_string(child, "linux,default-trigger", &led->cdev.default_trigger); - rv = devm_led_classdev_register(dev, &led->cdev); + init_data.fwnode = child; + init_data.devicename = "max77650"; + /* for backwards compatibility if `label` is not present */ + init_data.default_label = ":"; + + rv = devm_led_classdev_register_ext(dev, &led->cdev, + &init_data); if (rv) goto err_node_put; From 6b8274de375b0632cfbda1081011f18738c15221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:06 +0200 Subject: [PATCH 30/84] leds: mt6323: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Since init_data is passed with fwnode handle, we do not need to set the of_node member of the newly created LED classdev. Signed-off-by: Marek Behún Cc: Sean Wang Cc: John Crispin Cc: Ryder Lee Signed-off-by: Pavel Machek --- drivers/leds/leds-mt6323.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index 88deec9d0ef4..f61ad8448351 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -342,7 +342,6 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev, const char *state; int ret = 0; - led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; led->cdev.default_trigger = of_get_property(np, "linux,default-trigger", NULL); @@ -402,6 +401,8 @@ static int mt6323_led_probe(struct platform_device *pdev) } for_each_available_child_of_node(np, child) { + struct led_init_data init_data = {}; + ret = of_property_read_u32(child, "reg", ®); if (ret) { dev_err(dev, "Failed to read led 'reg' property\n"); @@ -437,13 +438,15 @@ static int mt6323_led_probe(struct platform_device *pdev) goto put_child_node; } - ret = devm_led_classdev_register(dev, &leds->led[reg]->cdev); + init_data.fwnode = of_fwnode_handle(child); + + ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev, + &init_data); if (ret) { dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); goto put_child_node; } - leds->led[reg]->cdev.dev->of_node = child; } return 0; From b23ca98af6114ee24b3ba085514677db4bfda53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:07 +0200 Subject: [PATCH 31/84] leds: mt6323: cosmetic change: use helper variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variable dev instead of always writing &pdev->dev. Signed-off-by: Marek Behún Cc: Sean Wang Cc: John Crispin Cc: Ryder Lee Signed-off-by: Pavel Machek --- drivers/leds/leds-mt6323.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index f61ad8448351..a1fceeb41d7e 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -368,9 +368,9 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev, static int mt6323_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev_of_node(&pdev->dev); + struct device_node *np = dev_of_node(dev); struct device_node *child; - struct mt6397_chip *hw = dev_get_drvdata(pdev->dev.parent); + struct mt6397_chip *hw = dev_get_drvdata(dev->parent); struct mt6323_leds *leds; struct mt6323_led *led; int ret; @@ -443,8 +443,7 @@ static int mt6323_led_probe(struct platform_device *pdev) ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev, &init_data); if (ret) { - dev_err(&pdev->dev, "Failed to register LED: %d\n", - ret); + dev_err(dev, "Failed to register LED: %d\n", ret); goto put_child_node; } } From eed951bbf737bb728006b1d248af6341abf79cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:08 +0200 Subject: [PATCH 32/84] leds: pm8058: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Signed-off-by: Marek Behún Cc: Linus Walleij Cc: Bjorn Andersson Signed-off-by: Pavel Machek --- drivers/leds/leds-pm8058.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index 69a7f7e63ea7..f19bd0563ee5 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -87,6 +87,7 @@ static enum led_brightness pm8058_led_get(struct led_classdev *cled) static int pm8058_led_probe(struct platform_device *pdev) { + struct led_init_data init_data = {}; struct pm8058_led *led; struct device_node *np = dev_of_node(&pdev->dev); int ret; @@ -113,8 +114,6 @@ static int pm8058_led_probe(struct platform_device *pdev) return -EINVAL; } - /* Use label else node name */ - led->cdev.name = of_get_property(np, "label", NULL) ? : np->name; led->cdev.default_trigger = of_get_property(np, "linux,default-trigger", NULL); led->cdev.brightness_set = pm8058_led_set; @@ -142,10 +141,12 @@ static int pm8058_led_probe(struct platform_device *pdev) led->ledtype == PM8058_LED_TYPE_FLASH) led->cdev.flags = LED_CORE_SUSPENDRESUME; - ret = devm_led_classdev_register(&pdev->dev, &led->cdev); + init_data.fwnode = of_fwnode_handle(np); + + ret = devm_led_classdev_register_ext(&pdev->dev, &led->cdev, + &init_data); if (ret) { - dev_err(&pdev->dev, "unable to register led \"%s\"\n", - led->cdev.name); + dev_err(&pdev->dev, "Failed to register LED for %pOF\n", np); return ret; } From fb270ba0d9ba76bf40326ac328024fe35b05c1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:09 +0200 Subject: [PATCH 33/84] leds: pm8058: cosmetic change: use helper variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variable dev instead of always writing &pdev->dev. Signed-off-by: Marek Behún Cc: Linus Walleij Cc: Bjorn Andersson Signed-off-by: Pavel Machek --- drivers/leds/leds-pm8058.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index f19bd0563ee5..db0699462e0d 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -88,29 +88,32 @@ static enum led_brightness pm8058_led_get(struct led_classdev *cled) static int pm8058_led_probe(struct platform_device *pdev) { struct led_init_data init_data = {}; + struct device *dev = &pdev->dev; struct pm8058_led *led; - struct device_node *np = dev_of_node(&pdev->dev); + struct device_node *np; int ret; struct regmap *map; const char *state; enum led_brightness maxbright; - led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL); + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; - led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev); + led->ledtype = (u32)(unsigned long)of_device_get_match_data(dev); - map = dev_get_regmap(pdev->dev.parent, NULL); + map = dev_get_regmap(dev->parent, NULL); if (!map) { - dev_err(&pdev->dev, "Parent regmap unavailable.\n"); + dev_err(dev, "Parent regmap unavailable.\n"); return -ENXIO; } led->map = map; + np = dev_of_node(dev); + ret = of_property_read_u32(np, "reg", &led->reg); if (ret) { - dev_err(&pdev->dev, "no register offset specified\n"); + dev_err(dev, "no register offset specified\n"); return -EINVAL; } @@ -143,10 +146,9 @@ static int pm8058_led_probe(struct platform_device *pdev) init_data.fwnode = of_fwnode_handle(np); - ret = devm_led_classdev_register_ext(&pdev->dev, &led->cdev, - &init_data); + ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (ret) { - dev_err(&pdev->dev, "Failed to register LED for %pOF\n", np); + dev_err(dev, "Failed to register LED for %pOF\n", np); return ret; } From 1016daf98179c657c226bfa820e65f286edc2d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:10 +0200 Subject: [PATCH 34/84] leds: pm8058: cosmetic change: no need to return in if guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can return the last ret value. Signed-off-by: Marek Behún Cc: Linus Walleij Cc: Bjorn Andersson Signed-off-by: Pavel Machek --- drivers/leds/leds-pm8058.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index db0699462e0d..5247b04abb7e 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -147,12 +147,10 @@ static int pm8058_led_probe(struct platform_device *pdev) init_data.fwnode = of_fwnode_handle(np); ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); - if (ret) { + if (ret) dev_err(dev, "Failed to register LED for %pOF\n", np); - return ret; - } - return 0; + return ret; } static const struct of_device_id pm8058_leds_id_table[] = { From 6be2030dd752041fe35a948df78029aaec598b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:12 +0200 Subject: [PATCH 35/84] leds: is31fl32xx: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Signed-off-by: Marek Behún Cc: H. Nikolaus Schaller Cc: David Rivshin Signed-off-by: Pavel Machek --- drivers/leds/leds-is31fl32xx.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index b3faf050eece..ea589d1a8954 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -332,9 +332,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev, int ret = 0; u32 reg; - if (of_property_read_string(child, "label", &cdev->name)) - cdev->name = child->name; - ret = of_property_read_u32(child, "reg", ®); if (ret || reg < 1 || reg > led_data->priv->cdef->channels) { dev_err(dev, @@ -373,6 +370,7 @@ static int is31fl32xx_parse_dt(struct device *dev, int ret = 0; for_each_available_child_of_node(dev_of_node(dev), child) { + struct led_init_data init_data = {}; struct is31fl32xx_led_data *led_data = &priv->leds[priv->num_leds]; const struct is31fl32xx_led_data *other_led_data; @@ -388,17 +386,18 @@ static int is31fl32xx_parse_dt(struct device *dev, led_data->channel); if (other_led_data) { dev_err(dev, - "%s and %s both attempting to use channel %d\n", - led_data->cdev.name, - other_led_data->cdev.name, - led_data->channel); + "Node %pOF 'reg' conflicts with another LED\n", + child); goto err; } - ret = devm_led_classdev_register(dev, &led_data->cdev); + init_data.fwnode = of_fwnode_handle(child); + + ret = devm_led_classdev_register_ext(dev, &led_data->cdev, + &init_data); if (ret) { - dev_err(dev, "failed to register PWM led for %s: %d\n", - led_data->cdev.name, ret); + dev_err(dev, "Failed to register LED for %pOF: %d\n", + child, ret); goto err; } From 40f97281ff0540d43d3d0343d74a8e96573ed227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:24 +0200 Subject: [PATCH 36/84] leds: ns2: use devres LED registering function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using devres version of LED registering function we can remove the .remove method from this driver. The probe method also gets simpler. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 22d38c83b6dc..1a7ef66464b5 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -227,16 +227,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, led_dat->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - ret = led_classdev_register(&pdev->dev, &led_dat->cdev); - if (ret < 0) - return ret; - - return 0; -} - -static void delete_ns2_led(struct ns2_led_data *led_dat) -{ - led_classdev_unregister(&led_dat->cdev); + return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); } #ifdef CONFIG_OF_GPIO @@ -380,11 +371,8 @@ static int ns2_led_probe(struct platform_device *pdev) for (i = 0; i < priv->num_leds; i++) { ret = create_ns2_led(pdev, &priv->leds_data[i], &pdata->leds[i]); - if (ret < 0) { - for (i = i - 1; i >= 0; i--) - delete_ns2_led(&priv->leds_data[i]); + if (ret < 0) return ret; - } } platform_set_drvdata(pdev, priv); @@ -392,22 +380,8 @@ static int ns2_led_probe(struct platform_device *pdev) return 0; } -static int ns2_led_remove(struct platform_device *pdev) -{ - int i; - struct ns2_led_priv *priv; - - priv = platform_get_drvdata(pdev); - - for (i = 0; i < priv->num_leds; i++) - delete_ns2_led(&priv->leds_data[i]); - - return 0; -} - static struct platform_driver ns2_led_driver = { .probe = ns2_led_probe, - .remove = ns2_led_remove, .driver = { .name = "leds-ns2", .of_match_table = of_match_ptr(of_ns2_leds_match), From 19d4deb7b24024fa01c6dcaa781b9e508d4f09c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:25 +0200 Subject: [PATCH 37/84] leds: ns2: alloc simple array instead of struct ns2_led_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since .remove method is not needed now that we use devres, there is no need to remember the number of LEDs in struct ns2_led_priv. Alloc simple array of ns2_led_data structs. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 1a7ef66464b5..8cd020b34084 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -334,15 +334,10 @@ static const struct of_device_id of_ns2_leds_match[] = { MODULE_DEVICE_TABLE(of, of_ns2_leds_match); #endif /* CONFIG_OF_GPIO */ -struct ns2_led_priv { - int num_leds; - struct ns2_led_data leds_data[]; -}; - static int ns2_led_probe(struct platform_device *pdev) { struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct ns2_led_priv *priv; + struct ns2_led_data *leds; int i; int ret; @@ -363,20 +358,18 @@ static int ns2_led_probe(struct platform_device *pdev) return -EINVAL; #endif /* CONFIG_OF_GPIO */ - priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds_data, pdata->num_leds), GFP_KERNEL); - if (!priv) + leds = devm_kzalloc(&pdev->dev, array_size(sizeof(*leds), + pdata->num_leds), + GFP_KERNEL); + if (!leds) return -ENOMEM; - priv->num_leds = pdata->num_leds; - for (i = 0; i < priv->num_leds; i++) { - ret = create_ns2_led(pdev, &priv->leds_data[i], - &pdata->leds[i]); + for (i = 0; i < pdata->num_leds; i++) { + ret = create_ns2_led(pdev, &leds[i], &pdata->leds[i]); if (ret < 0) return ret; } - platform_set_drvdata(pdev, priv); - return 0; } From 01d0b14d0e52d74ff7e0fc9b39c13be04acf27dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:26 +0200 Subject: [PATCH 38/84] leds: ns2: support OF probing only, forget platdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move forward from platform data to device tree only. Since commit c7896490dd1a ("leds: ns2: Absorb platform data") the platform data structure is absorbed into the driver, because nothing else in the source tree uses it. Since nobody complained and all usage of this driver is via device tree, change the code to work with device tree only. As Linus Walleij wrote, the device tree should be the preferred way forward anyway. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 8cd020b34084..0e9c2f49b635 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -39,7 +39,7 @@ struct ns2_led { struct ns2_led_modval *modval; }; -struct ns2_led_platform_data { +struct ns2_led_of { int num_leds; struct ns2_led *leds; }; @@ -230,12 +230,11 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); } -#ifdef CONFIG_OF_GPIO /* * Translate OpenFirmware node properties into platform_data. */ static int -ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) +ns2_leds_parse_of(struct device *dev, struct ns2_led_of *ofdata) { struct device_node *np = dev_of_node(dev); struct device_node *child; @@ -317,8 +316,8 @@ ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata) led++; } - pdata->leds = leds; - pdata->num_leds = num_leds; + ofdata->leds = leds; + ofdata->num_leds = num_leds; return 0; @@ -332,40 +331,31 @@ static const struct of_device_id of_ns2_leds_match[] = { {}, }; MODULE_DEVICE_TABLE(of, of_ns2_leds_match); -#endif /* CONFIG_OF_GPIO */ static int ns2_led_probe(struct platform_device *pdev) { - struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct ns2_led_of *ofdata; struct ns2_led_data *leds; int i; int ret; -#ifdef CONFIG_OF_GPIO - if (!pdata) { - pdata = devm_kzalloc(&pdev->dev, - sizeof(struct ns2_led_platform_data), - GFP_KERNEL); - if (!pdata) - return -ENOMEM; + ofdata = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_of), + GFP_KERNEL); + if (!ofdata) + return -ENOMEM; - ret = ns2_leds_get_of_pdata(&pdev->dev, pdata); - if (ret) - return ret; - } -#else - if (!pdata) - return -EINVAL; -#endif /* CONFIG_OF_GPIO */ + ret = ns2_leds_parse_of(&pdev->dev, ofdata); + if (ret) + return ret; leds = devm_kzalloc(&pdev->dev, array_size(sizeof(*leds), - pdata->num_leds), + ofdata->num_leds), GFP_KERNEL); if (!leds) return -ENOMEM; - for (i = 0; i < pdata->num_leds; i++) { - ret = create_ns2_led(pdev, &leds[i], &pdata->leds[i]); + for (i = 0; i < ofdata->num_leds; i++) { + ret = create_ns2_led(pdev, &leds[i], &ofdata->leds[i]); if (ret < 0) return ret; } From f72deb717d5b80b3b90ebcb4e4b73b041e2eb465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:27 +0200 Subject: [PATCH 39/84] leds: ns2: move parsing of one LED into separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move parsing of DT properties of one LED into separate function. This saves indentation level and is nicer to read. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 120 ++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 0e9c2f49b635..46d4f7e963c0 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -230,6 +230,57 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); } +static int ns2_leds_parse_one(struct device *dev, struct device_node *np, + struct ns2_led *led) +{ + struct ns2_led_modval *modval; + int nmodes, ret, i; + + ret = of_property_read_string(np, "label", &led->name); + if (ret) + led->name = np->name; + + led->cmd = gpiod_get_from_of_node(np, "cmd-gpio", 0, GPIOD_ASIS, + led->name); + if (IS_ERR(led->cmd)) + return PTR_ERR(led->cmd); + + led->slow = gpiod_get_from_of_node(np, "slow-gpio", 0, GPIOD_ASIS, + led->name); + if (IS_ERR(led->slow)) + return PTR_ERR(led->slow); + + of_property_read_string(np, "linux,default-trigger", + &led->default_trigger); + + ret = of_property_count_u32_elems(np, "modes-map"); + if (ret < 0 || ret % 3) { + dev_err(dev, "Missing or malformed modes-map for %pOF\n", np); + return -EINVAL; + } + + nmodes = ret / 3; + modval = devm_kcalloc(dev, nmodes, sizeof(*modval), GFP_KERNEL); + if (!modval) + return -ENOMEM; + + for (i = 0; i < nmodes; i++) { + u32 val; + + of_property_read_u32_index(np, "modes-map", 3 * i, &val); + modval[i].mode = val; + of_property_read_u32_index(np, "modes-map", 3 * i + 1, &val); + modval[i].cmd_level = val; + of_property_read_u32_index(np, "modes-map", 3 * i + 2, &val); + modval[i].slow_level = val; + } + + led->num_modes = nmodes; + led->modval = modval; + + return 0; +} + /* * Translate OpenFirmware node properties into platform_data. */ @@ -252,78 +303,17 @@ ns2_leds_parse_of(struct device *dev, struct ns2_led_of *ofdata) led = leds; for_each_available_child_of_node(np, child) { - const char *string; - int i, num_modes; - struct ns2_led_modval *modval; - struct gpio_desc *gd; - - ret = of_property_read_string(child, "label", &string); - led->name = (ret == 0) ? string : child->name; - - gd = gpiod_get_from_of_node(child, "cmd-gpio", 0, - GPIOD_ASIS, led->name); - if (IS_ERR(gd)) { - ret = PTR_ERR(gd); - goto err_node_put; + ret = ns2_leds_parse_one(dev, child, led++); + if (ret < 0) { + of_node_put(child); + return ret; } - led->cmd = gd; - gd = gpiod_get_from_of_node(child, "slow-gpio", 0, - GPIOD_ASIS, led->name); - if (IS_ERR(gd)) { - ret = PTR_ERR(gd); - goto err_node_put; - } - led->slow = gd; - - ret = of_property_read_string(child, "linux,default-trigger", - &string); - if (ret == 0) - led->default_trigger = string; - - ret = of_property_count_u32_elems(child, "modes-map"); - if (ret < 0 || ret % 3) { - dev_err(dev, - "Missing or malformed modes-map property\n"); - ret = -EINVAL; - goto err_node_put; - } - - num_modes = ret / 3; - modval = devm_kcalloc(dev, - num_modes, - sizeof(struct ns2_led_modval), - GFP_KERNEL); - if (!modval) { - ret = -ENOMEM; - goto err_node_put; - } - - for (i = 0; i < num_modes; i++) { - of_property_read_u32_index(child, - "modes-map", 3 * i, - (u32 *) &modval[i].mode); - of_property_read_u32_index(child, - "modes-map", 3 * i + 1, - (u32 *) &modval[i].cmd_level); - of_property_read_u32_index(child, - "modes-map", 3 * i + 2, - (u32 *) &modval[i].slow_level); - } - - led->num_modes = num_modes; - led->modval = modval; - - led++; } ofdata->leds = leds; ofdata->num_leds = num_leds; return 0; - -err_node_put: - of_node_put(child); - return ret; } static const struct of_device_id of_ns2_leds_match[] = { From 528c9515b28d48691f8ef545595be77857e211dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:28 +0200 Subject: [PATCH 40/84] leds: ns2: use devres API for getting GPIO descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This drivers leaks GPIO descriptors on driver removal. Use devres API function devm_gpiod_get_from_of_node instead of gpiod_get_from_of_node to avoid this. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Not-for-stable Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 46d4f7e963c0..fa06ab40ee14 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -240,13 +240,13 @@ static int ns2_leds_parse_one(struct device *dev, struct device_node *np, if (ret) led->name = np->name; - led->cmd = gpiod_get_from_of_node(np, "cmd-gpio", 0, GPIOD_ASIS, - led->name); + led->cmd = devm_gpiod_get_from_of_node(dev, np, "cmd-gpio", 0, + GPIOD_ASIS, led->name); if (IS_ERR(led->cmd)) return PTR_ERR(led->cmd); - led->slow = gpiod_get_from_of_node(np, "slow-gpio", 0, GPIOD_ASIS, - led->name); + led->slow = devm_gpiod_get_from_of_node(dev, np, "slow-gpio", 0, + GPIOD_ASIS, led->name); if (IS_ERR(led->slow)) return PTR_ERR(led->slow); From 01026cecf61998ddff76c280e7a710c5b396904e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:29 +0200 Subject: [PATCH 41/84] leds: ns2: cosmetic structure rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename structures: ns2_led -> ns2_led_of_one ns2_led_data -> ns2_led. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index fa06ab40ee14..6dba6208433c 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -30,7 +30,7 @@ struct ns2_led_modval { int slow_level; }; -struct ns2_led { +struct ns2_led_of_one { const char *name; const char *default_trigger; struct gpio_desc *cmd; @@ -40,8 +40,8 @@ struct ns2_led { }; struct ns2_led_of { - int num_leds; - struct ns2_led *leds; + int num_leds; + struct ns2_led_of_one *leds; }; /* @@ -51,7 +51,7 @@ struct ns2_led_of { * for the command/slow GPIOs corresponds to a LED mode. */ -struct ns2_led_data { +struct ns2_led { struct led_classdev cdev; struct gpio_desc *cmd; struct gpio_desc *slow; @@ -62,7 +62,7 @@ struct ns2_led_data { struct ns2_led_modval *modval; }; -static int ns2_led_get_mode(struct ns2_led_data *led_dat, +static int ns2_led_get_mode(struct ns2_led *led_dat, enum ns2_led_modes *mode) { int i; @@ -85,7 +85,7 @@ static int ns2_led_get_mode(struct ns2_led_data *led_dat, return ret; } -static void ns2_led_set_mode(struct ns2_led_data *led_dat, +static void ns2_led_set_mode(struct ns2_led *led_dat, enum ns2_led_modes mode) { int i; @@ -121,8 +121,8 @@ exit_unlock: static void ns2_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct ns2_led_data *led_dat = - container_of(led_cdev, struct ns2_led_data, cdev); + struct ns2_led *led_dat = + container_of(led_cdev, struct ns2_led, cdev); enum ns2_led_modes mode; if (value == LED_OFF) @@ -147,8 +147,8 @@ static ssize_t ns2_led_sata_store(struct device *dev, const char *buff, size_t count) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct ns2_led_data *led_dat = - container_of(led_cdev, struct ns2_led_data, cdev); + struct ns2_led *led_dat = + container_of(led_cdev, struct ns2_led, cdev); int ret; unsigned long enable; @@ -179,8 +179,8 @@ static ssize_t ns2_led_sata_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct ns2_led_data *led_dat = - container_of(led_cdev, struct ns2_led_data, cdev); + struct ns2_led *led_dat = + container_of(led_cdev, struct ns2_led, cdev); return sprintf(buf, "%d\n", led_dat->sata); } @@ -194,8 +194,8 @@ static struct attribute *ns2_led_attrs[] = { ATTRIBUTE_GROUPS(ns2_led); static int -create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, - const struct ns2_led *template) +create_ns2_led(struct platform_device *pdev, struct ns2_led *led_dat, + const struct ns2_led_of_one *template) { int ret; enum ns2_led_modes mode; @@ -231,7 +231,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, } static int ns2_leds_parse_one(struct device *dev, struct device_node *np, - struct ns2_led *led) + struct ns2_led_of_one *led) { struct ns2_led_modval *modval; int nmodes, ret, i; @@ -289,7 +289,7 @@ ns2_leds_parse_of(struct device *dev, struct ns2_led_of *ofdata) { struct device_node *np = dev_of_node(dev); struct device_node *child; - struct ns2_led *led, *leds; + struct ns2_led_of_one *led, *leds; int ret, num_leds = 0; num_leds = of_get_available_child_count(np); @@ -325,7 +325,7 @@ MODULE_DEVICE_TABLE(of, of_ns2_leds_match); static int ns2_led_probe(struct platform_device *pdev) { struct ns2_led_of *ofdata; - struct ns2_led_data *leds; + struct ns2_led *leds; int i; int ret; From a78bd8f33fd7f76aded73a4f371270f70e1f5cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:30 +0200 Subject: [PATCH 42/84] leds: ns2: cosmetic variable rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename variable led_dat to led in various functions. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 101 ++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 6dba6208433c..dde476420a73 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -62,21 +62,20 @@ struct ns2_led { struct ns2_led_modval *modval; }; -static int ns2_led_get_mode(struct ns2_led *led_dat, - enum ns2_led_modes *mode) +static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode) { int i; int ret = -EINVAL; int cmd_level; int slow_level; - cmd_level = gpiod_get_value_cansleep(led_dat->cmd); - slow_level = gpiod_get_value_cansleep(led_dat->slow); + cmd_level = gpiod_get_value_cansleep(led->cmd); + slow_level = gpiod_get_value_cansleep(led->slow); - for (i = 0; i < led_dat->num_modes; i++) { - if (cmd_level == led_dat->modval[i].cmd_level && - slow_level == led_dat->modval[i].slow_level) { - *mode = led_dat->modval[i].mode; + for (i = 0; i < led->num_modes; i++) { + if (cmd_level == led->modval[i].cmd_level && + slow_level == led->modval[i].slow_level) { + *mode = led->modval[i].mode; ret = 0; break; } @@ -85,15 +84,14 @@ static int ns2_led_get_mode(struct ns2_led *led_dat, return ret; } -static void ns2_led_set_mode(struct ns2_led *led_dat, - enum ns2_led_modes mode) +static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode) { int i; bool found = false; unsigned long flags; - for (i = 0; i < led_dat->num_modes; i++) - if (mode == led_dat->modval[i].mode) { + for (i = 0; i < led->num_modes; i++) + if (mode == led->modval[i].mode) { found = true; break; } @@ -101,38 +99,35 @@ static void ns2_led_set_mode(struct ns2_led *led_dat, if (!found) return; - write_lock_irqsave(&led_dat->rw_lock, flags); + write_lock_irqsave(&led->rw_lock, flags); - if (!led_dat->can_sleep) { - gpiod_set_value(led_dat->cmd, - led_dat->modval[i].cmd_level); - gpiod_set_value(led_dat->slow, - led_dat->modval[i].slow_level); + if (!led->can_sleep) { + gpiod_set_value(led->cmd, led->modval[i].cmd_level); + gpiod_set_value(led->slow, led->modval[i].slow_level); goto exit_unlock; } - gpiod_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level); - gpiod_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level); + gpiod_set_value_cansleep(led->cmd, led->modval[i].cmd_level); + gpiod_set_value_cansleep(led->slow, led->modval[i].slow_level); exit_unlock: - write_unlock_irqrestore(&led_dat->rw_lock, flags); + write_unlock_irqrestore(&led->rw_lock, flags); } static void ns2_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct ns2_led *led_dat = - container_of(led_cdev, struct ns2_led, cdev); + struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev); enum ns2_led_modes mode; if (value == LED_OFF) mode = NS_V2_LED_OFF; - else if (led_dat->sata) + else if (led->sata) mode = NS_V2_LED_SATA; else mode = NS_V2_LED_ON; - ns2_led_set_mode(led_dat, mode); + ns2_led_set_mode(led, mode); } static int ns2_led_set_blocking(struct led_classdev *led_cdev, @@ -147,8 +142,7 @@ static ssize_t ns2_led_sata_store(struct device *dev, const char *buff, size_t count) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct ns2_led *led_dat = - container_of(led_cdev, struct ns2_led, cdev); + struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev); int ret; unsigned long enable; @@ -158,18 +152,18 @@ static ssize_t ns2_led_sata_store(struct device *dev, enable = !!enable; - if (led_dat->sata == enable) + if (led->sata == enable) goto exit; - led_dat->sata = enable; + led->sata = enable; if (!led_get_brightness(led_cdev)) goto exit; if (enable) - ns2_led_set_mode(led_dat, NS_V2_LED_SATA); + ns2_led_set_mode(led, NS_V2_LED_SATA); else - ns2_led_set_mode(led_dat, NS_V2_LED_ON); + ns2_led_set_mode(led, NS_V2_LED_ON); exit: return count; @@ -179,10 +173,9 @@ static ssize_t ns2_led_sata_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct ns2_led *led_dat = - container_of(led_cdev, struct ns2_led, cdev); + struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev); - return sprintf(buf, "%d\n", led_dat->sata); + return sprintf(buf, "%d\n", led->sata); } static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); @@ -194,40 +187,38 @@ static struct attribute *ns2_led_attrs[] = { ATTRIBUTE_GROUPS(ns2_led); static int -create_ns2_led(struct platform_device *pdev, struct ns2_led *led_dat, +create_ns2_led(struct platform_device *pdev, struct ns2_led *led, const struct ns2_led_of_one *template) { int ret; enum ns2_led_modes mode; - rwlock_init(&led_dat->rw_lock); + rwlock_init(&led->rw_lock); - led_dat->cdev.name = template->name; - led_dat->cdev.default_trigger = template->default_trigger; - led_dat->cdev.blink_set = NULL; - led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; - led_dat->cdev.groups = ns2_led_groups; - led_dat->cmd = template->cmd; - led_dat->slow = template->slow; - led_dat->can_sleep = gpiod_cansleep(led_dat->cmd) | - gpiod_cansleep(led_dat->slow); - if (led_dat->can_sleep) - led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking; + led->cdev.name = template->name; + led->cdev.default_trigger = template->default_trigger; + led->cdev.blink_set = NULL; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; + led->cdev.groups = ns2_led_groups; + led->cmd = template->cmd; + led->slow = template->slow; + led->can_sleep = gpiod_cansleep(led->cmd) | gpiod_cansleep(led->slow); + if (led->can_sleep) + led->cdev.brightness_set_blocking = ns2_led_set_blocking; else - led_dat->cdev.brightness_set = ns2_led_set; - led_dat->modval = template->modval; - led_dat->num_modes = template->num_modes; + led->cdev.brightness_set = ns2_led_set; + led->modval = template->modval; + led->num_modes = template->num_modes; - ret = ns2_led_get_mode(led_dat, &mode); + ret = ns2_led_get_mode(led, &mode); if (ret < 0) return ret; /* Set LED initial state. */ - led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; - led_dat->cdev.brightness = - (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; + led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; + led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - return devm_led_classdev_register(&pdev->dev, &led_dat->cdev); + return devm_led_classdev_register(&pdev->dev, &led->cdev); } static int ns2_leds_parse_one(struct device *dev, struct device_node *np, From a2fc703cc955c6b4b6c7fbed42df62bbadc46422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:31 +0200 Subject: [PATCH 43/84] leds: ns2: cosmetic change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Return directly instead of setting result and breaking. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index dde476420a73..912db40c5118 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -65,7 +65,6 @@ struct ns2_led { static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode) { int i; - int ret = -EINVAL; int cmd_level; int slow_level; @@ -76,12 +75,11 @@ static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode) if (cmd_level == led->modval[i].cmd_level && slow_level == led->modval[i].slow_level) { *mode = led->modval[i].mode; - ret = 0; - break; + return 0; } } - return ret; + return -EINVAL; } static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode) From b3f96922839a589e8417c31a1837f78382d3f0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:32 +0200 Subject: [PATCH 44/84] leds: ns2: cosmetic change: use helper variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variable dev instead of always writing &pdev->dev. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 912db40c5118..801b7f851be7 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -185,7 +185,7 @@ static struct attribute *ns2_led_attrs[] = { ATTRIBUTE_GROUPS(ns2_led); static int -create_ns2_led(struct platform_device *pdev, struct ns2_led *led, +create_ns2_led(struct device *dev, struct ns2_led *led, const struct ns2_led_of_one *template) { int ret; @@ -216,7 +216,7 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led *led, led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - return devm_led_classdev_register(&pdev->dev, &led->cdev); + return devm_led_classdev_register(dev, &led->cdev); } static int ns2_leds_parse_one(struct device *dev, struct device_node *np, @@ -313,28 +313,27 @@ MODULE_DEVICE_TABLE(of, of_ns2_leds_match); static int ns2_led_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct ns2_led_of *ofdata; struct ns2_led *leds; int i; int ret; - ofdata = devm_kzalloc(&pdev->dev, sizeof(struct ns2_led_of), - GFP_KERNEL); + ofdata = devm_kzalloc(dev, sizeof(struct ns2_led_of), GFP_KERNEL); if (!ofdata) return -ENOMEM; - ret = ns2_leds_parse_of(&pdev->dev, ofdata); + ret = ns2_leds_parse_of(dev, ofdata); if (ret) return ret; - leds = devm_kzalloc(&pdev->dev, array_size(sizeof(*leds), - ofdata->num_leds), + leds = devm_kzalloc(dev, array_size(sizeof(*leds), ofdata->num_leds), GFP_KERNEL); if (!leds) return -ENOMEM; for (i = 0; i < ofdata->num_leds; i++) { - ret = create_ns2_led(pdev, &leds[i], &ofdata->leds[i]); + ret = create_ns2_led(dev, &leds[i], &ofdata->leds[i]); if (ret < 0) return ret; } From a4a469b4314e95818521daef82aa7f9071123245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:33 +0200 Subject: [PATCH 45/84] leds: ns2: register LED immediately after parsing DT properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register each LED immediately after parsing OF properties. This simplifies the driver. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 143 +++++++++++----------------------------- 1 file changed, 40 insertions(+), 103 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 801b7f851be7..9d9c9ff4dce6 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -30,20 +30,6 @@ struct ns2_led_modval { int slow_level; }; -struct ns2_led_of_one { - const char *name; - const char *default_trigger; - struct gpio_desc *cmd; - struct gpio_desc *slow; - int num_modes; - struct ns2_led_modval *modval; -}; - -struct ns2_led_of { - int num_leds; - struct ns2_led_of_one *leds; -}; - /* * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED * modes are available: off, on and SATA activity blinking. The LED modes are @@ -184,63 +170,29 @@ static struct attribute *ns2_led_attrs[] = { }; ATTRIBUTE_GROUPS(ns2_led); -static int -create_ns2_led(struct device *dev, struct ns2_led *led, - const struct ns2_led_of_one *template) -{ - int ret; - enum ns2_led_modes mode; - - rwlock_init(&led->rw_lock); - - led->cdev.name = template->name; - led->cdev.default_trigger = template->default_trigger; - led->cdev.blink_set = NULL; - led->cdev.flags |= LED_CORE_SUSPENDRESUME; - led->cdev.groups = ns2_led_groups; - led->cmd = template->cmd; - led->slow = template->slow; - led->can_sleep = gpiod_cansleep(led->cmd) | gpiod_cansleep(led->slow); - if (led->can_sleep) - led->cdev.brightness_set_blocking = ns2_led_set_blocking; - else - led->cdev.brightness_set = ns2_led_set; - led->modval = template->modval; - led->num_modes = template->num_modes; - - ret = ns2_led_get_mode(led, &mode); - if (ret < 0) - return ret; - - /* Set LED initial state. */ - led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; - led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - - return devm_led_classdev_register(dev, &led->cdev); -} - -static int ns2_leds_parse_one(struct device *dev, struct device_node *np, - struct ns2_led_of_one *led) +static int ns2_led_register(struct device *dev, struct device_node *np, + struct ns2_led *led) { struct ns2_led_modval *modval; + enum ns2_led_modes mode; int nmodes, ret, i; - ret = of_property_read_string(np, "label", &led->name); + ret = of_property_read_string(np, "label", &led->cdev.name); if (ret) - led->name = np->name; + led->cdev.name = np->name; led->cmd = devm_gpiod_get_from_of_node(dev, np, "cmd-gpio", 0, - GPIOD_ASIS, led->name); + GPIOD_ASIS, np->name); if (IS_ERR(led->cmd)) return PTR_ERR(led->cmd); led->slow = devm_gpiod_get_from_of_node(dev, np, "slow-gpio", 0, - GPIOD_ASIS, led->name); + GPIOD_ASIS, np->name); if (IS_ERR(led->slow)) return PTR_ERR(led->slow); of_property_read_string(np, "linux,default-trigger", - &led->default_trigger); + &led->cdev.default_trigger); ret = of_property_count_u32_elems(np, "modes-map"); if (ret < 0 || ret % 3) { @@ -264,45 +216,32 @@ static int ns2_leds_parse_one(struct device *dev, struct device_node *np, modval[i].slow_level = val; } + rwlock_init(&led->rw_lock); + + led->cdev.blink_set = NULL; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; + led->cdev.groups = ns2_led_groups; + led->can_sleep = gpiod_cansleep(led->cmd) || gpiod_cansleep(led->slow); + if (led->can_sleep) + led->cdev.brightness_set_blocking = ns2_led_set_blocking; + else + led->cdev.brightness_set = ns2_led_set; led->num_modes = nmodes; led->modval = modval; - return 0; -} + ret = ns2_led_get_mode(led, &mode); + if (ret < 0) + return ret; -/* - * Translate OpenFirmware node properties into platform_data. - */ -static int -ns2_leds_parse_of(struct device *dev, struct ns2_led_of *ofdata) -{ - struct device_node *np = dev_of_node(dev); - struct device_node *child; - struct ns2_led_of_one *led, *leds; - int ret, num_leds = 0; + /* Set LED initial state. */ + led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; + led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - num_leds = of_get_available_child_count(np); - if (!num_leds) - return -ENODEV; + ret = devm_led_classdev_register(dev, &led->cdev); + if (ret) + dev_err(dev, "Failed to register LED for node %pOF\n", np); - leds = devm_kcalloc(dev, num_leds, sizeof(struct ns2_led), - GFP_KERNEL); - if (!leds) - return -ENOMEM; - - led = leds; - for_each_available_child_of_node(np, child) { - ret = ns2_leds_parse_one(dev, child, led++); - if (ret < 0) { - of_node_put(child); - return ret; - } - } - - ofdata->leds = leds; - ofdata->num_leds = num_leds; - - return 0; + return ret; } static const struct of_device_id of_ns2_leds_match[] = { @@ -314,28 +253,26 @@ MODULE_DEVICE_TABLE(of, of_ns2_leds_match); static int ns2_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ns2_led_of *ofdata; + struct device_node *np, *child; struct ns2_led *leds; - int i; + int count; int ret; - ofdata = devm_kzalloc(dev, sizeof(struct ns2_led_of), GFP_KERNEL); - if (!ofdata) - return -ENOMEM; + np = dev_of_node(dev); + count = of_get_available_child_count(np); + if (!count) + return -ENODEV; - ret = ns2_leds_parse_of(dev, ofdata); - if (ret) - return ret; - - leds = devm_kzalloc(dev, array_size(sizeof(*leds), ofdata->num_leds), - GFP_KERNEL); + leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL); if (!leds) return -ENOMEM; - for (i = 0; i < ofdata->num_leds; i++) { - ret = create_ns2_led(dev, &leds[i], &ofdata->leds[i]); - if (ret < 0) + for_each_available_child_of_node(np, child) { + ret = ns2_led_register(dev, child, leds++); + if (ret) { + of_node_put(child); return ret; + } } return 0; From 48b77cdca50a180fd1f22f4ae3b3d1e4ec7d2e5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:34 +0200 Subject: [PATCH 46/84] leds: ns2: remove unneeded variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to use variable found, we can determine whether the mode was found by comparing iterator variable to its limit. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 9d9c9ff4dce6..e94bb8535f0a 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -71,16 +71,13 @@ static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode) static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode) { int i; - bool found = false; unsigned long flags; for (i = 0; i < led->num_modes; i++) - if (mode == led->modval[i].mode) { - found = true; + if (mode == led->modval[i].mode) break; - } - if (!found) + if (i == led->num_modes) return; write_lock_irqsave(&led->rw_lock, flags); From f847ef543ce45c917bcbcafb2555aa9e5968c385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Fri, 18 Sep 2020 00:33:37 +0200 Subject: [PATCH 47/84] leds: ns2: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Signed-off-by: Marek Behún Cc: Simon Guinot Cc: Simon Guinot Cc: Vincent Donnefort Cc: Thomas Petazzoni Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index e94bb8535f0a..030f426af3d7 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -170,14 +170,11 @@ ATTRIBUTE_GROUPS(ns2_led); static int ns2_led_register(struct device *dev, struct device_node *np, struct ns2_led *led) { + struct led_init_data init_data = {}; struct ns2_led_modval *modval; enum ns2_led_modes mode; int nmodes, ret, i; - ret = of_property_read_string(np, "label", &led->cdev.name); - if (ret) - led->cdev.name = np->name; - led->cmd = devm_gpiod_get_from_of_node(dev, np, "cmd-gpio", 0, GPIOD_ASIS, np->name); if (IS_ERR(led->cmd)) @@ -234,7 +231,9 @@ static int ns2_led_register(struct device *dev, struct device_node *np, led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - ret = devm_led_classdev_register(dev, &led->cdev); + init_data.fwnode = of_fwnode_handle(np); + + ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (ret) dev_err(dev, "Failed to register LED for node %pOF\n", np); From c4241abcd50019adafb11d8aa8269d242c4f42b4 Mon Sep 17 00:00:00 2001 From: Liu Shixin Date: Sat, 19 Sep 2020 18:08:53 +0800 Subject: [PATCH 48/84] leds: pca9532 - simplify the return expression of pca9532_remove Simplify the return expression. Signed-off-by: Liu Shixin Signed-off-by: Pavel Machek --- drivers/leds/leds-pca9532.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index f834550999dd..41229f775d35 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -545,13 +545,8 @@ static int pca9532_probe(struct i2c_client *client, static int pca9532_remove(struct i2c_client *client) { struct pca9532_data *data = i2c_get_clientdata(client); - int err; - err = pca9532_destroy_devices(data, data->chip_info->num_leds); - if (err) - return err; - - return 0; + return pca9532_destroy_devices(data, data->chip_info->num_leds); } module_i2c_driver(pca9532_driver); From 1ece06acd29e028734431f9ccc79a57c3fc6281e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 6 Sep 2020 22:51:02 +0300 Subject: [PATCH 49/84] leds: Add driver for Acer Iconia Tab A500 Acer Iconia Tab A500 is an Android tablet device which has two LEDs embedded into the Power Button. Orange LED indicates "battery charging" status and white LED indicates "wake-up/charge-done" status. The new LED driver provides control over both LEDs to userspace. Signed-off-by: Dmitry Osipenko Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 7 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-acer-a500.c | 129 ++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 drivers/leds/leds-acer-a500.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index a008170e73cd..849d3c5f908e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -921,6 +921,13 @@ config LEDS_SGM3140 This option enables support for the SGM3140 500mA Buck/Boost Charge Pump LED Driver. +config LEDS_ACER_A500 + tristate "Power button LED support for Acer Iconia Tab A500" + depends on LEDS_CLASS && MFD_ACER_A500_EC + help + This option enables support for the Power Button LED of + Acer Iconia Tab A500. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 778cb4bb8c52..73e603e1727e 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o # LED Platform Drivers (keep this sorted, M-| sort) obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o +obj-$(CONFIG_LEDS_ACER_A500) += leds-acer-a500.o obj-$(CONFIG_LEDS_ADP5520) += leds-adp5520.o obj-$(CONFIG_LEDS_AN30259A) += leds-an30259a.o obj-$(CONFIG_LEDS_APU) += leds-apu.o diff --git a/drivers/leds/leds-acer-a500.c b/drivers/leds/leds-acer-a500.c new file mode 100644 index 000000000000..8cf0b11f4390 --- /dev/null +++ b/drivers/leds/leds-acer-a500.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +#define A500_EC_LED_DELAY_USEC (100 * 1000) + +enum { + REG_RESET_LEDS = 0x40, + REG_POWER_LED_ON = 0x42, + REG_CHARGE_LED_ON = 0x43, + REG_ANDROID_LEDS_OFF = 0x5a, +}; + +struct a500_led { + struct led_classdev cdev; + const struct reg_sequence *enable_seq; + struct a500_led *other; + struct regmap *rmap; +}; + +static const struct reg_sequence a500_ec_leds_reset_seq[] = { + REG_SEQ(REG_RESET_LEDS, 0x0, A500_EC_LED_DELAY_USEC), + REG_SEQ(REG_ANDROID_LEDS_OFF, 0x0, A500_EC_LED_DELAY_USEC), +}; + +static const struct reg_sequence a500_ec_white_led_enable_seq[] = { + REG_SEQ(REG_POWER_LED_ON, 0x0, A500_EC_LED_DELAY_USEC), +}; + +static const struct reg_sequence a500_ec_orange_led_enable_seq[] = { + REG_SEQ(REG_CHARGE_LED_ON, 0x0, A500_EC_LED_DELAY_USEC), +}; + +static int a500_ec_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct a500_led *led = container_of(led_cdev, struct a500_led, cdev); + struct reg_sequence control_seq[2]; + unsigned int num_regs = 1; + + if (value) { + control_seq[0] = led->enable_seq[0]; + } else { + /* + * There is no separate controls which can disable LEDs + * individually, there is only RESET_LEDS command that turns + * off both LEDs. + * + * RESET_LEDS turns off both LEDs, thus restore other LED if + * it's turned ON. + */ + if (led->other->cdev.brightness) + num_regs = 2; + + control_seq[0] = a500_ec_leds_reset_seq[0]; + control_seq[1] = led->other->enable_seq[0]; + } + + return regmap_multi_reg_write(led->rmap, control_seq, num_regs); +} + +static int a500_ec_leds_probe(struct platform_device *pdev) +{ + struct a500_led *white_led, *orange_led; + struct regmap *rmap; + int err; + + rmap = dev_get_regmap(pdev->dev.parent, "KB930"); + if (!rmap) + return -EINVAL; + + /* reset and turn off LEDs */ + regmap_multi_reg_write(rmap, a500_ec_leds_reset_seq, 2); + + white_led = devm_kzalloc(&pdev->dev, sizeof(*white_led), GFP_KERNEL); + if (!white_led) + return -ENOMEM; + + white_led->cdev.name = "power:white"; + white_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set; + white_led->cdev.flags = LED_CORE_SUSPENDRESUME; + white_led->cdev.max_brightness = 1; + white_led->enable_seq = a500_ec_white_led_enable_seq; + white_led->rmap = rmap; + + orange_led = devm_kzalloc(&pdev->dev, sizeof(*orange_led), GFP_KERNEL); + if (!orange_led) + return -ENOMEM; + + orange_led->cdev.name = "power:orange"; + orange_led->cdev.brightness_set_blocking = a500_ec_led_brightness_set; + orange_led->cdev.flags = LED_CORE_SUSPENDRESUME; + orange_led->cdev.max_brightness = 1; + orange_led->enable_seq = a500_ec_orange_led_enable_seq; + orange_led->rmap = rmap; + + white_led->other = orange_led; + orange_led->other = white_led; + + err = devm_led_classdev_register(&pdev->dev, &white_led->cdev); + if (err) { + dev_err(&pdev->dev, "failed to register white LED\n"); + return err; + } + + err = devm_led_classdev_register(&pdev->dev, &orange_led->cdev); + if (err) { + dev_err(&pdev->dev, "failed to register orange LED\n"); + return err; + } + + return 0; +} + +static struct platform_driver a500_ec_leds_driver = { + .driver = { + .name = "acer-a500-iconia-leds", + }, + .probe = a500_ec_leds_probe, +}; +module_platform_driver(a500_ec_leds_driver); + +MODULE_DESCRIPTION("LED driver for Acer Iconia Tab A500 Power Button"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_ALIAS("platform:acer-a500-iconia-leds"); +MODULE_LICENSE("GPL"); From d3ab963cf980151f5f0ba16d842ddc80b232d9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:02:56 +0200 Subject: [PATCH 50/84] leds: lm36274: cosmetic: rename lm36274_data to chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename this variable so that it is easier to read and easier to write in 80 columns. Also rename variable of this type in lm36274_brightness_set from led to chip, to be consistent. Signed-off-by: Marek Behún Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 82 ++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index bfeee03a0053..4a9f786bb972 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -41,37 +41,36 @@ struct lm36274 { }; static int lm36274_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brt_val) + enum led_brightness brt_val) { - struct lm36274 *led = container_of(led_cdev, struct lm36274, led_dev); + struct lm36274 *chip = container_of(led_cdev, struct lm36274, led_dev); - return ti_lmu_common_set_brightness(&led->lmu_data, brt_val); + return ti_lmu_common_set_brightness(&chip->lmu_data, brt_val); } -static int lm36274_init(struct lm36274 *lm36274_data) +static int lm36274_init(struct lm36274 *chip) { int enable_val = 0; int i; - for (i = 0; i < lm36274_data->num_leds; i++) - enable_val |= (1 << lm36274_data->led_sources[i]); + for (i = 0; i < chip->num_leds; i++) + enable_val |= (1 << chip->led_sources[i]); if (!enable_val) { - dev_err(lm36274_data->dev, "No LEDs were enabled\n"); + dev_err(chip->dev, "No LEDs were enabled\n"); return -EINVAL; } enable_val |= LM36274_BL_EN; - return regmap_write(lm36274_data->regmap, LM36274_REG_BL_EN, - enable_val); + return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val); } -static int lm36274_parse_dt(struct lm36274 *lm36274_data) +static int lm36274_parse_dt(struct lm36274 *chip) { struct fwnode_handle *child = NULL; char label[LED_MAX_NAME_SIZE]; - struct device *dev = &lm36274_data->pdev->dev; + struct device *dev = &chip->pdev->dev; const char *name; int child_cnt; int ret = -EINVAL; @@ -84,37 +83,37 @@ static int lm36274_parse_dt(struct lm36274 *lm36274_data) device_for_each_child_node(dev, child) { ret = fwnode_property_read_string(child, "label", &name); if (ret) - snprintf(label, sizeof(label), - "%s::", lm36274_data->pdev->name); + snprintf(label, sizeof(label), "%s::", + chip->pdev->name); else - snprintf(label, sizeof(label), - "%s:%s", lm36274_data->pdev->name, name); + snprintf(label, sizeof(label), "%s:%s", + chip->pdev->name, name); - lm36274_data->num_leds = fwnode_property_count_u32(child, "led-sources"); - if (lm36274_data->num_leds <= 0) + chip->num_leds = fwnode_property_count_u32(child, "led-sources"); + if (chip->num_leds <= 0) return -ENODEV; ret = fwnode_property_read_u32_array(child, "led-sources", - lm36274_data->led_sources, - lm36274_data->num_leds); + chip->led_sources, + chip->num_leds); if (ret) { dev_err(dev, "led-sources property missing\n"); return ret; } fwnode_property_read_string(child, "linux,default-trigger", - &lm36274_data->led_dev.default_trigger); + &chip->led_dev.default_trigger); } - lm36274_data->lmu_data.regmap = lm36274_data->regmap; - lm36274_data->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; - lm36274_data->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; - lm36274_data->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; + chip->lmu_data.regmap = chip->regmap; + chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; + chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; + chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; - lm36274_data->led_dev.name = label; - lm36274_data->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; - lm36274_data->led_dev.brightness_set_blocking = lm36274_brightness_set; + chip->led_dev.name = label; + chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; + chip->led_dev.brightness_set_blocking = lm36274_brightness_set; return 0; } @@ -122,39 +121,38 @@ static int lm36274_parse_dt(struct lm36274 *lm36274_data) static int lm36274_probe(struct platform_device *pdev) { struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); - struct lm36274 *lm36274_data; + struct lm36274 *chip; int ret; - lm36274_data = devm_kzalloc(&pdev->dev, sizeof(*lm36274_data), - GFP_KERNEL); - if (!lm36274_data) + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) return -ENOMEM; - lm36274_data->pdev = pdev; - lm36274_data->dev = lmu->dev; - lm36274_data->regmap = lmu->regmap; - platform_set_drvdata(pdev, lm36274_data); + chip->pdev = pdev; + chip->dev = lmu->dev; + chip->regmap = lmu->regmap; + platform_set_drvdata(pdev, chip); - ret = lm36274_parse_dt(lm36274_data); + ret = lm36274_parse_dt(chip); if (ret) { - dev_err(lm36274_data->dev, "Failed to parse DT node\n"); + dev_err(chip->dev, "Failed to parse DT node\n"); return ret; } - ret = lm36274_init(lm36274_data); + ret = lm36274_init(chip); if (ret) { - dev_err(lm36274_data->dev, "Failed to init the device\n"); + dev_err(chip->dev, "Failed to init the device\n"); return ret; } - return led_classdev_register(lm36274_data->dev, &lm36274_data->led_dev); + return led_classdev_register(chip->dev, &chip->led_dev); } static int lm36274_remove(struct platform_device *pdev) { - struct lm36274 *lm36274_data = platform_get_drvdata(pdev); + struct lm36274 *chip = platform_get_drvdata(pdev); - led_classdev_unregister(&lm36274_data->led_dev); + led_classdev_unregister(&chip->led_dev); return 0; } From a448fcf19c9c5d3ddd9066accbd8d28c4950bb9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:02:57 +0200 Subject: [PATCH 51/84] leds: lm36274: don't iterate through children since there is only one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not use device_for_each_child_node. Since this driver works only with once child node present, use device_get_next_child_node instead. This also saves one level of indentation. Signed-off-by: Marek Behún Reviewed-by: Dan Murphy Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 46 +++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index 4a9f786bb972..e0fce74a7667 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -72,40 +72,36 @@ static int lm36274_parse_dt(struct lm36274 *chip) char label[LED_MAX_NAME_SIZE]; struct device *dev = &chip->pdev->dev; const char *name; - int child_cnt; - int ret = -EINVAL; + int ret; /* There should only be 1 node */ - child_cnt = device_get_child_node_count(dev); - if (child_cnt != 1) + if (device_get_child_node_count(dev) != 1) return -EINVAL; - device_for_each_child_node(dev, child) { - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(label, sizeof(label), "%s::", - chip->pdev->name); - else - snprintf(label, sizeof(label), "%s:%s", - chip->pdev->name, name); + child = device_get_next_child_node(dev, NULL); - chip->num_leds = fwnode_property_count_u32(child, "led-sources"); - if (chip->num_leds <= 0) - return -ENODEV; + ret = fwnode_property_read_string(child, "label", &name); + if (ret) + snprintf(label, sizeof(label), "%s::", chip->pdev->name); + else + snprintf(label, sizeof(label), "%s:%s", chip->pdev->name, name); - ret = fwnode_property_read_u32_array(child, "led-sources", - chip->led_sources, - chip->num_leds); - if (ret) { - dev_err(dev, "led-sources property missing\n"); - return ret; - } - - fwnode_property_read_string(child, "linux,default-trigger", - &chip->led_dev.default_trigger); + chip->num_leds = fwnode_property_count_u32(child, "led-sources"); + if (chip->num_leds <= 0) + return -ENODEV; + ret = fwnode_property_read_u32_array(child, "led-sources", + chip->led_sources, chip->num_leds); + if (ret) { + dev_err(dev, "led-sources property missing\n"); + return ret; } + fwnode_property_read_string(child, "linux,default-trigger", + &chip->led_dev.default_trigger); + + fwnode_handle_put(child); + chip->lmu_data.regmap = chip->regmap; chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; From 1aeef38c6a4a87d04bf5fc596dbf91a15525c987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:02:58 +0200 Subject: [PATCH 52/84] leds: lm36274: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Previously if the `label` DT property was not present, the code composed name for the LED in the form "parent_name::" For backwards compatibility we therefore set init_data->default_label = ":"; so that the LED will not get a different name if `label` property is not present, nor are `color` and `function`. Signed-off-by: Marek Behún Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 42 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index e0fce74a7667..ee4f90f04f19 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -66,12 +66,11 @@ static int lm36274_init(struct lm36274 *chip) return regmap_write(chip->regmap, LM36274_REG_BL_EN, enable_val); } -static int lm36274_parse_dt(struct lm36274 *chip) +static int lm36274_parse_dt(struct lm36274 *chip, + struct led_init_data *init_data) { - struct fwnode_handle *child = NULL; - char label[LED_MAX_NAME_SIZE]; struct device *dev = &chip->pdev->dev; - const char *name; + struct fwnode_handle *child; int ret; /* There should only be 1 node */ @@ -80,43 +79,45 @@ static int lm36274_parse_dt(struct lm36274 *chip) child = device_get_next_child_node(dev, NULL); - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(label, sizeof(label), "%s::", chip->pdev->name); - else - snprintf(label, sizeof(label), "%s:%s", chip->pdev->name, name); + init_data->fwnode = child; + init_data->devicename = chip->pdev->name; + /* for backwards compatibility when `label` property is not present */ + init_data->default_label = ":"; chip->num_leds = fwnode_property_count_u32(child, "led-sources"); - if (chip->num_leds <= 0) - return -ENODEV; + if (chip->num_leds <= 0) { + ret = -ENODEV; + goto err; + } ret = fwnode_property_read_u32_array(child, "led-sources", chip->led_sources, chip->num_leds); if (ret) { dev_err(dev, "led-sources property missing\n"); - return ret; + goto err; } fwnode_property_read_string(child, "linux,default-trigger", &chip->led_dev.default_trigger); - fwnode_handle_put(child); - chip->lmu_data.regmap = chip->regmap; chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; - chip->led_dev.name = label; chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; chip->led_dev.brightness_set_blocking = lm36274_brightness_set; return 0; +err: + fwnode_handle_put(child); + return ret; } static int lm36274_probe(struct platform_device *pdev) { struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); + struct led_init_data init_data = {}; struct lm36274 *chip; int ret; @@ -129,7 +130,7 @@ static int lm36274_probe(struct platform_device *pdev) chip->regmap = lmu->regmap; platform_set_drvdata(pdev, chip); - ret = lm36274_parse_dt(chip); + ret = lm36274_parse_dt(chip, &init_data); if (ret) { dev_err(chip->dev, "Failed to parse DT node\n"); return ret; @@ -141,7 +142,14 @@ static int lm36274_probe(struct platform_device *pdev) return ret; } - return led_classdev_register(chip->dev, &chip->led_dev); + ret = led_classdev_register_ext(chip->dev, &chip->led_dev, &init_data); + if (ret) + dev_err(chip->dev, "Failed to register LED for node %pfw\n", + init_data.fwnode); + + fwnode_handle_put(init_data.fwnode); + + return ret; } static int lm36274_remove(struct platform_device *pdev) From 484456712de44c516b016b23027ad500acac4d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:02:59 +0200 Subject: [PATCH 53/84] leds: lm36274: do not set chip settings in DT parsing function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These settings are not parsed from DT and therefore semantically should not be set in function with a name lm36274_parse_dt. Signed-off-by: Marek Behún Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index ee4f90f04f19..85a58a5cbdf9 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -100,14 +100,6 @@ static int lm36274_parse_dt(struct lm36274 *chip, fwnode_property_read_string(child, "linux,default-trigger", &chip->led_dev.default_trigger); - chip->lmu_data.regmap = chip->regmap; - chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; - chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; - chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; - - chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; - chip->led_dev.brightness_set_blocking = lm36274_brightness_set; - return 0; err: fwnode_handle_put(child); @@ -142,6 +134,14 @@ static int lm36274_probe(struct platform_device *pdev) return ret; } + chip->lmu_data.regmap = chip->regmap; + chip->lmu_data.max_brightness = MAX_BRIGHTNESS_11BIT; + chip->lmu_data.msb_brightness_reg = LM36274_REG_BRT_MSB; + chip->lmu_data.lsb_brightness_reg = LM36274_REG_BRT_LSB; + + chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; + chip->led_dev.brightness_set_blocking = lm36274_brightness_set; + ret = led_classdev_register_ext(chip->dev, &chip->led_dev, &init_data); if (ret) dev_err(chip->dev, "Failed to register LED for node %pfw\n", From 5c0d20a968ae878ccdb2a42a0438610cf02cff13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:03:00 +0200 Subject: [PATCH 54/84] leds: lm36274: use platform device as parent of LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of registering LED under the MFD device, this driver sets the parent of the LED it is registering to the parent of the MFD device (the I2C client device). Because of this we cannot use devres for LED registration, since it can result in use-after-free, see commit a0972fff0947 ("leds: lm36274: fix use-after-free on unbind"). The only other in-tree driver that also registers under the MFD device (drivers/regulator/lm363x-regulator.c) sets the parent to the MFD device. Set the parent of this LED to the MFD device, instead of the I2C client device. Signed-off-by: Marek Behún Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index 85a58a5cbdf9..74c236d1a60c 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -69,7 +69,7 @@ static int lm36274_init(struct lm36274 *chip) static int lm36274_parse_dt(struct lm36274 *chip, struct led_init_data *init_data) { - struct device *dev = &chip->pdev->dev; + struct device *dev = chip->dev; struct fwnode_handle *child; int ret; @@ -118,7 +118,7 @@ static int lm36274_probe(struct platform_device *pdev) return -ENOMEM; chip->pdev = pdev; - chip->dev = lmu->dev; + chip->dev = &pdev->dev; chip->regmap = lmu->regmap; platform_set_drvdata(pdev, chip); From 60bbd9d411e32328dbecaff9ec5dfab29b546aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:03:01 +0200 Subject: [PATCH 55/84] leds: lm36274: use devres LED registering function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the potential use-after-free issue is resolved we can use devres for LED registration in this driver. By using devres version of LED registering function we can remove the .remove method from this driver. Signed-off-by: Marek Behún Tested-by: Dan Murphy Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index 74c236d1a60c..10a63b7f2ecc 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -142,7 +142,8 @@ static int lm36274_probe(struct platform_device *pdev) chip->led_dev.max_brightness = MAX_BRIGHTNESS_11BIT; chip->led_dev.brightness_set_blocking = lm36274_brightness_set; - ret = led_classdev_register_ext(chip->dev, &chip->led_dev, &init_data); + ret = devm_led_classdev_register_ext(chip->dev, &chip->led_dev, + &init_data); if (ret) dev_err(chip->dev, "Failed to register LED for node %pfw\n", init_data.fwnode); @@ -152,15 +153,6 @@ static int lm36274_probe(struct platform_device *pdev) return ret; } -static int lm36274_remove(struct platform_device *pdev) -{ - struct lm36274 *chip = platform_get_drvdata(pdev); - - led_classdev_unregister(&chip->led_dev); - - return 0; -} - static const struct of_device_id of_lm36274_leds_match[] = { { .compatible = "ti,lm36274-backlight", }, {}, @@ -169,7 +161,6 @@ MODULE_DEVICE_TABLE(of, of_lm36274_leds_match); static struct platform_driver lm36274_driver = { .probe = lm36274_probe, - .remove = lm36274_remove, .driver = { .name = "lm36274-leds", }, From 4b64c0510b66d3d779d1c195de1d5662bb28e948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:03:02 +0200 Subject: [PATCH 56/84] leds: lm3532: don't parse label DT property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver uses extended LED registration, so we do not need to parse the `label` DT property on our own. Signed-off-by: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/leds-lm3532.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 946ad67eaecb..9b6973217cc0 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -129,7 +129,6 @@ struct lm3532_als_data { * @full_scale_current - The full-scale current setting for the current sink. * @led_strings - The LED strings supported in this array * @enabled - Enabled status - * @label - LED label */ struct lm3532_led { struct led_classdev led_dev; @@ -142,7 +141,6 @@ struct lm3532_led { int full_scale_current; unsigned int enabled:1; u32 led_strings[LM3532_MAX_CONTROL_BANKS]; - char label[LED_MAX_NAME_SIZE]; }; /** @@ -548,7 +546,6 @@ static int lm3532_parse_node(struct lm3532_data *priv) { struct fwnode_handle *child = NULL; struct lm3532_led *led; - const char *name; int control_bank; u32 ramp_time; size_t i = 0; @@ -646,16 +643,7 @@ static int lm3532_parse_node(struct lm3532_data *priv) fwnode_property_read_string(child, "linux,default-trigger", &led->led_dev.default_trigger); - ret = fwnode_property_read_string(child, "label", &name); - if (ret) - snprintf(led->label, sizeof(led->label), - "%s::", priv->client->name); - else - snprintf(led->label, sizeof(led->label), - "%s:%s", priv->client->name, name); - led->priv = priv; - led->led_dev.name = led->label; led->led_dev.brightness_set_blocking = lm3532_brightness_set; ret = devm_led_classdev_register_ext(priv->dev, &led->led_dev, &idata); From 006631969880fdc58a585d310c7e8d98dc648e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:03:03 +0200 Subject: [PATCH 57/84] leds: syscon: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Signed-off-by: Marek Behún Cc: Linus Walleij Signed-off-by: Pavel Machek --- drivers/leds/leds-syscon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index d7230da81543..f54935fa650a 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -55,6 +55,7 @@ static void syscon_led_set(struct led_classdev *led_cdev, static int syscon_led_probe(struct platform_device *pdev) { + struct led_init_data init_data = {}; struct device *dev = &pdev->dev; struct device_node *np = dev_of_node(dev); struct device *parent; @@ -84,8 +85,6 @@ static int syscon_led_probe(struct platform_device *pdev) return -EINVAL; if (of_property_read_u32(np, "mask", &sled->mask)) return -EINVAL; - sled->cdev.name = - of_get_property(np, "label", NULL) ? : np->name; sled->cdev.default_trigger = of_get_property(np, "linux,default-trigger", NULL); @@ -115,7 +114,9 @@ static int syscon_led_probe(struct platform_device *pdev) } sled->cdev.brightness_set = syscon_led_set; - ret = devm_led_classdev_register(dev, &sled->cdev); + init_data.fwnode = of_fwnode_handle(np); + + ret = devm_led_classdev_register_ext(dev, &sled->cdev, &init_data); if (ret < 0) return ret; From c49d6cab0d7fde39297949c4da257db69999292e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 19 Sep 2020 20:03:04 +0200 Subject: [PATCH 58/84] leds: parse linux,default-trigger DT property in LED core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do the parsing of `linux,default-trigger` DT property to LED core. Currently it is done in many different drivers and the code is repeated. This patch removes the parsing from 23 drivers: an30259a, aw2013, bcm6328, bcm6358, cr0014114, el15203000, gpio, is31fl32xx, lm3532, lm36274, lm3692x, lm3697, lp50xx, lp8860, lt3593, max77650, mt6323, ns2, pm8058, pwm, syscon, tlc591xx and turris-omnia. There is one driver in drivers/input which parses this property on it's own. I shall send a separate patch there after this is applied. There are still 8 drivers that parse this property on their own because they do not pass the led_init_data structure to the registering function. I will try to refactor those in the future. Signed-off-by: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/led-class.c | 5 +++++ drivers/leds/leds-an30259a.c | 3 --- drivers/leds/leds-aw2013.c | 3 --- drivers/leds/leds-bcm6328.c | 4 ---- drivers/leds/leds-bcm6358.c | 4 ---- drivers/leds/leds-cr0014114.c | 3 --- drivers/leds/leds-el15203000.c | 3 --- drivers/leds/leds-gpio.c | 3 --- drivers/leds/leds-is31fl32xx.c | 3 --- drivers/leds/leds-lm3532.c | 3 --- drivers/leds/leds-lm36274.c | 3 --- drivers/leds/leds-lm3692x.c | 3 --- drivers/leds/leds-lm3697.c | 3 --- drivers/leds/leds-lp50xx.c | 3 --- drivers/leds/leds-lp8860.c | 4 ---- drivers/leds/leds-lt3593.c | 3 --- drivers/leds/leds-max77650.c | 3 --- drivers/leds/leds-mt6323.c | 4 ---- drivers/leds/leds-ns2.c | 3 --- drivers/leds/leds-pm8058.c | 2 -- drivers/leds/leds-pwm.c | 5 ----- drivers/leds/leds-syscon.c | 2 -- drivers/leds/leds-tlc591xx.c | 3 --- drivers/leds/leds-turris-omnia.c | 2 -- 24 files changed, 5 insertions(+), 72 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index cc3929f858b6..131ca83f5fb3 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -354,6 +354,11 @@ int led_classdev_register_ext(struct device *parent, ret = led_compose_name(parent, init_data, composed_name); if (ret < 0) return ret; + + if (init_data->fwnode) + fwnode_property_read_string(init_data->fwnode, + "linux,default-trigger", + &led_cdev->default_trigger); } else { proposed_name = led_cdev->name; } diff --git a/drivers/leds/leds-an30259a.c b/drivers/leds/leds-an30259a.c index 9749f1cc3e15..a0df1fb28774 100644 --- a/drivers/leds/leds-an30259a.c +++ b/drivers/leds/leds-an30259a.c @@ -238,9 +238,6 @@ static int an30259a_dt_init(struct i2c_client *client, led->default_state = STATE_OFF; } - of_property_read_string(child, "linux,default-trigger", - &led->cdev.default_trigger); - i++; } diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c index 927c5ba32592..80d937454aee 100644 --- a/drivers/leds/leds-aw2013.c +++ b/drivers/leds/leds-aw2013.c @@ -297,9 +297,6 @@ static int aw2013_probe_dt(struct aw2013 *chip) "DT property led-max-microamp is missing\n"); } - of_property_read_string(child, "linux,default-trigger", - &led->cdev.default_trigger); - led->cdev.brightness_set_blocking = aw2013_brightness_set; led->cdev.blink_set = aw2013_blink_set; diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c index d79aeb956c9b..226d17d253ed 100644 --- a/drivers/leds/leds-bcm6328.c +++ b/drivers/leds/leds-bcm6328.c @@ -346,10 +346,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg, if (of_property_read_bool(nc, "active-low")) led->active_low = true; - led->cdev.default_trigger = of_get_property(nc, - "linux,default-trigger", - NULL); - if (!of_property_read_string(nc, "default-state", &state)) { if (!strcmp(state, "on")) { led->cdev.brightness = LED_FULL; diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c index 0fd495103a4d..9d2e487fa08a 100644 --- a/drivers/leds/leds-bcm6358.c +++ b/drivers/leds/leds-bcm6358.c @@ -110,10 +110,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg, if (of_property_read_bool(nc, "active-low")) led->active_low = true; - led->cdev.default_trigger = of_get_property(nc, - "linux,default-trigger", - NULL); - if (!of_property_read_string(nc, "default-state", &state)) { if (!strcmp(state, "on")) { led->cdev.brightness = LED_FULL; diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index 2da448ae718e..d03cfd3c0bfb 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -188,9 +188,6 @@ static int cr0014114_probe_dt(struct cr0014114 *priv) device_for_each_child_node(priv->dev, child) { led = &priv->leds[i]; - fwnode_property_read_string(child, "linux,default-trigger", - &led->ldev.default_trigger); - led->priv = priv; led->ldev.max_brightness = CR_MAX_BRIGHTNESS; led->ldev.brightness_set_blocking = cr0014114_set_sync; diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c index 298b13e4807a..6ca47f2a2004 100644 --- a/drivers/leds/leds-el15203000.c +++ b/drivers/leds/leds-el15203000.c @@ -263,9 +263,6 @@ static int el15203000_probe_dt(struct el15203000 *priv) return -EINVAL; } - fwnode_property_read_string(child, "linux,default-trigger", - &led->ldev.default_trigger); - led->priv = priv; led->ldev.max_brightness = LED_ON; led->ldev.brightness_set_blocking = el15203000_set_blocking; diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index cf84096d88ce..93f5b1b60fde 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -160,9 +160,6 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev) led_dat->gpiod = led.gpiod; - fwnode_property_read_string(child, "linux,default-trigger", - &led.default_trigger); - if (!fwnode_property_read_string(child, "default-state", &state)) { if (!strcmp(state, "keep")) diff --git a/drivers/leds/leds-is31fl32xx.c b/drivers/leds/leds-is31fl32xx.c index ea589d1a8954..2180255ad339 100644 --- a/drivers/leds/leds-is31fl32xx.c +++ b/drivers/leds/leds-is31fl32xx.c @@ -341,9 +341,6 @@ static int is31fl32xx_parse_child_dt(const struct device *dev, } led_data->channel = reg; - of_property_read_string(child, "linux,default-trigger", - &cdev->default_trigger); - cdev->brightness_set_blocking = is31fl32xx_brightness_set; return 0; diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 9b6973217cc0..10ded9192fb1 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -640,9 +640,6 @@ static int lm3532_parse_node(struct lm3532_data *priv) goto child_out; } - fwnode_property_read_string(child, "linux,default-trigger", - &led->led_dev.default_trigger); - led->priv = priv; led->led_dev.brightness_set_blocking = lm3532_brightness_set; diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index 10a63b7f2ecc..582c6a821dc8 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -97,9 +97,6 @@ static int lm36274_parse_dt(struct lm36274 *chip, goto err; } - fwnode_property_read_string(child, "linux,default-trigger", - &chip->led_dev.default_trigger); - return 0; err: fwnode_handle_put(child); diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c index 1d7ea1b76a12..e945de45388c 100644 --- a/drivers/leds/leds-lm3692x.c +++ b/drivers/leds/leds-lm3692x.c @@ -433,9 +433,6 @@ static int lm3692x_probe_dt(struct lm3692x_led *led) return -ENODEV; } - fwnode_property_read_string(child, "linux,default-trigger", - &led->led_dev.default_trigger); - ret = fwnode_property_read_u32(child, "reg", &led->led_enable); if (ret) { dev_err(&led->client->dev, "reg DT property missing\n"); diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index a7779ce931ab..64c0794801e6 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -268,9 +268,6 @@ static int lm3697_probe_dt(struct lm3697 *priv) if (ret) dev_warn(dev, "runtime-ramp properties missing\n"); - fwnode_property_read_string(child, "linux,default-trigger", - &led->led_dev.default_trigger); - init_data.fwnode = child; init_data.devicename = priv->client->name; /* for backwards compatibility if `label` is not present */ diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 47144a37cb94..5fb4f24aeb2e 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -508,9 +508,6 @@ static int lp50xx_probe_dt(struct lp50xx *priv) led_cdev = &led->mc_cdev.led_cdev; led_cdev->brightness_set_blocking = lp50xx_brightness_set; - fwnode_property_read_string(child, "linux,default-trigger", - &led_cdev->default_trigger); - ret = devm_led_classdev_multicolor_register_ext(&priv->client->dev, &led->mc_cdev, &init_data); diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index e9b16f3358d6..f0533a337bc1 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -392,10 +392,6 @@ static int lp8860_probe(struct i2c_client *client, if (!child_node) return -EINVAL; - led->led_dev.default_trigger = of_get_property(child_node, - "linux,default-trigger", - NULL); - led->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(led->enable_gpio)) { diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 061f02e3995a..68e06434ac08 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -86,9 +86,6 @@ static int lt3593_led_probe(struct platform_device *pdev) child = device_get_next_child_node(dev, NULL); - fwnode_property_read_string(child, "linux,default-trigger", - &led_data->cdev.default_trigger); - if (!fwnode_property_read_string(child, "default-state", &tmp)) { if (!strcmp(tmp, "on")) state = LEDS_GPIO_DEFSTATE_ON; diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c index acc1174197c3..1eeac56b0014 100644 --- a/drivers/leds/leds-max77650.c +++ b/drivers/leds/leds-max77650.c @@ -100,9 +100,6 @@ static int max77650_led_probe(struct platform_device *pdev) led->cdev.brightness_set_blocking = max77650_led_brightness_set; led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS; - fwnode_property_read_string(child, "linux,default-trigger", - &led->cdev.default_trigger); - init_data.fwnode = child; init_data.devicename = "max77650"; /* for backwards compatibility if `label` is not present */ diff --git a/drivers/leds/leds-mt6323.c b/drivers/leds/leds-mt6323.c index a1fceeb41d7e..f59e0e8bda8b 100644 --- a/drivers/leds/leds-mt6323.c +++ b/drivers/leds/leds-mt6323.c @@ -342,10 +342,6 @@ static int mt6323_led_set_dt_default(struct led_classdev *cdev, const char *state; int ret = 0; - led->cdev.default_trigger = of_get_property(np, - "linux,default-trigger", - NULL); - state = of_get_property(np, "default-state", NULL); if (state) { if (!strcmp(state, "keep")) { diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index 030f426af3d7..e1ec5cbed07e 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -185,9 +185,6 @@ static int ns2_led_register(struct device *dev, struct device_node *np, if (IS_ERR(led->slow)) return PTR_ERR(led->slow); - of_property_read_string(np, "linux,default-trigger", - &led->cdev.default_trigger); - ret = of_property_count_u32_elems(np, "modes-map"); if (ret < 0 || ret % 3) { dev_err(dev, "Missing or malformed modes-map for %pOF\n", np); diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index 5247b04abb7e..fb2ab72c0c40 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -117,8 +117,6 @@ static int pm8058_led_probe(struct platform_device *pdev) return -EINVAL; } - led->cdev.default_trigger = - of_get_property(np, "linux,default-trigger", NULL); led->cdev.brightness_set = pm8058_led_set; led->cdev.brightness_get = pm8058_led_get; if (led->ledtype == PM8058_LED_TYPE_COMMON) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 4a014d296412..2a16ae0bf022 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -20,7 +20,6 @@ struct led_pwm { const char *name; - const char *default_trigger; u8 active_low; unsigned int max_brightness; }; @@ -70,7 +69,6 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->active_low = led->active_low; led_data->cdev.name = led->name; - led_data->cdev.default_trigger = led->default_trigger; led_data->cdev.brightness = LED_OFF; led_data->cdev.max_brightness = led->max_brightness; led_data->cdev.flags = LED_CORE_SUSPENDRESUME; @@ -124,9 +122,6 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) return -EINVAL; } - fwnode_property_read_string(fwnode, "linux,default-trigger", - &led.default_trigger); - led.active_low = fwnode_property_read_bool(fwnode, "active-low"); fwnode_property_read_u32(fwnode, "max-brightness", diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c index f54935fa650a..7eddb8ecb44e 100644 --- a/drivers/leds/leds-syscon.c +++ b/drivers/leds/leds-syscon.c @@ -85,8 +85,6 @@ static int syscon_led_probe(struct platform_device *pdev) return -EINVAL; if (of_property_read_u32(np, "mask", &sled->mask)) return -EINVAL; - sled->cdev.default_trigger = - of_get_property(np, "linux,default-trigger", NULL); state = of_get_property(np, "default-state", NULL); if (state) { diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index 5e84a0c7aacb..f24271337bd8 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -199,9 +199,6 @@ tlc591xx_probe(struct i2c_client *client, led = &priv->leds[reg]; led->active = true; - led->ldev.default_trigger = - of_get_property(child, "linux,default-trigger", NULL); - led->priv = priv; led->led_no = reg; led->ldev.brightness_set_blocking = tlc591xx_brightness_set; diff --git a/drivers/leds/leds-turris-omnia.c b/drivers/leds/leds-turris-omnia.c index 117976cf75c8..8c5bdc3847ee 100644 --- a/drivers/leds/leds-turris-omnia.c +++ b/drivers/leds/leds-turris-omnia.c @@ -121,8 +121,6 @@ static int omnia_led_register(struct i2c_client *client, struct omnia_led *led, cdev->max_brightness = 255; cdev->brightness_set_blocking = omnia_led_brightness_set_blocking; - of_property_read_string(np, "linux,default-trigger", &cdev->default_trigger); - /* put the LED into software mode */ ret = i2c_smbus_write_byte_data(client, CMD_LED_MODE, CMD_LED_MODE_LED(led->reg) | From 38b393fec298569c8ec154c750a107299bc8385d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:36 +0200 Subject: [PATCH 59/84] leds: tca6507: Absorb platform data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only in-tree usage of this driver is via device-tree. No on else includes linux/leds-tca6507.h, so absorb the definition of platdata structure. Signed-off-by: Marek Behún Cc: NeilBrown Reviewed-by: Linus Walleij Tested-by: H. Nikolaus Schaller Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 11 ++++++++++- include/linux/leds-tca6507.h | 21 --------------------- 2 files changed, 10 insertions(+), 22 deletions(-) delete mode 100644 include/linux/leds-tca6507.h diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index a7e9fd85b6dd..b5b5bafe2176 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -95,7 +95,6 @@ #include #include #include -#include #include /* LED select registers determine the source that drives LED outputs */ @@ -108,6 +107,16 @@ #define TCA6507_LS_BLINK0 0x6 /* Blink at Bank0 rate */ #define TCA6507_LS_BLINK1 0x7 /* Blink at Bank1 rate */ +struct tca6507_platform_data { + struct led_platform_data leds; +#ifdef CONFIG_GPIOLIB + int gpio_base; + void (*setup)(unsigned gpio_base, unsigned ngpio); +#endif +}; + +#define TCA6507_MAKE_GPIO 1 + enum { BANK0, BANK1, diff --git a/include/linux/leds-tca6507.h b/include/linux/leds-tca6507.h deleted file mode 100644 index 50d330ed1100..000000000000 --- a/include/linux/leds-tca6507.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * TCA6507 LED chip driver. - * - * Copyright (C) 2011 Neil Brown - */ - -#ifndef __LINUX_TCA6507_H -#define __LINUX_TCA6507_H -#include - -struct tca6507_platform_data { - struct led_platform_data leds; -#ifdef CONFIG_GPIOLIB - int gpio_base; - void (*setup)(unsigned gpio_base, unsigned ngpio); -#endif -}; - -#define TCA6507_MAKE_GPIO 1 -#endif /* __LINUX_TCA6507_H*/ From 96f524105b9c62904b8452dff2c2531a84e44e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:37 +0200 Subject: [PATCH 60/84] leds: tca6507: use fwnode API instead of OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert to use fwnode API instead of OF. It is more generic and if someone wants to use this driver without device-tree yet still, they will be able to via swnode fwnodes. Remove the gpio setup function from platdata. Signed-off-by: Marek Behún Cc: NeilBrown Cc: Linus Walleij Tested-by: H. Nikolaus Schaller Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 66 ++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index b5b5bafe2176..3e01fe2510f7 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -94,8 +94,8 @@ #include #include #include +#include #include -#include /* LED select registers determine the source that drives LED outputs */ #define TCA6507_LS_LED_OFF 0x0 /* Output HI-Z (off) */ @@ -111,7 +111,6 @@ struct tca6507_platform_data { struct led_platform_data leds; #ifdef CONFIG_GPIOLIB int gpio_base; - void (*setup)(unsigned gpio_base, unsigned ngpio); #endif }; @@ -672,8 +671,6 @@ static int tca6507_probe_gpios(struct i2c_client *client, tca->gpio.ngpio = 0; return err; } - if (pdata->setup) - pdata->setup(tca->gpio.base, tca->gpio.ngpio); return 0; } @@ -694,44 +691,50 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) } #endif /* CONFIG_GPIOLIB */ -#ifdef CONFIG_OF static struct tca6507_platform_data * tca6507_led_dt_init(struct i2c_client *client) { - struct device_node *np = dev_of_node(&client->dev), *child; struct tca6507_platform_data *pdata; + struct fwnode_handle *child; struct led_info *tca_leds; int count; - count = of_get_available_child_count(np); + count = device_get_child_node_count(&client->dev); if (!count || count > NUM_LEDS) return ERR_PTR(-ENODEV); - tca_leds = devm_kcalloc(&client->dev, - NUM_LEDS, sizeof(struct led_info), GFP_KERNEL); + tca_leds = devm_kcalloc(&client->dev, NUM_LEDS, sizeof(struct led_info), + GFP_KERNEL); if (!tca_leds) return ERR_PTR(-ENOMEM); - for_each_available_child_of_node(np, child) { + device_for_each_child_node(&client->dev, child) { struct led_info led; u32 reg; int ret; - led.name = - of_get_property(child, "label", NULL) ? : child->name; - led.default_trigger = - of_get_property(child, "linux,default-trigger", NULL); + if (fwnode_property_read_string(child, "label", &led.name)) + led.name = fwnode_get_name(child); + + fwnode_property_read_string(child, "linux,default-trigger", + &led.default_trigger); + led.flags = 0; - if (of_property_match_string(child, "compatible", "gpio") >= 0) + if (fwnode_property_match_string(child, "compatible", + "gpio") >= 0) led.flags |= TCA6507_MAKE_GPIO; - ret = of_property_read_u32(child, "reg", ®); - if (ret != 0 || reg >= NUM_LEDS) - continue; + + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg >= NUM_LEDS) { + fwnode_handle_put(child); + return ERR_PTR(ret); + } tca_leds[reg] = led; } - pdata = devm_kzalloc(&client->dev, - sizeof(struct tca6507_platform_data), GFP_KERNEL); + + pdata = devm_kzalloc(&client->dev, sizeof(struct tca6507_platform_data), + GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); @@ -740,6 +743,7 @@ tca6507_led_dt_init(struct i2c_client *client) #ifdef CONFIG_GPIOLIB pdata->gpio_base = -1; #endif + return pdata; } @@ -749,15 +753,6 @@ static const struct of_device_id of_tca6507_leds_match[] = { }; MODULE_DEVICE_TABLE(of, of_tca6507_leds_match); -#else -static struct tca6507_platform_data * -tca6507_led_dt_init(struct i2c_client *client) -{ - return ERR_PTR(-ENODEV); -} - -#endif - static int tca6507_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -768,18 +763,15 @@ static int tca6507_probe(struct i2c_client *client, int i = 0; adapter = client->adapter; - pdata = dev_get_platdata(&client->dev); if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -EIO; - if (!pdata || pdata->leds.num_leds != NUM_LEDS) { - pdata = tca6507_led_dt_init(client); - if (IS_ERR(pdata)) { - dev_err(&client->dev, "Need %d entries in platform-data list\n", - NUM_LEDS); - return PTR_ERR(pdata); - } + pdata = tca6507_led_dt_init(client); + if (IS_ERR(pdata)) { + dev_err(&client->dev, "Need %d entries in platform-data list\n", + NUM_LEDS); + return PTR_ERR(pdata); } tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); if (!tca) From e8b7dabc6565d9bf74e66312cf7b8b87450c7caa Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 25 Sep 2020 11:24:12 +0200 Subject: [PATCH 61/84] leds: tca6507: fix warning triggered by fwnode conversion. Robot complains about: All warnings (new ones prefixed by >>): >> drivers/leds/leds-tca6507.c:750:34: warning: unused variable 'of_tca6507_leds_match' [-Wunused-const-variable] static const struct of_device_id of_tca6507_leds_match[] = { Fix it. Reported-by: kernel test robot Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 3e01fe2510f7..4b10ef9ae221 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -747,7 +747,7 @@ tca6507_led_dt_init(struct i2c_client *client) return pdata; } -static const struct of_device_id of_tca6507_leds_match[] = { +static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = { { .compatible = "ti,tca6507", }, {}, }; From a238098251b690b7408f26d7c5b4c6ba44d7084c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 26 Sep 2020 21:43:02 +0200 Subject: [PATCH 62/84] leds: tca6507: fix potential zero passed to ERR_PTR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix potential ERR_PTR(0). Signed-off-by: Marek Behún Fixes: d78b10f5713d9 ("leds: tca6507: use fwnode API instead of OF") Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 4b10ef9ae221..d589c89930fd 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -727,7 +727,7 @@ tca6507_led_dt_init(struct i2c_client *client) ret = fwnode_property_read_u32(child, "reg", ®); if (ret || reg >= NUM_LEDS) { fwnode_handle_put(child); - return ERR_PTR(ret); + return ERR_PTR(ret ? : -EINVAL); } tca_leds[reg] = led; From 39118499a62623d32c67ffd93d94ed5f27bfc736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:54 +0200 Subject: [PATCH 63/84] leds: pca963x: cosmetic: use helper variables, better indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variables: instead of writing &client->dev at many places, write only dev. The same with pca963x->chip->chipdef, pca963x->chip->client). Use helper variable u8 val for i2c_smbus_write_byte_data, for better indentation. Indent better on various places. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 139 ++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index d288acbc99c7..c03871f92fec 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -116,35 +116,38 @@ struct pca963x_led { }; static int pca963x_brightness(struct pca963x_led *pca963x, - enum led_brightness brightness) + enum led_brightness brightness) { - u8 ledout_addr = pca963x->chip->chipdef->ledout_base - + (pca963x->led_num / 4); - u8 ledout; - int shift = 2 * (pca963x->led_num % 4); - u8 mask = 0x3 << shift; + struct i2c_client *client = pca963x->chip->client; + struct pca963x_chipdef *chipdef = pca963x->chip->chipdef; + u8 ledout_addr, ledout, mask, val; + int shift; int ret; - ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); + ledout_addr = chipdef->ledout_base + (pca963x->led_num / 4); + shift = 2 * (pca963x->led_num % 4); + mask = 0x3 << shift; + ledout = i2c_smbus_read_byte_data(client, ledout_addr); + switch (brightness) { case LED_FULL: - ret = i2c_smbus_write_byte_data(pca963x->chip->client, - ledout_addr, - (ledout & ~mask) | (PCA963X_LED_ON << shift)); + val = (ledout & ~mask) | (PCA963X_LED_ON << shift); + ret = i2c_smbus_write_byte_data(client, ledout_addr, val); break; case LED_OFF: - ret = i2c_smbus_write_byte_data(pca963x->chip->client, - ledout_addr, ledout & ~mask); + val = ledout & ~mask; + ret = i2c_smbus_write_byte_data(client, ledout_addr, val); break; default: - ret = i2c_smbus_write_byte_data(pca963x->chip->client, - PCA963X_PWM_BASE + pca963x->led_num, - brightness); + ret = i2c_smbus_write_byte_data(client, + PCA963X_PWM_BASE + + pca963x->led_num, + brightness); if (ret < 0) return ret; - ret = i2c_smbus_write_byte_data(pca963x->chip->client, - ledout_addr, - (ledout & ~mask) | (PCA963X_LED_PWM << shift)); + + val = (ledout & ~mask) | (PCA963X_LED_PWM << shift); + ret = i2c_smbus_write_byte_data(client, ledout_addr, val); break; } @@ -153,36 +156,40 @@ static int pca963x_brightness(struct pca963x_led *pca963x, static void pca963x_blink(struct pca963x_led *pca963x) { - u8 ledout_addr = pca963x->chip->chipdef->ledout_base + - (pca963x->led_num / 4); - u8 ledout; - u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, - PCA963X_MODE2); - int shift = 2 * (pca963x->led_num % 4); - u8 mask = 0x3 << shift; + struct i2c_client *client = pca963x->chip->client; + struct pca963x_chipdef *chipdef = pca963x->chip->chipdef; + u8 ledout_addr, ledout, mask, val, mode2; + int shift; - i2c_smbus_write_byte_data(pca963x->chip->client, - pca963x->chip->chipdef->grppwm, pca963x->gdc); + ledout_addr = chipdef->ledout_base + (pca963x->led_num / 4); + shift = 2 * (pca963x->led_num % 4); + mask = 0x3 << shift; + mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); - i2c_smbus_write_byte_data(pca963x->chip->client, - pca963x->chip->chipdef->grpfreq, pca963x->gfrq); + i2c_smbus_write_byte_data(client, chipdef->grppwm, pca963x->gdc); + + i2c_smbus_write_byte_data(client, chipdef->grpfreq, pca963x->gfrq); if (!(mode2 & PCA963X_MODE2_DMBLNK)) - i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, - mode2 | PCA963X_MODE2_DMBLNK); + i2c_smbus_write_byte_data(client, PCA963X_MODE2, + mode2 | PCA963X_MODE2_DMBLNK); mutex_lock(&pca963x->chip->mutex); - ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); - if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) - i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr, - (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift)); + + ledout = i2c_smbus_read_byte_data(client, ledout_addr); + if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) { + val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift); + i2c_smbus_write_byte_data(client, ledout_addr, val); + } + mutex_unlock(&pca963x->chip->mutex); } static int pca963x_power_state(struct pca963x_led *pca963x) { + struct i2c_client *client = pca963x->chip->client; unsigned long *leds_on = &pca963x->chip->leds_on; - unsigned long cached_leds = pca963x->chip->leds_on; + unsigned long cached_leds = *leds_on; if (pca963x->led_cdev.brightness) set_bit(pca963x->led_num, leds_on); @@ -190,14 +197,14 @@ static int pca963x_power_state(struct pca963x_led *pca963x) clear_bit(pca963x->led_num, leds_on); if (!(*leds_on) != !cached_leds) - return i2c_smbus_write_byte_data(pca963x->chip->client, - PCA963X_MODE1, *leds_on ? 0 : BIT(4)); + return i2c_smbus_write_byte_data(client, PCA963X_MODE1, + *leds_on ? 0 : BIT(4)); return 0; } static int pca963x_led_set(struct led_classdev *led_cdev, - enum led_brightness value) + enum led_brightness value) { struct pca963x_led *pca963x; int ret; @@ -217,7 +224,7 @@ unlock: } static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, - unsigned int val) + unsigned int val) { unsigned int scaling = pca963x->chip->chipdef->scaling; @@ -225,7 +232,7 @@ static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, } static int pca963x_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, unsigned long *delay_off) + unsigned long *delay_on, unsigned long *delay_off) { struct pca963x_led *pca963x; unsigned long time_on, time_off, period; @@ -278,23 +285,23 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, } static struct pca963x_platform_data * -pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip) +pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) { struct pca963x_platform_data *pdata; struct led_info *pca963x_leds; struct fwnode_handle *child; int count; - count = device_get_child_node_count(&client->dev); + count = device_get_child_node_count(dev); if (!count || count > chip->n_leds) return ERR_PTR(-ENODEV); - pca963x_leds = devm_kcalloc(&client->dev, - chip->n_leds, sizeof(struct led_info), GFP_KERNEL); + pca963x_leds = devm_kcalloc(dev, chip->n_leds, sizeof(struct led_info), + GFP_KERNEL); if (!pca963x_leds) return ERR_PTR(-ENOMEM); - device_for_each_child_node(&client->dev, child) { + device_for_each_child_node(dev, child) { struct led_info led = {}; u32 reg; int res; @@ -312,8 +319,8 @@ pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip) pca963x_leds[reg] = led; } - pdata = devm_kzalloc(&client->dev, - sizeof(struct pca963x_platform_data), GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(struct pca963x_platform_data), + GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); @@ -321,23 +328,23 @@ pca963x_get_pdata(struct i2c_client *client, struct pca963x_chipdef *chip) pdata->leds.num_leds = chip->n_leds; /* default to open-drain unless totem pole (push-pull) is specified */ - if (device_property_read_bool(&client->dev, "nxp,totem-pole")) + if (device_property_read_bool(dev, "nxp,totem-pole")) pdata->outdrv = PCA963X_TOTEM_POLE; else pdata->outdrv = PCA963X_OPEN_DRAIN; /* default to software blinking unless hardware blinking is specified */ - if (device_property_read_bool(&client->dev, "nxp,hw-blink")) + if (device_property_read_bool(dev, "nxp,hw-blink")) pdata->blink_type = PCA963X_HW_BLINK; else pdata->blink_type = PCA963X_SW_BLINK; - if (device_property_read_u32(&client->dev, "nxp,period-scale", + if (device_property_read_u32(dev, "nxp,period-scale", &chip->scaling)) chip->scaling = 1000; /* default to non-inverted output, unless inverted is specified */ - if (device_property_read_bool(&client->dev, "nxp,inverted-out")) + if (device_property_read_bool(dev, "nxp,inverted-out")) pdata->dir = PCA963X_INVERTED; else pdata->dir = PCA963X_NORMAL; @@ -355,8 +362,9 @@ static const struct of_device_id of_pca963x_match[] = { MODULE_DEVICE_TABLE(of, of_pca963x_match); static int pca963x_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { + struct device *dev = &client->dev; struct pca963x *pca963x_chip; struct pca963x_led *pca963x; struct pca963x_platform_data *pdata; @@ -364,29 +372,26 @@ static int pca963x_probe(struct i2c_client *client, int i, err; chip = &pca963x_chipdefs[id->driver_data]; - pdata = dev_get_platdata(&client->dev); + pdata = dev_get_platdata(dev); if (!pdata) { - pdata = pca963x_get_pdata(client, chip); + pdata = pca963x_get_pdata(dev, chip); if (IS_ERR(pdata)) { - dev_warn(&client->dev, "could not parse configuration\n"); + dev_warn(dev, "could not parse configuration\n"); pdata = NULL; } } if (pdata && (pdata->leds.num_leds < 1 || - pdata->leds.num_leds > chip->n_leds)) { - dev_err(&client->dev, "board info must claim 1-%d LEDs", - chip->n_leds); + pdata->leds.num_leds > chip->n_leds)) { + dev_err(dev, "board info must claim 1-%d LEDs", chip->n_leds); return -EINVAL; } - pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip), - GFP_KERNEL); + pca963x_chip = devm_kzalloc(dev, sizeof(*pca963x_chip), GFP_KERNEL); if (!pca963x_chip) return -ENOMEM; - pca963x = devm_kcalloc(&client->dev, chip->n_leds, sizeof(*pca963x), - GFP_KERNEL); + pca963x = devm_kcalloc(dev, chip->n_leds, sizeof(*pca963x), GFP_KERNEL); if (!pca963x) return -ENOMEM; @@ -427,7 +432,7 @@ static int pca963x_probe(struct i2c_client *client, if (pdata && pdata->blink_type == PCA963X_HW_BLINK) pca963x[i].led_cdev.blink_set = pca963x_blink_set; - err = led_classdev_register(&client->dev, &pca963x[i].led_cdev); + err = led_classdev_register(dev, &pca963x[i].led_cdev); if (err < 0) goto exit; } @@ -436,8 +441,7 @@ static int pca963x_probe(struct i2c_client *client, i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); if (pdata) { - u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client, - PCA963X_MODE2); + u8 mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); /* Configure output: open-drain or totem pole (push-pull) */ if (pdata->outdrv == PCA963X_OPEN_DRAIN) mode2 &= ~PCA963X_MODE2_OUTDRV; @@ -446,8 +450,7 @@ static int pca963x_probe(struct i2c_client *client, /* Configure direction: normal or inverted */ if (pdata->dir == PCA963X_INVERTED) mode2 |= PCA963X_MODE2_INVRT; - i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2, - mode2); + i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2); } return 0; From af26bebea1199d8cbefd39b42ade40698504afba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:55 +0200 Subject: [PATCH 64/84] leds: pca963x: use devres LED registering function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using devres version of LED registering function we can remove the .remove method from this driver. The probe method also gets simpler. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index c03871f92fec..cbb3bf6c044f 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -432,9 +432,9 @@ static int pca963x_probe(struct i2c_client *client, if (pdata && pdata->blink_type == PCA963X_HW_BLINK) pca963x[i].led_cdev.blink_set = pca963x_blink_set; - err = led_classdev_register(dev, &pca963x[i].led_cdev); + err = devm_led_classdev_register(dev, &pca963x[i].led_cdev); if (err < 0) - goto exit; + return err; } /* Disable LED all-call address, and power down initially */ @@ -454,23 +454,6 @@ static int pca963x_probe(struct i2c_client *client, } return 0; - -exit: - while (i--) - led_classdev_unregister(&pca963x[i].led_cdev); - - return err; -} - -static int pca963x_remove(struct i2c_client *client) -{ - struct pca963x *pca963x = i2c_get_clientdata(client); - int i; - - for (i = 0; i < pca963x->chipdef->n_leds; i++) - led_classdev_unregister(&pca963x->leds[i].led_cdev); - - return 0; } static struct i2c_driver pca963x_driver = { @@ -479,7 +462,6 @@ static struct i2c_driver pca963x_driver = { .of_match_table = of_pca963x_match, }, .probe = pca963x_probe, - .remove = pca963x_remove, .id_table = pca963x_id, }; From fc0b1eca2ef0d2e5a8ea9ddfd45d6858df8fb02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:56 +0200 Subject: [PATCH 65/84] leds: pca963x: cosmetic: rename variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename variables chip and pca963x_chip to chipdef and chip, respectively, so that their names correspond to the names of their types. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 55 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index cbb3bf6c044f..bdb014c76a07 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -285,7 +285,7 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, } static struct pca963x_platform_data * -pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) +pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chipdef) { struct pca963x_platform_data *pdata; struct led_info *pca963x_leds; @@ -293,11 +293,11 @@ pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) int count; count = device_get_child_node_count(dev); - if (!count || count > chip->n_leds) + if (!count || count > chipdef->n_leds) return ERR_PTR(-ENODEV); - pca963x_leds = devm_kcalloc(dev, chip->n_leds, sizeof(struct led_info), - GFP_KERNEL); + pca963x_leds = devm_kcalloc(dev, chipdef->n_leds, + sizeof(struct led_info), GFP_KERNEL); if (!pca963x_leds) return ERR_PTR(-ENOMEM); @@ -307,7 +307,7 @@ pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) int res; res = fwnode_property_read_u32(child, "reg", ®); - if ((res != 0) || (reg >= chip->n_leds)) + if ((res != 0) || (reg >= chipdef->n_leds)) continue; res = fwnode_property_read_string(child, "label", &led.name); @@ -325,7 +325,7 @@ pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) return ERR_PTR(-ENOMEM); pdata->leds.leds = pca963x_leds; - pdata->leds.num_leds = chip->n_leds; + pdata->leds.num_leds = chipdef->n_leds; /* default to open-drain unless totem pole (push-pull) is specified */ if (device_property_read_bool(dev, "nxp,totem-pole")) @@ -340,8 +340,8 @@ pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chip) pdata->blink_type = PCA963X_SW_BLINK; if (device_property_read_u32(dev, "nxp,period-scale", - &chip->scaling)) - chip->scaling = 1000; + &chipdef->scaling)) + chipdef->scaling = 1000; /* default to non-inverted output, unless inverted is specified */ if (device_property_read_bool(dev, "nxp,inverted-out")) @@ -365,17 +365,17 @@ static int pca963x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; - struct pca963x *pca963x_chip; - struct pca963x_led *pca963x; + struct pca963x_chipdef *chipdef; struct pca963x_platform_data *pdata; - struct pca963x_chipdef *chip; + struct pca963x_led *pca963x; + struct pca963x *chip; int i, err; - chip = &pca963x_chipdefs[id->driver_data]; + chipdef = &pca963x_chipdefs[id->driver_data]; pdata = dev_get_platdata(dev); if (!pdata) { - pdata = pca963x_get_pdata(dev, chip); + pdata = pca963x_get_pdata(dev, chipdef); if (IS_ERR(pdata)) { dev_warn(dev, "could not parse configuration\n"); pdata = NULL; @@ -383,32 +383,33 @@ static int pca963x_probe(struct i2c_client *client, } if (pdata && (pdata->leds.num_leds < 1 || - pdata->leds.num_leds > chip->n_leds)) { - dev_err(dev, "board info must claim 1-%d LEDs", chip->n_leds); + pdata->leds.num_leds > chipdef->n_leds)) { + dev_err(dev, "board info must claim 1-%d LEDs", + chipdef->n_leds); return -EINVAL; } - pca963x_chip = devm_kzalloc(dev, sizeof(*pca963x_chip), GFP_KERNEL); - if (!pca963x_chip) + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) return -ENOMEM; - pca963x = devm_kcalloc(dev, chip->n_leds, sizeof(*pca963x), GFP_KERNEL); + pca963x = devm_kcalloc(dev, chipdef->n_leds, sizeof(*pca963x), GFP_KERNEL); if (!pca963x) return -ENOMEM; - i2c_set_clientdata(client, pca963x_chip); + i2c_set_clientdata(client, chip); - mutex_init(&pca963x_chip->mutex); - pca963x_chip->chipdef = chip; - pca963x_chip->client = client; - pca963x_chip->leds = pca963x; + mutex_init(&chip->mutex); + chip->chipdef = chipdef; + chip->client = client; + chip->leds = pca963x; /* Turn off LEDs by default*/ - for (i = 0; i < chip->n_leds / 4; i++) - i2c_smbus_write_byte_data(client, chip->ledout_base + i, 0x00); + for (i = 0; i < chipdef->n_leds / 4; i++) + i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00); - for (i = 0; i < chip->n_leds; i++) { + for (i = 0; i < chipdef->n_leds; i++) { pca963x[i].led_num = i; - pca963x[i].chip = pca963x_chip; + pca963x[i].chip = chip; /* Platform data can specify LED names and default triggers */ if (pdata && i < pdata->leds.num_leds) { From 5db8509349cea5df0e6562537d84f3e90fda3270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:57 +0200 Subject: [PATCH 66/84] leds: pca963x: cosmetic: rename variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename variable of type struct pca963x_led from pca963x to simple led. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 104 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index bdb014c76a07..a4096694925f 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -115,17 +115,17 @@ struct pca963x_led { u8 gfrq; }; -static int pca963x_brightness(struct pca963x_led *pca963x, +static int pca963x_brightness(struct pca963x_led *led, enum led_brightness brightness) { - struct i2c_client *client = pca963x->chip->client; - struct pca963x_chipdef *chipdef = pca963x->chip->chipdef; + struct i2c_client *client = led->chip->client; + struct pca963x_chipdef *chipdef = led->chip->chipdef; u8 ledout_addr, ledout, mask, val; int shift; int ret; - ledout_addr = chipdef->ledout_base + (pca963x->led_num / 4); - shift = 2 * (pca963x->led_num % 4); + ledout_addr = chipdef->ledout_base + (led->led_num / 4); + shift = 2 * (led->led_num % 4); mask = 0x3 << shift; ledout = i2c_smbus_read_byte_data(client, ledout_addr); @@ -141,7 +141,7 @@ static int pca963x_brightness(struct pca963x_led *pca963x, default: ret = i2c_smbus_write_byte_data(client, PCA963X_PWM_BASE + - pca963x->led_num, + led->led_num, brightness); if (ret < 0) return ret; @@ -154,27 +154,27 @@ static int pca963x_brightness(struct pca963x_led *pca963x, return ret; } -static void pca963x_blink(struct pca963x_led *pca963x) +static void pca963x_blink(struct pca963x_led *led) { - struct i2c_client *client = pca963x->chip->client; - struct pca963x_chipdef *chipdef = pca963x->chip->chipdef; + struct i2c_client *client = led->chip->client; + struct pca963x_chipdef *chipdef = led->chip->chipdef; u8 ledout_addr, ledout, mask, val, mode2; int shift; - ledout_addr = chipdef->ledout_base + (pca963x->led_num / 4); - shift = 2 * (pca963x->led_num % 4); + ledout_addr = chipdef->ledout_base + (led->led_num / 4); + shift = 2 * (led->led_num % 4); mask = 0x3 << shift; mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); - i2c_smbus_write_byte_data(client, chipdef->grppwm, pca963x->gdc); + i2c_smbus_write_byte_data(client, chipdef->grppwm, led->gdc); - i2c_smbus_write_byte_data(client, chipdef->grpfreq, pca963x->gfrq); + i2c_smbus_write_byte_data(client, chipdef->grpfreq, led->gfrq); if (!(mode2 & PCA963X_MODE2_DMBLNK)) i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2 | PCA963X_MODE2_DMBLNK); - mutex_lock(&pca963x->chip->mutex); + mutex_lock(&led->chip->mutex); ledout = i2c_smbus_read_byte_data(client, ledout_addr); if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift)) { @@ -182,19 +182,19 @@ static void pca963x_blink(struct pca963x_led *pca963x) i2c_smbus_write_byte_data(client, ledout_addr, val); } - mutex_unlock(&pca963x->chip->mutex); + mutex_unlock(&led->chip->mutex); } -static int pca963x_power_state(struct pca963x_led *pca963x) +static int pca963x_power_state(struct pca963x_led *led) { - struct i2c_client *client = pca963x->chip->client; - unsigned long *leds_on = &pca963x->chip->leds_on; + struct i2c_client *client = led->chip->client; + unsigned long *leds_on = &led->chip->leds_on; unsigned long cached_leds = *leds_on; - if (pca963x->led_cdev.brightness) - set_bit(pca963x->led_num, leds_on); + if (led->led_cdev.brightness) + set_bit(led->led_num, leds_on); else - clear_bit(pca963x->led_num, leds_on); + clear_bit(led->led_num, leds_on); if (!(*leds_on) != !cached_leds) return i2c_smbus_write_byte_data(client, PCA963X_MODE1, @@ -206,27 +206,27 @@ static int pca963x_power_state(struct pca963x_led *pca963x) static int pca963x_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct pca963x_led *pca963x; + struct pca963x_led *led; int ret; - pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); + led = container_of(led_cdev, struct pca963x_led, led_cdev); - mutex_lock(&pca963x->chip->mutex); + mutex_lock(&led->chip->mutex); - ret = pca963x_brightness(pca963x, value); + ret = pca963x_brightness(led, value); if (ret < 0) goto unlock; - ret = pca963x_power_state(pca963x); + ret = pca963x_power_state(led); unlock: - mutex_unlock(&pca963x->chip->mutex); + mutex_unlock(&led->chip->mutex); return ret; } -static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, +static unsigned int pca963x_period_scale(struct pca963x_led *led, unsigned int val) { - unsigned int scaling = pca963x->chip->chipdef->scaling; + unsigned int scaling = led->chip->chipdef->scaling; return scaling ? DIV_ROUND_CLOSEST(val * scaling, 1000) : val; } @@ -234,11 +234,11 @@ static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, static int pca963x_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { - struct pca963x_led *pca963x; unsigned long time_on, time_off, period; + struct pca963x_led *led; u8 gdc, gfrq; - pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); + led = container_of(led_cdev, struct pca963x_led, led_cdev); time_on = *delay_on; time_off = *delay_off; @@ -249,14 +249,14 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, time_off = 500; } - period = pca963x_period_scale(pca963x, time_on + time_off); + period = pca963x_period_scale(led, time_on + time_off); /* If period not supported by hardware, default to someting sane. */ if ((period < PCA963X_BLINK_PERIOD_MIN) || (period > PCA963X_BLINK_PERIOD_MAX)) { time_on = 500; time_off = 500; - period = pca963x_period_scale(pca963x, 1000); + period = pca963x_period_scale(led, 1000); } /* @@ -264,7 +264,7 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, * (time_on / period) = (GDC / 256) -> * GDC = ((time_on * 256) / period) */ - gdc = (pca963x_period_scale(pca963x, time_on) * 256) / period; + gdc = (pca963x_period_scale(led, time_on) * 256) / period; /* * From manual: period = ((GFRQ + 1) / 24) in seconds. @@ -273,10 +273,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, */ gfrq = (period * 24 / 1000) - 1; - pca963x->gdc = gdc; - pca963x->gfrq = gfrq; + led->gdc = gdc; + led->gfrq = gfrq; - pca963x_blink(pca963x); + pca963x_blink(led); *delay_on = time_on; *delay_off = time_off; @@ -367,7 +367,7 @@ static int pca963x_probe(struct i2c_client *client, struct device *dev = &client->dev; struct pca963x_chipdef *chipdef; struct pca963x_platform_data *pdata; - struct pca963x_led *pca963x; + struct pca963x_led *leds; struct pca963x *chip; int i, err; @@ -392,8 +392,8 @@ static int pca963x_probe(struct i2c_client *client, chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - pca963x = devm_kcalloc(dev, chipdef->n_leds, sizeof(*pca963x), GFP_KERNEL); - if (!pca963x) + leds = devm_kcalloc(dev, chipdef->n_leds, sizeof(*leds), GFP_KERNEL); + if (!leds) return -ENOMEM; i2c_set_clientdata(client, chip); @@ -401,39 +401,41 @@ static int pca963x_probe(struct i2c_client *client, mutex_init(&chip->mutex); chip->chipdef = chipdef; chip->client = client; - chip->leds = pca963x; + chip->leds = leds; /* Turn off LEDs by default*/ for (i = 0; i < chipdef->n_leds / 4; i++) i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00); for (i = 0; i < chipdef->n_leds; i++) { - pca963x[i].led_num = i; - pca963x[i].chip = chip; + struct pca963x_led *led = &leds[i]; + + led->led_num = i; + led->chip = chip; /* Platform data can specify LED names and default triggers */ if (pdata && i < pdata->leds.num_leds) { if (pdata->leds.leds[i].name) - snprintf(pca963x[i].name, - sizeof(pca963x[i].name), "pca963x:%s", + snprintf(led->name, + sizeof(led->name), "pca963x:%s", pdata->leds.leds[i].name); if (pdata->leds.leds[i].default_trigger) - pca963x[i].led_cdev.default_trigger = + led->led_cdev.default_trigger = pdata->leds.leds[i].default_trigger; } if (!pdata || i >= pdata->leds.num_leds || !pdata->leds.leds[i].name) - snprintf(pca963x[i].name, sizeof(pca963x[i].name), + snprintf(led->name, sizeof(led->name), "pca963x:%d:%.2x:%d", client->adapter->nr, client->addr, i); - pca963x[i].led_cdev.name = pca963x[i].name; - pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set; + led->led_cdev.name = led->name; + led->led_cdev.brightness_set_blocking = pca963x_led_set; if (pdata && pdata->blink_type == PCA963X_HW_BLINK) - pca963x[i].led_cdev.blink_set = pca963x_blink_set; + led->led_cdev.blink_set = pca963x_blink_set; - err = devm_led_classdev_register(dev, &pca963x[i].led_cdev); + err = devm_led_classdev_register(dev, &led->led_cdev); if (err < 0) return err; } From b5a3b44f2ddc4af49420f430b208ff8060ab7555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:58 +0200 Subject: [PATCH 67/84] leds: pca963x: use flexible array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of doing two allocations, allocate only once, by utilizing flexible array members. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index a4096694925f..73dc00787bee 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -96,15 +96,7 @@ static const struct i2c_device_id pca963x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca963x_id); -struct pca963x_led; - -struct pca963x { - struct pca963x_chipdef *chipdef; - struct mutex mutex; - struct i2c_client *client; - struct pca963x_led *leds; - unsigned long leds_on; -}; +struct pca963x; struct pca963x_led { struct pca963x *chip; @@ -115,6 +107,14 @@ struct pca963x_led { u8 gfrq; }; +struct pca963x { + struct pca963x_chipdef *chipdef; + struct mutex mutex; + struct i2c_client *client; + unsigned long leds_on; + struct pca963x_led leds[]; +}; + static int pca963x_brightness(struct pca963x_led *led, enum led_brightness brightness) { @@ -367,7 +367,6 @@ static int pca963x_probe(struct i2c_client *client, struct device *dev = &client->dev; struct pca963x_chipdef *chipdef; struct pca963x_platform_data *pdata; - struct pca963x_led *leds; struct pca963x *chip; int i, err; @@ -389,26 +388,23 @@ static int pca963x_probe(struct i2c_client *client, return -EINVAL; } - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, struct_size(chip, leds, chipdef->n_leds), + GFP_KERNEL); if (!chip) return -ENOMEM; - leds = devm_kcalloc(dev, chipdef->n_leds, sizeof(*leds), GFP_KERNEL); - if (!leds) - return -ENOMEM; i2c_set_clientdata(client, chip); mutex_init(&chip->mutex); chip->chipdef = chipdef; chip->client = client; - chip->leds = leds; /* Turn off LEDs by default*/ for (i = 0; i < chipdef->n_leds / 4; i++) i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00); for (i = 0; i < chipdef->n_leds; i++) { - struct pca963x_led *led = &leds[i]; + struct pca963x_led *led = &chip->leds[i]; led->led_num = i; led->chip = chip; From 9e955a421d1586bfc56c667b9f2e81f4f226cfef Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 22 Sep 2020 14:06:37 -0500 Subject: [PATCH 68/84] leds: lm3532: Fix warnings for undefined parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warnings for undefined parameters when W=1 is used. Signed-off-by: Dan Murphy Reviewed-by: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/leds-lm3532.c | 50 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/leds/leds-lm3532.c b/drivers/leds/leds-lm3532.c index 10ded9192fb1..0bf25bdde02f 100644 --- a/drivers/leds/leds-lm3532.c +++ b/drivers/leds/leds-lm3532.c @@ -96,15 +96,15 @@ /* * struct lm3532_als_data - * @config - value of ALS configuration register - * @als1_imp_sel - value of ALS1 resistor select register - * @als2_imp_sel - value of ALS2 resistor select register - * @als_avrg_time - ALS averaging time - * @als_input_mode - ALS input mode for brightness control - * @als_vmin - Minimum ALS voltage - * @als_vmax - Maximum ALS voltage - * @zone_lo - values of ALS lo ZB(Zone Boundary) registers - * @zone_hi - values of ALS hi ZB(Zone Boundary) registers + * @config: value of ALS configuration register + * @als1_imp_sel: value of ALS1 resistor select register + * @als2_imp_sel: value of ALS2 resistor select register + * @als_avrg_time: ALS averaging time + * @als_input_mode: ALS input mode for brightness control + * @als_vmin: Minimum ALS voltage + * @als_vmax: Maximum ALS voltage + * @zone_lo: values of ALS lo ZB(Zone Boundary) registers + * @zone_hi: values of ALS hi ZB(Zone Boundary) registers */ struct lm3532_als_data { u8 config; @@ -121,14 +121,14 @@ struct lm3532_als_data { /** * struct lm3532_led * @led_dev: led class device - * @priv - Pointer the device data structure - * @control_bank - Control bank the LED is associated to - * @mode - Mode of the LED string - * @ctrl_brt_pointer - Zone target register that controls the sink - * @num_leds - Number of LED strings are supported in this array - * @full_scale_current - The full-scale current setting for the current sink. - * @led_strings - The LED strings supported in this array - * @enabled - Enabled status + * @priv: Pointer the device data structure + * @control_bank: Control bank the LED is associated to + * @mode: Mode of the LED string + * @ctrl_brt_pointer: Zone target register that controls the sink + * @num_leds: Number of LED strings are supported in this array + * @full_scale_current: The full-scale current setting for the current sink. + * @led_strings: The LED strings supported in this array + * @enabled: Enabled status */ struct lm3532_led { struct led_classdev led_dev; @@ -145,16 +145,16 @@ struct lm3532_led { /** * struct lm3532_data - * @enable_gpio - Hardware enable gpio + * @enable_gpio: Hardware enable gpio * @regulator: regulator * @client: i2c client - * @regmap - Devices register map - * @dev - Pointer to the devices device struct - * @lock - Lock for reading/writing the device - * @als_data - Pointer to the als data struct - * @runtime_ramp_up - Runtime ramp up setting - * @runtime_ramp_down - Runtime ramp down setting - * @leds - Array of LED strings + * @regmap: Devices register map + * @dev: Pointer to the devices device struct + * @lock: Lock for reading/writing the device + * @als_data: Pointer to the als data struct + * @runtime_ramp_up: Runtime ramp up setting + * @runtime_ramp_down: Runtime ramp down setting + * @leds: Array of LED strings */ struct lm3532_data { struct gpio_desc *enable_gpio; From 9adc8af4c2f414a03235ae5403433ff1090a00ff Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 22 Sep 2020 14:06:38 -0500 Subject: [PATCH 69/84] leds: lm36274: Fix warning for undefined parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warnings for undefined parameters when building with W=1. Signed-off-by: Dan Murphy Reviewed-by: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/leds-lm36274.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index 582c6a821dc8..aadb03468a40 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -26,8 +26,8 @@ * @lmu_data: Register and setting values for common code * @regmap: Devices register map * @dev: Pointer to the devices device struct - * @led_sources - The LED strings supported in this array - * @num_leds - Number of LED strings are supported in this array + * @led_sources: The LED strings supported in this array + * @num_leds: Number of LED strings are supported in this array */ struct lm36274 { struct platform_device *pdev; @@ -160,6 +160,7 @@ static struct platform_driver lm36274_driver = { .probe = lm36274_probe, .driver = { .name = "lm36274-leds", + .of_match_table = of_lm36274_leds_match, }, }; module_platform_driver(lm36274_driver) From 2a378856e32c98f747bde3fd338ca0e322aae8cb Mon Sep 17 00:00:00 2001 From: Markus Moll Date: Tue, 22 Sep 2020 21:28:35 +0200 Subject: [PATCH 70/84] leds: pca9532: correct shift computation in pca9532_getled Each led setting occupies two bits in a corresponding led register. Accessing these bits requires shifting and masking, which was implemented incorrectly in pca9532_getled. Two new helper macros concentrate the computation of those masks in one place. Signed-off-by: Markus Moll Signed-off-by: Pavel Machek --- drivers/leds/leds-pca9532.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 41229f775d35..d37fd9577d4b 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -27,6 +27,8 @@ #define PCA9532_REG_PWM(m, i) (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2) #define LED_REG(m, led) (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2)) #define LED_NUM(led) (led & 0x3) +#define LED_SHIFT(led) (LED_NUM(led) * 2) +#define LED_MASK(led) (0x3 << LED_SHIFT(led)) #define ldev_to_led(c) container_of(c, struct pca9532_led, ldev) @@ -162,9 +164,9 @@ static void pca9532_setled(struct pca9532_led *led) mutex_lock(&data->update_lock); reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id)); /* zero led bits */ - reg = reg & ~(0x3<id)*2); + reg = reg & ~LED_MASK(led->id); /* set the new value */ - reg = reg | (led->state << LED_NUM(led->id)*2); + reg = reg | (led->state << LED_SHIFT(led->id)); i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg); mutex_unlock(&data->update_lock); } @@ -260,7 +262,7 @@ static enum pca9532_state pca9532_getled(struct pca9532_led *led) mutex_lock(&data->update_lock); reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id)); - ret = reg >> LED_NUM(led->id)/2; + ret = (reg & LED_MASK(led->id)) >> LED_SHIFT(led->id); mutex_unlock(&data->update_lock); return ret; } From 7ac5338c3c7c849729f629b6a35d88ac3d43cc56 Mon Sep 17 00:00:00 2001 From: Markus Moll Date: Tue, 22 Sep 2020 21:31:15 +0200 Subject: [PATCH 71/84] leds: pca9532: read pwm settings from device tree While the two pca9532 pwms can be configured in the platform data struct, there was no corresponding dt binding. Users need to configure the pwm if some leds should blink or continue blinking during boot. Signed-off-by: Markus Moll Signed-off-by: Pavel Machek --- drivers/leds/leds-pca9532.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index d37fd9577d4b..27d027165472 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -480,6 +480,11 @@ pca9532_of_populate_pdata(struct device *dev, struct device_node *np) if (!pdata) return ERR_PTR(-ENOMEM); + of_property_read_u8_array(np, "nxp,pwm", &pdata->pwm[0], + ARRAY_SIZE(pdata->pwm)); + of_property_read_u8_array(np, "nxp,psc", &pdata->psc[0], + ARRAY_SIZE(pdata->psc)); + for_each_available_child_of_node(np, child) { if (of_property_read_string(child, "label", &pdata->leds[i].name)) From 364682d1bc16277b67f31e411a00e13c50002d2e Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 25 Sep 2020 11:29:17 +0200 Subject: [PATCH 72/84] leds: TODO: Add documentation about possible subsystem improvements Help welcome :-). Signed-off-by: Pavel Machek --- drivers/leds/TODO | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 drivers/leds/TODO diff --git a/drivers/leds/TODO b/drivers/leds/TODO new file mode 100644 index 000000000000..bfa60fa1d812 --- /dev/null +++ b/drivers/leds/TODO @@ -0,0 +1,75 @@ +-*- org -*- + +* On/off LEDs should have max_brightness of 1 +* Get rid of enum led_brightness + +It is really an integer, as maximum is configurable. Get rid of it, or +make it into typedef or something. + +* Review atomicity requirements in LED subsystem + +Calls that may and that may not block are mixed in same structure, and +semantics is sometimes non-intuitive. (For example blink callback may +not sleep.) Review the requirements for any bugs and document them +clearly. + +* LED names are still a mess + +No two LEDs have same name, so the names are probably unusable for the +userland. Nudge authors into creating common LED names for common +functionality. + +? Perhaps check for known LED names during boot, and warn if there are +LEDs not on the list? + +* Split drivers into subdirectories + +The number of drivers is getting big, and driver for on/off LED on a +i/o port is really quite different from camera flash LED, which is +really different from driver for RGB color LED that can run its own +microcode. Split the drivers somehow. + +* Figure out what to do with RGB leds + +Multicolor is a bit too abstract. Yes, we can have +Green-Magenta-Ultraviolet LED, but so far all the LEDs we support are +RGB, and not even RGB-White or RGB-Yellow variants emerged. + +Multicolor is not a good fit for RGB LED. It does not really know +about LED color. In particular, there's no way to make LED "white". + +Userspace is interested in knowing "this LED can produce arbitrary +color", which not all multicolor LEDs can. + + Proposal: let's add "rgb" to led_colors in drivers/leds/led-core.c, + add corresponding device tree defines, and use that, instead of + multicolor for RGB LEDs. + + We really need to do that now; "white" stuff can wait. + +RGB LEDs are quite common, and it would be good to be able to turn LED +white and to turn it into any arbitrary color. It is essential that +userspace is able to set arbitrary colors, and it might be good to +have that ability from kernel, too... to allow full-color triggers. + +* Command line utility to manipulate the LEDs? + +/sys interface is not really suitable to use by hand, should we have +an utility to perform LED control? + +In particular, LED names are still a mess (see above) and utility +could help there by presenting both old and new names while we clean +them up. + +In future, I'd like utility to accept both old and new names while we +clean them up. + +It would be also nice to have useful listing mode -- name, type, +current brightness/trigger... + +In future, it would be good to be able to set rgb led to particular +color. + +And probably user-friendly interface to access LEDs for particular +ethernet interface would be nice. + From abcc131292aa8c7de2c5f0ed76a717436c21de63 Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sat, 19 Sep 2020 11:34:58 +0200 Subject: [PATCH 73/84] ledtrig-cpu: Limit to 8 CPUs Some machines have thousands of CPUs... and trigger mechanisms was not really meant for thousands of triggers. I doubt anyone uses this trigger on many-CPU machine; but if they do, they'll need to do it properly. Signed-off-by: Pavel Machek --- drivers/leds/trigger/ledtrig-cpu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c index 869976d1b734..fca62d503590 100644 --- a/drivers/leds/trigger/ledtrig-cpu.c +++ b/drivers/leds/trigger/ledtrig-cpu.c @@ -2,14 +2,18 @@ /* * ledtrig-cpu.c - LED trigger based on CPU activity * - * This LED trigger will be registered for each possible CPU and named as - * cpu0, cpu1, cpu2, cpu3, etc. + * This LED trigger will be registered for first 8 CPUs and named + * as cpu0..cpu7. There's additional trigger called cpu that + * is on when any CPU is active. + * + * If you want support for arbitrary number of CPUs, make it one trigger, + * with additional sysfs file selecting which CPU to watch. * * It can be bound to any LED just like other triggers using either a * board file or via sysfs interface. * * An API named ledtrig_cpu is exported for any user, who want to add CPU - * activity indication in their code + * activity indication in their code. * * Copyright 2011 Linus Walleij * Copyright 2011 - 2012 Bryan Wu @@ -145,6 +149,9 @@ static int __init ledtrig_cpu_init(void) for_each_possible_cpu(cpu) { struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu); + if (cpu >= 8) + continue; + snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu); led_trigger_register_simple(trig->name, &trig->_trig); From 9694881d92f4163d556ac9e4c6d2614cb90d74e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:38 +0200 Subject: [PATCH 74/84] dt-bindings: leds: tca6507: convert to YAML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This converts the tca6507 LED binding to yaml. Signed-off-by: Marek Behún Cc: NeilBrown Cc: Linus Walleij Cc: H. Nikolaus Schaller Cc: Tony Lindgren Cc: Adam Ford Cc: Viresh Kumar Reviewed-by: Rob Herring Cc: devicetree@vger.kernel.org Signed-off-by: Pavel Machek --- .../devicetree/bindings/leds/tca6507.txt | 49 ------- .../devicetree/bindings/leds/ti,tca6507.yaml | 134 ++++++++++++++++++ 2 files changed, 134 insertions(+), 49 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/tca6507.txt create mode 100644 Documentation/devicetree/bindings/leds/ti,tca6507.yaml diff --git a/Documentation/devicetree/bindings/leds/tca6507.txt b/Documentation/devicetree/bindings/leds/tca6507.txt deleted file mode 100644 index bad9102796f3..000000000000 --- a/Documentation/devicetree/bindings/leds/tca6507.txt +++ /dev/null @@ -1,49 +0,0 @@ -LEDs connected to tca6507 - -Required properties: -- compatible : should be : "ti,tca6507". -- #address-cells: must be 1 -- #size-cells: must be 0 -- reg: typically 0x45. - -Optional properties: -- gpio-controller: allows lines to be used as output-only GPIOs. -- #gpio-cells: if present, must not be 0. - -Each led is represented as a sub-node of the ti,tca6507 device. - -LED sub-node properties: -- label : (optional) see Documentation/devicetree/bindings/leds/common.txt -- reg : number of LED line (could be from 0 to 6) -- linux,default-trigger : (optional) - see Documentation/devicetree/bindings/leds/common.txt -- compatible: either "led" (the default) or "gpio". - -Examples: - -tca6507@45 { - compatible = "ti,tca6507"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x45>; - - gpio-controller; - #gpio-cells = <2>; - - led0: red-aux@0 { - label = "red:aux"; - reg = <0x0>; - }; - - led1: green-aux@1 { - label = "green:aux"; - reg = <0x5>; - linux,default-trigger = "default-on"; - }; - - wifi-reset@6 { - reg = <0x6>; - compatible = "gpio"; - }; -}; - diff --git a/Documentation/devicetree/bindings/leds/ti,tca6507.yaml b/Documentation/devicetree/bindings/leds/ti,tca6507.yaml new file mode 100644 index 000000000000..94c307c98762 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/ti,tca6507.yaml @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/ti,tca6507.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TCA6507 LED and GPIO controller + +maintainers: + - NeilBrown + +description: + The TCA6507 is a programmable LED controller connected via I2C that can drive + 7 separate lines either by holding them low, or by pulsing them with modulated + width. + +properties: + compatible: + const: ti,tca6507 + + reg: + description: I2C slave address of the controller. + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + gpio-line-names: true + +patternProperties: + "^led@[0-6]$": + type: object + + $ref: common.yaml# + + properties: + reg: + minimum: 0 + maximum: 6 + + required: + - reg + + "^gpio@[0-6]$": + type: object + + properties: + compatible: + const: gpio + + reg: + minimum: 0 + maximum: 6 + + additionalProperties: false + + required: + - reg + - compatible + +if: + patternProperties: + "^gpio@[0-6]$": + properties: + compatible: + contains: + const: gpio +then: + required: + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + + #include + #include + + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@45 { + compatible = "ti,tca6507"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x45>; + + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = "wifi_reset@6"; + + led@0 { + label = "gta04:red:aux"; + reg = <0x0>; + }; + + led@1 { + label = "gta04:green:aux"; + reg = <0x1>; + }; + + led@3 { + reg = <0x3>; + color = ; + function = LED_FUNCTION_POWER; + linux,default-trigger = "default-on"; + }; + + led@4 { + color = ; + function = LED_FUNCTION_POWER; + reg = <0x4>; + }; + + gpio@6 { + compatible = "gpio"; + reg = <0x6>; + }; + }; + }; + +... From b7f0b3bd1fe362160164a3dec3e8063ba3389549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:40 +0200 Subject: [PATCH 75/84] leds: tca6507: do not set GPIO names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not set GPIO names. Let gpiolib determine GPIO names from the DT property `gpio-line-names`. Signed-off-by: Marek Behún Cc: NeilBrown Cc: Linus Walleij Cc: H. Nikolaus Schaller Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index d589c89930fd..5004278c6b99 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -197,7 +197,6 @@ struct tca6507_chip { } leds[NUM_LEDS]; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; - const char *gpio_name[NUM_LEDS]; int gpio_map[NUM_LEDS]; #endif }; @@ -647,7 +646,6 @@ static int tca6507_probe_gpios(struct i2c_client *client, for (i = 0; i < NUM_LEDS; i++) if (pdata->leds.leds[i].name && pdata->leds.leds[i].flags) { /* Configure as a gpio */ - tca->gpio_name[gpios] = pdata->leds.leds[i].name; tca->gpio_map[gpios] = i; gpios++; } @@ -656,7 +654,6 @@ static int tca6507_probe_gpios(struct i2c_client *client, return 0; tca->gpio.label = "gpio-tca6507"; - tca->gpio.names = tca->gpio_name; tca->gpio.ngpio = gpios; tca->gpio.base = pdata->gpio_base; tca->gpio.owner = THIS_MODULE; From c1ff1a1d3598964bd4bfe1effff1100aa0e79f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:41 +0200 Subject: [PATCH 76/84] leds: tca6507: cosmetic change: use helper variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use helper variable dev instead of always writing &client->dev. Signed-off-by: Marek Behún Cc: NeilBrown Cc: Linus Walleij Cc: H. Nikolaus Schaller Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 5004278c6b99..80505da55e37 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -635,7 +635,7 @@ static int tca6507_gpio_direction_output(struct gpio_chip *gc, return 0; } -static int tca6507_probe_gpios(struct i2c_client *client, +static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { @@ -659,9 +659,9 @@ static int tca6507_probe_gpios(struct i2c_client *client, tca->gpio.owner = THIS_MODULE; tca->gpio.direction_output = tca6507_gpio_direction_output; tca->gpio.set = tca6507_gpio_set_value; - tca->gpio.parent = &client->dev; + tca->gpio.parent = dev; #ifdef CONFIG_OF_GPIO - tca->gpio.of_node = of_node_get(dev_of_node(&client->dev)); + tca->gpio.of_node = of_node_get(dev_of_node(dev)); #endif err = gpiochip_add_data(&tca->gpio, tca); if (err) { @@ -677,7 +677,7 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) gpiochip_remove(&tca->gpio); } #else /* CONFIG_GPIOLIB */ -static int tca6507_probe_gpios(struct i2c_client *client, +static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { @@ -689,23 +689,23 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) #endif /* CONFIG_GPIOLIB */ static struct tca6507_platform_data * -tca6507_led_dt_init(struct i2c_client *client) +tca6507_led_dt_init(struct device *dev) { struct tca6507_platform_data *pdata; struct fwnode_handle *child; struct led_info *tca_leds; int count; - count = device_get_child_node_count(&client->dev); + count = device_get_child_node_count(dev); if (!count || count > NUM_LEDS) return ERR_PTR(-ENODEV); - tca_leds = devm_kcalloc(&client->dev, NUM_LEDS, sizeof(struct led_info), + tca_leds = devm_kcalloc(dev, NUM_LEDS, sizeof(struct led_info), GFP_KERNEL); if (!tca_leds) return ERR_PTR(-ENOMEM); - device_for_each_child_node(&client->dev, child) { + device_for_each_child_node(dev, child) { struct led_info led; u32 reg; int ret; @@ -730,7 +730,7 @@ tca6507_led_dt_init(struct i2c_client *client) tca_leds[reg] = led; } - pdata = devm_kzalloc(&client->dev, sizeof(struct tca6507_platform_data), + pdata = devm_kzalloc(dev, sizeof(struct tca6507_platform_data), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); @@ -753,8 +753,9 @@ MODULE_DEVICE_TABLE(of, of_tca6507_leds_match); static int tca6507_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tca6507_chip *tca; + struct device *dev = &client->dev; struct i2c_adapter *adapter; + struct tca6507_chip *tca; struct tca6507_platform_data *pdata; int err; int i = 0; @@ -764,13 +765,12 @@ static int tca6507_probe(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -EIO; - pdata = tca6507_led_dt_init(client); + pdata = tca6507_led_dt_init(dev); if (IS_ERR(pdata)) { - dev_err(&client->dev, "Need %d entries in platform-data list\n", - NUM_LEDS); + dev_err(dev, "Need %d entries in platform-data list\n", NUM_LEDS); return PTR_ERR(pdata); } - tca = devm_kzalloc(&client->dev, sizeof(*tca), GFP_KERNEL); + tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL); if (!tca) return -ENOMEM; @@ -791,13 +791,12 @@ static int tca6507_probe(struct i2c_client *client, l->led_cdev.brightness_set = tca6507_brightness_set; l->led_cdev.blink_set = tca6507_blink_set; l->bank = -1; - err = led_classdev_register(&client->dev, - &l->led_cdev); + err = led_classdev_register(dev, &l->led_cdev); if (err < 0) goto exit; } } - err = tca6507_probe_gpios(client, tca, pdata); + err = tca6507_probe_gpios(dev, tca, pdata); if (err) goto exit; /* set all registers to known state - zero */ From 7e2dc43da2c0e9352766de5d578edbcfd2c548eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 00:15:43 +0200 Subject: [PATCH 77/84] leds: tca6507: remove binding comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the binding comment at the beginning. The information for platdata is now obsolete and DT binding is documented in device-tree bindings. Signed-off-by: Marek Behún Cc: NeilBrown Cc: Linus Walleij Cc: H. Nikolaus Schaller Signed-off-by: Pavel Machek --- drivers/leds/leds-tca6507.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index 80505da55e37..225b765830bd 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -69,23 +69,6 @@ * defaulted. Similarly the banks know if each time was explicit or a * default. Defaults are permitted to be changed freely - they are * not recognised when matching. - * - * - * An led-tca6507 device must be provided with platform data or - * configured via devicetree. - * - * The platform-data lists for each output: the name, default trigger, - * and whether the signal is being used as a GPIO rather than an LED. - * 'struct led_plaform_data' is used for this. If 'name' is NULL, the - * output isn't used. If 'flags' is TCA6507_MAKE_GPIO, the output is - * a GPO. The "struct led_platform_data" can be embedded in a "struct - * tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and - * a 'setup' callback which is called once the GPIOs are available. - * - * When configured via devicetree there is one child for each output. - * The "reg" determines the output number and "compatible" determines - * whether it is an LED or a GPIO. "linux,default-trigger" can set a - * default trigger. */ #include From 85fc8efe85d405b80904f73e4e23184a84283753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:24:59 +0200 Subject: [PATCH 78/84] leds: pca963x: register LEDs immediately after parsing, get rid of platdata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register LEDs immediately after parsing their properties. This allows us to get rid of platdata, and since no one in tree uses header linux/platform_data/leds-pca963x.h, remove it. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 196 ++++++++------------- include/linux/platform_data/leds-pca963x.h | 35 ---- 2 files changed, 75 insertions(+), 156 deletions(-) delete mode 100644 include/linux/platform_data/leds-pca963x.h diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 73dc00787bee..5083ccce1a51 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -32,7 +32,6 @@ #include #include #include -#include /* LED select registers determine the source that drives LED outputs */ #define PCA963X_LED_OFF 0x0 /* LED driver off */ @@ -102,7 +101,6 @@ struct pca963x_led { struct pca963x *chip; struct led_classdev led_cdev; int led_num; /* 0 .. 15 potentially */ - char name[32]; u8 gdc; u8 gfrq; }; @@ -284,72 +282,85 @@ static int pca963x_blink_set(struct led_classdev *led_cdev, return 0; } -static struct pca963x_platform_data * -pca963x_get_pdata(struct device *dev, struct pca963x_chipdef *chipdef) +static int pca963x_register_leds(struct i2c_client *client, + struct pca963x *chip) { - struct pca963x_platform_data *pdata; - struct led_info *pca963x_leds; + struct pca963x_chipdef *chipdef = chip->chipdef; + struct pca963x_led *led = chip->leds; + struct device *dev = &client->dev; struct fwnode_handle *child; - int count; - - count = device_get_child_node_count(dev); - if (!count || count > chipdef->n_leds) - return ERR_PTR(-ENODEV); - - pca963x_leds = devm_kcalloc(dev, chipdef->n_leds, - sizeof(struct led_info), GFP_KERNEL); - if (!pca963x_leds) - return ERR_PTR(-ENOMEM); - - device_for_each_child_node(dev, child) { - struct led_info led = {}; - u32 reg; - int res; - - res = fwnode_property_read_u32(child, "reg", ®); - if ((res != 0) || (reg >= chipdef->n_leds)) - continue; - - res = fwnode_property_read_string(child, "label", &led.name); - if ((res != 0) && is_of_node(child)) - led.name = to_of_node(child)->name; - - fwnode_property_read_string(child, "linux,default-trigger", - &led.default_trigger); - - pca963x_leds[reg] = led; - } - pdata = devm_kzalloc(dev, sizeof(struct pca963x_platform_data), - GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - pdata->leds.leds = pca963x_leds; - pdata->leds.num_leds = chipdef->n_leds; - - /* default to open-drain unless totem pole (push-pull) is specified */ - if (device_property_read_bool(dev, "nxp,totem-pole")) - pdata->outdrv = PCA963X_TOTEM_POLE; - else - pdata->outdrv = PCA963X_OPEN_DRAIN; - - /* default to software blinking unless hardware blinking is specified */ - if (device_property_read_bool(dev, "nxp,hw-blink")) - pdata->blink_type = PCA963X_HW_BLINK; - else - pdata->blink_type = PCA963X_SW_BLINK; + const char *name; + char label[64]; + bool hw_blink; + s32 mode2; + u32 reg; + int ret; if (device_property_read_u32(dev, "nxp,period-scale", &chipdef->scaling)) chipdef->scaling = 1000; + hw_blink = device_property_read_bool(dev, "nxp,hw-blink"); + + mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); + if (mode2 < 0) + return mode2; + + /* default to open-drain unless totem pole (push-pull) is specified */ + if (device_property_read_bool(dev, "nxp,totem-pole")) + mode2 |= PCA963X_MODE2_OUTDRV; + else + mode2 &= ~PCA963X_MODE2_OUTDRV; + /* default to non-inverted output, unless inverted is specified */ if (device_property_read_bool(dev, "nxp,inverted-out")) - pdata->dir = PCA963X_INVERTED; + mode2 |= PCA963X_MODE2_INVRT; else - pdata->dir = PCA963X_NORMAL; + mode2 &= ~PCA963X_MODE2_INVRT; - return pdata; + ret = i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2); + if (ret < 0) + return ret; + + device_for_each_child_node(dev, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg >= chipdef->n_leds) { + dev_err(dev, "Invalid 'reg' property for node %pfw\n", + child); + ret = -EINVAL; + goto err; + } + + ret = fwnode_property_read_string(child, "label", &name); + if (!fwnode_property_read_string(child, "label", &name)) + snprintf(label, sizeof(label), "pca963x:%s", name); + else + snprintf(label, sizeof(label), "pca963x::"); + + fwnode_property_read_string(child, "linux,default-trigger", + &led->led_cdev.default_trigger); + + led->led_num = reg; + led->chip = chip; + led->led_cdev.name = label; + led->led_cdev.brightness_set_blocking = pca963x_led_set; + if (hw_blink) + led->led_cdev.blink_set = pca963x_blink_set; + + ret = devm_led_classdev_register(dev, &led->led_cdev); + if (ret) { + dev_err(dev, "Failed to register LED for node %pfw\n", + child); + goto err; + } + + ++led; + } + + return 0; +err: + fwnode_handle_put(child); + return ret; } static const struct of_device_id of_pca963x_match[] = { @@ -366,30 +377,19 @@ static int pca963x_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct pca963x_chipdef *chipdef; - struct pca963x_platform_data *pdata; struct pca963x *chip; - int i, err; + int i, count; chipdef = &pca963x_chipdefs[id->driver_data]; - pdata = dev_get_platdata(dev); - if (!pdata) { - pdata = pca963x_get_pdata(dev, chipdef); - if (IS_ERR(pdata)) { - dev_warn(dev, "could not parse configuration\n"); - pdata = NULL; - } - } - - if (pdata && (pdata->leds.num_leds < 1 || - pdata->leds.num_leds > chipdef->n_leds)) { - dev_err(dev, "board info must claim 1-%d LEDs", - chipdef->n_leds); + count = device_get_child_node_count(dev); + if (!count || count > chipdef->n_leds) { + dev_err(dev, "Node %pfw must define between 1 and %d LEDs\n", + dev_fwnode(dev), chipdef->n_leds); return -EINVAL; } - chip = devm_kzalloc(dev, struct_size(chip, leds, chipdef->n_leds), - GFP_KERNEL); + chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -403,56 +403,10 @@ static int pca963x_probe(struct i2c_client *client, for (i = 0; i < chipdef->n_leds / 4; i++) i2c_smbus_write_byte_data(client, chipdef->ledout_base + i, 0x00); - for (i = 0; i < chipdef->n_leds; i++) { - struct pca963x_led *led = &chip->leds[i]; - - led->led_num = i; - led->chip = chip; - - /* Platform data can specify LED names and default triggers */ - if (pdata && i < pdata->leds.num_leds) { - if (pdata->leds.leds[i].name) - snprintf(led->name, - sizeof(led->name), "pca963x:%s", - pdata->leds.leds[i].name); - if (pdata->leds.leds[i].default_trigger) - led->led_cdev.default_trigger = - pdata->leds.leds[i].default_trigger; - } - if (!pdata || i >= pdata->leds.num_leds || - !pdata->leds.leds[i].name) - snprintf(led->name, sizeof(led->name), - "pca963x:%d:%.2x:%d", client->adapter->nr, - client->addr, i); - - led->led_cdev.name = led->name; - led->led_cdev.brightness_set_blocking = pca963x_led_set; - - if (pdata && pdata->blink_type == PCA963X_HW_BLINK) - led->led_cdev.blink_set = pca963x_blink_set; - - err = devm_led_classdev_register(dev, &led->led_cdev); - if (err < 0) - return err; - } - /* Disable LED all-call address, and power down initially */ i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); - if (pdata) { - u8 mode2 = i2c_smbus_read_byte_data(client, PCA963X_MODE2); - /* Configure output: open-drain or totem pole (push-pull) */ - if (pdata->outdrv == PCA963X_OPEN_DRAIN) - mode2 &= ~PCA963X_MODE2_OUTDRV; - else - mode2 |= PCA963X_MODE2_OUTDRV; - /* Configure direction: normal or inverted */ - if (pdata->dir == PCA963X_INVERTED) - mode2 |= PCA963X_MODE2_INVRT; - i2c_smbus_write_byte_data(client, PCA963X_MODE2, mode2); - } - - return 0; + return pca963x_register_leds(client, chip); } static struct i2c_driver pca963x_driver = { diff --git a/include/linux/platform_data/leds-pca963x.h b/include/linux/platform_data/leds-pca963x.h deleted file mode 100644 index 6091337ce4bf..000000000000 --- a/include/linux/platform_data/leds-pca963x.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * PCA963X LED chip driver. - * - * Copyright 2012 bct electronic GmbH - * Copyright 2013 Qtechnology A/S - */ - -#ifndef __LINUX_PCA963X_H -#define __LINUX_PCA963X_H -#include - -enum pca963x_outdrv { - PCA963X_OPEN_DRAIN, - PCA963X_TOTEM_POLE, /* aka push-pull */ -}; - -enum pca963x_blink_type { - PCA963X_SW_BLINK, - PCA963X_HW_BLINK, -}; - -enum pca963x_direction { - PCA963X_NORMAL, - PCA963X_INVERTED, -}; - -struct pca963x_platform_data { - struct led_platform_data leds; - enum pca963x_outdrv outdrv; - enum pca963x_blink_type blink_type; - enum pca963x_direction dir; -}; - -#endif /* __LINUX_PCA963X_H*/ From 564ead1280d7590f0015d8225637d546e9fa94eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sun, 20 Sep 2020 02:25:00 +0200 Subject: [PATCH 79/84] leds: pca963x: use struct led_init_data when registering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using struct led_init_data when registering we do not need to parse `label` DT property. Moreover `label` is deprecated and if it is not present but `color` and `function` are, LED core will compose a name from these properties instead. Previously if the `label` DT property was not present, the code composed name for the LED in the form "pca963x:%d:%.2x:%u" For backwards compatibility we therefore set init_data->default_label to this value so that the LED will not get a different name if `label` property is not present, nor are `color` and `function`. Signed-off-by: Marek Behún Cc: Peter Meerwald Cc: Ricardo Ribalda Cc: Zahari Petkov Signed-off-by: Pavel Machek --- drivers/leds/leds-pca963x.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index 5083ccce1a51..00aecd67e348 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c @@ -289,8 +289,6 @@ static int pca963x_register_leds(struct i2c_client *client, struct pca963x_led *led = chip->leds; struct device *dev = &client->dev; struct fwnode_handle *child; - const char *name; - char label[64]; bool hw_blink; s32 mode2; u32 reg; @@ -323,6 +321,9 @@ static int pca963x_register_leds(struct i2c_client *client, return ret; device_for_each_child_node(dev, child) { + struct led_init_data init_data = {}; + char default_label[32]; + ret = fwnode_property_read_u32(child, "reg", ®); if (ret || reg >= chipdef->n_leds) { dev_err(dev, "Invalid 'reg' property for node %pfw\n", @@ -331,23 +332,21 @@ static int pca963x_register_leds(struct i2c_client *client, goto err; } - ret = fwnode_property_read_string(child, "label", &name); - if (!fwnode_property_read_string(child, "label", &name)) - snprintf(label, sizeof(label), "pca963x:%s", name); - else - snprintf(label, sizeof(label), "pca963x::"); - - fwnode_property_read_string(child, "linux,default-trigger", - &led->led_cdev.default_trigger); - led->led_num = reg; led->chip = chip; - led->led_cdev.name = label; led->led_cdev.brightness_set_blocking = pca963x_led_set; if (hw_blink) led->led_cdev.blink_set = pca963x_blink_set; - ret = devm_led_classdev_register(dev, &led->led_cdev); + init_data.fwnode = child; + /* for backwards compatibility */ + init_data.devicename = "pca963x"; + snprintf(default_label, sizeof(default_label), "%d:%.2x:%u", + client->adapter->nr, client->addr, reg); + init_data.default_label = default_label; + + ret = devm_led_classdev_register_ext(dev, &led->led_cdev, + &init_data); if (ret) { dev_err(dev, "Failed to register LED for node %pfw\n", child); From 108f4664e3449828114780a05393eb8d2be7fdd0 Mon Sep 17 00:00:00 2001 From: Tobias Jordan Date: Sat, 26 Sep 2020 02:51:17 +0200 Subject: [PATCH 80/84] leds: tlc591xx: fix leak of device node iterator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In one of the error paths of the for_each_child_of_node loop in tlc591xx_probe, add missing call to of_node_put. Fixes: 1ab4531ad132 ("leds: tlc591xx: simplify driver by using the managed led API") Signed-off-by: Tobias Jordan Reviewed-by: Marek Behún Reviewed-by: Tomi Valkeinen Signed-off-by: Pavel Machek --- drivers/leds/leds-tlc591xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c index f24271337bd8..5b9dfdf743ec 100644 --- a/drivers/leds/leds-tlc591xx.c +++ b/drivers/leds/leds-tlc591xx.c @@ -205,10 +205,12 @@ tlc591xx_probe(struct i2c_client *client, led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS; err = devm_led_classdev_register_ext(dev, &led->ldev, &init_data); - if (err < 0) + if (err < 0) { + of_node_put(child); return dev_err_probe(dev, err, "couldn't register LED %s\n", led->ldev.name); + } } return 0; } From 940cca1ab5d6c3bc1f8db0c804cf7c5e0caf1853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 26 Sep 2020 22:11:30 +0200 Subject: [PATCH 81/84] leds: ns2: convert to fwnode API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert from OF api to fwnode API, so that it is possible to bind this driver without device-tree. The fwnode API does not expose a function to read a specific element of an array. We therefore change the types of the ns2_led_modval structure so that we can read the whole modval array with one fwnode call. Signed-off-by: Marek Behún Tested-by: Simon Guinot Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 55 +++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index e1ec5cbed07e..dba6bdfa861b 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -24,11 +24,16 @@ enum ns2_led_modes { NS_V2_LED_SATA, }; +/* + * If the size of this structure or types of its members is changed, + * the filling of array modval in function ns2_led_register must be changed + * accordingly. + */ struct ns2_led_modval { - enum ns2_led_modes mode; - int cmd_level; - int slow_level; -}; + u32 mode; + u32 cmd_level; + u32 slow_level; +} __packed; /* * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED @@ -167,27 +172,28 @@ static struct attribute *ns2_led_attrs[] = { }; ATTRIBUTE_GROUPS(ns2_led); -static int ns2_led_register(struct device *dev, struct device_node *np, +static int ns2_led_register(struct device *dev, struct fwnode_handle *node, struct ns2_led *led) { struct led_init_data init_data = {}; struct ns2_led_modval *modval; enum ns2_led_modes mode; - int nmodes, ret, i; + int nmodes, ret; - led->cmd = devm_gpiod_get_from_of_node(dev, np, "cmd-gpio", 0, - GPIOD_ASIS, np->name); + led->cmd = devm_fwnode_gpiod_get_index(dev, node, "cmd", 0, GPIOD_ASIS, + fwnode_get_name(node)); if (IS_ERR(led->cmd)) return PTR_ERR(led->cmd); - led->slow = devm_gpiod_get_from_of_node(dev, np, "slow-gpio", 0, - GPIOD_ASIS, np->name); + led->slow = devm_fwnode_gpiod_get_index(dev, node, "slow", 0, + GPIOD_ASIS, + fwnode_get_name(node)); if (IS_ERR(led->slow)) return PTR_ERR(led->slow); - ret = of_property_count_u32_elems(np, "modes-map"); + ret = fwnode_property_count_u32(node, "modes-map"); if (ret < 0 || ret % 3) { - dev_err(dev, "Missing or malformed modes-map for %pOF\n", np); + dev_err(dev, "Missing or malformed modes-map for %pfw\n", node); return -EINVAL; } @@ -196,16 +202,8 @@ static int ns2_led_register(struct device *dev, struct device_node *np, if (!modval) return -ENOMEM; - for (i = 0; i < nmodes; i++) { - u32 val; - - of_property_read_u32_index(np, "modes-map", 3 * i, &val); - modval[i].mode = val; - of_property_read_u32_index(np, "modes-map", 3 * i + 1, &val); - modval[i].cmd_level = val; - of_property_read_u32_index(np, "modes-map", 3 * i + 2, &val); - modval[i].slow_level = val; - } + fwnode_property_read_u32_array(node, "modes-map", (void *)modval, + nmodes * 3); rwlock_init(&led->rw_lock); @@ -228,11 +226,11 @@ static int ns2_led_register(struct device *dev, struct device_node *np, led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0; led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL; - init_data.fwnode = of_fwnode_handle(np); + init_data.fwnode = node; ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); if (ret) - dev_err(dev, "Failed to register LED for node %pOF\n", np); + dev_err(dev, "Failed to register LED for node %pfw\n", node); return ret; } @@ -246,13 +244,12 @@ MODULE_DEVICE_TABLE(of, of_ns2_leds_match); static int ns2_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np, *child; + struct fwnode_handle *child; struct ns2_led *leds; int count; int ret; - np = dev_of_node(dev); - count = of_get_available_child_count(np); + count = device_get_child_node_count(dev); if (!count) return -ENODEV; @@ -260,10 +257,10 @@ static int ns2_led_probe(struct platform_device *pdev) if (!leds) return -ENOMEM; - for_each_available_child_of_node(np, child) { + device_for_each_child_node(dev, child) { ret = ns2_led_register(dev, child, leds++); if (ret) { - of_node_put(child); + fwnode_handle_put(child); return ret; } } From 8fd8f94235c2c925d80b2316e0ab2bdd00af9bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Sat, 26 Sep 2020 22:11:31 +0200 Subject: [PATCH 82/84] leds: ns2: do not guard OF match pointer with of_match_ptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not match OF match pointer with of_match_ptr, so that even if CONFIG_OF is disabled, the driver can still be bound via another method. Move definition of of_ns2_leds_match just before ns2_led_driver definition, since it is not needed sooner. Signed-off-by: Marek Behún Tested-by: Simon Guinot Signed-off-by: Pavel Machek --- drivers/leds/leds-ns2.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index dba6bdfa861b..1677d66d8b0e 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -235,12 +235,6 @@ static int ns2_led_register(struct device *dev, struct fwnode_handle *node, return ret; } -static const struct of_device_id of_ns2_leds_match[] = { - { .compatible = "lacie,ns2-leds", }, - {}, -}; -MODULE_DEVICE_TABLE(of, of_ns2_leds_match); - static int ns2_led_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -268,11 +262,17 @@ static int ns2_led_probe(struct platform_device *pdev) return 0; } +static const struct of_device_id of_ns2_leds_match[] = { + { .compatible = "lacie,ns2-leds", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_ns2_leds_match); + static struct platform_driver ns2_led_driver = { .probe = ns2_led_probe, .driver = { .name = "leds-ns2", - .of_match_table = of_match_ptr(of_ns2_leds_match), + .of_match_table = of_ns2_leds_match, }, }; From 98d278ca00bd8f62c8bc98bd9e65372d16eb6956 Mon Sep 17 00:00:00 2001 From: Gabriel David Date: Fri, 2 Oct 2020 18:27:00 -0400 Subject: [PATCH 83/84] leds: lm3697: Fix out-of-bound access If both LED banks aren't used in device tree, an out-of-bounds condition in lm3697_init occurs because of the for loop assuming that all the banks are used. Fix it by adding a variable that contains the number of used banks. Signed-off-by: Gabriel David [removed extra rename, minor tweaks] Signed-off-by: Pavel Machek Cc: stable@kernel.org --- drivers/leds/leds-lm3697.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 64c0794801e6..7d216cdb91a8 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -78,6 +78,7 @@ struct lm3697 { struct mutex lock; int bank_cfg; + int num_banks; struct lm3697_led leds[]; }; @@ -180,7 +181,7 @@ static int lm3697_init(struct lm3697 *priv) if (ret) dev_err(dev, "Cannot write OUTPUT config\n"); - for (i = 0; i < LM3697_MAX_CONTROL_BANKS; i++) { + for (i = 0; i < priv->num_banks; i++) { led = &priv->leds[i]; ret = ti_lmu_common_set_ramp(&led->lmu_data); if (ret) @@ -301,8 +302,8 @@ static int lm3697_probe(struct i2c_client *client, int ret; count = device_get_child_node_count(dev); - if (!count) { - dev_err(dev, "LEDs are not defined in device tree!"); + if (!count || count > LM3697_MAX_CONTROL_BANKS) { + dev_err(dev, "Strange device tree!"); return -ENODEV; } @@ -315,6 +316,7 @@ static int lm3697_probe(struct i2c_client *client, led->client = client; led->dev = dev; + led->num_banks = count; led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config); if (IS_ERR(led->regmap)) { ret = PTR_ERR(led->regmap); From 19d2e0cef0b14f8c7210162f58327485f5fa7c51 Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Mon, 5 Oct 2020 22:34:40 +0200 Subject: [PATCH 84/84] leds: pwm: Remove platform_data support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 141f15c66d94 ("leds: pwm: remove header") that platform interface is not usable from outside and there seems to be no in tree user anymore. All in-tree users of the leds-pwm driver seem to use DT currently. Getting rid of the old platform interface allows the leds-pwm driver to switch over from 'devm_led_classdev_register()' to 'devm_led_classdev_register_ext()'. Signed-off-by: Alexander Dahl Cc: Denis Osterland-Heim Reviewed-by: Marek Behún Signed-off-by: Pavel Machek --- drivers/leds/leds-pwm.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 2a16ae0bf022..f53f9309ca6c 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -24,11 +24,6 @@ struct led_pwm { unsigned int max_brightness; }; -struct led_pwm_platform_data { - int num_leds; - struct led_pwm *leds; -}; - struct led_pwm_data { struct led_classdev cdev; struct pwm_device *pwm; @@ -60,6 +55,7 @@ static int led_pwm_set(struct led_classdev *led_cdev, return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate); } +__attribute__((nonnull)) static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, struct led_pwm *led, struct fwnode_handle *fwnode) { @@ -73,10 +69,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv, led_data->cdev.max_brightness = led->max_brightness; led_data->cdev.flags = LED_CORE_SUSPENDRESUME; - if (fwnode) - led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL); - else - led_data->pwm = devm_pwm_get(dev, led->name); + led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL); if (IS_ERR(led_data->pwm)) return dev_err_probe(dev, PTR_ERR(led_data->pwm), "unable to request PWM for %s\n", @@ -139,15 +132,11 @@ static int led_pwm_create_fwnode(struct device *dev, struct led_pwm_priv *priv) static int led_pwm_probe(struct platform_device *pdev) { - struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev); struct led_pwm_priv *priv; - int count, i; int ret = 0; + int count; - if (pdata) - count = pdata->num_leds; - else - count = device_get_child_node_count(&pdev->dev); + count = device_get_child_node_count(&pdev->dev); if (!count) return -EINVAL; @@ -157,16 +146,7 @@ static int led_pwm_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - if (pdata) { - for (i = 0; i < count; i++) { - ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i], - NULL); - if (ret) - break; - } - } else { - ret = led_pwm_create_fwnode(&pdev->dev, priv); - } + ret = led_pwm_create_fwnode(&pdev->dev, priv); if (ret) return ret;