All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Dooks <ben.dooks@sifive.com>
To: linux-pwm@vger.kernel.org
Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Lee Jones <lee.jones@linaro.org>,
	u.kleine-koenig@pengutronix.de,
	Thierry Reding <thierry.reding@gmail.com>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Greentime Hu <greentime.hu@sifive.com>,
	jarkko.nikula@linux.intel.com,
	William Salmon <william.salmon@sifive.com>,
	Jude Onyenegecha <jude.onyenegecha@sifive.com>,
	Ben Dooks <ben.dooks@sifive.com>
Subject: [PATCH v6 10/10] pwm: dwc: use clock rate in hz to avoid rounding issues
Date: Thu, 20 Oct 2022 16:16:10 +0100	[thread overview]
Message-ID: <20221020151610.59443-11-ben.dooks@sifive.com> (raw)
In-Reply-To: <20221020151610.59443-1-ben.dooks@sifive.com>

As noted, the clock-rate when not a nice multiple of ns is probably
going to end up with inacurate caculations, as well as on a non pci
system the rate may change (although we've not put a clock rate
change notifier in this code yet) so we also add some quick checks
of the rate when we do any calculations with it.

Signed-off-by; Ben Dooks <ben.dooks@sifive.com>
Reported-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-dwc-of.c |  2 +-
 drivers/pwm/pwm-dwc.c    | 29 ++++++++++++++++++++---------
 drivers/pwm/pwm-dwc.h    |  2 +-
 3 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm-dwc-of.c b/drivers/pwm/pwm-dwc-of.c
index c5b4351cc7b0..5f7f066859d4 100644
--- a/drivers/pwm/pwm-dwc-of.c
+++ b/drivers/pwm/pwm-dwc-of.c
@@ -50,7 +50,7 @@ static int dwc_pwm_plat_probe(struct platform_device *pdev)
 		return dev_err_probe(dev, PTR_ERR(dwc->clk),
 				     "failed to get timer clock\n");
 
-	dwc->clk_ns = NSEC_PER_SEC / clk_get_rate(dwc->clk);
+	dwc->clk_rate = clk_get_rate(dwc->clk);
 	return devm_pwmchip_add(dev, &dwc->chip);
 }
 
diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index 5ef0fe7ea3e9..f48a6245a3b5 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -43,18 +43,22 @@ static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc,
 	u32 high;
 	u32 low;
 
+	if (dwc->clk)
+		dwc->clk_rate = clk_get_rate(dwc->clk);
+
 	/*
 	 * Calculate width of low and high period in terms of input clock
 	 * periods and check are the result within HW limits between 1 and
 	 * 2^32 periods.
 	 */
-	tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
+	tmp = state->duty_cycle * dwc->clk_rate;
+	tmp = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC);
 	if (tmp < 1 || tmp > (1ULL << 32))
 		return -ERANGE;
 	low = tmp - 1;
 
-	tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle,
-				    dwc->clk_ns);
+	tmp = (state->period - state->duty_cycle) * dwc->clk_rate;
+	tmp = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC);
 	if (tmp < 1 || tmp > (1ULL << 32))
 		return -ERANGE;
 	high = tmp - 1;
@@ -120,6 +124,7 @@ static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 			      struct pwm_state *state)
 {
 	struct dwc_pwm *dwc = to_dwc_pwm(chip);
+	unsigned long clk_rate;
 	u64 duty, period;
 	u32 ctrl, ld, ld2;
 
@@ -129,22 +134,28 @@ static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
 	ld = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm));
 	ld2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm));
 
+	if (dwc->clk)
+		dwc->clk_rate = clk_get_rate(dwc->clk);
+
+	clk_rate = dwc->clk_rate;
 	state->enabled = !!(ctrl & DWC_TIM_CTRL_EN);
 
 	/* If we're not in PWM, technically the output is a 50-50
 	 * based on the timer load-count only.
 	 */
 	if (ctrl & DWC_TIM_CTRL_PWM) {
-		duty = (ld + 1) * dwc->clk_ns;
-		period = (ld2 + 1)  * dwc->clk_ns;
+		duty = ld + 1;
+		period = ld2 + 1;
 		period += duty;
 	} else {
-		duty = (ld + 1) * dwc->clk_ns;
+		duty = ld + 1;
 		period = duty * 2;
 	}
 
