]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
pwm: Let pwm_set_waveform() succeed even if lowlevel driver rounded up
authorUwe Kleine-König <u.kleine-koenig@baylibre.com>
Sat, 5 Apr 2025 09:27:12 +0000 (11:27 +0200)
committerUwe Kleine-König <ukleinek@kernel.org>
Mon, 7 Apr 2025 13:10:13 +0000 (15:10 +0200)
Waveform parameters are supposed to be rounded down to the next value
possible for the hardware. However when a requested value is too small,
.round_waveform_tohw() is supposed to pick the next bigger value and
return 1. Let pwm_set_waveform() behave in the same way.

This creates consistency between pwm_set_waveform_might_sleep() with
exact=false and pwm_round_waveform_might_sleep() +
pwm_set_waveform_might_sleep() with exact=true.

The PWM_DEBUG rounding check has to be adapted to only trigger if no
uprounding happend.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
Tested-by: Trevor Gamblin <tgamblin@baylibre.com>
Link: https://lore.kernel.org/r/353dc6ae31be815e41fd3df89c257127ca0d1a09.1743844730.git.u.kleine-koenig@baylibre.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
drivers/pwm/core.c

index a40c511e0096526c1023217558c698fddc99f3d1..0387bd838487b1d93a7d8c786b03ffcaa9070b0d 100644 (file)
@@ -322,7 +322,7 @@ static int __pwm_set_waveform(struct pwm_device *pwm,
        const struct pwm_ops *ops = chip->ops;
        char wfhw[WFHWSIZE];
        struct pwm_waveform wf_rounded;
-       int err;
+       int err, ret_tohw;
 
        BUG_ON(WFHWSIZE < ops->sizeof_wfhw);
 
@@ -332,16 +332,16 @@ static int __pwm_set_waveform(struct pwm_device *pwm,
        if (!pwm_wf_valid(wf))
                return -EINVAL;
 
-       err = __pwm_round_waveform_tohw(chip, pwm, wf, &wfhw);
-       if (err)
-               return err;
+       ret_tohw = __pwm_round_waveform_tohw(chip, pwm, wf, &wfhw);
+       if (ret_tohw < 0)
+               return ret_tohw;
 
        if ((IS_ENABLED(CONFIG_PWM_DEBUG) || exact) && wf->period_length_ns) {
                err = __pwm_round_waveform_fromhw(chip, pwm, &wfhw, &wf_rounded);
                if (err)
                        return err;
 
-               if (IS_ENABLED(CONFIG_PWM_DEBUG) && !pwm_check_rounding(wf, &wf_rounded))
+               if (IS_ENABLED(CONFIG_PWM_DEBUG) && ret_tohw == 0 && !pwm_check_rounding(wf, &wf_rounded))
                        dev_err(&chip->dev, "Wrong rounding: requested %llu/%llu [+%llu], result %llu/%llu [+%llu]\n",
                                wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns,
                                wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns);
@@ -382,7 +382,8 @@ static int __pwm_set_waveform(struct pwm_device *pwm,
                                wf_rounded.duty_length_ns, wf_rounded.period_length_ns, wf_rounded.duty_offset_ns,
                                wf_set.duty_length_ns, wf_set.period_length_ns, wf_set.duty_offset_ns);
        }
-       return 0;
+
+       return ret_tohw;
 }
 
 /**