* [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings
@ 2026-10-13 18:09 Svyatoslav Ryhel
2026-10-13 18:09 ` [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 Svyatoslav Ryhel
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-13 18:09 UTC (permalink / raw)
To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Liam Girdwood, Mark Brown, Daniel Thompson,
Jingoo Han, Svyatoslav Ryhel
Cc: linux-leds, devicetree, linux-kernel, mfd, dri-devel
Document Skyworks AAT2870 into schema, convert existing driver to
use OF bindings and remove platform data, add support for
in-supplies.
---
Changes in v2:
- fixed led-max-microamp scaling
- fixed max_brightness parsing
- fixed regulator init_data and of_node passing
- of_platform_populate > devm_of_platform_populate
Changes in v3:
- removed max-brightness property
- switched from dedicated max_brightness property to dynamically
calculating brightness steps
- update regulator registration to use mostly core regulator framework
---
Svyatoslav Ryhel (4):
dt-bindings: mfd: Document Skyworks AAT2870
mfd: aat2870: Derive brightness steps from max current
mfd: aat2870: Convert to use OF bindings
mfd: aat2870: Add support for VIN and IN-LDO power supplies
.../bindings/leds/skyworks,aat2870.yaml | 124 ++++++++++++++
drivers/mfd/aat2870-core.c | 120 ++++---------
drivers/regulator/aat2870-regulator.c | 160 ++++++++----------
drivers/video/backlight/aat2870_bl.c | 77 ++++-----
include/linux/mfd/aat2870.h | 95 +----------
5 files changed, 259 insertions(+), 317 deletions(-)
create mode 100644 Documentation/devicetree/bindings/leds/skyworks,aat2870.yaml
--
2.53.0
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 2026-10-13 18:09 [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel @ 2026-10-13 18:09 ` Svyatoslav Ryhel 2026-10-13 18:16 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current Svyatoslav Ryhel ` (2 subsequent siblings) 3 siblings, 1 reply; 9+ messages in thread From: Svyatoslav Ryhel @ 2026-10-13 18:09 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Liam Girdwood, Mark Brown, Daniel Thompson, Jingoo Han, Svyatoslav Ryhel Cc: linux-leds, devicetree, linux-kernel, mfd, dri-devel Document Skyworks AAT2870 LED Backlight Driver and Multiple LDO Lighting Management Unit. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- .../bindings/leds/skyworks,aat2870.yaml | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Documentation/devicetree/bindings/leds/skyworks,aat2870.yaml diff --git a/Documentation/devicetree/bindings/leds/skyworks,aat2870.yaml b/Documentation/devicetree/bindings/leds/skyworks,aat2870.yaml new file mode 100644 index 0000000000000..0b4b8be9015bf --- /dev/null +++ b/Documentation/devicetree/bindings/leds/skyworks,aat2870.yaml @@ -0,0 +1,124 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/skyworks,aat2870.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AAT2870 LED Backlight Driver and Multiple LDO Lighting Management Unit + +maintainers: + - Svyatoslav Ryhel <clamor95@gmail.com> + +properties: + compatible: + const: skyworks,aat2870 + + reg: + maxItems: 1 + + enable-gpios: + description: GPIO connected to EN pin. + maxItems: 1 + + vin-supply: + description: Regulator providing power to the "IN" pin. + + backlight: + $ref: /schemas/leds/backlight/common.yaml# + unevaluatedProperties: false + + properties: + compatible: + const: skyworks,aat2870-backlight + + led-max-microamp: + minimum: 450 + maximum: 27900 + default: 450 + + skyworks,channels: + description: layout of active channels, where each bit represents + one of 8 channels. + $ref: /schemas/types.yaml#/definitions/uint8 + default: 0xff + + required: + - compatible + + regulators: + type: object + additionalProperties: false + + properties: + compatible: + const: skyworks,aat2870-regulator + + in-ldo-supply: + description: Phandle to parent supply of regulators populated under + regulators node. They all share same parent. + + patternProperties: + "^ldo-(a|b|c|d)$": + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + + required: + - compatible + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@60 { + compatible = "skyworks,aat2870"; + reg = <0x60>; + + enable-gpios = <&gpio 139 GPIO_ACTIVE_HIGH>; + vin-supply = <&vdd_3v3_vbat>; + + backlight { + compatible = "skyworks,aat2870-backlight"; + + skyworks,channels = /bits/ 8 <0xff>; + led-max-microamp = <27900>; + }; + + regulators { + compatible = "skyworks,aat2870-regulator"; + + in-ldo-supply = <&vdd_3v3_vbat>; + + ldo-a { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + ldo-b { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + ldo-c { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + ldo-d { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2800000>; + }; + }; + }; + }; -- 2.53.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 2026-10-13 18:09 ` [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 Svyatoslav Ryhel @ 2026-10-13 18:16 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-10-13 18:16 UTC (permalink / raw) To: Svyatoslav Ryhel; +Cc: linux-leds, mfd, lee > Document Skyworks AAT2870 LED Backlight Driver and Multiple LDO Lighting > Management Unit. > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> Sashiko has reviewed this patch and found no issues. It looks great! -- Sashiko AI review · https://sashiko.dev/#/patchset/20261013180933.487013-1-clamor95@gmail.com?part=1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current 2026-10-13 18:09 [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel 2026-10-13 18:09 ` [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 Svyatoslav Ryhel @ 2026-10-13 18:09 ` Svyatoslav Ryhel 2026-10-13 18:16 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel 2026-10-13 18:09 ` [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies Svyatoslav Ryhel 3 siblings, 1 reply; 9+ messages in thread From: Svyatoslav Ryhel @ 2026-10-13 18:09 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Liam Girdwood, Mark Brown, Daniel Thompson, Jingoo Han, Svyatoslav Ryhel Cc: linux-leds, devicetree, linux-kernel, mfd, dri-devel The AAT2870 allows only 32 steps of brightness, with this amount defined by the maximum supported current. Remove the need for max_brightness by calculating the allowed number of steps from the maximum current. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- drivers/video/backlight/aat2870_bl.c | 30 ++++++++++------------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index 8b790df1e842b..eb686e315921d 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -24,18 +24,6 @@ struct aat2870_bl_driver_data { int brightness; /* current brightness */ }; -static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl, - int brightness) -{ - struct backlight_device *bd = aat2870_bl->bd; - int val; - - val = brightness * (aat2870_bl->max_current - 1); - val /= bd->props.max_brightness; - - return val; -} - static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl) { struct aat2870_data *aat2870 @@ -69,10 +57,11 @@ static int aat2870_bl_update_status(struct backlight_device *bd) dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n", bd->props.brightness, bd->props.power, bd->props.state); - ret = aat2870->write(aat2870, AAT2870_BLM, - (u8)aat2870_brightness(aat2870_bl, brightness)); - if (ret < 0) - return ret; + if (brightness) { + ret = aat2870->write(aat2870, AAT2870_BLM, (u8)brightness - 1); + if (ret < 0) + return ret; + } if (brightness == 0) { ret = aat2870_bl_disable(aat2870_bl); @@ -150,10 +139,11 @@ static int aat2870_bl_probe(struct platform_device *pdev) else aat2870_bl->max_current = AAT2870_CURRENT_27_9; - if (pdata->max_brightness > 0) - bd->props.max_brightness = pdata->max_brightness; - else - bd->props.max_brightness = 255; + /* + * The maximum number of brightness steps is determined by the max current. + * The aat2870_current enum maps directly to the allowed brightness steps. + */ + bd->props.max_brightness = pdata->max_current; aat2870_bl->brightness = 0; bd->props.power = BACKLIGHT_POWER_ON; -- 2.53.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current 2026-10-13 18:09 ` [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current Svyatoslav Ryhel @ 2026-10-13 18:16 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-10-13 18:16 UTC (permalink / raw) To: Svyatoslav Ryhel Cc: linux-leds, devicetree, mfd, dri-devel, robh, conor+dt, lee Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] mfd: aat2870: Backlight max_brightness incorrectly initialized to 0 -- commit 236a2bd14466123f025d53f0e3094d82e1e098d7 Author: Svyatoslav Ryhel <clamor95@gmail.com> mfd: aat2870: Derive brightness steps from max current The AAT2870 allows only 32 steps of brightness, with this amount defined by the maximum supported current. Remove the need for max_brightness by calculating the allowed number of steps from the maximum current. > diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c > index 8b790df1e842b..eb686e315921d 100644 > --- a/drivers/video/backlight/aat2870_bl.c > +++ b/drivers/video/backlight/aat2870_bl.c [ ... ] > @@ -150,10 +139,11 @@ static int aat2870_bl_probe(struct platform_device *pdev) > else > aat2870_bl->max_current = AAT2870_CURRENT_27_9; > > - if (pdata->max_brightness > 0) > - bd->props.max_brightness = pdata->max_brightness; > - else > - bd->props.max_brightness = 255; > + /* > + * The maximum number of brightness steps is determined by the max current. > + * The aat2870_current enum maps directly to the allowed brightness steps. > + */ > + bd->props.max_brightness = pdata->max_current; [Severity: High] Should this be assigning aat2870_bl->max_current instead of pdata->max_current? If pdata->max_current is 0, this bypasses the fallback logic applied just above and assigns 0 to bd->props.max_brightness. Could this cause a regression where aat2870_bl_update_status() rejects all valid positive brightness updates? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261013180933.487013-1-clamor95@gmail.com?part=2 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings 2026-10-13 18:09 [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel 2026-10-13 18:09 ` [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 Svyatoslav Ryhel 2026-10-13 18:09 ` [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current Svyatoslav Ryhel @ 2026-10-13 18:09 ` Svyatoslav Ryhel 2026-10-13 18:21 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies Svyatoslav Ryhel 3 siblings, 1 reply; 9+ messages in thread From: Svyatoslav Ryhel @ 2026-10-13 18:09 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Liam Girdwood, Mark Brown, Daniel Thompson, Jingoo Han, Svyatoslav Ryhel Cc: linux-leds, devicetree, linux-kernel, mfd, dri-devel Conversion of the AAT2870 driver to use OF bindings requires a few complex changes that should be done simultaneously. The AAT2870 essentially provides two functions via child devices: backlight and regulators. Both functions are fairly self-sufficient and may not be populated on the final board. Consequently, the MFD registration API was replaced with of_platform_populate(), and each sub-device was given its own compatible string. Additionally, aat2870-core utilizes an enable GPIO. Obtaining this GPIO was converted to use modern gpiod/OF helpers, allowing the redundant aat2870_enable() and aat2870_disable() helpers to be removed. The aat2870-regulator driver was updated to register each of the four LDOs from a dedicated OF node using modern regulator framework. The aat2870-backlight driver was changed to populate all required properties from a dedicated Device Tree node. Its channel map was updated to use u8 instead of int. Furthermore, because the maximum current is now parsed as an absolute value rather than an enum entry, the calculation and application of the maximum current were updated accordingly. All of the changes above allow platform data to be removed entirely. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- drivers/mfd/aat2870-core.c | 115 +++++-------------- drivers/regulator/aat2870-regulator.c | 159 +++++++++++--------------- drivers/video/backlight/aat2870_bl.c | 51 +++++---- include/linux/mfd/aat2870.h | 95 +-------------- 4 files changed, 121 insertions(+), 299 deletions(-) diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 0d56cd6fbc6a5..909c14ee60323 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -16,8 +16,15 @@ #include <linux/gpio/legacy.h> #include <linux/mfd/core.h> #include <linux/mfd/aat2870.h> +#include <linux/of_platform.h> #include <linux/regulator/machine.h> +struct aat2870_register { + bool readable; + bool writeable; + u8 value; +}; + static struct aat2870_register aat2870_regs[AAT2870_REG_NUM] = { /* readable, writeable, value */ { 0, 1, 0x00 }, /* 0x00 AAT2870_BL_CH_EN */ @@ -61,34 +68,6 @@ static struct aat2870_register aat2870_regs[AAT2870_REG_NUM] = { { 0, 1, 0x00 }, /* 0x26 AAT2870_LDO_EN */ }; -static struct mfd_cell aat2870_devs[] = { - { - .name = "aat2870-backlight", - .id = AAT2870_ID_BL, - .pdata_size = sizeof(struct aat2870_bl_platform_data), - }, - { - .name = "aat2870-regulator", - .id = AAT2870_ID_LDOA, - .pdata_size = sizeof(struct regulator_init_data), - }, - { - .name = "aat2870-regulator", - .id = AAT2870_ID_LDOB, - .pdata_size = sizeof(struct regulator_init_data), - }, - { - .name = "aat2870-regulator", - .id = AAT2870_ID_LDOC, - .pdata_size = sizeof(struct regulator_init_data), - }, - { - .name = "aat2870-regulator", - .id = AAT2870_ID_LDOD, - .pdata_size = sizeof(struct regulator_init_data), - }, -}; - static int __aat2870_read(struct aat2870_data *aat2870, u8 addr, u8 *val) { int ret; @@ -196,22 +175,6 @@ static int aat2870_update(struct aat2870_data *aat2870, u8 addr, u8 mask, return ret; } -static inline void aat2870_enable(struct aat2870_data *aat2870) -{ - if (aat2870->en_pin >= 0) - gpio_set_value(aat2870->en_pin, 1); - - aat2870->is_enable = 1; -} - -static inline void aat2870_disable(struct aat2870_data *aat2870) -{ - if (aat2870->en_pin >= 0) - gpio_set_value(aat2870->en_pin, 0); - - aat2870->is_enable = 0; -} - #ifdef CONFIG_DEBUG_FS static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf) { @@ -332,9 +295,7 @@ static inline void aat2870_init_debugfs(struct aat2870_data *aat2870) static int aat2870_i2c_probe(struct i2c_client *client) { - struct aat2870_platform_data *pdata = dev_get_platdata(&client->dev); struct aat2870_data *aat2870; - int i, j; int ret = 0; aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data), @@ -348,60 +309,29 @@ static int aat2870_i2c_probe(struct i2c_client *client) aat2870->reg_cache = aat2870_regs; - if (pdata->en_pin < 0) - aat2870->en_pin = -1; - else - aat2870->en_pin = pdata->en_pin; + aat2870->en_pin = devm_gpiod_get_optional(&client->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(aat2870->en_pin)) + return dev_err_probe(&client->dev, PTR_ERR(aat2870->en_pin), + "Failed to get EN GPIO\n"); - aat2870->init = pdata->init; - aat2870->uninit = pdata->uninit; aat2870->read = aat2870_read; aat2870->write = aat2870_write; aat2870->update = aat2870_update; mutex_init(&aat2870->io_lock); - if (aat2870->init) - aat2870->init(aat2870); - - if (aat2870->en_pin >= 0) { - ret = devm_gpio_request_one(&client->dev, aat2870->en_pin, - GPIOF_OUT_INIT_HIGH, "aat2870-en"); - if (ret < 0) { - dev_err(&client->dev, - "Failed to request GPIO %d\n", aat2870->en_pin); - return ret; - } - } - - aat2870_enable(aat2870); - - for (i = 0; i < pdata->num_subdevs; i++) { - for (j = 0; j < ARRAY_SIZE(aat2870_devs); j++) { - if ((pdata->subdevs[i].id == aat2870_devs[j].id) && - !strcmp(pdata->subdevs[i].name, - aat2870_devs[j].name)) { - aat2870_devs[j].platform_data = - pdata->subdevs[i].platform_data; - break; - } - } - } + gpiod_set_value(aat2870->en_pin, 1); - ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, - ARRAY_SIZE(aat2870_devs), NULL, 0, NULL); - if (ret != 0) { - dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); - goto out_disable; + ret = devm_of_platform_populate(&client->dev); + if (ret) { + gpiod_set_value(aat2870->en_pin, 0); + return dev_err_probe(&client->dev, ret, "Failed to populate cells\n"); } aat2870_init_debugfs(aat2870); return 0; - -out_disable: - aat2870_disable(aat2870); - return ret; } static int aat2870_i2c_suspend(struct device *dev) @@ -409,7 +339,7 @@ static int aat2870_i2c_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct aat2870_data *aat2870 = i2c_get_clientdata(client); - aat2870_disable(aat2870); + gpiod_set_value(aat2870->en_pin, 0); return 0; } @@ -421,7 +351,7 @@ static int aat2870_i2c_resume(struct device *dev) struct aat2870_register *reg = NULL; int i; - aat2870_enable(aat2870); + gpiod_set_value(aat2870->en_pin, 1); /* restore registers */ for (i = 0; i < AAT2870_REG_NUM; i++) { @@ -436,6 +366,12 @@ static int aat2870_i2c_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend, aat2870_i2c_resume); +static const struct of_device_id aat2870_match_table[] = { + { .compatible = "skyworks,aat2870" }, + { } +}; +MODULE_DEVICE_TABLE(of, aat2870_match_table); + static const struct i2c_device_id aat2870_i2c_id_table[] = { { "aat2870" }, { } @@ -444,6 +380,7 @@ static const struct i2c_device_id aat2870_i2c_id_table[] = { static struct i2c_driver aat2870_i2c_driver = { .driver = { .name = "aat2870", + .of_match_table = aat2870_match_table, .pm = pm_sleep_ptr(&aat2870_pm_ops), .suppress_bind_attrs = true, }, diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 970d86f2bbb81..9b8eb8df220a7 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -15,73 +15,74 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/aat2870.h> - -struct aat2870_regulator { - struct aat2870_data *aat2870; - struct regulator_desc desc; - - u8 enable_addr; - u8 enable_shift; - u8 enable_mask; - - u8 voltage_addr; - u8 voltage_shift; - u8 voltage_mask; +#include <linux/regulator/of_regulator.h> + +#define AAT2870_LDO_AB_A_MASK GENMASK(7, 4) +#define AAT2870_LDO_AB_B_MASK GENMASK(3, 0) +#define AAT2870_LDO_CD_C_MASK GENMASK(7, 4) +#define AAT2870_LDO_CD_D_MASK GENMASK(3, 0) + +/* Device IDs */ +enum aat2870_regulator_id { + AAT2870_ID_LDOA, + AAT2870_ID_LDOB, + AAT2870_ID_LDOC, + AAT2870_ID_LDOD }; static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = ri->aat2870; + struct aat2870_data *aat2870 = rdev_get_drvdata(rdev); + const struct regulator_desc *rdesc = rdev->desc; - return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask, - selector << ri->voltage_shift); + return aat2870->update(aat2870, rdesc->vsel_reg, rdesc->vsel_mask, + (selector << __ffs(rdesc->vsel_mask)) & rdesc->vsel_mask); } static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) { - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = ri->aat2870; + struct aat2870_data *aat2870 = rdev_get_drvdata(rdev); + const struct regulator_desc *rdesc = rdev->desc; u8 val; int ret; - ret = aat2870->read(aat2870, ri->voltage_addr, &val); + ret = aat2870->read(aat2870, rdesc->vsel_reg, &val); if (ret) return ret; - return (val & ri->voltage_mask) >> ri->voltage_shift; + return (val & rdesc->vsel_mask) >> __ffs(rdesc->vsel_mask); } static int aat2870_ldo_enable(struct regulator_dev *rdev) { - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = ri->aat2870; + struct aat2870_data *aat2870 = rdev_get_drvdata(rdev); + const struct regulator_desc *rdesc = rdev->desc; - return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, - ri->enable_mask); + return aat2870->update(aat2870, rdesc->enable_reg, rdesc->enable_mask, + rdesc->enable_mask); } static int aat2870_ldo_disable(struct regulator_dev *rdev) { - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = ri->aat2870; + struct aat2870_data *aat2870 = rdev_get_drvdata(rdev); + const struct regulator_desc *rdesc = rdev->desc; - return aat2870->update(aat2870, ri->enable_addr, ri->enable_mask, 0); + return aat2870->update(aat2870, rdesc->enable_reg, rdesc->enable_mask, 0); } static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) { - struct aat2870_regulator *ri = rdev_get_drvdata(rdev); - struct aat2870_data *aat2870 = ri->aat2870; + struct aat2870_data *aat2870 = rdev_get_drvdata(rdev); + const struct regulator_desc *rdesc = rdev->desc; u8 val; int ret; - ret = aat2870->read(aat2870, ri->enable_addr, &val); + ret = aat2870->read(aat2870, rdesc->enable_reg, &val); if (ret) return ret; - return val & ri->enable_mask ? 1 : 0; + return (val & rdesc->enable_mask) >> __ffs(rdesc->enable_mask); } static const struct regulator_ops aat2870_ldo_ops = { @@ -101,84 +102,60 @@ static const unsigned int aat2870_ldo_voltages[] = { 3000000, 3100000, 3200000, 3300000, }; -#define AAT2870_LDO(ids) \ - { \ - .desc = { \ - .name = #ids, \ - .id = AAT2870_ID_##ids, \ - .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ - .volt_table = aat2870_ldo_voltages, \ - .ops = &aat2870_ldo_ops, \ - .type = REGULATOR_VOLTAGE, \ - .owner = THIS_MODULE, \ - }, \ - } +#define AAT2870_LDO(ids, match, vsel, vmask) { \ + .name = #ids, \ + .of_match = (match), \ + .id = AAT2870_ID_##ids, \ + .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ + .volt_table = aat2870_ldo_voltages, \ + .ops = &aat2870_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .vsel_reg = (vsel), \ + .vsel_mask = (vmask), \ + .enable_reg = AAT2870_LDO_EN, \ + .enable_mask = BIT(AAT2870_ID_##ids), \ +} -static struct aat2870_regulator aat2870_regulators[] = { - AAT2870_LDO(LDOA), - AAT2870_LDO(LDOB), - AAT2870_LDO(LDOC), - AAT2870_LDO(LDOD), +static struct regulator_desc aat2870_regulators[] = { + AAT2870_LDO(LDOA, "ldo-a", AAT2870_LDO_AB, AAT2870_LDO_AB_A_MASK), + AAT2870_LDO(LDOB, "ldo-b", AAT2870_LDO_AB, AAT2870_LDO_AB_B_MASK), + AAT2870_LDO(LDOC, "ldo-c", AAT2870_LDO_CD, AAT2870_LDO_CD_C_MASK), + AAT2870_LDO(LDOD, "ldo-d", AAT2870_LDO_CD, AAT2870_LDO_CD_D_MASK), }; -static struct aat2870_regulator *aat2870_get_regulator(int id) -{ - struct aat2870_regulator *ri = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) { - ri = &aat2870_regulators[i]; - if (ri->desc.id == id) - break; - } - - if (i == ARRAY_SIZE(aat2870_regulators)) - return NULL; - - ri->enable_addr = AAT2870_LDO_EN; - ri->enable_shift = id - AAT2870_ID_LDOA; - ri->enable_mask = 0x1 << ri->enable_shift; - - ri->voltage_addr = (id - AAT2870_ID_LDOA) / 2 ? - AAT2870_LDO_CD : AAT2870_LDO_AB; - ri->voltage_shift = (id - AAT2870_ID_LDOA) % 2 ? 0 : 4; - ri->voltage_mask = 0xF << ri->voltage_shift; - - return ri; -} - static int aat2870_regulator_probe(struct platform_device *pdev) { - struct aat2870_regulator *ri; + struct device *dev = &pdev->dev; struct regulator_config config = { }; struct regulator_dev *rdev; - ri = aat2870_get_regulator(pdev->id); - if (!ri) { - dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id); - return -EINVAL; - } - ri->aat2870 = dev_get_drvdata(pdev->dev.parent); - - config.dev = &pdev->dev; - config.driver_data = ri; - config.init_data = dev_get_platdata(&pdev->dev); + config.dev = dev; + config.driver_data = dev_get_drvdata(dev->parent); - rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "Failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + for (int i = 0; i < ARRAY_SIZE(aat2870_regulators); i++) { + rdev = devm_regulator_register(dev, &aat2870_regulators[i], &config); + if (IS_ERR(rdev)) { + return dev_err_probe(dev, PTR_ERR(rdev), + "Failed to register regulator %s\n", + aat2870_regulators[i].name); + } } - platform_set_drvdata(pdev, rdev); return 0; } +static const struct of_device_id aat2870_regulator_match_table[] = { + { .compatible = "skyworks,aat2870-regulator" }, + { } +}; +MODULE_DEVICE_TABLE(of, aat2870_regulator_match_table); + static struct platform_driver aat2870_regulator_driver = { .driver = { .name = "aat2870-regulator", .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = aat2870_regulator_match_table, }, .probe = aat2870_regulator_probe, }; diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c index eb686e315921d..705a8d32d224f 100644 --- a/drivers/video/backlight/aat2870_bl.c +++ b/drivers/video/backlight/aat2870_bl.c @@ -15,11 +15,19 @@ #include <linux/backlight.h> #include <linux/mfd/aat2870.h> +/* Backlight has 8 channels, each bit represents one channel */ +#define AAT2870_BL_CH_ALL 0xff + +/* Backlight current magnitude (uA), 450uA current is eq to 0 */ +#define AAT2870_CURRENT_MIN 450 +#define AAT2870_CURRENT_MAX 27900 +#define AAT2870_CURRENT_STEP 900 + struct aat2870_bl_driver_data { struct platform_device *pdev; struct backlight_device *bd; - int channels; + u8 channels; int max_current; int brightness; /* current brightness */ }; @@ -30,7 +38,7 @@ static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl) = dev_get_drvdata(aat2870_bl->pdev->dev.parent); return aat2870->write(aat2870, AAT2870_BL_CH_EN, - (u8)aat2870_bl->channels); + aat2870_bl->channels); } static inline int aat2870_bl_disable(struct aat2870_bl_driver_data *aat2870_bl) @@ -85,24 +93,11 @@ static const struct backlight_ops aat2870_bl_ops = { static int aat2870_bl_probe(struct platform_device *pdev) { - struct aat2870_bl_platform_data *pdata = dev_get_platdata(&pdev->dev); struct aat2870_bl_driver_data *aat2870_bl; struct backlight_device *bd; struct backlight_properties props; int ret = 0; - if (!pdata) { - dev_err(&pdev->dev, "No platform data\n"); - ret = -ENXIO; - goto out; - } - - if (pdev->id != AAT2870_ID_BL) { - dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id); - ret = -EINVAL; - goto out; - } - aat2870_bl = devm_kzalloc(&pdev->dev, sizeof(struct aat2870_bl_driver_data), GFP_KERNEL); @@ -129,21 +124,20 @@ static int aat2870_bl_probe(struct platform_device *pdev) aat2870_bl->bd = bd; - if (pdata->channels > 0) - aat2870_bl->channels = pdata->channels; - else - aat2870_bl->channels = AAT2870_BL_CH_ALL; + aat2870_bl->channels = AAT2870_BL_CH_ALL; + device_property_read_u8(&pdev->dev, "skyworks,channels", &aat2870_bl->channels); - if (pdata->max_current > 0) - aat2870_bl->max_current = pdata->max_current; - else - aat2870_bl->max_current = AAT2870_CURRENT_27_9; + device_property_read_u32(&pdev->dev, "led-max-microamp", &aat2870_bl->max_current); + aat2870_bl->max_current = clamp(aat2870_bl->max_current, AAT2870_CURRENT_MIN, + AAT2870_CURRENT_MAX); + aat2870_bl->max_current /= AAT2870_CURRENT_STEP; /* * The maximum number of brightness steps is determined by the max current. - * The aat2870_current enum maps directly to the allowed brightness steps. + * The aat2870_bl->max_current value maps to the allowed brightness steps + * with +1 offset since max_current 0 is still 450uA. */ - bd->props.max_brightness = pdata->max_current; + bd->props.max_brightness = aat2870_bl->max_current + 1; aat2870_bl->brightness = 0; bd->props.power = BACKLIGHT_POWER_ON; @@ -171,9 +165,16 @@ static void aat2870_bl_remove(struct platform_device *pdev) backlight_update_status(bd); } +static const struct of_device_id aat2870_bl_match_table[] = { + { .compatible = "skyworks,aat2870-backlight" }, + { } +}; +MODULE_DEVICE_TABLE(of, aat2870_bl_match_table); + static struct platform_driver aat2870_bl_driver = { .driver = { .name = "aat2870-backlight", + .of_match_table = aat2870_bl_match_table, }, .probe = aat2870_bl_probe, .remove = aat2870_bl_remove, diff --git a/include/linux/mfd/aat2870.h b/include/linux/mfd/aat2870.h index c7a3c53eba681..a7b482b790b4e 100644 --- a/include/linux/mfd/aat2870.h +++ b/include/linux/mfd/aat2870.h @@ -54,80 +54,13 @@ #define AAT2870_LDO_EN 0x26 #define AAT2870_REG_NUM 0x27 -/* Device IDs */ -enum aat2870_id { - AAT2870_ID_BL, - AAT2870_ID_LDOA, - AAT2870_ID_LDOB, - AAT2870_ID_LDOC, - AAT2870_ID_LDOD -}; - -/* Backlight channels */ -#define AAT2870_BL_CH1 0x01 -#define AAT2870_BL_CH2 0x02 -#define AAT2870_BL_CH3 0x04 -#define AAT2870_BL_CH4 0x08 -#define AAT2870_BL_CH5 0x10 -#define AAT2870_BL_CH6 0x20 -#define AAT2870_BL_CH7 0x40 -#define AAT2870_BL_CH8 0x80 -#define AAT2870_BL_CH_ALL 0xFF - -/* Backlight current magnitude (mA) */ -enum aat2870_current { - AAT2870_CURRENT_0_45 = 1, - AAT2870_CURRENT_0_90, - AAT2870_CURRENT_1_80, - AAT2870_CURRENT_2_70, - AAT2870_CURRENT_3_60, - AAT2870_CURRENT_4_50, - AAT2870_CURRENT_5_40, - AAT2870_CURRENT_6_30, - AAT2870_CURRENT_7_20, - AAT2870_CURRENT_8_10, - AAT2870_CURRENT_9_00, - AAT2870_CURRENT_9_90, - AAT2870_CURRENT_10_8, - AAT2870_CURRENT_11_7, - AAT2870_CURRENT_12_6, - AAT2870_CURRENT_13_5, - AAT2870_CURRENT_14_4, - AAT2870_CURRENT_15_3, - AAT2870_CURRENT_16_2, - AAT2870_CURRENT_17_1, - AAT2870_CURRENT_18_0, - AAT2870_CURRENT_18_9, - AAT2870_CURRENT_19_8, - AAT2870_CURRENT_20_7, - AAT2870_CURRENT_21_6, - AAT2870_CURRENT_22_5, - AAT2870_CURRENT_23_4, - AAT2870_CURRENT_24_3, - AAT2870_CURRENT_25_2, - AAT2870_CURRENT_26_1, - AAT2870_CURRENT_27_0, - AAT2870_CURRENT_27_9 -}; - -struct aat2870_register { - bool readable; - bool writeable; - u8 value; -}; - struct aat2870_data { struct device *dev; struct i2c_client *client; struct mutex io_lock; struct aat2870_register *reg_cache; /* register cache */ - int en_pin; /* enable GPIO pin (if < 0, ignore this value) */ - bool is_enable; - - /* init and uninit for platform specified */ - int (*init)(struct aat2870_data *aat2870); - void (*uninit)(struct aat2870_data *aat2870); + struct gpio_desc *en_pin; /* i2c io funcntions */ int (*read)(struct aat2870_data *aat2870, u8 addr, u8 *val); @@ -135,30 +68,4 @@ struct aat2870_data { int (*update)(struct aat2870_data *aat2870, u8 addr, u8 mask, u8 val); }; -struct aat2870_subdev_info { - int id; - const char *name; - void *platform_data; -}; - -struct aat2870_platform_data { - int en_pin; /* enable GPIO pin (if < 0, ignore this value) */ - - struct aat2870_subdev_info *subdevs; - int num_subdevs; - - /* init and uninit for platform specified */ - int (*init)(struct aat2870_data *aat2870); - void (*uninit)(struct aat2870_data *aat2870); -}; - -struct aat2870_bl_platform_data { - /* backlight channels, default is AAT2870_BL_CH_ALL */ - int channels; - /* backlight current magnitude, default is AAT2870_CURRENT_27_9 */ - int max_current; - /* maximum brightness, default is 255 */ - int max_brightness; -}; - #endif /* __LINUX_MFD_AAT2870_H */ -- 2.53.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings 2026-10-13 18:09 ` [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel @ 2026-10-13 18:21 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-10-13 18:21 UTC (permalink / raw) To: Svyatoslav Ryhel Cc: linux-leds, devicetree, mfd, dri-devel, robh, conor+dt, lee Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [Medium] video: missing default value for optional led-max-microamp property - [Medium] mfd: aat2870: WARNING triggered by gpiod_set_value on sleepable GPIOs - [Low] video: incompatible pointer type in device_property_read_u32 - [Low] regulator: missing const on aat2870_regulators array -- commit 44f47c7fe6dfacca37d21c28bab7fce4a68f379a Author: Svyatoslav Ryhel <clamor95@gmail.com> mfd: aat2870: Convert to use OF bindings This commit converts the AAT2870 driver to use OF bindings by replacing mfd_add_devices() with of_platform_populate() and adding separate compatible strings for its backlight and regulator sub-devices. It also updates the GPIO enable logic to use gpiod helpers and modifies the child drivers to parse properties directly from the Device Tree, allowing the removal of platform data. > diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c > index 0d56cd6fbc6a5..909c14ee60323 100644 > --- a/drivers/mfd/aat2870-core.c > +++ b/drivers/mfd/aat2870-core.c [ ... ] > @@ -348,60 +309,29 @@ static int aat2870_i2c_probe(struct i2c_client *client) > > aat2870->reg_cache = aat2870_regs; > > - if (pdata->en_pin < 0) > - aat2870->en_pin = -1; > - else > - aat2870->en_pin = pdata->en_pin; > + aat2870->en_pin = devm_gpiod_get_optional(&client->dev, "enable", > + GPIOD_OUT_HIGH); > + if (IS_ERR(aat2870->en_pin)) > + return dev_err_probe(&client->dev, PTR_ERR(aat2870->en_pin), > + "Failed to get EN GPIO\n"); > > - aat2870->init = pdata->init; > - aat2870->uninit = pdata->uninit; > aat2870->read = aat2870_read; > aat2870->write = aat2870_write; > aat2870->update = aat2870_update; > > mutex_init(&aat2870->io_lock); > > - if (aat2870->init) > - aat2870->init(aat2870); > - > - if (aat2870->en_pin >= 0) { > - ret = devm_gpio_request_one(&client->dev, aat2870->en_pin, > - GPIOF_OUT_INIT_HIGH, "aat2870-en"); > - if (ret < 0) { > - dev_err(&client->dev, > - "Failed to request GPIO %d\n", aat2870->en_pin); > - return ret; > - } > - } > - > - aat2870_enable(aat2870); > - > - for (i = 0; i < pdata->num_subdevs; i++) { > - for (j = 0; j < ARRAY_SIZE(aat2870_devs); j++) { > - if ((pdata->subdevs[i].id == aat2870_devs[j].id) && > - !strcmp(pdata->subdevs[i].name, > - aat2870_devs[j].name)) { > - aat2870_devs[j].platform_data = > - pdata->subdevs[i].platform_data; > - break; > - } > - } > - } > + gpiod_set_value(aat2870->en_pin, 1); [Severity: Medium] Should this use gpiod_set_value_cansleep() instead? Since this device is an I2C MFD, the enable GPIO could be attached to an I2C or SPI expander, which means toggling it might sleep. Using the non-cansleep gpiod_set_value() here, as well as in the probe error path and suspend/resume callbacks, could trigger a WARN_ON() in gpiolib if the underlying controller requires sleeping. > > - ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, > - ARRAY_SIZE(aat2870_devs), NULL, 0, NULL); > - if (ret != 0) { > - dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); > - goto out_disable; > + ret = devm_of_platform_populate(&client->dev); > + if (ret) { > + gpiod_set_value(aat2870->en_pin, 0); [Severity: Medium] Similar to the above, would gpiod_set_value_cansleep() be safer here on the error path to avoid a potential gpiolib WARN_ON()? > + return dev_err_probe(&client->dev, ret, "Failed to populate cells\n"); > } > > aat2870_init_debugfs(aat2870); > > return 0; > - > -out_disable: > - aat2870_disable(aat2870); > - return ret; > } > > static int aat2870_i2c_suspend(struct device *dev) > @@ -409,7 +339,7 @@ static int aat2870_i2c_suspend(struct device *dev) > struct i2c_client *client = to_i2c_client(dev); > struct aat2870_data *aat2870 = i2c_get_clientdata(client); > > - aat2870_disable(aat2870); > + gpiod_set_value(aat2870->en_pin, 0); [Severity: Medium] Should we use gpiod_set_value_cansleep() here in the suspend handler? > > return 0; > } > @@ -421,7 +351,7 @@ static int aat2870_i2c_resume(struct device *dev) > struct aat2870_register *reg = NULL; > int i; > > - aat2870_enable(aat2870); > + gpiod_set_value(aat2870->en_pin, 1); [Severity: Medium] Should we use gpiod_set_value_cansleep() here in the resume handler? > > /* restore registers */ > for (i = 0; i < AAT2870_REG_NUM; i++) { > diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c > index 970d86f2bbb81..9b8eb8df220a7 100644 > --- a/drivers/regulator/aat2870-regulator.c > +++ b/drivers/regulator/aat2870-regulator.c [ ... ] > @@ -101,84 +102,60 @@ static const unsigned int aat2870_ldo_voltages[] = { > 3000000, 3100000, 3200000, 3300000, > }; > > -#define AAT2870_LDO(ids) \ > - { \ > - .desc = { \ > - .name = #ids, \ > - .id = AAT2870_ID_##ids, \ > - .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ > - .volt_table = aat2870_ldo_voltages, \ > - .ops = &aat2870_ldo_ops, \ > - .type = REGULATOR_VOLTAGE, \ > - .owner = THIS_MODULE, \ > - }, \ > - } > +#define AAT2870_LDO(ids, match, vsel, vmask) { \ > + .name = #ids, \ > + .of_match = (match), \ > + .id = AAT2870_ID_##ids, \ > + .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ > + .volt_table = aat2870_ldo_voltages, \ > + .ops = &aat2870_ldo_ops, \ > + .type = REGULATOR_VOLTAGE, \ > + .owner = THIS_MODULE, \ > + .vsel_reg = (vsel), \ > + .vsel_mask = (vmask), \ > + .enable_reg = AAT2870_LDO_EN, \ > + .enable_mask = BIT(AAT2870_ID_##ids), \ > +} > > -static struct aat2870_regulator aat2870_regulators[] = { > - AAT2870_LDO(LDOA), > - AAT2870_LDO(LDOB), > - AAT2870_LDO(LDOC), > - AAT2870_LDO(LDOD), > +static struct regulator_desc aat2870_regulators[] = { [Severity: Low] Could we add the const qualifier to this array? Since the descriptions are static and never modified at runtime, and devm_regulator_register() expects a const struct regulator_desc *, adding const would allow this array to be placed in read-only .rodata memory instead of mutable .data. > + AAT2870_LDO(LDOA, "ldo-a", AAT2870_LDO_AB, AAT2870_LDO_AB_A_MASK), > + AAT2870_LDO(LDOB, "ldo-b", AAT2870_LDO_AB, AAT2870_LDO_AB_B_MASK), > + AAT2870_LDO(LDOC, "ldo-c", AAT2870_LDO_CD, AAT2870_LDO_CD_C_MASK), > + AAT2870_LDO(LDOD, "ldo-d", AAT2870_LDO_CD, AAT2870_LDO_CD_D_MASK), > }; > > diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c > index eb686e315921d..705a8d32d224f 100644 > --- a/drivers/video/backlight/aat2870_bl.c > +++ b/drivers/video/backlight/aat2870_bl.c [ ... ] > @@ -129,21 +124,20 @@ static int aat2870_bl_probe(struct platform_device *pdev) > > aat2870_bl->bd = bd; > > - if (pdata->channels > 0) > - aat2870_bl->channels = pdata->channels; > - else > - aat2870_bl->channels = AAT2870_BL_CH_ALL; > + aat2870_bl->channels = AAT2870_BL_CH_ALL; > + device_property_read_u8(&pdev->dev, "skyworks,channels", &aat2870_bl->channels); > > - if (pdata->max_current > 0) > - aat2870_bl->max_current = pdata->max_current; > - else > - aat2870_bl->max_current = AAT2870_CURRENT_27_9; > + device_property_read_u32(&pdev->dev, "led-max-microamp", &aat2870_bl->max_current); [Severity: Low] Does this cause an incompatible pointer type warning? aat2870_bl->max_current is defined as a signed int, but device_property_read_u32() expects a u32 pointer. This could break builds that treat -Wincompatible-pointer-types as an error. [Severity: Medium] What happens if the optional "led-max-microamp" property is missing from the device tree? If the property is missing, device_property_read_u32() leaves max_current at 0 (its initial value from devm_kzalloc). When passed into clamp(0, 450, 27900), it gets forced to 450, and dividing by 900 evaluates to 0. This sets bd->props.max_brightness to 1 (0 + 1), silently degrading the backlight limits to an almost invisible state, whereas the previous behavior correctly defaulted to 27.9mA (32 steps). Should max_current be initialized to a default value before reading the property? > + aat2870_bl->max_current = clamp(aat2870_bl->max_current, AAT2870_CURRENT_MIN, > + AAT2870_CURRENT_MAX); > + aat2870_bl->max_current /= AAT2870_CURRENT_STEP; > > /* > * The maximum number of brightness steps is determined by the max current. > - * The aat2870_current enum maps directly to the allowed brightness steps. > + * The aat2870_bl->max_current value maps to the allowed brightness steps > + * with +1 offset since max_current 0 is still 450uA. > */ > - bd->props.max_brightness = pdata->max_current; > + bd->props.max_brightness = aat2870_bl->max_current + 1; > > aat2870_bl->brightness = 0; > bd->props.power = BACKLIGHT_POWER_ON; -- Sashiko AI review · https://sashiko.dev/#/patchset/20261013180933.487013-1-clamor95@gmail.com?part=3 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies 2026-10-13 18:09 [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel ` (2 preceding siblings ...) 2026-10-13 18:09 ` [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel @ 2026-10-13 18:09 ` Svyatoslav Ryhel 2026-10-13 18:18 ` sashiko-bot 3 siblings, 1 reply; 9+ messages in thread From: Svyatoslav Ryhel @ 2026-10-13 18:09 UTC (permalink / raw) To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Liam Girdwood, Mark Brown, Daniel Thompson, Jingoo Han, Svyatoslav Ryhel Cc: linux-leds, devicetree, linux-kernel, mfd, dri-devel The AAT2870 supports a dedicated main power supply input alongside parent power supply for its internal regulators. Add support for retrieving and managing these supply regulators (vin-supply and in-ldo-supply) using the regulator framework to ensure proper power supply dependencies and power-up sequencing. Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com> --- drivers/mfd/aat2870-core.c | 5 +++++ drivers/regulator/aat2870-regulator.c | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 909c14ee60323..0bd430b90bc1b 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -17,6 +17,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/aat2870.h> #include <linux/of_platform.h> +#include <linux/regulator/consumer.h> #include <linux/regulator/machine.h> struct aat2870_register { @@ -309,6 +310,10 @@ static int aat2870_i2c_probe(struct i2c_client *client) aat2870->reg_cache = aat2870_regs; + ret = devm_regulator_get_enable(&client->dev, "vin"); + if (ret) + return dev_err_probe(&client->dev, ret, "Failed to enable regulator\n"); + aat2870->en_pin = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(aat2870->en_pin)) diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 9b8eb8df220a7..6f19b19f694fd 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -105,6 +105,7 @@ static const unsigned int aat2870_ldo_voltages[] = { #define AAT2870_LDO(ids, match, vsel, vmask) { \ .name = #ids, \ .of_match = (match), \ + .supply_name = "in-ldo", \ .id = AAT2870_ID_##ids, \ .n_voltages = ARRAY_SIZE(aat2870_ldo_voltages), \ .volt_table = aat2870_ldo_voltages, \ -- 2.53.0 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies 2026-10-13 18:09 ` [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies Svyatoslav Ryhel @ 2026-10-13 18:18 ` sashiko-bot 0 siblings, 0 replies; 9+ messages in thread From: sashiko-bot @ 2026-10-13 18:18 UTC (permalink / raw) To: Svyatoslav Ryhel Cc: linux-leds, devicetree, mfd, dri-devel, robh, conor+dt, lee Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] mfd: aat2870: Missing GPIO teardown causes backpowering risk -- commit 878c16709c6ee44d1728f13a2ff6e9ad29023883 Author: Svyatoslav Ryhel <clamor95@gmail.com> mfd: aat2870: Add support for VIN and IN-LDO power supplies This commit adds support for retrieving and managing the VIN and IN-LDO power supplies using the regulator framework to ensure proper power supply dependencies and power-up sequencing. > diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c > index 909c14ee60323..0bd430b90bc1b 100644 > --- a/drivers/mfd/aat2870-core.c > +++ b/drivers/mfd/aat2870-core.c [ ... ] > @@ -309,6 +310,10 @@ static int aat2870_i2c_probe(struct i2c_client *client) > > aat2870->reg_cache = aat2870_regs; > > + ret = devm_regulator_get_enable(&client->dev, "vin"); > + if (ret) > + return dev_err_probe(&client->dev, ret, "Failed to enable regulator\n"); > + > aat2870->en_pin = devm_gpiod_get_optional(&client->dev, "enable", > GPIOD_OUT_HIGH); [Severity: High] Does this unwinding order create a backpowering regression when the device is removed? Because the regulator is acquired before the GPIO, devres unwinds in reverse order. It will release the GPIO descriptor first during device unbind (e.g., during parent I2C adapter removal), without actually driving the pin low. After the GPIO descriptor is released, devm_regulator_get_enable() will disable the vin regulator. This leaves the enable GPIO driven high into the unpowered AAT2870 device. Since aat2870_i2c_driver lacks a .remove callback to explicitly drive the GPIO low before devres unwinds, could this backpowering state cause hardware damage? Would it be safer to add a devm action or a .remove callback to pull the enable pin low first? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261013180933.487013-1-clamor95@gmail.com?part=4 ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-13 18:21 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-13 18:09 [PATCH v3 0/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel 2026-10-13 18:09 ` [PATCH v3 1/4] dt-bindings: mfd: Document Skyworks AAT2870 Svyatoslav Ryhel 2026-10-13 18:16 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 2/4] mfd: aat2870: Derive brightness steps from max current Svyatoslav Ryhel 2026-10-13 18:16 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 3/4] mfd: aat2870: Convert to use OF bindings Svyatoslav Ryhel 2026-10-13 18:21 ` sashiko-bot 2026-10-13 18:09 ` [PATCH v3 4/4] mfd: aat2870: Add support for VIN and IN-LDO power supplies Svyatoslav Ryhel 2026-10-13 18:18 ` sashiko-bot
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.