-	state->period = period;
-	state->duty_cycle = duty;
+	duty *= NSEC_PER_SEC;
+	period *= NSEC_PER_SEC;
+	state->period = DIV_ROUND_CLOSEST_ULL(period, clk_rate);
+	state->duty_cycle = DIV_ROUND_CLOSEST_ULL(duty, clk_rate);
 	state->polarity = PWM_POLARITY_INVERSED;
 
 	pm_runtime_put_sync(chip->dev);
@@ -164,7 +175,7 @@ struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
 	if (!dwc)
 		return NULL;
 
-	dwc->clk_ns = 10;
+	dwc->clk_rate = NSEC_PER_SEC / 10;
 	dwc->chip.dev = dev;
 	dwc->chip.ops = &dwc_pwm_ops;
 	dwc->chip.npwm = DWC_TIMERS_TOTAL;
diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h
index dc451cb2eff5..19bdc2224690 100644
--- a/drivers/pwm/pwm-dwc.h
+++ b/drivers/pwm/pwm-dwc.h
@@ -41,7 +41,7 @@ struct dwc_pwm {
 	struct pwm_chip chip;
 	void __iomem *base;
 	struct clk *clk;
-	unsigned int clk_ns;
+	unsigned long clk_rate;
 	struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
 };
 #define to_dwc_pwm(p)	(container_of((p), struct dwc_pwm, chip))
-- 
2.35.1


  parent reply	other threads:[~2022-10-20 15:17 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-20 15:16 [PATCH v6 00/10] Designware PWM driver updates for OF Ben Dooks
2022-10-20 15:16 ` [PATCH v6 01/10] dt-bindings: pwm: Document Synopsys DesignWare snps,pwm-dw-apb-timers-pwm2 Ben Dooks
2022-10-20 15:36   ` Krzysztof Kozlowski
2022-10-24 15:45     ` Ben Dooks
2022-10-20 15:39   ` Uwe Kleine-König
2022-11-17 16:10   ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 02/10] pwm: dwc: allow driver to be built with COMPILE_TEST Ben Dooks
2022-10-20 15:51   ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 03/10] pwm: dwc: change &pci->dev to dev in probe Ben Dooks
2022-10-20 15:16 ` [PATCH v6 04/10] pwm: dwc: move memory alloc to own function Ben Dooks
2022-11-10 15:35   ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 05/10] pwm: dwc: use devm_pwmchip_add Ben Dooks
2022-10-20 15:55   ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 06/10] pwm: dwc: split pci out of core driver Ben Dooks
2022-11-10 15:29   ` Uwe Kleine-König
2022-11-10 16:35     ` Ben Dooks
2022-11-17 16:15       ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 07/10] pwm: dwc: make timer clock configurable Ben Dooks
2022-11-10 15:39   ` Uwe Kleine-König
2022-10-20 15:16 ` [PATCH v6 08/10] pwm: dwc: add of/platform support Ben Dooks
2022-10-20 15:16 ` [PATCH v6 09/10] pwm: dwc: add PWM bit unset in get_state call Ben Dooks
2022-10-20 15:16 ` Ben Dooks [this message]
2022-11-10 15:42   ` [PATCH v6 10/10] pwm: dwc: use clock rate in hz to avoid rounding issues Uwe Kleine-König
2022-11-10 16:29     ` Ben Dooks
2022-10-24  8:39 ` [PATCH v6 00/10] Designware PWM driver updates for OF Jarkko Nikula
2022-10-24 15:40   ` Ben Dooks
2022-11-08 11:19   ` Ben Dooks
2022-11-08 11:48     ` Uwe Kleine-König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221020151610.59443-11-ben.dooks@sifive.com \
    --to=ben.dooks@sifive.com \
    --cc=devicetree@vger.kernel.org \
    --cc=greentime.hu@sifive.com \
    --cc=jarkko.nikula@linux.intel.com \
    --cc=jude.onyenegecha@sifive.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=lee.jones@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    --cc=william.salmon@sifive.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.