From patchwork Sun Oct 18 04:29:12 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Agner X-Patchwork-Id: 7428761 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 34846BEEA4 for ; Sun, 18 Oct 2015 04:31:54 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 25BEB206E6 for ; Sun, 18 Oct 2015 04:31:53 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2453F2063D for ; Sun, 18 Oct 2015 04:31:52 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Znfat-0007Sg-Mg; Sun, 18 Oct 2015 04:29:15 +0000 Received: from mail.kmu-office.ch ([178.209.48.109]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Znfaq-0007Q4-8B for linux-arm-kernel@lists.infradead.org; Sun, 18 Oct 2015 04:29:13 +0000 Received: from localhost.localdomain (unknown [IPv6:2601:602:8b00:ffde:ad4:cff:fe03:1df8]) by mail.kmu-office.ch (Postfix) with ESMTPSA id 8BFDE5C180A; Sun, 18 Oct 2015 06:27:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=agner.ch; s=dkim; t=1445142423; bh=OhrOJvte9vi8xeiBgZba8WxhQUhhYXqKHJcAm7WwrkQ=; h=From:To:Cc:Subject:Date:From; b=Uswghlm4D6zjY9IHSX1CRD3HTikDiu8QrXNouIJTe6G2qTzAHu2ZWs7+JLjAvXgxc 451G29OiQ0AUme+VzhBnaDDKWMRYsbb+IoO7X7PNhlrsEa9yrXuGjsaC5eOYMHHaxX uvdRr2RwB3r1cwGqShearzPMOp4x9jY0y7vQkU7I= From: Stefan Agner To: thierry.reding@gmail.com Subject: [PATCH RESEND] pwm: ftm: fix clock enable/disable when using PM Date: Sat, 17 Oct 2015 21:29:12 -0700 Message-Id: <1445142552-3530-1-git-send-email-stefan@agner.ch> X-Mailer: git-send-email 2.6.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151017_212912_650681_5FCB79E1 X-CRM114-Status: GOOD ( 17.18 ) X-Spam-Score: -1.3 (-) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-pwm@vger.kernel.org, Stefan Agner , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The driver has multiple issues when enabling/disabling clocks. A given instance enables/disables three clocks: the bus clock, the counter clock and the PWM clock. The bus clock gets enabled on pwm_request, whereas the counter and PWM clocks will be enabled upon pwm_enable. When entering suspend, the current behavior relies on the FTM_OUTMASK register: If a PWM output is unmasked, the driver assumes the clocks are enabled. However, some PWM instances, e.g. Vybrid's FTM1, only have 2 channels connected. In that case, the FTM_OUTMASK reads only 0x3, even when it was initialized with 0xff. Hence for those PWM instances, the current approach does not work at all. A second issue is that the three clocks are not treated differently regarding PWM's enabled/requested state. This can lead to clocks getting disabled which have not been enabled in the first place (a PWM channel which only has been requested). A third issue applies to the bus clock only, which can get enabled multiple times (once for each PWM channel of a PWM chip). This is fine, however when entering suspend mode, the clock only gets disabled once. To fix the issues this change introduces a different approach by relying on the enable/prepared counters of the clock framework. Clocks get disabled during suspend and back enabled on resume regarding to the PWM channels individual state. However, since we do not count the clocks locally, this change no longer clears the Status and Control registers Clock Source Selection (FTM_SC[CLKS]). There have not observed issues with that approach so far. Signed-off-by: Stefan Agner --- drivers/pwm/pwm-fsl-ftm.c | 58 ++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index f9dfc8b..5e1dd96 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -80,7 +80,6 @@ struct fsl_pwm_chip { struct mutex lock; - unsigned int use_count; unsigned int cnt_select; unsigned int clk_ps; @@ -300,9 +299,6 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc) { int ret; - if (fpc->use_count++ != 0) - return 0; - /* select counter clock source */ regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, FTM_SC_CLK(fpc->cnt_select)); @@ -334,25 +330,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } -static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc) -{ - /* - * already disabled, do nothing - */ - if (fpc->use_count == 0) - return; - - /* there are still users, so can't disable yet */ - if (--fpc->use_count > 0) - return; - - /* no users left, disable PWM counter clock */ - regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0); - - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); - clk_disable_unprepare(fpc->clk[fpc->cnt_select]); -} - static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); @@ -362,7 +339,8 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm), BIT(pwm->hwpwm)); - fsl_counter_clock_disable(fpc); + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); + clk_disable_unprepare(fpc->clk[fpc->cnt_select]); regmap_read(fpc->regmap, FTM_OUTMASK, &val); if ((val & 0xFF) == 0xFF) @@ -492,17 +470,24 @@ static int fsl_pwm_remove(struct platform_device *pdev) static int fsl_pwm_suspend(struct device *dev) { struct fsl_pwm_chip *fpc = dev_get_drvdata(dev); - u32 val; + int i; regcache_cache_only(fpc->regmap, true); regcache_mark_dirty(fpc->regmap); - /* read from cache */ - regmap_read(fpc->regmap, FTM_OUTMASK, &val); - if ((val & 0xFF) != 0xFF) { + for (i = 0; i < fpc->chip.npwm; i++) { + struct pwm_device *pwm = &fpc->chip.pwms[i]; + + if (!test_bit(PWMF_REQUESTED, &pwm->flags)) + continue; + + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + + if (!test_bit(PWMF_ENABLED, &pwm->flags)) + continue; + clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]); clk_disable_unprepare(fpc->clk[fpc->cnt_select]); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); } return 0; @@ -511,12 +496,19 @@ static int fsl_pwm_suspend(struct device *dev) static int fsl_pwm_resume(struct device *dev) { struct fsl_pwm_chip *fpc = dev_get_drvdata(dev); - u32 val; + int i; + + for (i = 0; i < fpc->chip.npwm; i++) { + struct pwm_device *pwm = &fpc->chip.pwms[i]; + + if (!test_bit(PWMF_REQUESTED, &pwm->flags)) + continue; - /* read from cache */ - regmap_read(fpc->regmap, FTM_OUTMASK, &val); - if ((val & 0xFF) != 0xFF) { clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + + if (!test_bit(PWMF_ENABLED, &pwm->flags)) + continue; + clk_prepare_enable(fpc->clk[fpc->cnt_select]); clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]); }