|
@@ -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,
|
|
|
};
|
|
|
|