[PATCH v3 5/6] leds: aw2013: Prevent writes to unpowered chip

From: Paul Sajna

Date: Tue Oct 13 2026 - 01:41:22 EST


Replace chip_in_use check with chip->enabled boolean in
aw20xx_brightness_set

During teardown, probe, or unregistration, the LED core initializes
cdev->brightness to 0 and queues a work to set the brightness to 0.
This can also be triggered by unprivileged user space via sysfs by
writing 0 to the brightness file when already 0.

When this occurs, aw2013_chip_in_use() evaluates to false and skips
enabling the regulators:

Because aw2013_chip_enable() is skipped, the driver then unconditionally
calls regmap_write() and regmap_update_bits(), which perform I2C
transactions to the unpowered chip.

To prevent writing gcr=0 when we couldn't power on the chip,
add aw2013_chip_poweroff()

To prevent turning the chip on/off unneccessarily, add a check for
writing brightness to 0.

Signed-off-by: Paul Sajna <sajattack@xxxxxxxxxxxxxxxx>
---
drivers/leds/leds-aw2013.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/leds/leds-aw2013.c b/drivers/leds/leds-aw2013.c
index 3b2be960c04d..6e661afd7775 100644
--- a/drivers/leds/leds-aw2013.c
+++ b/drivers/leds/leds-aw2013.c
@@ -193,15 +193,13 @@ static int aw2013_chip_init(struct aw2013 *chip)
return ret;
}

-static void aw2013_chip_disable(struct aw2013 *chip)
+static void aw2013_chip_poweroff(struct aw2013 *chip)
{
int ret;

if (!chip->enabled)
return;

- regmap_write(chip->regmap, AW2013_GCR, 0);
-
ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators),
chip->regulators);
if (ret) {
@@ -213,6 +211,16 @@ static void aw2013_chip_disable(struct aw2013 *chip)
chip->enabled = false;
}

+static void aw2013_chip_disable(struct aw2013 *chip)
+{
+ if (!chip->enabled)
+ return;
+
+ regmap_write(chip->regmap, AW2013_GCR, 0);
+
+ aw2013_chip_poweroff(chip);
+}
+
static int aw2013_chip_enable(struct aw2013 *chip)
{
int ret;
@@ -231,7 +239,7 @@ static int aw2013_chip_enable(struct aw2013 *chip)

ret = aw2013_chip_init(chip);
if (ret)
- aw2013_chip_disable(chip);
+ aw2013_chip_poweroff(chip);

return ret;
}
@@ -253,9 +261,12 @@ static int aw2013_brightness_set(struct led_classdev *cdev,
struct aw2013_led *led = container_of(cdev, struct aw2013_led, cdev);
int ret, num;

+ if (!led->chip->enabled && brightness == 0)
+ return 0;
+
mutex_lock(&led->chip->mutex);

- if (aw2013_chip_in_use(led->chip)) {
+ if (!led->chip->enabled) {
ret = aw2013_chip_enable(led->chip);
if (ret)
goto error;
@@ -284,7 +295,12 @@ static int aw2013_brightness_set(struct led_classdev *cdev,
if (!aw2013_chip_in_use(led->chip))
aw2013_chip_disable(led->chip);

+ mutex_unlock(&led->chip->mutex);
+
+ return ret;
+
error:
+ aw2013_chip_poweroff(led->chip);
mutex_unlock(&led->chip->mutex);

return ret;

--
2.55.0