All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Joseph Telaak" <joseph@telaak.dev>
Cc: linux-leds@vger.kernel.org, devicetree@vger.kernel.org,
	robh@kernel.org, conor+dt@kernel.org, lee@kernel.org
Subject: Re: [PATCH 07/10] leds: rgb: ktd202x: Add hardware pattern support
Date: Mon, 02 Nov 2026 02:31:20 +0000	[thread overview]
Message-ID: <sashiko-outbox-192836@kernel.org> (raw)
In-Reply-To: <20261101-ktd202x-et6326-v1-7-eb51eddad08c@telaak.dev>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] leds: ktd202x: ktd202x_pattern_program() enables PWM1 on 0-brightness channels
--

commit cb2ed015f23bfa814b09df784ba07474c986d4de
Author: Joseph Telaak <joseph@telaak.dev>

leds: rgb: ktd202x: Add hardware pattern support

This commit adds hardware pattern support to the ktd202x LED driver by
implementing the pattern_set and pattern_clear callbacks using the chip's
hardware flash timer and rise/fall ramp registers.

> diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c
> index 67e65c1fcb5fb..ed0e8e74c9eab 100644
> --- a/drivers/leds/rgb/leds-ktd202x.c
> +++ b/drivers/leds/rgb/leds-ktd202x.c
[ ... ]
> @@ -420,6 +446,148 @@ static int ktd202x_blink_mc_set(struct led_classdev *cdev,
[ ... ]
> +static int ktd202x_pattern_program(struct ktd202x_led *led,
> +				   struct led_pattern *pattern,
> +				   struct mc_subled *subleds,
> +				   unsigned int num_channels)
> +{
> +	const struct ktd202x_info *info = led->chip->info;
> +	unsigned int t[KTD202X_PATTERN_LEN];
> +	unsigned int rise, fall, num_steps, on;
> +	unsigned long period_ms, ton_ms;
> +	u8 ctrl_mask = 0;
> +	u8 ctrl_pwm1 = 0;
> +	int ret;
> +	int i;
> +
> +	for (i = 0; i < num_channels; i++) {
> +		int channel = subleds[i].channel;
> +
> +		ctrl_mask |= KTD202X_CHANNEL_CTRL_MASK(channel);
> +		ctrl_pwm1 |= KTD202X_CHANNEL_CTRL_PWM1(channel);
> +	}
> +
> +	for (i = 0; i < KTD202X_PATTERN_LEN; i++)
> +		t[i] = min_t(u32, pattern[i].delta_t, KTD202X_PATTERN_MAX_MS);
> +
> +	rise = min_t(unsigned int, KTD202X_RAMP_MAX_STEPS,
> +		     DIV_ROUND_CLOSEST(t[0], KTD202X_RAMP_STEP_MS));
> +	fall = min_t(unsigned int, KTD202X_RAMP_MAX_STEPS,
> +		     DIV_ROUND_CLOSEST(t[2], KTD202X_RAMP_STEP_MS));
> +
> +	/* Round the period up so that the fall ramp is not cut short */
> +	period_ms = t[0] + t[1] + t[2] + t[3];
> +	num_steps = ktd202x_flash_period_steps(info, period_ms +
> +					       KTD202X_FLASH_PERIOD_STEP_MS - 1);
> +	period_ms = ktd202x_flash_period_ms(info, num_steps);
> +
> +	/* The on time includes the rise time */
> +	ton_ms = t[0] + t[1];
> +	on = clamp_t(unsigned long,
> +		     DIV_ROUND_CLOSEST(ton_ms * KTD202X_FLASH_ON_MAX, period_ms),
> +		     1, KTD202X_FLASH_ON_MAX - 1);
> +
> +	mutex_lock(&led->chip->mutex);
> +
> +	ret = regmap_write(led->chip->regmap, KTD202X_REG_FLASH_PERIOD, num_steps);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(led->chip->regmap, KTD202X_REG_PWM1_TIMER, on);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_write(led->chip->regmap, KTD202X_REG_TRISE_FALL,
> +			   KTD202X_RAMP_TFALL(fall) | KTD202X_RAMP_TRISE(rise));
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,
> +				 ctrl_mask, ctrl_pwm1);
> +out:
> +	mutex_unlock(&led->chip->mutex);
> +	return ret;
> +}
> +
> +static int ktd202x_pattern_single_set(struct led_classdev *cdev,
> +				      struct led_pattern *pattern, u32 len,
> +				      int repeat)
> +{
> +	struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev);
> +	struct mc_subled info;
> +	int ret;
> +
> +	ret = ktd202x_pattern_check(cdev, pattern, len, repeat);
> +	if (ret)
> +		return ret;
> +
> +	ret = ktd202x_brightness_single_set(cdev, pattern[1].brightness);
> +	if (ret)
> +		return ret;
> +
> +	info.channel = led->index;
> +
> +	return ktd202x_pattern_program(led, pattern, &info, 1);
> +}
> +
> +static int ktd202x_pattern_single_clear(struct led_classdev *cdev)
> +{
> +	return ktd202x_brightness_single_set(cdev, LED_OFF);
> +}
> +
> +static int ktd202x_pattern_mc_set(struct led_classdev *cdev,
> +				  struct led_pattern *pattern, u32 len,
> +				  int repeat)
> +{
> +	struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
> +	struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev);
> +	int ret;
> +
> +	ret = ktd202x_pattern_check(cdev, pattern, len, repeat);
> +	if (ret)
> +		return ret;
> +
> +	ret = ktd202x_brightness_mc_set(cdev, pattern[1].brightness);
> +	if (ret)
> +		return ret;
> +
> +	return ktd202x_pattern_program(led, pattern, mc->subled_info,
> +				       mc->num_colors);
> +}

