[PATCH v2] pwm: dwc: Balance the runtime PM reference when configuring fails

From: shao.mingyin

Date: Sun Nov 08 2026 - 02:12:06 EST


From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>

dwc_pwm_apply() takes a runtime PM reference with pm_runtime_get_sync()
when transitioning a channel from disabled to enabled and returns the
result of __dwc_pwm_configure_timer() directly. If that call fails (e.g.
with -ERANGE for an out-of-range duty cycle or period) the reference is
never put, so the device never reaches the suspended state again and the
usage counter keeps growing.

Put the reference when the configuration fails on the enable transition.

Fixes: 1ed2b3fca645 ("pwm: Add DesignWare PWM Controller Driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
This supersedes 4/5 of the v1 series; 1/5, 2/5, 3/5 and 5/5 are unchanged.

v2:
- point Fixes: at 1ed2b3fca645 ("pwm: Add DesignWare PWM Controller
Driver"), which introduced the unbalanced pm_runtime_get_sync();
721ee1884883 only moved dwc_pwm_apply() to pwm-dwc-core.c
v1: https://lore.kernel.org/all/20261107000734514kOTBjwDH_ZQx5Rq7e_WwC@xxxxxxxxxx/

diff --git a/drivers/pwm/pwm-dwc-core.c b/drivers/pwm/pwm-dwc-core.c
index 6dabec93a3c6..cfeefae68969 100644
--- a/drivers/pwm/pwm-dwc-core.c
+++ b/drivers/pwm/pwm-dwc-core.c
@@ -99,6 +99,7 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct dwc_pwm *dwc = to_dwc_pwm(chip);
+ int ret;

if (state->polarity != PWM_POLARITY_INVERSED)
return -EINVAL;
@@ -106,7 +107,10 @@ static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (state->enabled) {
if (!pwm->state.enabled)
pm_runtime_get_sync(pwmchip_parent(chip));
- return __dwc_pwm_configure_timer(dwc, pwm, state);
+ ret = __dwc_pwm_configure_timer(dwc, pwm, state);
+ if (ret && !pwm->state.enabled)
+ pm_runtime_put_sync(pwmchip_parent(chip));
+ return ret;
} else {
if (pwm->state.enabled) {
__dwc_pwm_set_enable(dwc, pwm->hwpwm, false);
--
2.47.0