Skip to content

Commit 5d82e66

Browse files
martenlithierryreding
authored andcommitted
pwm: pwm-samsung: Trigger manual update when disabling PWM
When duty-cycle is at full level (100%), the TCNTn and TCMPn registers needs to be flushed in order to disable the signal. The PWM manual does not say anything about this, but states that only clearing the TCON auto-reload bit should be needed, and this seems to be true when the PWM duty-cycle is not at full level. This can be observed on an Axis ARTPEC-8, by running: echo <period> > pwm/period echo <period> > pwm/duty_cycle echo 1 > pwm/enable echo 0 > pwm/enable Since the TCNTn and TCMPn registers are activated when enabling the PWM (setting TCON auto-reload bit), and are not touched when disabling the PWM, the double buffered auto-reload function seems to be still active. Lowering duty-cycle, and restoring it again in between the enabling and disabling, makes the disable work since it triggers a reload of the TCNTn and TCMPn registers. Fix this by securing a reload of the TCNTn and TCMPn registers when disabling the PWM and having a full duty-cycle. Signed-off-by: Mårten Lindahl <marten.lindahl@axis.com> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
1 parent 6facd84 commit 5d82e66

1 file changed

Lines changed: 22 additions & 8 deletions

File tree

drivers/pwm/pwm-samsung.c

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,20 @@ static inline unsigned int to_tcon_channel(unsigned int channel)
117117
return (channel == 0) ? 0 : (channel + 1);
118118
}
119119

120+
static void __pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
121+
struct pwm_device *pwm)
122+
{
123+
unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
124+
u32 tcon;
125+
126+
tcon = readl(chip->base + REG_TCON);
127+
tcon |= TCON_MANUALUPDATE(tcon_chan);
128+
writel(tcon, chip->base + REG_TCON);
129+
130+
tcon &= ~TCON_MANUALUPDATE(tcon_chan);
131+
writel(tcon, chip->base + REG_TCON);
132+
}
133+
120134
static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
121135
unsigned int channel, u8 divisor)
122136
{
@@ -276,6 +290,13 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
276290
tcon &= ~TCON_AUTORELOAD(tcon_chan);
277291
writel(tcon, our_chip->base + REG_TCON);
278292

293+
/*
294+
* In case the PWM is at 100% duty cycle, force a manual
295+
* update to prevent the signal from staying high.
296+
*/
297+
if (readl(our_chip->base + REG_TCMPB(pwm->hwpwm)) == (u32)-1U)
298+
__pwm_samsung_manual_update(our_chip, pwm);
299+
279300
our_chip->disabled_mask |= BIT(pwm->hwpwm);
280301

281302
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
@@ -284,18 +305,11 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
284305
static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
285306
struct pwm_device *pwm)
286307
{
287-
unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
288-
u32 tcon;
289308
unsigned long flags;
290309

291310
spin_lock_irqsave(&samsung_pwm_lock, flags);
292311

293-
tcon = readl(chip->base + REG_TCON);
294-
tcon |= TCON_MANUALUPDATE(tcon_chan);
295-
writel(tcon, chip->base + REG_TCON);
296-
297-
tcon &= ~TCON_MANUALUPDATE(tcon_chan);
298-
writel(tcon, chip->base + REG_TCON);
312+
__pwm_samsung_manual_update(chip, pwm);
299313

300314
spin_unlock_irqrestore(&samsung_pwm_lock, flags);
301315
}

0 commit comments

Comments
 (0)