From: Jerome Brunet <jbrunet@baylibre.com> To: Thierry Reding <thierry.reding@gmail.com>, Kevin Hilman <khilman@baylibre.com>, Neil Armstrong <narmstrong@baylibre.com> Cc: Jerome Brunet <jbrunet@baylibre.com>, Carlo Caione <carlo@caione.org>, linux-pwm@vger.kernel.org, linux-amlogic@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 3/3] pwm: meson: improve pwm calculation precision. Date: Thu, 8 Jun 2017 14:24:16 +0200 [thread overview] Message-ID: <20170608122416.1993-4-jbrunet@baylibre.com> (raw) In-Reply-To: <20170608122416.1993-1-jbrunet@baylibre.com> When using input clocks with high rates, such as clk81 (166MHz), the fin_ns = NSEC_PER_SEC / fin_freq can introduce a significant error. Ex: fin_freq = 166666667, NSEC_PER_SEC = 1000000000 fin_ns = 5,9999999 which is, of course, rounded down to 5. This introduce an error of ~20% on the period requested from the pwm. This patch use ps instead of ns (and 64bits integer) to perform the calculation. This should give a good enough precision. Fixes: 211ed630753d ("pwm: Add support for Meson PWM Controller") Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> --- drivers/pwm/pwm-meson.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index b911a944744a..4cdc66f7f718 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -163,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, unsigned int duty, unsigned int period) { unsigned int pre_div, cnt, duty_cnt; - unsigned long fin_freq = -1, fin_ns; + unsigned long fin_freq = -1; + u64 fin_ps; if (~(meson->inverter_mask >> id) & 0x1) duty = period - duty; @@ -179,13 +180,14 @@ static int meson_pwm_calc(struct meson_pwm *meson, } dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); - fin_ns = NSEC_PER_SEC / fin_freq; + fin_ps = ((u64)NSEC_PER_SEC * 1000) / fin_freq; /* Calc pre_div with the period */ for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { - cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1)); - dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n", - fin_ns, pre_div, cnt); + cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, + fin_ps * (pre_div + 1)); + dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", + fin_ps, pre_div, cnt); if (cnt <= 0xffff) break; } @@ -208,7 +210,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, channel->lo = cnt; } else { /* Then check is we can have the duty with the same pre_div */ - duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1)); + duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000, + fin_ps * (pre_div + 1)); if (duty_cnt > 0xffff) { dev_err(meson->chip.dev, "unable to get duty cycle\n"); return -EINVAL; -- 2.9.4
WARNING: multiple messages have this Message-ID (diff)
From: jbrunet@baylibre.com (Jerome Brunet) To: linus-amlogic@lists.infradead.org Subject: [PATCH v2 3/3] pwm: meson: improve pwm calculation precision. Date: Thu, 8 Jun 2017 14:24:16 +0200 [thread overview] Message-ID: <20170608122416.1993-4-jbrunet@baylibre.com> (raw) In-Reply-To: <20170608122416.1993-1-jbrunet@baylibre.com> When using input clocks with high rates, such as clk81 (166MHz), the fin_ns = NSEC_PER_SEC / fin_freq can introduce a significant error. Ex: fin_freq = 166666667, NSEC_PER_SEC = 1000000000 fin_ns = 5,9999999 which is, of course, rounded down to 5. This introduce an error of ~20% on the period requested from the pwm. This patch use ps instead of ns (and 64bits integer) to perform the calculation. This should give a good enough precision. Fixes: 211ed630753d ("pwm: Add support for Meson PWM Controller") Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> --- drivers/pwm/pwm-meson.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index b911a944744a..4cdc66f7f718 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -163,7 +163,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, unsigned int duty, unsigned int period) { unsigned int pre_div, cnt, duty_cnt; - unsigned long fin_freq = -1, fin_ns; + unsigned long fin_freq = -1; + u64 fin_ps; if (~(meson->inverter_mask >> id) & 0x1) duty = period - duty; @@ -179,13 +180,14 @@ static int meson_pwm_calc(struct meson_pwm *meson, } dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq); - fin_ns = NSEC_PER_SEC / fin_freq; + fin_ps = ((u64)NSEC_PER_SEC * 1000) / fin_freq; /* Calc pre_div with the period */ for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { - cnt = DIV_ROUND_CLOSEST(period, fin_ns * (pre_div + 1)); - dev_dbg(meson->chip.dev, "fin_ns=%lu pre_div=%u cnt=%u\n", - fin_ns, pre_div, cnt); + cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, + fin_ps * (pre_div + 1)); + dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", + fin_ps, pre_div, cnt); if (cnt <= 0xffff) break; } @@ -208,7 +210,8 @@ static int meson_pwm_calc(struct meson_pwm *meson, channel->lo = cnt; } else { /* Then check is we can have the duty with the same pre_div */ - duty_cnt = DIV_ROUND_CLOSEST(duty, fin_ns * (pre_div + 1)); + duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000, + fin_ps * (pre_div + 1)); if (duty_cnt > 0xffff) { dev_err(meson->chip.dev, "unable to get duty cycle\n"); return -EINVAL; -- 2.9.4
next prev parent reply other threads:[~2017-06-08 12:24 UTC|newest] Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top 2017-06-08 12:24 [PATCH v2 0/3] pwm: add pwm AO on meson gx Jerome Brunet 2017-06-08 12:24 ` Jerome Brunet 2017-06-08 12:24 ` [PATCH v2 1/3] dt-bindings: pwm: meson: add comptabible for gxbb ao pwms Jerome Brunet 2017-06-08 12:24 ` Jerome Brunet 2017-06-13 22:18 ` Rob Herring 2017-06-13 22:18 ` Rob Herring 2017-06-08 12:24 ` [PATCH v2 2/3] pwm: meson: add compatible for the " Jerome Brunet 2017-06-08 12:24 ` Jerome Brunet 2017-06-14 17:38 ` Kevin Hilman 2017-06-14 17:38 ` Kevin Hilman 2017-06-08 12:24 ` Jerome Brunet [this message] 2017-06-08 12:24 ` [PATCH v2 3/3] pwm: meson: improve pwm calculation precision Jerome Brunet 2017-06-08 12:35 ` Neil Armstrong 2017-06-08 12:35 ` Neil Armstrong 2017-07-06 21:21 ` Thierry Reding 2017-07-06 21:21 ` Thierry Reding 2017-07-07 8:57 ` Jerome Brunet 2017-07-07 8:57 ` Jerome Brunet 2017-07-06 6:59 ` [PATCH v2 0/3] pwm: add pwm AO on meson gx Thierry Reding 2017-07-06 6:59 ` Thierry Reding 2017-07-06 9:02 ` Jerome Brunet 2017-07-06 9:02 ` Jerome Brunet 2017-07-06 9:02 ` Jerome Brunet 2017-07-06 9:17 ` Thierry Reding 2017-07-06 9:17 ` Thierry Reding 2017-07-08 1:46 ` Jeremy Kerr 2017-07-14 5:51 ` Jeremy Kerr 2017-07-14 5:51 ` Jeremy Kerr 2017-07-18 14:52 ` Thierry Reding 2017-07-18 14:52 ` Thierry Reding
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=20170608122416.1993-4-jbrunet@baylibre.com \ --to=jbrunet@baylibre.com \ --cc=carlo@caione.org \ --cc=khilman@baylibre.com \ --cc=linux-amlogic@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-pwm@vger.kernel.org \ --cc=narmstrong@baylibre.com \ --cc=thierry.reding@gmail.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: linkBe 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.