aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pwm/pwm-samsung.c32
1 files changed, 31 insertions, 1 deletions
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 3e9b5835a4af..ff201e1b9219 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -269,12 +269,31 @@ static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
269 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 269 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
270} 270}
271 271
272static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
273 struct pwm_device *pwm)
274{
275 unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
276 u32 tcon;
277 unsigned long flags;
278
279 spin_lock_irqsave(&samsung_pwm_lock, flags);
280
281 tcon = readl(chip->base + REG_TCON);
282 tcon |= TCON_MANUALUPDATE(tcon_chan);
283 writel(tcon, chip->base + REG_TCON);
284
285 tcon &= ~TCON_MANUALUPDATE(tcon_chan);
286 writel(tcon, chip->base + REG_TCON);
287
288 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
289}
290
272static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm, 291static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
273 int duty_ns, int period_ns) 292 int duty_ns, int period_ns)
274{ 293{
275 struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip); 294 struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
276 struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm); 295 struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
277 u32 tin_ns = chan->tin_ns, tcnt, tcmp; 296 u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp;
278 297
279 /* 298 /*
280 * We currently avoid using 64bit arithmetic by using the 299 * We currently avoid using 64bit arithmetic by using the
@@ -288,6 +307,7 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
288 return 0; 307 return 0;
289 308
290 tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm)); 309 tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
310 oldtcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm));
291 311
292 /* We need tick count for calculation, not last tick. */ 312 /* We need tick count for calculation, not last tick. */
293 ++tcnt; 313 ++tcnt;
@@ -335,6 +355,16 @@ static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
335 writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm)); 355 writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
336 writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm)); 356 writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
337 357
358 /*
359 * In case the PWM is currently at 100% duty cycle, force a manual
360 * update to prevent the signal staying high if the PWM is disabled
361 * shortly afer this update (before it autoreloaded the new values).
362 */
363 if (oldtcmp == (u32) -1) {
364 dev_dbg(our_chip->chip.dev, "Forcing manual update");
365 pwm_samsung_manual_update(our_chip, pwm);
366 }
367
338 chan->period_ns = period_ns; 368 chan->period_ns = period_ns;
339 chan->tin_ns = tin_ns; 369 chan->tin_ns = tin_ns;
340 chan->duty_ns = duty_ns; 370 chan->duty_ns = duty_ns;