From patchwork Wed Mar 27 23:16:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Cercueil X-Patchwork-Id: 10874123 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0527B186D for ; Wed, 27 Mar 2019 23:19:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EADB5289B2 for ; Wed, 27 Mar 2019 23:19:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DEB3C289CB; Wed, 27 Mar 2019 23:19:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0101228B1D for ; Wed, 27 Mar 2019 23:19:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732502AbfC0XRl (ORCPT ); Wed, 27 Mar 2019 19:17:41 -0400 Received: from outils.crapouillou.net ([89.234.176.41]:59018 "EHLO crapouillou.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726102AbfC0XRi (ORCPT ); Wed, 27 Mar 2019 19:17:38 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=crapouillou.net; s=mail; t=1553728654; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:in-reply-to: references:references; bh=GkICgK8vBLcuX0i49vbljswblHjkddWYl4PLQNv7YN4=; b=fBCn0n2kr2zKU+fYHSy5pOAEVW5H1+Z8POU4Iedav/d33XjWF7EkWJ0I6Ww3f04a/Lt15L 5l/GlIMhZkk9Dlez0weEgBb1s8dqcuMFZNUYT5WfMovwHML1KFwBy9L0zRqab9x0t3tAIj XNVfmx1UlnLdJtqmsmuryOdvkKUn9BA= From: Paul Cercueil To: Rob Herring , Mark Rutland , Thierry Reding , Daniel Lezcano , Thomas Gleixner , Wim Van Sebroeck , Ralf Baechle , Paul Burton , James Hogan , Jonathan Corbet , Michael Turquette , Stephen Boyd Cc: Mathieu Malaterre , od@zcrc.me, linux-pwm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-mips@vger.kernel.org, linux-doc@vger.kernel.org, linux-clk@vger.kernel.org, Paul Cercueil Subject: [PATCH v11 14/27] pwm: jz4740: Improve algorithm of clock calculation Date: Thu, 28 Mar 2019 00:16:18 +0100 Message-Id: <20190327231631.15708-15-paul@crapouillou.net> In-Reply-To: <20190327231631.15708-1-paul@crapouillou.net> References: <20190327231631.15708-1-paul@crapouillou.net> Sender: linux-watchdog-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-watchdog@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The previous algorithm hardcoded details about how the TCU clocks work. The new algorithm will compute the maximum frequency at which the clock can run for the given period/duty parameters, and use clk_set_max_rate() to ensure that we will always compute period/duty values that fit in our 16-bit register fields. Signed-off-by: Paul Cercueil Tested-by: Mathieu Malaterre Tested-by: Artur Rojek --- drivers/pwm/pwm-jz4740.c | 51 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 1a0eab0abafe..b55ee879e23d 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -108,24 +108,47 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); struct clk *clk = pwm_get_chip_data(pwm), *parent_clk = clk_get_parent(clk); - unsigned long rate, period, duty; + unsigned long rate, parent_rate, period, duty; unsigned long long tmp; - unsigned int prescaler = 0; + int ret; - rate = clk_get_rate(parent_clk); - tmp = (unsigned long long)rate * state->period; - do_div(tmp, 1000000000); - period = tmp; + parent_rate = clk_get_rate(parent_clk); + + jz4740_pwm_disable(chip, pwm); + + /* Reset the clock to the maximum rate, and we'll reduce it if needed */ + ret = clk_set_rate(clk, parent_rate); + if (ret) + return ret; - while (period > 0xffff && prescaler < 6) { - period >>= 2; - rate >>= 2; - ++prescaler; + /* + * Limit the clock to a maximum rate that still gives us a period value + * which fits in 16 bits. + */ + tmp = 0xffffull * NSEC_PER_SEC; + do_div(tmp, state->period); + + ret = clk_set_max_rate(clk, tmp); + if (ret) { + dev_err(chip->dev, "Unable to set max rate: %i\n", ret); + return ret; } - if (prescaler == 6) - return -EINVAL; + /* + * Read back the clock rate, as it may have been modified by + * clk_set_max_rate() + */ + rate = clk_get_rate(clk); + + if (rate != parent_rate) + dev_dbg(chip->dev, "PWM clock updated to %lu Hz\n", rate); + /* Calculate period value */ + tmp = (unsigned long long)rate * state->period; + do_div(tmp, NSEC_PER_SEC); + period = (unsigned long)tmp; + + /* Calculate duty value */ tmp = (unsigned long long)period * state->duty_cycle; do_div(tmp, state->period); duty = period - tmp; @@ -133,8 +156,6 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (duty >= period) duty = period - 1; - jz4740_pwm_disable(chip, pwm); - /* * Set abrupt shutdown. * @@ -144,8 +165,6 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD); - clk_set_rate(clk, rate); - /* Reset counter to 0 */ regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0);