summaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-lpss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pwm/pwm-lpss.c')
-rw-r--r--drivers/pwm/pwm-lpss.c23
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;
}