[PATCH V2 2/4] drivers: pwm: pwm-bcm-kona: Switch to using atomic PWM Framework
From: Sheetal Tigadoli
Date: Wed Jan 16 2019 - 15:15:25 EST
Switch to using atomic PWM Framework on broadcom PWM kona driver
Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@xxxxxxxxxxxx>
---
drivers/pwm/pwm-bcm-kona.c | 201 +++++++++++++++++++--------------------------
1 file changed, 83 insertions(+), 118 deletions(-)
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 09a95ae..fe63289 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -108,151 +108,116 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
ndelay(400);
}
-static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
-{
- struct kona_pwmc *kp = to_kona_pwmc(chip);
- u64 val, div, rate;
- unsigned long prescale = PRESCALE_MIN, pc, dc;
- unsigned int value, chan = pwm->hwpwm;
-
- /*
- * Find period count, duty count and prescale to suit duty_ns and
- * period_ns. This is done according to formulas described below:
- *
- * period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE
- * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
- *
- * PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
- * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
- */
-
- rate = clk_get_rate(kp->clk);
-
- while (1) {
- div = 1000000000;
- div *= 1 + prescale;
- val = rate * period_ns;
- pc = div64_u64(val, div);
- val = rate * duty_ns;
- dc = div64_u64(val, div);
-
- /* If duty_ns or period_ns are not achievable then return */
- if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
- return -EINVAL;
-
- /* If pc and dc are in bounds, the calculation is done */
- if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
- break;
-
- /* Otherwise, increase prescale and recalculate pc and dc */
- if (++prescale > PRESCALE_MAX)
- return -EINVAL;
- }
-
- /*
- * Don't apply settings if disabled. The period and duty cycle are
- * always calculated above to ensure the new values are
- * validated immediately instead of on enable.
- */
- if (pwm_is_enabled(pwm)) {
- kona_pwmc_prepare_for_settings(kp, chan);
-
- value = readl(kp->base + PRESCALE_OFFSET);
- value &= ~PRESCALE_MASK(chan);
- value |= prescale << PRESCALE_SHIFT(chan);
- writel(value, kp->base + PRESCALE_OFFSET);
-
- writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
-
- writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
-
- kona_pwmc_apply_settings(kp, chan);
- }
-
- return 0;
-}
-
-static int kona_pwmc_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
- enum pwm_polarity polarity)
+static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct kona_pwmc *kp = to_kona_pwmc(chip);
unsigned int chan = pwm->hwpwm;
unsigned int value;
- int ret;
-
- ret = clk_prepare_enable(kp->clk);
- if (ret < 0) {
- dev_err(chip->dev, "failed to enable clock: %d\n", ret);
- return ret;
- }
kona_pwmc_prepare_for_settings(kp, chan);
- value = readl(kp->base + PWM_CONTROL_OFFSET);
-
- if (polarity == PWM_POLARITY_NORMAL)
- value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
- else
- value &= ~(1 << PWM_CONTROL_POLARITY_SHIFT(chan));
+ /* Simulate a disable by configuring for zero duty */
+ writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
+ writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
- writel(value, kp->base + PWM_CONTROL_OFFSET);
+ /* Set prescale to 0 for this channel */
+ value = readl(kp->base + PRESCALE_OFFSET);
+ value &= ~PRESCALE_MASK(chan);
+ writel(value, kp->base + PRESCALE_OFFSET);
kona_pwmc_apply_settings(kp, chan);
clk_disable_unprepare(kp->clk);
-
- return 0;
}
-static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
{
struct kona_pwmc *kp = to_kona_pwmc(chip);
+ struct pwm_state cstate;
+ u64 val, div, rate;
+ unsigned long prescale = PRESCALE_MIN, pc, dc;
+ unsigned int value, chan = pwm->hwpwm;
int ret;
- ret = clk_prepare_enable(kp->clk);
- if (ret < 0) {
- dev_err(chip->dev, "failed to enable clock: %d\n", ret);
- return ret;
- }
-
- ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm),
- pwm_get_period(pwm));
- if (ret < 0) {
- clk_disable_unprepare(kp->clk);
- return ret;
- }
+ pwm_get_state(pwm, &cstate);
+
+ if (state->enabled) {
+ /*
+ * Find period count, duty count and prescale to suit duty_ns
+ * and period_ns. This is done according to formulas described
+ * below:
+ *
+ * period_ns = 10^9 * (PRESCALE + 1) * PC / PWM_CLK_RATE
+ * duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
+ *
+ * PC = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
+ * DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
+ */
+ rate = clk_get_rate(kp->clk);
+
+ while (1) {
+ div = 1000000000;
+ div *= 1 + prescale;
+ val = rate * state->period;
+ pc = div64_u64(val, div);
+ val = rate * state->duty_cycle;
+ dc = div64_u64(val, div);
+
+ /* If duty_ns or period_ns are not achievable then
+ * return
+ */
+ if (pc < PERIOD_COUNT_MIN || dc < DUTY_CYCLE_HIGH_MIN)
+ return -EINVAL;
+
+ /* If pc & dc are in bounds, the calculation is done */
+ if (pc <= PERIOD_COUNT_MAX && dc <= DUTY_CYCLE_HIGH_MAX)
+ break;
+
+ /* Otherwise, increase prescale & recalculate pc & dc */
+ if (++prescale > PRESCALE_MAX)
+ return -EINVAL;
+ }
+
+ if (!cstate.enabled) {
+ ret = clk_prepare_enable(kp->clk);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+ }
- return 0;
-}
-
-static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct kona_pwmc *kp = to_kona_pwmc(chip);
- unsigned int chan = pwm->hwpwm;
- unsigned int value;
+ kona_pwmc_prepare_for_settings(kp, chan);
- kona_pwmc_prepare_for_settings(kp, chan);
+ value = readl(kp->base + PRESCALE_OFFSET);
+ value &= ~PRESCALE_MASK(chan);
+ value |= prescale << PRESCALE_SHIFT(chan);
+ writel(value, kp->base + PRESCALE_OFFSET);
+ writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
+ writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
- /* Simulate a disable by configuring for zero duty */
- writel(0, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
- writel(0, kp->base + PERIOD_COUNT_OFFSET(chan));
+ if (cstate.polarity != state->polarity) {
+ value = readl(kp->base + PWM_CONTROL_OFFSET);
+ if (state->polarity == PWM_POLARITY_NORMAL)
+ value |= 1 << PWM_CONTROL_POLARITY_SHIFT(chan);
+ else
+ value &= ~(1 <<
+ PWM_CONTROL_POLARITY_SHIFT(chan));
- /* Set prescale to 0 for this channel */
- value = readl(kp->base + PRESCALE_OFFSET);
- value &= ~PRESCALE_MASK(chan);
- writel(value, kp->base + PRESCALE_OFFSET);
+ writel(value, kp->base + PWM_CONTROL_OFFSET);
+ }
- kona_pwmc_apply_settings(kp, chan);
+ kona_pwmc_apply_settings(kp, chan);
+ } else if (cstate.enabled) {
+ kona_pwmc_disable(chip, pwm);
+ }
- clk_disable_unprepare(kp->clk);
+ return 0;
}
static const struct pwm_ops kona_pwm_ops = {
- .config = kona_pwmc_config,
- .set_polarity = kona_pwmc_set_polarity,
- .enable = kona_pwmc_enable,
- .disable = kona_pwmc_disable,
+ .apply = kona_pwmc_apply,
.owner = THIS_MODULE,
};
--
1.9.1