diff options
-rw-r--r-- | drivers/pwm/pwm-lpss.c | 23 |
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index ebf8450a2a09..295b963dbddb 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -13,6 +13,7 @@ * published by the Free Software Foundation. */ +#include <linux/delay.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> @@ -80,6 +81,13 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value) writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM); } +static void pwm_lpss_update(struct pwm_device *pwm) +{ + pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); + /* Give it some time to propagate */ + usleep_range(10, 50); +} + static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { @@ -117,10 +125,15 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, base_unit &= (base_unit_range - 1); ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT; ctrl |= on_time_div; - /* request PWM to update on next cycle */ - ctrl |= PWM_SW_UPDATE; 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; @@ -129,6 +142,12 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) { pm_runtime_get_sync(chip->dev); + + /* + * 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; } |