]> git.ipfire.org Git - thirdparty/openwrt.git/commit
qualcommbe: fix pwm period calculation 23916/head
authorKenneth Kasilag <kenneth@kasilag.me>
Sun, 21 Jun 2026 23:26:43 +0000 (23:26 +0000)
committerMarkus Stockhausen <markus.stockhausen@gmx.de>
Tue, 23 Jun 2026 05:40:16 +0000 (07:40 +0200)
commit8db23dc91a015bf843f1e3fbd0891574594e86f9
tree70f3b6f266cafbebf97d653f5161ed8b0a715b79
parent8ebf189e60fe9e703d8a687ea1da25f0fe25862a
qualcommbe: fix pwm period calculation

During testing on the Askey SBE1V1K, it was noticed that only very low
PWM frequencies would work, and 100% duty cycles also did not work.

Comparing the proposed upstream pwm-ipq driver to the downstream vendor
driver, `ipq_pwm_apply()` fixed pwm_div at its maximum and derived only
pre_div from the requested period. Since the period spans
`(pre_div + 1) * (pwm_div + 1)` input clocks, pinning pwm_div near its
maximum forces pre_div towards zero for short periods: once pre_div
rounds to 0 the shortest representable period is
`(pwm_div + 1) / clk_rate` (~2.7 ms, i.e. ~366 Hz, at a 24 MHz clock),
and any shorter request is silently stretched to that. The high
duration then truncates to 0, so the output collapses to ~0% duty.

Since 4-wire fans commonly expect a ~25kHz PWM, it was effectively
unusable, since every duty cycle programs a ~zero high time.

Search for the (pre_div, pwm_div) pair whose period best approximates
the request instead of fixing pwm_div. Starting pre_div at the smallest
value that keeps pwm_div within its field and stopping once pre_div
exceeds pwm_div bounds the loop and keeps pwm_div as large as possible
for fine duty resolution. For a 25 kHz request at 24 MHz this selects
pre_div = 0, pwm_div = 959, giving full 0..960 duty resolution.

While reworking the high-duration computation, round it to nearest
rather than truncating, so mid-range duty cycles are not biased low, and
clamp it to pwm_div + 1. Rounding, or a 100% duty request, could
otherwise push hi_dur past the period length and overflow the 16-bit
HI_DURATION field.

Also compute hi_div in `get_state()` in 64-bit; `hi_dur * (pre_div + 1)`
can exceed 32 bits before the existing promotion.

Fixes: 01fb4a6daadb ("qualcommbe: update pwm patches and add missing symbol")
Signed-off-by: Kenneth Kasilag <kenneth@kasilag.me>
Link: https://github.com/openwrt/openwrt/pull/23916
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
target/linux/qualcommbe/patches-6.18/0403-pwm-fix-period-calculation.patch [new file with mode: 0644]