| From 146955f4810077c416efbcd2d38483add62ffeb8 Mon Sep 17 00:00:00 2001 |
| From: David Wu <david.wu@rock-chips.com> |
| Date: Wed, 1 Mar 2017 19:10:55 +0800 |
| Subject: [PATCH] pwm: rockchip: State of PWM clock should synchronize with PWM |
| enabled state |
| |
| commit a900152b5c29aea8134cc7a4c5db25552b3cd8f7 upstream. |
| |
| If the PWM was not enabled at U-Boot loader, PWM could not work for |
| clock always disabled at PWM driver. The PWM clock is enabled at |
| beginning of pwm_apply(), but disabled at end of pwm_apply(). |
| |
| If the PWM was enabled at U-Boot loader, PWM clock is always enabled |
| unless closed by ATF. The pwm-backlight might turn off the power at |
| early suspend, should disable PWM clock for saving power consume. |
| |
| It is important to provide opportunity to enable/disable clock at PWM |
| driver, the PWM consumer should ensure correct order to call PWM enable |
| and disable, and PWM driver ensure state of PWM clock synchronized with |
| PWM enabled state. |
| |
| Fixes: 2bf1c98aa5a4 ("pwm: rockchip: Add support for atomic update") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: David Wu <david.wu@rock-chips.com> |
| Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com> |
| Signed-off-by: Thierry Reding <thierry.reding@gmail.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c |
| index ef89df1f7336..744d56197286 100644 |
| --- a/drivers/pwm/pwm-rockchip.c |
| +++ b/drivers/pwm/pwm-rockchip.c |
| @@ -191,6 +191,28 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
| return 0; |
| } |
| |
| +static int rockchip_pwm_enable(struct pwm_chip *chip, |
| + struct pwm_device *pwm, |
| + bool enable, |
| + enum pwm_polarity polarity) |
| +{ |
| + struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); |
| + int ret; |
| + |
| + if (enable) { |
| + ret = clk_enable(pc->clk); |
| + if (ret) |
| + return ret; |
| + } |
| + |
| + pc->data->set_enable(chip, pwm, enable, polarity); |
| + |
| + if (!enable) |
| + clk_disable(pc->clk); |
| + |
| + return 0; |
| +} |
| + |
| static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
| struct pwm_state *state) |
| { |
| @@ -207,22 +229,26 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
| return ret; |
| |
| if (state->polarity != curstate.polarity && enabled) { |
| - pc->data->set_enable(chip, pwm, false, state->polarity); |
| + ret = rockchip_pwm_enable(chip, pwm, false, state->polarity); |
| + if (ret) |
| + goto out; |
| enabled = false; |
| } |
| |
| ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period); |
| if (ret) { |
| if (enabled != curstate.enabled) |
| - pc->data->set_enable(chip, pwm, !enabled, |
| - state->polarity); |
| - |
| + rockchip_pwm_enable(chip, pwm, !enabled, |
| + state->polarity); |
| goto out; |
| } |
| |
| - if (state->enabled != enabled) |
| - pc->data->set_enable(chip, pwm, state->enabled, |
| - state->polarity); |
| + if (state->enabled != enabled) { |
| + ret = rockchip_pwm_enable(chip, pwm, state->enabled, |
| + state->polarity); |
| + if (ret) |
| + goto out; |
| + } |
| |
| /* |
| * Update the state with the real hardware, which can differ a bit |
| -- |
| 2.12.0 |
| |