From patchwork Tue Jan 3 14:57:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandre Belloni X-Patchwork-Id: 710506 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ttHF21FDQz9t0v for ; Wed, 4 Jan 2017 02:00:38 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935401AbdACO5y (ORCPT ); Tue, 3 Jan 2017 09:57:54 -0500 Received: from mail.free-electrons.com ([62.4.15.54]:34290 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935114AbdACO5k (ORCPT ); Tue, 3 Jan 2017 09:57:40 -0500 Received: by mail.free-electrons.com (Postfix, from userid 110) id 5340B206FA; Tue, 3 Jan 2017 15:57:38 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT, URIBL_BLOCKED shortcircuit=ham autolearn=disabled version=3.4.0 Received: from localhost (unknown [88.191.26.124]) by mail.free-electrons.com (Postfix) with ESMTPSA id 2CB27204AE; Tue, 3 Jan 2017 15:57:38 +0100 (CET) From: Alexandre Belloni To: Thierry Reding Cc: Maxime Ripard , Chen-Yu Tsai , linux-pwm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Olliver Schinagl , Alexandre Belloni Subject: [PATCH] pwm: sunxi: wait for the READY bit Date: Tue, 3 Jan 2017 15:57:32 +0100 Message-Id: <20170103145732.2108-1-alexandre.belloni@free-electrons.com> X-Mailer: git-send-email 2.11.0 Sender: linux-pwm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pwm@vger.kernel.org Most of the call sites in the kernel are not really prepared to handle -EBUSY when calling pwm_config(). This means that they will either fail silently or fail without letting the user retry at a later time. This can be seen for example when using pwm-backlight (the most common use case for this driver). It will first call pwm_config() with a 0 duty cycle and disable the pwm. Then it will call pwm_config() that fails because the pwm had no chance to update its period internally and pwm_enable() ending up with a duty cycle of 0. Instead, actually wait for the RDY bit to go low before continuing. Signed-off-by: Alexandre Belloni --- drivers/pwm/pwm-sun4i.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index b0803f6c64d9..be489388e006 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -103,7 +104,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u32 prd, dty, val, clk_gate; u64 clk_rate, div = 0; unsigned int prescaler = 0; - int err; + int err = 0; clk_rate = clk_get_rate(sun4i_pwm->clk); @@ -154,18 +155,22 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, spin_lock(&sun4i_pwm->ctrl_lock); val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); - if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) { - spin_unlock(&sun4i_pwm->ctrl_lock); - clk_disable_unprepare(sun4i_pwm->clk); - return -EBUSY; - } - clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - if (clk_gate) { - val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); + + if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) { + val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm); sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG); + + err = readl_poll_timeout(sun4i_pwm->base + PWM_CTRL_REG, val, + !(val & PWM_RDY(pwm->hwpwm)), 400, + 500000); + if (err) + goto finish; } + val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); + sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG); + val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm); val |= BIT_CH(prescaler, pwm->hwpwm); @@ -174,6 +179,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, val = (dty & PWM_DTY_MASK) | PWM_PRD(prd); sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm)); +finish: if (clk_gate) { val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); val |= clk_gate; @@ -183,7 +189,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, spin_unlock(&sun4i_pwm->ctrl_lock); clk_disable_unprepare(sun4i_pwm->clk); - return 0; + return err; } static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,