[PATCH v2 2/4] leds: pca9532: check return value in pca9532_setled()
From: haibo . chen
Date: Wed Jul 29 2026 - 03:50:33 EST
From: Haibo Chen <haibo.chen@xxxxxxx>
pca9532_setled() reads the LED register with i2c_smbus_read_byte_data()
but never checks its return value. On an I2C read failure the function
returns a negative error code (e.g. -EIO) which was silently truncated
into a signed char, then bitwise modified and written back to the
device.
Since one LED register controls four LEDs, writing this bogus value back
corrupts the state of the other three LEDs sharing the same register.
Fixes: e14fa82439d3 ("leds: Add pca9532 led driver")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: VeroCoder:claude-sonnet-4
Signed-off-by: Haibo Chen <haibo.chen@xxxxxxx>
---
drivers/leds/leds-pca9532.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index e8ee17b8bd547a92372a8e74a6781b95ae831fe2..adfb5aa50e8e1f3ca0deb9261d8c9103903ef928 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -159,21 +159,29 @@ static int pca9532_setpwm(struct i2c_client *client, int pwm)
}
/* Set LED routing */
-static void pca9532_setled(struct pca9532_led *led)
+static int pca9532_setled(struct pca9532_led *led)
{
struct i2c_client *client = led->client;
struct pca9532_data *data = i2c_get_clientdata(client);
u8 maxleds = data->chip_info->num_leds;
- char reg;
+ int reg;
+ int ret = 0;
mutex_lock(&data->update_lock);
reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
+ if (reg < 0) {
+ dev_warn(&client->dev, "failed to read LED register: %d\n", reg);
+ ret = reg;
+ goto out;
+ }
/* zero led bits */
reg = reg & ~LED_MASK(led->id);
/* set the new value */
reg = reg | (led->state << LED_SHIFT(led->id));
- i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
+ ret = i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
+out:
mutex_unlock(&data->update_lock);
+ return ret;
}
static int pca9532_set_brightness(struct led_classdev *led_cdev,
@@ -196,8 +204,7 @@ static int pca9532_set_brightness(struct led_classdev *led_cdev,
}
if (led->state == PCA9532_PWM0)
pca9532_setpwm(led->client, PCA9532_PWM_ID_0);
- pca9532_setled(led);
- return err;
+ return pca9532_setled(led);
}
static int pca9532_update_hw_blink(struct pca9532_led *led,
@@ -257,9 +264,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
if (err)
return err;
- pca9532_setled(led);
-
- return 0;
+ return pca9532_setled(led);
}
static int pca9532_event(struct input_dev *dev, unsigned int type,
@@ -334,9 +339,7 @@ static int pca9532_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
else
led->state = PCA9532_ON;
- pca9532_setled(led);
-
- return 0;
+ return pca9532_setled(led);
}
static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
--
2.34.1