Skip to content

Commit 5d087c4

Browse files
ukleinekUwe Kleine-König
authored andcommitted
pwm: stm32: Fix rounding issue for requests with inverted polarity
The calculation of the number of pwm clk ticks from a time length in nanoseconds involves a division and thus some rounding. That might result in duty_ticks + offset_ticks < period_ticks despite duty_length_ns + duty_offset_ns >= period_length_ns . The stm32 PWM cannot configure offset_ticks freely, it can only select 0 or period_length_ns - duty_length_ns---that is the classic normal and inverted polarity. The decision to select the hardware polarity must be done using the ticks values and not the nanoseconds times to adhere to the rounding rules by the pwm core. With the pwm clk running at 208900 kHz on my test machine (stm32mp135f-dk), a test case that was handled wrong is: # pwmround -P 9999962 -O 24970 -D 9974992 period_length = 9999962 duty_length = 9974840 duty_offset = 25123 With this change applied the rounding is done correctly: # pwmround -P 9999962 -O 24970 -D 9974992 period_length = 9999962 duty_length = 9974840 duty_offset = 0 Fixes: deaba9c ("pwm: stm32: Implementation of the waveform callbacks") Signed-off-by: Uwe Kleine-König <[email protected]> Link: https://patch.msgid.link/c5e7767cee821b5f6e00f95bd14a5e13015646fb.1776264104.git.u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König <[email protected]>
1 parent aa8f351 commit 5d087c4

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

drivers/pwm/pwm-stm32.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip,
6868
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
6969
unsigned int ch = pwm->hwpwm;
7070
unsigned long rate;
71-
u64 ccr, duty;
71+
u64 duty_ticks, offset_ticks;
7272
int ret;
7373

7474
if (wf->period_length_ns == 0) {
@@ -164,23 +164,25 @@ static int stm32_pwm_round_waveform_tohw(struct pwm_chip *chip,
164164
wfhw->arr = min_t(u64, arr, priv->max_arr) - 1;
165165
}
166166

167-
duty = mul_u64_u64_div_u64(wf->duty_length_ns, rate,
168-
(u64)NSEC_PER_SEC * (wfhw->psc + 1));
169-
duty = min_t(u64, duty, wfhw->arr + 1);
167+
duty_ticks = mul_u64_u64_div_u64(wf->duty_length_ns, rate,
168+
(u64)NSEC_PER_SEC * (wfhw->psc + 1));
169+
duty_ticks = min_t(u64, duty_ticks, wfhw->arr + 1);
170170

171-
if (wf->duty_length_ns && wf->duty_offset_ns &&
172-
wf->duty_length_ns + wf->duty_offset_ns >= wf->period_length_ns) {
171+
offset_ticks = mul_u64_u64_div_u64(wf->duty_offset_ns, rate,
172+
(u64)NSEC_PER_SEC * (wfhw->psc + 1));
173+
offset_ticks = min_t(u64, offset_ticks, wfhw->arr + 1);
174+
175+
if (duty_ticks && offset_ticks &&
176+
duty_ticks + offset_ticks >= wfhw->arr + 1) {
173177
wfhw->ccer |= TIM_CCER_CCxP(ch + 1);
174178
if (priv->have_complementary_output)
175179
wfhw->ccer |= TIM_CCER_CCxNP(ch + 1);
176180

177-
ccr = wfhw->arr + 1 - duty;
181+
wfhw->ccr = wfhw->arr + 1 - duty_ticks;
178182
} else {
179-
ccr = duty;
183+
wfhw->ccr = duty_ticks;
180184
}
181185

182-
wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1);
183-
184186
out:
185187
dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n",
186188
pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns,

0 commit comments

Comments
 (0)