linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] pwm: meson: fix harware duty calculation
@ 2017-11-29  3:03 Yixun Lan
  2017-11-29  7:34 ` Jerome Brunet
  0 siblings, 1 reply; 2+ messages in thread
From: Yixun Lan @ 2017-11-29  3:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm, linux-amlogic
  Cc: Neil Armstrong, Jerome Brunet, Carlo Caione, Kevin Hilman,
	Yixun Lan, linux-arm-kernel, linux-kernel, Jian Hu

From: Jian Hu <jian.hu@amlogic.com>

The actual HIGH/LOW signal output from the PWM is equal to
the value programed to HW register plus one, this is designed by HW.

This fix should apply to all Meson SoC(include GX/GXL/GXBB, Meson6,8)

Fixes: 211ed630753d ("pwm: Add support for Meson PWM Controller")
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
---
 drivers/pwm/pwm-meson.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index d589331d1884..78d9b8c1a4bc 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -193,6 +193,11 @@ static int meson_pwm_calc(struct meson_pwm *meson,
 			break;
 	}
 
+	if (cnt < 2) {
+		dev_err(meson->chip.dev, "invalid period\n");
+		return -EINVAL;
+	}
+
 	if (pre_div == MISC_CLK_DIV_MASK) {
 		dev_err(meson->chip.dev, "unable to get period pre_div\n");
 		return -EINVAL;
@@ -201,19 +206,23 @@ static int meson_pwm_calc(struct meson_pwm *meson,
 	dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period,
 		pre_div, cnt);
 
+	/*
+	 * Due to the design of hardware, values of 'hi', 'lo' are 1 based
+	 * which mean the actual output from hardware is 'hi' + 1, 'lo' + 1
+	 */
 	if (duty == period) {
 		channel->pre_div = pre_div;
-		channel->hi = cnt;
+		channel->hi = cnt - 1;
 		channel->lo = 0;
 	} else if (duty == 0) {
 		channel->pre_div = pre_div;
 		channel->hi = 0;
-		channel->lo = cnt;
+		channel->lo = cnt - 1;
 	} else {
 		/* Then check is we can have the duty with the same pre_div */
 		duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
 						 fin_ps * (pre_div + 1));
-		if (duty_cnt > 0xffff) {
+		if (duty_cnt > 0xffff || !duty_cnt) {
 			dev_err(meson->chip.dev, "unable to get duty cycle\n");
 			return -EINVAL;
 		}
@@ -222,8 +231,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
 			duty, pre_div, duty_cnt);
 
 		channel->pre_div = pre_div;
-		channel->hi = duty_cnt;
-		channel->lo = cnt - duty_cnt;
+		channel->hi = duty_cnt - 1;
+		channel->lo = cnt - duty_cnt - 1;
 	}
 
 	return 0;
-- 
2.15.0

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] pwm: meson: fix harware duty calculation
  2017-11-29  3:03 [PATCH] pwm: meson: fix harware duty calculation Yixun Lan
@ 2017-11-29  7:34 ` Jerome Brunet
  0 siblings, 0 replies; 2+ messages in thread
From: Jerome Brunet @ 2017-11-29  7:34 UTC (permalink / raw)
  To: Yixun Lan, Thierry Reding, linux-pwm, linux-amlogic
  Cc: Neil Armstrong, Carlo Caione, Kevin Hilman, linux-arm-kernel,
	linux-kernel, Jian Hu

On Wed, 2017-11-29 at 11:03 +0800, Yixun Lan wrote:
> From: Jian Hu <jian.hu@amlogic.com>
> 
> The actual HIGH/LOW signal output from the PWM is equal to
> the value programed to HW register plus one, this is designed by HW.
> 
> This fix should apply to all Meson SoC(include GX/GXL/GXBB, Meson6,8)
> 
> Fixes: 211ed630753d ("pwm: Add support for Meson PWM Controller")
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
> ---
>  drivers/pwm/pwm-meson.c | 19 ++++++++++++++-----
>  1 file changed, 14 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
> index d589331d1884..78d9b8c1a4bc 100644
> --- a/drivers/pwm/pwm-meson.c
> +++ b/drivers/pwm/pwm-meson.c
> @@ -193,6 +193,11 @@ static int meson_pwm_calc(struct meson_pwm *meson,
>  			break;
>  	}
>  
> +	if (cnt < 2) {
> +		dev_err(meson->chip.dev, "invalid period\n");
> +		return -EINVAL;
> +	}
> +
>  	if (pre_div == MISC_CLK_DIV_MASK) {
>  		dev_err(meson->chip.dev, "unable to get period pre_div\n");
>  		return -EINVAL;
> @@ -201,19 +206,23 @@ static int meson_pwm_calc(struct meson_pwm *meson,
>  	dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period,
>  		pre_div, cnt);
>  
> +	/*
> +	 * Due to the design of hardware, values of 'hi', 'lo' are 1 based
> +	 * which mean the actual output from hardware is 'hi' + 1, 'lo' + 1
> +	 */
>  	if (duty == period) {
>  		channel->pre_div = pre_div;
> -		channel->hi = cnt;
> +		channel->hi = cnt - 1;
>  		channel->lo = 0;
>  	} else if (duty == 0) {
>  		channel->pre_div = pre_div;
>  		channel->hi = 0;
> -		channel->lo = cnt;
> +		channel->lo = cnt - 1;
>  	} else {
>  		/* Then check is we can have the duty with the same pre_div
> */
>  		duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
>  						 fin_ps * (pre_div + 1));
> -		if (duty_cnt > 0xffff) {
> +		if (duty_cnt > 0xffff || !duty_cnt) {

duty_cnt = 0 is a valid value here. It will be the case for duty != 0 but low
enough for the HW (calculation) to approximate the duty cycle to zero.

>  			dev_err(meson->chip.dev, "unable to get duty
> cycle\n");
>  			return -EINVAL;
>  		}
> @@ -222,8 +231,8 @@ static int meson_pwm_calc(struct meson_pwm *meson,
>  			duty, pre_div, duty_cnt);
>  
>  		channel->pre_div = pre_div;
> -		channel->hi = duty_cnt;
> -		channel->lo = cnt - duty_cnt;
> +		channel->hi = duty_cnt - 1;

As explained above, duty_cnt could be zero, you need to take care of this here

> +		channel->lo = cnt - duty_cnt - 1;

Same here, it is possible duty_cnt to be egual to cnt so you also need to be
careful here

>  	}
>  
>  	return 0;

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2017-11-29  7:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-29  3:03 [PATCH] pwm: meson: fix harware duty calculation Yixun Lan
2017-11-29  7:34 ` Jerome Brunet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).