]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pwm: imx27: Fix variable truncation in .apply()
authorRonaldo Nunez <rnunez@baylibre.com>
Fri, 22 May 2026 19:13:48 +0000 (16:13 -0300)
committerUwe Kleine-König <ukleinek@kernel.org>
Sat, 23 May 2026 16:54:48 +0000 (18:54 +0200)
Fix a variable truncation when calculating period in microseconds as
part of the solution for the ERR051198 in .apply() callback.

Example scenario:
 - Period of 3us (PWMPR = 196 and prescaler = 1)
 - Expected value in tmp: 198000000000 (NSEC_PER_SEC * (196 + 2) * 1)
 - Actual value is 431504384 (truncation to u32)

Signed-off-by: Ronaldo Nunez <rnunez@baylibre.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260522191348.6227-1-rnunez@baylibre.com
Fixes: a25351e4c774 ("pwm: imx27: Workaround of the pwm output bug when decrease the duty cycle")
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
drivers/pwm/pwm-imx27.c

index 3d34cdc4a3a51b0d29b42fce25fc7f4347d60843..c8b801fcb5251f8431242a2aa194999dd2e6b64c 100644 (file)
@@ -200,7 +200,7 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip,
 static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                           const struct pwm_state *state)
 {
-       unsigned long period_cycles, duty_cycles, prescale, period_us, tmp;
+       unsigned long period_cycles, duty_cycles, prescale, period_us;
        struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
        unsigned long long c;
        unsigned long long clkrate;
@@ -208,6 +208,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        int val;
        int ret;
        u32 cr;
+       u64 tmp;
 
        clkrate = clk_get_rate(imx->clks[PWM_IMX27_PER].clk);
        c = clkrate * state->period;
@@ -249,6 +250,11 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        val = readl(imx->mmio_base + MX3_PWMPR);
        val = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
        cr = readl(imx->mmio_base + MX3_PWMCR);
+
+       /*
+        * tmp stores period in nanoseconds. Result fits in u64 since
+        * val <= 0xfffe and prescaler in [1, 0x1000].
+        */
        tmp = NSEC_PER_SEC * (u64)(val + 2) * MX3_PWMCR_PRESCALER_GET(cr);
        tmp = DIV_ROUND_UP_ULL(tmp, clkrate);
        period_us = DIV_ROUND_UP_ULL(tmp, 1000);