Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+46 -14
+34 -4
drivers/pwm/pwm-atmel-tcb.c
··· 50 50 spinlock_t lock; 51 51 u8 channel; 52 52 u8 width; 53 + unsigned long rate; 54 + unsigned long slow_rate; 53 55 struct regmap *regmap; 54 56 struct clk *clk; 55 57 struct clk *gclk; ··· 268 266 int slowclk = 0; 269 267 unsigned period; 270 268 unsigned duty; 271 - unsigned rate = clk_get_rate(tcbpwmc->clk); 269 + unsigned long rate = tcbpwmc->rate; 272 270 unsigned long long min; 273 271 unsigned long long max; 274 272 ··· 296 294 */ 297 295 if (i == ARRAY_SIZE(atmel_tcb_divisors)) { 298 296 i = slowclk; 299 - rate = clk_get_rate(tcbpwmc->slow_clk); 297 + rate = tcbpwmc->slow_rate; 300 298 min = div_u64(NSEC_PER_SEC, rate); 301 299 max = min << tcbpwmc->width; 302 300 ··· 433 431 } 434 432 435 433 chip->ops = &atmel_tcb_pwm_ops; 434 + chip->atomic = true; 436 435 tcbpwmc->channel = channel; 437 436 tcbpwmc->width = config->counter_width; 438 437 439 - err = clk_prepare_enable(tcbpwmc->slow_clk); 438 + err = clk_prepare_enable(tcbpwmc->clk); 440 439 if (err) 441 440 goto err_gclk; 441 + 442 + err = clk_prepare_enable(tcbpwmc->slow_clk); 443 + if (err) 444 + goto err_disable_clk;; 445 + 446 + err = clk_rate_exclusive_get(tcbpwmc->clk); 447 + if (err) 448 + goto err_disable_slow_clk; 449 + 450 + err = clk_rate_exclusive_get(tcbpwmc->slow_clk); 451 + if (err) 452 + goto err_clk_unlock; 453 + 454 + tcbpwmc->rate = clk_get_rate(tcbpwmc->clk); 455 + tcbpwmc->slow_rate = clk_get_rate(tcbpwmc->slow_clk); 442 456 443 457 spin_lock_init(&tcbpwmc->lock); 444 458 445 459 err = pwmchip_add(chip); 446 460 if (err < 0) 447 - goto err_disable_clk; 461 + goto err_slow_clk_unlock; 448 462 449 463 platform_set_drvdata(pdev, chip); 450 464 451 465 return 0; 452 466 467 + err_slow_clk_unlock: 468 + clk_rate_exclusive_put(tcbpwmc->slow_clk); 469 + 470 + err_clk_unlock: 471 + clk_rate_exclusive_put(tcbpwmc->clk); 472 + 453 473 err_disable_clk: 474 + clk_disable_unprepare(tcbpwmc->clk); 475 + 476 + err_disable_slow_clk: 454 477 clk_disable_unprepare(tcbpwmc->slow_clk); 455 478 456 479 err_gclk: ··· 497 470 498 471 pwmchip_remove(chip); 499 472 473 + clk_rate_exclusive_put(tcbpwmc->slow_clk); 474 + clk_rate_exclusive_put(tcbpwmc->clk); 475 + clk_disable_unprepare(tcbpwmc->clk); 500 476 clk_disable_unprepare(tcbpwmc->slow_clk); 501 477 clk_put(tcbpwmc->gclk); 502 478 clk_put(tcbpwmc->clk);
+12 -10
drivers/pwm/pwm-stm32.c
··· 68 68 struct stm32_pwm *priv = to_stm32_pwm_dev(chip); 69 69 unsigned int ch = pwm->hwpwm; 70 70 unsigned long rate; 71 - u64 ccr, duty; 71 + u64 duty_ticks, offset_ticks; 72 72 int ret; 73 73 74 74 if (wf->period_length_ns == 0) { ··· 164 164 wfhw->arr = min_t(u64, arr, priv->max_arr) - 1; 165 165 } 166 166 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); 170 170 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) { 173 177 wfhw->ccer |= TIM_CCER_CCxP(ch + 1); 174 178 if (priv->have_complementary_output) 175 179 wfhw->ccer |= TIM_CCER_CCxNP(ch + 1); 176 180 177 - ccr = wfhw->arr + 1 - duty; 181 + wfhw->ccr = wfhw->arr + 1 - duty_ticks; 178 182 } else { 179 - ccr = duty; 183 + wfhw->ccr = duty_ticks; 180 184 } 181 - 182 - wfhw->ccr = min_t(u64, ccr, wfhw->arr + 1); 183 185 184 186 out: 185 187 dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> CCER: %08x, PSC: %08x, ARR: %08x, CCR: %08x\n",