Skip to content

Commit 9dd42d0

Browse files
ukleinekUwe Kleine-König
authored andcommitted
pwm: Allow pwm state transitions from an invalid state
While driving a PWM via the sysfs API it's hard to determine the right order of writes to the pseudo files "period" and "duty_cycle": If you want to go from duty_cycle/period = 50/100 to 150/300 you have to write period first (because 150/100 is invalid). If however you start at 400/500 the duty_cycle must be configured first. The rule that works is: If you increase period write period first, otherwise write duty_cycle first. A complication however is that it's usually sensible to configure the polarity before both period and duty_cycle. This can only be done if the current state's duty_cycle and period configuration isn't bogus though. It is still worse (but I think only theoretic) if you have a PWM that only supports inverted polarity and you start with period = 0 and polarity = normal. Then you can change neither period (because polarity = normal is refused) nor polarity (because there is still period = 0). To simplify the corner cases for userspace, let invalid target states pass if the current state is invalid already. Signed-off-by: Uwe Kleine-König <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Uwe Kleine-König <[email protected]>
1 parent 14b9dc6 commit 9dd42d0

File tree

1 file changed

+37
-2
lines changed

1 file changed

+37
-2
lines changed

drivers/pwm/core.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,25 @@ static void pwm_apply_debug(struct pwm_device *pwm,
137137
}
138138
}
139139

140+
static bool pwm_state_valid(const struct pwm_state *state)
141+
{
142+
/*
143+
* For a disabled state all other state description is irrelevant and
144+
* and supposed to be ignored. So also ignore any strange values and
145+
* consider the state ok.
146+
*/
147+
if (state->enabled)
148+
return true;
149+
150+
if (!state->period)
151+
return false;
152+
153+
if (state->duty_cycle > state->period)
154+
return false;
155+
156+
return true;
157+
}
158+
140159
/**
141160
* __pwm_apply() - atomically apply a new state to a PWM device
142161
* @pwm: PWM device
@@ -147,10 +166,26 @@ static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state)
147166
struct pwm_chip *chip;
148167
int err;
149168

150-
if (!pwm || !state || !state->period ||
151-
state->duty_cycle > state->period)
169+
if (!pwm || !state)
152170
return -EINVAL;
153171

172+
if (!pwm_state_valid(state)) {
173+
/*
174+
* Allow to transition from one invalid state to another.
175+
* This ensures that you can e.g. change the polarity while
176+
* the period is zero. (This happens on stm32 when the hardware
177+
* is in its poweron default state.) This greatly simplifies
178+
* working with the sysfs API where you can only change one
179+
* parameter at a time.
180+
*/
181+
if (!pwm_state_valid(&pwm->state)) {
182+
pwm->state = *state;
183+
return 0;
184+
}
185+
186+
return -EINVAL;
187+
}
188+
154189
chip = pwm->chip;
155190

156191
if (state->period == pwm->state.period &&

0 commit comments

Comments
 (0)