Instead of just clearing the START bit to stop the PWM, disable 
the autoreload bit and let it finish the current period. This ensures
that TOUT stays at a known output level after the PWM is stopped,
and is the recommended procedure as per Samsung's technical docs.

This is tested on 3.7 but should be applicable up to 3.11. A similar
fix was implemented in mainline in 3.12.

Signed-off-by: Guillermo Rodriguez <[email protected]>
---


Index: linux-3.7/drivers/pwm/pwm-samsung.c
===================================================================
--- linux-3.7.orig/drivers/pwm/pwm-samsung.c    2014-06-10 13:48:04.393351182 
+0200
+++ linux-3.7/drivers/pwm/pwm-samsung.c 2014-06-10 13:48:11.212203000 +0200
@@ -66,7 +66,13 @@
        local_irq_save(flags);
 
        tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_start(s3c);
+       tcon &= ~pwm_tcon_start(s3c);
+       tcon |= pwm_tcon_manulupdate(s3c);
+       tcon |= pwm_tcon_autoreload(s3c);
+       __raw_writel(tcon, S3C2410_TCON);
+       
+       tcon &= ~pwm_tcon_manulupdate(s3c);
+       tcon |= pwm_tcon_start(s3c);    
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
@@ -82,8 +88,11 @@
 
        local_irq_save(flags);
 
+       /* Disable autoreload instead of clearing the 'start' bit to ensure
+        * that TOUT goes to a known level after the timer is stopped. */
+        
        tcon = __raw_readl(S3C2410_TCON);
-       tcon &= ~pwm_tcon_start(s3c);
+       tcon &= ~pwm_tcon_autoreload(s3c);      
        __raw_writel(tcon, S3C2410_TCON);
 
        local_irq_restore(flags);
@@ -115,7 +124,6 @@
        unsigned long tin_ns;
        unsigned long period;
        unsigned long flags;
-       unsigned long tcon;
        unsigned long tcnt;
        long tcmp;
 
@@ -176,21 +184,14 @@
        if (tcmp < 0)
                tcmp = 0;
 
-       /* Update the PWM register block. */
+       /* Update the TCMP/TCNT registers. The rest of the work is done in
+        * s3c_pwm_enable */
 
        local_irq_save(flags);
 
        __raw_writel(tcmp, S3C2410_TCMPB(s3c->pwm_id));
        __raw_writel(tcnt, S3C2410_TCNTB(s3c->pwm_id));
 
-       tcon = __raw_readl(S3C2410_TCON);
-       tcon |= pwm_tcon_manulupdate(s3c);
-       tcon |= pwm_tcon_autoreload(s3c);
-       __raw_writel(tcon, S3C2410_TCON);
-
-       tcon &= ~pwm_tcon_manulupdate(s3c);
-       __raw_writel(tcon, S3C2410_TCON);
-
        local_irq_restore(flags);
 
        return 0;



Reply via email to