Merge branch 'for-v5.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
[linux-2.6-microblaze.git] / drivers / pwm / pwm-atmel.c
index 5813339..29b5ad0 100644 (file)
@@ -124,6 +124,7 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
 }
 
 static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
+                                            unsigned long clkrate,
                                             const struct pwm_state *state,
                                             unsigned long *cprd, u32 *pres)
 {
@@ -132,7 +133,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
        int shift;
 
        /* Calculate the period cycles and prescale value */
-       cycles *= clk_get_rate(atmel_pwm->clk);
+       cycles *= clkrate;
        do_div(cycles, NSEC_PER_SEC);
 
        /*
@@ -158,12 +159,14 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
 }
 
 static void atmel_pwm_calculate_cdty(const struct pwm_state *state,
-                                    unsigned long cprd, unsigned long *cdty)
+                                    unsigned long clkrate, unsigned long cprd,
+                                    u32 pres, unsigned long *cdty)
 {
        unsigned long long cycles = state->duty_cycle;
 
-       cycles *= cprd;
-       do_div(cycles, state->period);
+       cycles *= clkrate;
+       do_div(cycles, NSEC_PER_SEC);
+       cycles >>= pres;
        *cdty = cprd - cycles;
 }
 
@@ -244,17 +247,23 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        pwm_get_state(pwm, &cstate);
 
        if (state->enabled) {
+               unsigned long clkrate = clk_get_rate(atmel_pwm->clk);
+
                if (cstate.enabled &&
                    cstate.polarity == state->polarity &&
                    cstate.period == state->period) {
+                       u32 cmr = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
+
                        cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
                                                  atmel_pwm->data->regs.period);
-                       atmel_pwm_calculate_cdty(state, cprd, &cdty);
+                       pres = cmr & PWM_CMR_CPRE_MSK;
+
+                       atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
                        atmel_pwm_update_cdty(chip, pwm, cdty);
                        return 0;
                }
 
-               ret = atmel_pwm_calculate_cprd_and_pres(chip, state, &cprd,
+               ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd,
                                                        &pres);
                if (ret) {
                        dev_err(chip->dev,
@@ -262,7 +271,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
                        return ret;
                }
 
-               atmel_pwm_calculate_cdty(state, cprd, &cdty);
+               atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
 
                if (cstate.enabled) {
                        atmel_pwm_disable(chip, pwm, false);
@@ -319,7 +328,7 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 
                cdty = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
                                          atmel_pwm->data->regs.duty);
-               tmp = (u64)cdty * NSEC_PER_SEC;
+               tmp = (u64)(cprd - cdty) * NSEC_PER_SEC;
                tmp <<= pres;
                state->duty_cycle = DIV64_U64_ROUND_UP(tmp, rate);
 
@@ -429,7 +438,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)
        atmel_pwm->chip.ops = &atmel_pwm_ops;
        atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
        atmel_pwm->chip.of_pwm_n_cells = 3;
-       atmel_pwm->chip.base = -1;
        atmel_pwm->chip.npwm = 4;
 
        ret = pwmchip_add(&atmel_pwm->chip);
@@ -451,10 +459,12 @@ static int atmel_pwm_remove(struct platform_device *pdev)
 {
        struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
 
+       pwmchip_remove(&atmel_pwm->chip);
+
        clk_unprepare(atmel_pwm->clk);
        mutex_destroy(&atmel_pwm->isr_lock);
 
-       return pwmchip_remove(&atmel_pwm->chip);
+       return 0;
 }
 
 static struct platform_driver atmel_pwm_driver = {