| From e73b0101ae5124bf7cd3fb5d250302ad2f16a416 Mon Sep 17 00:00:00 2001 |
| From: Baruch Siach <baruch@tkos.co.il> |
| Date: Sun, 17 Jan 2021 15:17:02 +0200 |
| Subject: gpio: mvebu: fix pwm .get_state period calculation |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Baruch Siach <baruch@tkos.co.il> |
| |
| commit e73b0101ae5124bf7cd3fb5d250302ad2f16a416 upstream. |
| |
| The period is the sum of on and off values. That is, calculate period as |
| |
| ($on + $off) / clkrate |
| |
| instead of |
| |
| $off / clkrate - $on / clkrate |
| |
| that makes no sense. |
| |
| Reported-by: Russell King <linux@armlinux.org.uk> |
| Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| Fixes: 757642f9a584e ("gpio: mvebu: Add limited PWM support") |
| Signed-off-by: Baruch Siach <baruch@tkos.co.il> |
| Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> |
| [baruch: backport to kernels <= v5.10] |
| Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| Signed-off-by: Baruch Siach <baruch@tkos.co.il> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/gpio/gpio-mvebu.c | 25 ++++++++++--------------- |
| 1 file changed, 10 insertions(+), 15 deletions(-) |
| |
| --- a/drivers/gpio/gpio-mvebu.c |
| +++ b/drivers/gpio/gpio-mvebu.c |
| @@ -654,9 +654,8 @@ static void mvebu_pwm_get_state(struct p |
| |
| spin_lock_irqsave(&mvpwm->lock, flags); |
| |
| - val = (unsigned long long) |
| - readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); |
| - val *= NSEC_PER_SEC; |
| + u = readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm)); |
| + val = (unsigned long long) u * NSEC_PER_SEC; |
| do_div(val, mvpwm->clk_rate); |
| if (val > UINT_MAX) |
| state->duty_cycle = UINT_MAX; |
| @@ -665,21 +664,17 @@ static void mvebu_pwm_get_state(struct p |
| else |
| state->duty_cycle = 1; |
| |
| - val = (unsigned long long) |
| - readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); |
| + val = (unsigned long long) u; /* on duration */ |
| + /* period = on + off duration */ |
| + val += readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm)); |
| val *= NSEC_PER_SEC; |
| do_div(val, mvpwm->clk_rate); |
| - if (val < state->duty_cycle) { |
| + if (val > UINT_MAX) |
| + state->period = UINT_MAX; |
| + else if (val) |
| + state->period = val; |
| + else |
| state->period = 1; |
| - } else { |
| - val -= state->duty_cycle; |
| - if (val > UINT_MAX) |
| - state->period = UINT_MAX; |
| - else if (val) |
| - state->period = val; |
| - else |
| - state->period = 1; |
| - } |
| |
| regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u); |
| if (u) |