[PATCH v14 4/5] pwm: sifive: Fix rounding issues in apply and get_state functions
Nylon Chen
nylon.chen at sifive.com
Fri May 9 02:52:33 PDT 2025
Fix PWM apply and get_state rounding to ensure consistency between
setting and reading values
This fixes the reported errors:
pwm-sifive 10021000.pwm: .apply is supposed to round down
duty_cycle (requested: 360/504000, applied: 361/504124)
pwm-sifive 10021000.pwm: .apply is supposed to round down
period (requested: 504000, applied: 504124)
Reported-by: kernel test robot <lkp at intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202505080303.dBfU5YMS-lkp@intel.com/
Co-developed-by: Zong Li <zong.li at sifive.com>
Signed-off-by: Zong Li <zong.li at sifive.com>
Signed-off-by: Nylon Chen <nylon.chen at sifive.com>
---
drivers/pwm/pwm-sifive.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 6259f8500f71..70cf644cde4a 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -122,8 +122,8 @@ static int pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->enabled = false;
state->period = ddata->real_period;
- state->duty_cycle =
- (u64)duty * ddata->real_period >> PWM_SIFIVE_CMPWIDTH;
+ state->duty_cycle = DIV_ROUND_UP_ULL((u64)duty * ddata->real_period,
+ (1U << PWM_SIFIVE_CMPWIDTH));
state->polarity = PWM_POLARITY_NORMAL;
return 0;
@@ -138,7 +138,8 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long num;
bool enabled;
int ret = 0;
- u32 frac, inactive;
+ u64 frac;
+ u32 inactive;
if (state->polarity != PWM_POLARITY_NORMAL)
return -EINVAL;
@@ -157,9 +158,11 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* consecutively
*/
num = (u64)duty_cycle * (1U << PWM_SIFIVE_CMPWIDTH);
- frac = DIV64_U64_ROUND_CLOSEST(num, state->period);
+ frac = num;
+ do_div(frac, state->period);
/* The hardware cannot generate a 0% duty cycle */
- frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
+ frac = min(frac, (u64)(1U << PWM_SIFIVE_CMPWIDTH) - 1);
+ /* pwmcmp register must be loaded with the inactive(invert the duty) */
inactive = (1U << PWM_SIFIVE_CMPWIDTH) - 1 - frac;
mutex_lock(&ddata->lock);
--
2.34.1
More information about the linux-riscv
mailing list