[PATCH v2 07/13] leds: st1202: Program the channel current for hardware patterns

From: Manuel Fombuena

Date: Tue Sep 15 2026 - 09:19:55 EST


A channel's output is ILED x Pattern_PWM / 4095, so a pattern is only
visible while the analog current register holds a non-zero value.
st1202_led_pattern_set() programs the PWM slots and starts the sequencer
but never writes ILED, so a channel whose current is zero stays dark
while pattern_set() reports success.

Zero is reached by ordinary use. Writing 0 to brightness sets it, and so
does switching away from the pattern trigger, because
pattern_trig_deactivate() ends with led_set_brightness(LED_OFF). A
sequence as simple as

echo none > trigger
echo pattern > trigger
echo "255 500 0 500" > hw_pattern

therefore programs a pattern that never lights up.

Program the current in pattern_set() and release it in pattern_clear(),
so the pattern path owns ILED for as long as a pattern is loaded.
Releasing it matters because the trigger calls pattern_clear() before it
parses a new pattern: without that, a rejected or empty hw_pattern write
would leave the channel at full current with every PWM slot at full
scale, latching the LED on. Clearing before the slots are raised also
avoids a brief full-brightness flash on every reprogram.

A current of zero is not enough to release the channel, though: the
datasheet notes that it does not switch the channel off but leaves a
small uncontrolled current, which shows as a faint glow. pattern_clear()
therefore also disables the channel, and pattern_set() enables it again.
Both are done before the sequencer is stopped, so an I2C error partway
through a clear cannot leave the channel lit.

Probe clears every channel, so the LEDs now reach user space switched
off. Until now they came up lit at the chip's power-on current, because
pattern_clear() fills every slot at full scale. Probe no longer enables
the channels itself either: st1202_setup() has already disabled them
all, and each path that lights a channel enables it when needed.

The current is programmed to the same max_brightness the PWM values are
scaled against, so a pattern step of N produces the same output as
writing N to brightness, and a board declaring a lower ceiling through
the max-brightness property keeps it on both paths.

Note that this makes a hardware pattern take the channel to its maximum
current, so brightness reads back as max_brightness once a pattern is
loaded and as zero once it is cleared. The pattern's own values, not the
last brightness written, decide what the channel shows while a pattern
is running.

Fixes: 259230378c65 ("leds: Add LED1202 I2C driver")
Signed-off-by: Manuel Fombuena <fombuena@xxxxxxxxxxx>
Assisted-by: LLM
---
drivers/leds/leds-st1202.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c
index 5558ac9612a1..41eac6195659 100644
--- a/drivers/leds/leds-st1202.c
+++ b/drivers/leds/leds-st1202.c
@@ -221,6 +221,14 @@ static int st1202_led_pattern_clear(struct led_classdev *ldev)

guard(mutex)(&chip->lock);

+ ret = st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, LED_OFF);
+ if (ret != 0)
+ return ret;
+
+ ret = __st1202_channel_set(chip, led->led_num, false);
+ if (ret != 0)
+ return ret;
+
ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_PHASE_SHIFT);
if (ret != 0)
return ret;
@@ -287,6 +295,10 @@ static int st1202_led_pattern_set(struct led_classdev *ldev,
if (ret != 0)
return ret;

+ ret = st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, max_brightness);
+ if (ret != 0)
+ return ret;
+
ret = __st1202_channel_set(chip, led->led_num, true);
if (ret != 0)
return ret;
@@ -455,7 +467,7 @@ static int st1202_setup(struct st1202_chip *chip)
/* Duration of initialization */
usleep_range(6500, 10000);

- /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */
+ /* Deactivate all LEDs (channels); each is enabled when it is lit */
ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL);
if (ret < 0)
return ret;
@@ -502,11 +514,6 @@ static int st1202_probe(struct i2c_client *client)
if (!led->is_active)
continue;

- ret = st1202_channel_set(led->chip, led->led_num, true);
- if (ret < 0)
- return dev_err_probe(&client->dev, ret,
- "Failed to activate LED channel\n");
-
ret = st1202_led_pattern_clear(&led->led_cdev);
if (ret < 0)
return dev_err_probe(&client->dev, ret,
--
2.55.0