[Severity: Medium]
When a hardware pattern is set on a multicolor LED where one or more color
channels have a computed brightness of 0 (for example, via multi_intensity),
won't ktd202x_pattern_program() turn those 0-brightness channels on at their
previous or reset-default (10 mA) current?

In ktd202x_pattern_mc_set(), the call to ktd202x_brightness_mc_set() computes
per-channel brightness into mc->subled_info[i].brightness and calls
ktd202x_brightness_set():

drivers/leds/rgb/leds-ktd202x.c:ktd202x_brightness_set() {
	...
	for (i = 0; i < num_channels; i++) {
		enum led_brightness brightness;
		int mode;

		brightness = subleds[i].brightness;
		channel = subleds[i].channel;

		if (brightness) {
			/* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */
			ret = regmap_write(led->chip->regmap, KTD202X_REG_LED_IOUT(channel),
					   brightness - 1);
			...
		} else {
			mode = KTD202X_CHANNEL_CTRL_OFF;
		}
		ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,
					 KTD202X_CHANNEL_CTRL_MASK(channel), mode);
		...
	}
}

Because KTD202X_REG_LED_IOUT(channel) encodes currents starting at 0.125 mA
(brightness - 1) and cannot encode 0 mA, channels with brightness == 0 do not
update KTD202X_REG_LED_IOUT(channel) and instead rely on
KTD202X_CHANNEL_CTRL_OFF in KTD202X_REG_CHANNEL_CTRL to remain off.

However, ktd202x_pattern_program() then loops over all num_channels and
unconditionally sets KTD202X_CHANNEL_CTRL_PWM1(channel) in ctrl_pwm1 for every
channel regardless of subleds[i].brightness, overwriting
KTD202X_REG_CHANNEL_CTRL so that the 0-brightness channels also breathe on
PWM1.

Also note that ktd202x_pattern_single_set() leaves info.brightness
uninitialized on the stack before passing &info to ktd202x_pattern_program(),
and ktd202x_pattern_program() builds ctrl_pwm1 before acquiring
led->chip->mutex (after ktd202x_brightness_mc_set() has already dropped it).

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261101-ktd202x-et6326-v1-0-eb51eddad08c@telaak.dev?part=7

  reply	other threads:[~2026-11-02  2:31 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02  2:12 [PATCH 00/10] leds: ktd202x: Add Etek ET6326, hardware breathing and fixes Joseph Telaak via B4 Relay
2026-11-02  2:12 ` Joseph Telaak
2026-11-02  2:12 ` [PATCH 01/10] leds: rgb: ktd202x: Fix the flash period of short blinks on 32 bit Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:20   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 02/10] leds: rgb: ktd202x: Fix an out-of-bounds read with unused channels Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:20   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 03/10] leds: rgb: ktd202x: Never program an on time of zero Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:20   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 04/10] leds: rgb: ktd202x: Fix a division by zero with long blinks Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:17   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 05/10] dt-bindings: leds: kinetic,ktd202x: Add Etek ET6326 Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:17   ` sashiko-bot
2026-11-02 11:44   ` Krzysztof Kozlowski
2026-11-02  2:12 ` [PATCH 06/10] leds: rgb: ktd202x: Add Etek ET6326 support Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:20   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 07/10] leds: rgb: ktd202x: Add hardware pattern support Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:31   ` sashiko-bot [this message]
2026-11-02  2:12 ` [PATCH 08/10] leds: rgb: ktd202x: Limit the LED current to led-max-microamp Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:29   ` sashiko-bot
2026-11-02  2:12 ` [PATCH 09/10] leds: rgb: ktd202x: Fail the probe when the chip does not answer Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:22   ` sashiko-bot
2026-11-02  2:38     ` Joseph Telaak
2026-11-02  2:12 ` [PATCH 10/10] leds: rgb: ktd202x: Don't let a blinking LED retime another one Joseph Telaak via B4 Relay
2026-11-02  2:12   ` Joseph Telaak
2026-11-02  2:39   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-192836@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=joseph@telaak.dev \
    --cc=lee@kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.