pwm: lpss: Switch to new atomic API
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Sat, 28 Jan 2017 15:10:41 +0000 (17:10 +0200)
committerThierry Reding <thierry.reding@gmail.com>
Mon, 30 Jan 2017 07:13:55 +0000 (08:13 +0100)
Instead of doing things separately, which is not so reliable on some platforms,
switch the driver to use new atomic API, i.e. ->apply() callback.

The change has been tested on Intel platforms such as Broxton, BayTrail, and
Merrifield.

Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
drivers/pwm/pwm-lpss.c

index ffa01ab907a6f24b04cff6bb03e2581b88095915..09869f91d2d0917e60fddec50a01b5de9d357a31 100644 (file)
@@ -82,15 +82,20 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
 
 static void pwm_lpss_update(struct pwm_device *pwm)
 {
+       /*
+        * Set a limit for busyloop since not all implementations correctly
+        * clear PWM_SW_UPDATE bit (at least it's not visible on OS side).
+        */
+       unsigned int count = 10;
+
        pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
-       /* Give it some time to propagate */
-       usleep_range(10, 50);
+       while (pwm_lpss_read(pwm) & PWM_SW_UPDATE && --count)
+               usleep_range(10, 20);
 }
 
-static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                          int duty_ns, int period_ns)
+static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
+                            int duty_ns, int period_ns)
 {
-       struct pwm_lpss_chip *lpwm = to_lpwm(chip);
        unsigned long long on_time_div;
        unsigned long c = lpwm->info->clk_rate, base_unit_range;
        unsigned long long base_unit, freq = NSEC_PER_SEC;
@@ -111,8 +116,6 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
        do_div(on_time_div, period_ns);
        on_time_div = 255ULL - on_time_div;
 
-       pm_runtime_get_sync(chip->dev);
-
        ctrl = pwm_lpss_read(pwm);
        ctrl &= ~PWM_ON_TIME_DIV_MASK;
        ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
@@ -120,42 +123,33 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
        ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
        ctrl |= on_time_div;
        pwm_lpss_write(pwm, ctrl);
-
-       /*
-        * If the PWM is already enabled we need to notify the hardware
-        * about the change by setting PWM_SW_UPDATE.
-        */
-       if (pwm_is_enabled(pwm))
-               pwm_lpss_update(pwm);
-
-       pm_runtime_put(chip->dev);
-
-       return 0;
 }
 
-static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                         struct pwm_state *state)
 {
-       pm_runtime_get_sync(chip->dev);
+       struct pwm_lpss_chip *lpwm = to_lpwm(chip);
 
-       /*
-        * Hardware must first see PWM_SW_UPDATE before the PWM can be
-        * enabled.
-        */
-       pwm_lpss_update(pwm);
-       pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
-       return 0;
-}
+       if (state->enabled) {
+               if (!pwm_is_enabled(pwm)) {
+                       pm_runtime_get_sync(chip->dev);
+                       pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
+                       pwm_lpss_update(pwm);
+                       pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
+               } else {
+                       pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
+                       pwm_lpss_update(pwm);
+               }
+       } else if (pwm_is_enabled(pwm)) {
+               pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
+               pm_runtime_put(chip->dev);
+       }
 
-static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-       pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
-       pm_runtime_put(chip->dev);
+       return 0;
 }
 
 static const struct pwm_ops pwm_lpss_ops = {
-       .config = pwm_lpss_config,
-       .enable = pwm_lpss_enable,
-       .disable = pwm_lpss_disable,
+       .apply = pwm_lpss_apply,
        .owner = THIS_MODULE,
 };