Merge tag 'pwm/for-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry...
[sfrench/cifs-2.6.git] / drivers / pwm / pwm-jz4740.c
index 88a51a40e695697e78b10a2ecb318e09ea66c599..f901e8a0d33dc2d86a25f6f46655de80e4fe1f86 100644 (file)
@@ -63,7 +63,15 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
        uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm);
 
-       /* Disable PWM output.
+       /*
+        * Set duty > period. This trick allows the TCU channels in TCU2 mode to
+        * properly return to their init level.
+        */
+       jz4740_timer_set_duty(pwm->hwpwm, 0xffff);
+       jz4740_timer_set_period(pwm->hwpwm, 0x0);
+
+       /*
+        * Disable PWM output.
         * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the
         * counter is stopped, while in TCU1 mode the order does not matter.
         */
@@ -74,17 +82,16 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
        jz4740_timer_disable(pwm->hwpwm);
 }
 
-static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-                            int duty_ns, int period_ns)
+static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+                           struct pwm_state *state)
 {
        struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip);
        unsigned long long tmp;
        unsigned long period, duty;
        unsigned int prescaler = 0;
        uint16_t ctrl;
-       bool is_enabled;
 
-       tmp = (unsigned long long)clk_get_rate(jz4740->clk) * period_ns;
+       tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period;
        do_div(tmp, 1000000000);
        period = tmp;
 
@@ -96,16 +103,14 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
        if (prescaler == 6)
                return -EINVAL;
 
-       tmp = (unsigned long long)period * duty_ns;
-       do_div(tmp, period_ns);
+       tmp = (unsigned long long)period * state->duty_cycle;
+       do_div(tmp, state->period);
        duty = period - tmp;
 
        if (duty >= period)
                duty = period - 1;
 
-       is_enabled = jz4740_timer_is_enabled(pwm->hwpwm);
-       if (is_enabled)
-               jz4740_pwm_disable(chip, pwm);
+       jz4740_pwm_disable(chip, pwm);
 
        jz4740_timer_set_count(pwm->hwpwm, 0);
        jz4740_timer_set_duty(pwm->hwpwm, duty);
@@ -116,18 +121,7 @@ static int jz4740_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
        jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
 
-       if (is_enabled)
-               jz4740_pwm_enable(chip, pwm);
-
-       return 0;
-}
-
-static int jz4740_pwm_set_polarity(struct pwm_chip *chip,
-               struct pwm_device *pwm, enum pwm_polarity polarity)
-{
-       uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm);
-
-       switch (polarity) {
+       switch (state->polarity) {
        case PWM_POLARITY_NORMAL:
                ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW;
                break;
@@ -137,16 +131,17 @@ static int jz4740_pwm_set_polarity(struct pwm_chip *chip,
        }
 
        jz4740_timer_set_ctrl(pwm->hwpwm, ctrl);
+
+       if (state->enabled)
+               jz4740_pwm_enable(chip, pwm);
+
        return 0;
 }
 
 static const struct pwm_ops jz4740_pwm_ops = {
        .request = jz4740_pwm_request,
        .free = jz4740_pwm_free,
-       .config = jz4740_pwm_config,
-       .set_polarity = jz4740_pwm_set_polarity,
-       .enable = jz4740_pwm_enable,
-       .disable = jz4740_pwm_disable,
+       .apply = jz4740_pwm_apply,
        .owner = THIS_MODULE,
 };
 
@@ -184,8 +179,6 @@ static int jz4740_pwm_remove(struct platform_device *pdev)
 #ifdef CONFIG_OF
 static const struct of_device_id jz4740_pwm_dt_ids[] = {
        { .compatible = "ingenic,jz4740-pwm", },
-       { .compatible = "ingenic,jz4770-pwm", },
-       { .compatible = "ingenic,jz4780-pwm", },
        {},
 };
 MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);