Re: [PATCH v4 1/1] leds: st1202: Add hardware-accelerated blink support

[email protected] Tue, 28 Jul 2026 11:15:14 +0000
Newsgroups org.kernel.vger.linux-leds
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 5 potential issue(=
s) to consider:

New issues:
- [High] State corruption of other active LEDs during blink configuration
- [Medium] Hardcoded maximum brightness in hardware blink setup
- [Medium] Early return on I2C failure leaves hardware in an inconsistent, =
broken state

Pre-existing issues:
- [High] Sleeping function assigned to non-blocking `brightness_set` callba=
ck
- [High] Use-After-Free due to missing reference count on cached `fwnode`
--

--- Patch [1]: [PATCH v4 1/1] leds: st1202: Add hardware-accelerated blink =
support ---
commit 1ace91a22756ce86eb8f13dd6355ad0a1403ce04
Author: Manuel Fombuena <[email protected]>

leds: st1202: Add hardware-accelerated blink support

This patch implements blink_set() for the st1202 LED driver to enable
hardware-accelerated blinking using the timer trigger. It utilizes the chip=
's
pattern engine to create the blink sequence and clamps user-requested delays
to the supported hardware ranges.

> Other active channels have their PWM slots zeroed for
> both pattern steps so they remain dark rather than outputting unintended
> values when the sequencer runs.

[Severity: High]
Is this description accurate? Looking at st1202_brightness_set(), it appears
steady-ON LEDs are configured with ST1202_PATTERN_PWM_FULL across their
pattern slots, meaning they naturally stay solid-ON when the global sequenc=
er
is running.

Could zeroing out the PWM slots here inadvertently corrupt the hardware
state of other active LEDs, forcing them permanently off until user-space
reconfigures them?

> diff --git a/drivers/leds/leds-st1202.c b/drivers/leds/leds-st1202.c
> index 168df5ecf27b7..4e0128c7c94d4 100644
> --- a/drivers/leds/leds-st1202.c
> +++ b/drivers/leds/leds-st1202.c
[ ... ]
> @@ -275,6 +276,86 @@ static int st1202_led_pattern_set(struct led_classde=
v *ldev,
>  	return 0;
>  }
> =20
> +static int st1202_blink_set(struct led_classdev *led_cdev,
> +			unsigned long *delay_on, unsigned long *delay_off)
> +{
[ ... ]
> +	ret =3D st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHF=
T);
> +	if (ret)
> +		return ret;
> +
> +	/* Zero out PWM for all other active channels to prevent them from blin=
king */
> +	for (int i =3D 0; i < ST1202_MAX_LEDS; i++) {
> +		if (!chip->leds[i].is_active || i =3D=3D led->led_num)
> +			continue;
> +		ret =3D st1202_pwm_pattern_write(chip, i, 0, LED_OFF);
> +		if (ret)
> +			return ret;
> +		ret =3D st1202_pwm_pattern_write(chip, i, 1, LED_OFF);
> +		if (ret)
> +			return ret;

[Severity: Medium]
If one of these I2C writes fails, we return early and release the mutex. Si=
nce
the sequencer was stopped by the initial ST1202_CONFIG_REG write and PWM
slots for other LEDs might now be partially clobbered, would this error path
leave the chip in a permanently inconsistent state where all active LEDs st=
op
functioning?

> +	}
> +
> +	ret =3D st1202_pwm_pattern_write(chip, led->led_num, 0, ST1202_PATTERN_=
PWM_FULL);
> +	if (ret)
> +		return ret;
> +	ret =3D st1202_pwm_pattern_write(chip, led->led_num, 1, LED_OFF);
> +	if (ret)
> +		return ret;
[ ... ]
> +	ret =3D st1202_write_reg(chip, ST1202_PATTERN_REP, U8_MAX);
> +	if (ret)
> +		return ret;
> +
> +	ret =3D st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, U8_MAX);

[Severity: Medium]
Will writing U8_MAX to the analog brightness register cause hardware blinki=
ng
to always occur at maximum brightness, completely overriding the user's
previously configured brightness level?

> +	if (ret)
> +		return ret;
> +
> +	ret =3D __st1202_channel_set(chip, led->led_num, true);
[ ... ]
> @@ -301,6 +382,7 @@ static int st1202_dt_init(struct st1202_chip *chip)

[Severity: High]
This isn't a bug introduced by this patch, but looking at st1202_dt_init()
earlier in this function:

    led =3D &chip->leds[reg];
    led->is_active =3D true;
    led->fwnode =3D of_fwnode_handle(child);

Might caching the fwnode pointer here result in a use-after-free later on?
The for_each_available_child_of_node_scoped() iterator automatically drops =
the
device tree node reference at the end of each iteration. If the node is
dynamically removed or memory is freed before devm_led_classdev_register_ex=
t()
uses it, this stale pointer could be accessed.

>  		led->led_cdev.pattern_set =3D st1202_led_pattern_set;
>  		led->led_cdev.pattern_clear =3D st1202_led_pattern_clear;
>  		led->led_cdev.default_trigger =3D "pattern";
> +		led->led_cdev.blink_set =3D st1202_blink_set;
>  		led->led_cdev.brightness_set =3D st1202_brightness_set;

[Severity: High]
This is a pre-existing issue, but is there a risk of a "sleeping in atomic
context" panic here?

The LED subsystem requires brightness_set to be strictly non-blocking since
it can be called from software timers or other atomic contexts. Looking at
st1202_brightness_set(), it acquires a mutex and performs I2C transfers whi=
ch
can sleep.

Should this driver rely exclusively on brightness_set_blocking instead?

>  		led->led_cdev.brightness_get =3D st1202_brightness_get;
>  	}

--=20
Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/GV1PR08MB84978D8B51=
[email protected]?part=3D1