Skip to content

Commit 8841842

Browse files
committed
Merge tag 'pwm/fixes-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux
Pull pwm fixes from Uwe Kleine-König: "Two driver fixes After having added some more code to libpwm checking the pwm rounding rules for the userspace interface I spotted an issue in the pwm-stm32 driver where in some cases involving inverted polarity the wrong hardware settings for the duty offset are chosen. I think it has little practical effect because the duty offset is in most cases an artificial property of the output waveform. Still it's relevant to get this fixed because this driver serves as a reference implementation for the still young waveform API. The second fix addresses a sleep-in-atomic issue in the pwm-atmel-tcb driver" * tag 'pwm/fixes-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux: pwm: atmel-tcb: Cache clock rates and mark chip as atomic pwm: stm32: Fix rounding issue for requests with inverted polarity
2 parents df7bf83 + 68637b6 commit 8841842

2 files changed

Lines changed: 46 additions & 14 deletions

File tree

drivers/pwm/pwm-atmel-tcb.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip {
5050
spinlock_t lock;
5151
u8 channel;
5252
u8 width;
53+
unsigned long rate;
54+
unsigned long slow_rate;
5355
struct regmap *regmap;
5456
struct clk *clk;
5557
struct clk *gclk;
@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
266268
int slowclk = 0;
267269
unsigned period;
268270
unsigned duty;
269-
unsigned rate = clk_get_rate(tcbpwmc->clk);
271+
unsigned long rate = tcbpwmc->rate;
270272
unsigned long long min;
271273
unsigned long long max;
272274

@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
294296
*/
295297
if (i == ARRAY_SIZE(atmel_tcb_divisors)) {
296298
i = slowclk;
297-
rate = clk_get_rate(tcbpwmc->slow_clk);
299+
rate = tcbpwmc->slow_rate;
298300
min = div_u64(NSEC_PER_SEC, rate);
299301
max = min << tcbpwmc->width;
300302

@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
431433
}
432434

433435
chip->ops = &atmel_tcb_pwm_ops;
436+
chip->atomic = true;
434437
tcbpwmc->channel = channel;
435438
tcbpwmc->width = config->counter_width;
436439

437-
err = clk_prepare_enable(tcbpwmc->slow_clk);
440+
err = clk_prepare_enable(tcbpwmc->clk);
438441
if (err)
439442
goto err_gclk;
440443

444+
err = clk_prepare_enable(tcbpwmc->slow_clk);
445+
if (err)
446+
goto err_disable_clk;;
447+
448+
err = clk_rate_exclusive_get(tcbpwmc->clk);
449+
if (err)
450+
goto err_disable_slow_clk;
451+
452+
err = clk_rate_exclusive_get(tcbpwmc->slow_clk);
453+
if (err)
454+
goto err_clk_unlock;
455+
456+
tcbpwmc->rate = clk_get_rate(tcbpwmc->clk);
457+
tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk);
458+
441459
spin_lock_init(&tcbpwmc->lock);
442460

443461
err = pwmchip_add(chip);
444462
if (err < 0)
445-
goto err_disable_clk;
463+
goto err_slow_clk_unlock;
446464

447465
platform_set_drvdata(pdev, chip);
448466

449467
return 0;
450468

469+
err_slow_clk_unlock:
470+
clk_rate_exclusive_put(tcbpwmc->slow_clk);
471+
472+
err_clk_unlock:
473+
clk_rate_exclusive_put(tcbpwmc->clk);
474+
451475
err_disable_clk:
476+
clk_disable_unprepare(tcbpwmc->clk);
477+
478+
err_disable_slow_clk:
452479
clk_disable_unprepare(tcbpwmc->slow_clk);
453480

454481
err_gclk:
@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev)
470497

471498
pwmchip_remove(chip);
472499

500+
clk_rate_exclusive_put(tcbpwmc->slow_clk);
501+
clk_rate_exclusive_put(tcbpwmc->clk);
502+
clk_disable_unprepare(tcbpwmc->clk);
473503
clk_disable_unprepare(tcbpwmc->slow_clk);
474504
clk_put(tcbpwmc->gclk);
475505
clk_put(tcbpwmc->clk);

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)