pwm: sti: Sync between enable/disable calls
authorAjit Pal Singh <ajitpal.singh@st.com>
Mon, 14 Jul 2014 14:33:31 +0000 (15:33 +0100)
committerThierry Reding <thierry.reding@gmail.com>
Fri, 8 Aug 2014 11:12:45 +0000 (13:12 +0200)
ST PWM IP has a common enable/disable control for all the PWM
channels on a PWM cell. Disables PWM output on the PWM HW only
when disable is called for the last channel.

Signed-off-by: Ajit Pal Singh <ajitpal.singh@st.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
drivers/pwm/pwm-sti.c

index 2d3260571b5a1a949af55d799cd1773e2981d250..f98afe4906fbf5258ac47b7e7cbd11f6209b5573 100644 (file)
@@ -59,6 +59,8 @@ struct sti_pwm_chip {
        unsigned long *pwm_periods;
        struct pwm_chip chip;
        struct pwm_device *cur;
+       unsigned int en_count;
+       struct mutex sti_pwm_lock; /* To sync between enable/disable calls */
        void __iomem *mmio;
 };
 
@@ -236,32 +238,44 @@ static int sti_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
        struct device *dev = pc->dev;
-       int ret;
-
-       ret = clk_enable(pc->clk);
-       if (ret)
-               return ret;
+       int ret = 0;
 
-       ret = regmap_field_write(pc->pwm_en, 1);
-       if (ret)
-               dev_err(dev, "%s,pwm_en write failed\n", __func__);
+       /*
+        * Since we have a common enable for all PWM channels,
+        * do not enable if already enabled.
+        */
+       mutex_lock(&pc->sti_pwm_lock);
+       if (!pc->en_count) {
+               ret = clk_enable(pc->clk);
+               if (ret)
+                       goto out;
 
+               ret = regmap_field_write(pc->pwm_en, 1);
+               if (ret) {
+                       dev_err(dev, "failed to enable PWM device:%d\n",
+                               pwm->hwpwm);
+                       goto out;
+               }
+       }
+       pc->en_count++;
+out:
+       mutex_unlock(&pc->sti_pwm_lock);
        return ret;
 }
 
 static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
-       struct device *dev = pc->dev;
-       unsigned int val;
 
+       mutex_lock(&pc->sti_pwm_lock);
+       if (--pc->en_count) {
+               mutex_unlock(&pc->sti_pwm_lock);
+               return;
+       }
        regmap_field_write(pc->pwm_en, 0);
 
-       regmap_read(pc->regmap, STI_CNT, &val);
-
-       dev_dbg(dev, "pwm counter :%u\n", val);
-
        clk_disable(pc->clk);
+       mutex_unlock(&pc->sti_pwm_lock);
 }
 
 static const struct pwm_ops sti_pwm_ops = {
@@ -352,6 +366,8 @@ static int sti_pwm_probe(struct platform_device *pdev)
 
        pc->cdata = cdata;
        pc->dev = dev;
+       pc->en_count = 0;
+       mutex_init(&pc->sti_pwm_lock);
 
        ret = sti_pwm_probe_dt(pc);
        if (ret)