All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <uwe@kleine-koenig.org>
To: Jeff LaBundy <jeff@labundy.com>,
	Thierry Reding <thierry.reding@gmail.com>
Cc: linux-pwm@vger.kernel.org, "Lee Jones" <lee.jones@linaro.org>,
	kernel@pengutronix.de,
	"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
Subject: [PATCH v2] pwm: iqs620a: Fix overflow and optimize calculations
Date: Fri, 27 Nov 2020 21:32:44 +0100	[thread overview]
Message-ID: <20201127203244.3439478-1-uwe@kleine-koenig.org> (raw)
In-Reply-To: <20201127201051.GA32257@labundy.com>

From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

If state->duty_cycle is 0x100000000000000, the previous calculation of
duty_scale overflows and yields a duty cycle ratio of 0% instead of
100%. Fix this by comparing the requested duty cycle against the maximal
possible duty cycle first. This way it is possible to use a native
integer division instead of a (depending on the architecture) more
expensive 64bit division. Also duty_val cannot be bigger than 0xff which
allows to simplify the code a bit further down.

Fixes: 6f0841a8197b ("pwm: Add support for Azoteq IQS620A PWM generator")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
Hello Jeff,

On Fri, Nov 27, 2020 at 02:10:51PM -0600, Jeff LaBundy wrote:
> I tested this patch on actual hardware but the newly calculated register
> values are incorrect. We used to get:
>
> [...]
> >                     goto err_mutex;
> >     }
> >  
> > -   if (duty_scale) {
> > -           u8 duty_val = min_t(u64, duty_scale - 1, 0xff);
> > -
> > +   if (duty_val) {
> 
> This is part of the problem; the device's formula for duty cycle has a
> plus one that is getting dropped now (see comments in iqs620_pwm_apply).

Good catch, I indeed missed that - 1.

This patch should be better in this regard.

Thanks for particular attention and testing,
Uwe

 drivers/pwm/pwm-iqs620a.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
index 7d33e3646436..6789e117f123 100644
--- a/drivers/pwm/pwm-iqs620a.c
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -46,7 +46,7 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 {
 	struct iqs620_pwm_private *iqs620_pwm;
 	struct iqs62x_core *iqs62x;
-	u64 duty_scale;
+	u8 duty_val;
 	int ret;
 
 	if (state->polarity != PWM_POLARITY_NORMAL)
@@ -70,29 +70,31 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	 * For lower duty cycles (e.g. 0), the PWM output is simply disabled to
 	 * allow an external pull-down resistor to hold the GPIO3/LTX pin low.
 	 */
-	duty_scale = div_u64(state->duty_cycle * 256, IQS620_PWM_PERIOD_NS);
+
+	if (state->duty_cycle < IQS620_PWM_PERIOD_NS)
+		duty_val = ((unsigned int)state->duty_cycle * 256) / IQS620_PWM_PERIOD_NS;
+	else
+		duty_val = 256;
 
 	mutex_lock(&iqs620_pwm->lock);
 
-	if (!state->enabled || !duty_scale) {
+	if (!state->enabled || !duty_val) {
 		ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
 					 IQS620_PWR_SETTINGS_PWM_OUT, 0);
 		if (ret)
 			goto err_mutex;
 	}
 
-	if (duty_scale) {
-		u8 duty_val = min_t(u64, duty_scale - 1, 0xff);
-
+	if (duty_val) {
 		ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE,
-				   duty_val);
+				   duty_val - 1);
 		if (ret)
 			goto err_mutex;
 
 		iqs620_pwm->duty_val = duty_val;
 	}
 
-	if (state->enabled && duty_scale) {
+	if (state->enabled && duty_val) {
 		ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
 					 IQS620_PWR_SETTINGS_PWM_OUT, 0xff);
 		if (ret)
-- 
2.29.2


  reply	other threads:[~2020-11-27 20:33 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-27 14:14 [PATCH] pwm: iqs620a: Fix overflow and optimize calculations Uwe Kleine-König
2020-11-27 20:10 ` Jeff LaBundy
2020-11-27 20:32   ` Uwe Kleine-König [this message]
2020-11-28  1:00     ` [PATCH v2] " Jeff LaBundy
2020-11-29 12:03       ` Uwe Kleine-König
2020-11-29 21:15         ` Jeff LaBundy

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=20201127203244.3439478-1-uwe@kleine-koenig.org \
    --to=uwe@kleine-koenig.org \
    --cc=jeff@labundy.com \
    --cc=kernel@pengutronix.de \
    --cc=lee.jones@linaro.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    /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.