Skip to content

Commit a020f22

Browse files
pcercueithierryreding
authored andcommitted
pwm: jz4740: Make PWM start with the active part
The PWM in Ingenic SoCs starts in inactive state until the internal timer reaches the duty value, then becomes active until the timer reaches the period value. In theory, we should then use (period - duty) as the real duty value, as a high duty value would otherwise result in the PWM pin being inactive most of the time. This is the reason why the duty value was inverted in the driver until now, but it still had the problem that it would not start with the active part. To address this remaining issue, the common trick is to invert the duty, and invert the polarity when the PWM is enabled. Since the duty was already inverted, and we invert it again, we now program the hardware for the requested duty, and simply invert the polarity when the PWM is enabled. Signed-off-by: Paul Cercueil <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 9017dc4 commit a020f22

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

drivers/pwm/pwm-jz4740.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* Limitations:
77
* - The .apply callback doesn't complete the currently running period before
88
* reconfiguring the hardware.
9-
* - Each period starts with the inactive part.
109
*/
1110

1211
#include <linux/clk.h>
@@ -163,7 +162,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
163162
/* Calculate duty value */
164163
tmp = (unsigned long long)rate * state->duty_cycle;
165164
do_div(tmp, NSEC_PER_SEC);
166-
duty = period - tmp;
165+
duty = tmp;
167166

168167
if (duty >= period)
169168
duty = period - 1;
@@ -189,18 +188,26 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
189188
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
190189
TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD);
191190

192-
/* Set polarity */
193-
switch (state->polarity) {
194-
case PWM_POLARITY_NORMAL:
191+
/*
192+
* Set polarity.
193+
*
194+
* The PWM starts in inactive state until the internal timer reaches the
195+
* duty value, then becomes active until the timer reaches the period
196+
* value. In theory, we should then use (period - duty) as the real duty
197+
* value, as a high duty value would otherwise result in the PWM pin
198+
* being inactive most of the time.
199+
*
200+
* Here, we don't do that, and instead invert the polarity of the PWM
201+
* when it is active. This trick makes the PWM start with its active
202+
* state instead of its inactive state.
203+
*/
204+
if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled)
195205
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
196206
TCU_TCSR_PWM_INITL_HIGH, 0);
197-
break;
198-
case PWM_POLARITY_INVERSED:
207+
else
199208
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
200209
TCU_TCSR_PWM_INITL_HIGH,
201210
TCU_TCSR_PWM_INITL_HIGH);
202-
break;
203-
}
204211

205212
if (state->enabled)
206213
jz4740_pwm_enable(chip, pwm);

0 commit comments

Comments
 (0)