|
@@ -32,15 +32,6 @@
|
|
|
/* Size of each PWM register space if multiple */
|
|
|
#define PWM_SIZE 0x400
|
|
|
|
|
|
-#define MAX_PWMS 4
|
|
|
-
|
|
|
-struct pwm_lpss_chip {
|
|
|
- struct pwm_chip chip;
|
|
|
- void __iomem *regs;
|
|
|
- const struct pwm_lpss_boardinfo *info;
|
|
|
- u32 saved_ctrl[MAX_PWMS];
|
|
|
-};
|
|
|
-
|
|
|
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
|
|
|
{
|
|
|
return container_of(chip, struct pwm_lpss_chip, chip);
|
|
@@ -97,7 +88,7 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
|
|
|
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;
|
|
|
- u32 ctrl;
|
|
|
+ u32 orig_ctrl, ctrl;
|
|
|
|
|
|
do_div(freq, period_ns);
|
|
|
|
|
@@ -114,13 +105,17 @@ static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
|
|
|
do_div(on_time_div, period_ns);
|
|
|
on_time_div = 255ULL - on_time_div;
|
|
|
|
|
|
- ctrl = pwm_lpss_read(pwm);
|
|
|
+ orig_ctrl = ctrl = pwm_lpss_read(pwm);
|
|
|
ctrl &= ~PWM_ON_TIME_DIV_MASK;
|
|
|
ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
|
|
|
base_unit &= base_unit_range;
|
|
|
ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
|
|
|
ctrl |= on_time_div;
|
|
|
- pwm_lpss_write(pwm, ctrl);
|
|
|
+
|
|
|
+ if (orig_ctrl != ctrl) {
|
|
|
+ pwm_lpss_write(pwm, ctrl);
|
|
|
+ pwm_lpss_write(pwm, ctrl | PWM_SW_UPDATE);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond)
|
|
@@ -144,7 +139,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
|
return ret;
|
|
|
}
|
|
|
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
|
|
|
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
|
|
|
pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false);
|
|
|
ret = pwm_lpss_wait_for_update(pwm);
|
|
|
if (ret) {
|
|
@@ -157,7 +151,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
|
|
|
- pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
|
|
|
return pwm_lpss_wait_for_update(pwm);
|
|
|
}
|
|
|
} else if (pwm_is_enabled(pwm)) {
|
|
@@ -168,8 +161,42 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* This function gets called once from pwmchip_add to get the initial state */
|
|
|
+static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
|
|
+ struct pwm_state *state)
|
|
|
+{
|
|
|
+ struct pwm_lpss_chip *lpwm = to_lpwm(chip);
|
|
|
+ unsigned long base_unit_range;
|
|
|
+ unsigned long long base_unit, freq, on_time_div;
|
|
|
+ u32 ctrl;
|
|
|
+
|
|
|
+ base_unit_range = BIT(lpwm->info->base_unit_bits);
|
|
|
+
|
|
|
+ ctrl = pwm_lpss_read(pwm);
|
|
|
+ on_time_div = 255 - (ctrl & PWM_ON_TIME_DIV_MASK);
|
|
|
+ base_unit = (ctrl >> PWM_BASE_UNIT_SHIFT) & (base_unit_range - 1);
|
|
|
+
|
|
|
+ freq = base_unit * lpwm->info->clk_rate;
|
|
|
+ do_div(freq, base_unit_range);
|
|
|
+ if (freq == 0)
|
|
|
+ state->period = NSEC_PER_SEC;
|
|
|
+ else
|
|
|
+ state->period = NSEC_PER_SEC / (unsigned long)freq;
|
|
|
+
|
|
|
+ on_time_div *= state->period;
|
|
|
+ do_div(on_time_div, 255);
|
|
|
+ state->duty_cycle = on_time_div;
|
|
|
+
|
|
|
+ state->polarity = PWM_POLARITY_NORMAL;
|
|
|
+ state->enabled = !!(ctrl & PWM_ENABLE);
|
|
|
+
|
|
|
+ if (state->enabled)
|
|
|
+ pm_runtime_get(chip->dev);
|
|
|
+}
|
|
|
+
|
|
|
static const struct pwm_ops pwm_lpss_ops = {
|
|
|
.apply = pwm_lpss_apply,
|
|
|
+ .get_state = pwm_lpss_get_state,
|
|
|
.owner = THIS_MODULE,
|
|
|
};
|
|
|
|
|
@@ -214,6 +241,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
|
|
|
|
|
|
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
|
|
|
{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < lpwm->info->npwm; i++) {
|
|
|
+ if (pwm_is_enabled(&lpwm->chip.pwms[i]))
|
|
|
+ pm_runtime_put(lpwm->chip.dev);
|
|
|
+ }
|
|
|
return pwmchip_remove(&lpwm->chip);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
|