leds: rgb: leds-qcom-lpg: Fix pwm resolution max for Hi-Res PWMs
authorAbel Vesa <abel.vesa@linaro.org>
Wed, 5 Mar 2025 13:09:05 +0000 (15:09 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Apr 2025 08:45:28 +0000 (10:45 +0200)
commit b7881eacc07fdf50be3f33c662997541bb59366d upstream.

Ideally, the requested duty cycle should never translate to a PWM
value higher than the selected resolution (PWM size), but currently the
best matched period is never reported back to the PWM consumer, so the
consumer will still be using the requested period which is higher than
the best matched one. This will result in PWM consumer requesting
duty cycle values higher than the allowed PWM value.

For example, a consumer might request a period of 5ms while the best
(closest) period the PWM hardware will do is 4.26ms. For this best
matched resolution, if the selected resolution is 8-bit wide, when
the consumer asks for a duty cycle of 5ms, the PWM value will be 300,
which is outside of what the resolution allows. This will happen with
all possible resolutions when selected.

Since for these Hi-Res PWMs, the current implementation is capping the PWM
value at a 15-bit resolution, even when lower resolutions are selected,
the value will be wrapped around by the HW internal logic to the selected
resolution.

Fix the issue by capping the PWM value to the maximum value allowed by
the selected resolution.

Cc: stable@vger.kernel.org # 6.4
Fixes: b00d2ed37617 ("leds: rgb: leds-qcom-lpg: Add support for high resolution PWM")
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
Reviewed-by: Bjorn Andersson <andersson@kernel.org>
Reviewed-by: Sebastian Reichel <sre@kernel.org>
Link: https://lore.kernel.org/r/20250305-leds-qcom-lpg-fix-max-pwm-on-hi-res-v4-2-bfe124a53a9f@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/leds/rgb/leds-qcom-lpg.c

index df469aaa7e6e7ecf00d4be99f736c8da5fd262f4..2115709fca5236337827553fde04321109260b47 100644 (file)
@@ -379,7 +379,7 @@ static void lpg_calc_duty(struct lpg_channel *chan, uint64_t duty)
        unsigned int clk_rate;
 
        if (chan->subtype == LPG_SUBTYPE_HI_RES_PWM) {
-               max = LPG_RESOLUTION_15BIT - 1;
+               max = BIT(lpg_pwm_resolution_hi_res[chan->pwm_resolution_sel]) - 1;
                clk_rate = lpg_clk_rates_hi_res[chan->clk_sel];
        } else {
                max = LPG_RESOLUTION_9BIT - 1;