Linux-Renesas-SoC Archive on lore.kernel.org
 help / Atom feed
* [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation
@ 2019-01-09  8:19 Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 1/4] pwm: rcar: Add support "atomic" API Yoshihiro Shimoda
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Yoshihiro Shimoda @ 2019-01-09  8:19 UTC (permalink / raw)
  To: thierry.reding; +Cc: linux-pwm, linux-renesas-soc, Yoshihiro Shimoda

This patch series adds support for PWM "atomic" API and improve
the clock calculation.

Changes from v2 [1]:
 - Add Acked-by of Uwe in patch [234]/4.
 - Modify a condition to support normal polarity only.
 - Fix possible to output wrong a duty cycle when disabling in patch 1/4.
 - Fix overflow value on 32-bit arch in patch 4/4.

Changes from v1 [2]:
 - Remove workaround code of output pseudo low level for now because it is
   rejected on the ML.
 - Add a condition for polarity because the HW doesn't support polarity change
   in patch 1/4.
 - Improve the clock calculation in patch 4/4.

[1]
https://patchwork.kernel.org/project/linux-renesas-soc/list/?series=63219

Remarks:
On the email thread of patch 2/4, we discuss about suspend/resume
handling and I suposed to improve it. However, I need more time
how to improve it. So, for now, I don't improve it on this patch series.

[2]
https://patchwork.kernel.org/project/linux-renesas-soc/list/?series=53193


Yoshihiro Shimoda (4):
  pwm: rcar: Add support "atomic" API
  pwm: rcar: Use "atomic" API on rcar_pwm_resume()
  pwm: rcar: remove legacy APIs
  pwm: rcar: improve calculation of divider

 drivers/pwm/pwm-rcar.c | 99 ++++++++++++++++++++++++--------------------------
 1 file changed, 48 insertions(+), 51 deletions(-)

-- 
1.9.1


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

* [PATCH v3 1/4] pwm: rcar: Add support "atomic" API
  2019-01-09  8:19 [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation Yoshihiro Shimoda
@ 2019-01-09  8:19 ` Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 2/4] pwm: rcar: Use "atomic" API on rcar_pwm_resume() Yoshihiro Shimoda
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Yoshihiro Shimoda @ 2019-01-09  8:19 UTC (permalink / raw)
  To: thierry.reding; +Cc: linux-pwm, linux-renesas-soc, Yoshihiro Shimoda

This patch adds support for "atomic" API. This behavior differs with
legacy APIs a little.

 Legacy APIs:
  The PWMCNT register will be updated in rcar_pwm_config() even if
  the PWM state is disabled.

 Atomic API:
  The PWMCNT register will be updated in rcar_pwm_apply() only if
  the PWM state is enabled. Otherwize, if a PWM runs with 30% duty
  cycles and the pwm_apply_state() is called with state->enabled = 0,
  ->duty_cycle = 60 and ->period = 100, this is possible to output
  a 60% duty cycle.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/pwm/pwm-rcar.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index a41812f..e3ab663 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -192,12 +192,49 @@ static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR);
 }
 
+static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			  struct pwm_state *state)
+{
+	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+	struct pwm_state cur_state;
+	int div, ret;
+
+	/* This HW/driver only supports normal polarity */
+	pwm_get_state(pwm, &cur_state);
+	if (state->polarity != PWM_POLARITY_NORMAL)
+		return -ENOTSUPP;
+
+	if (!state->enabled) {
+		rcar_pwm_disable(chip, pwm);
+		return 0;
+	}
+
+	div = rcar_pwm_get_clock_division(rp, state->period);
+	if (div < 0)
+		return div;
+
+	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
+
+	ret = rcar_pwm_set_counter(rp, div, state->duty_cycle, state->period);
+	if (!ret)
+		rcar_pwm_set_clock_control(rp, div);
+
+	/* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */
+	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR);
+
+	if (!ret && state->enabled)
+		ret = rcar_pwm_enable(chip, pwm);
+
+	return ret;
+}
+
 static const struct pwm_ops rcar_pwm_ops = {
 	.request = rcar_pwm_request,
 	.free = rcar_pwm_free,
 	.config = rcar_pwm_config,
 	.enable = rcar_pwm_enable,
 	.disable = rcar_pwm_disable,
+	.apply = rcar_pwm_apply,
 	.owner = THIS_MODULE,
 };
 
-- 
1.9.1


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

* [PATCH v3 2/4] pwm: rcar: Use "atomic" API on rcar_pwm_resume()
  2019-01-09  8:19 [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 1/4] pwm: rcar: Add support "atomic" API Yoshihiro Shimoda
@ 2019-01-09  8:19 ` Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 3/4] pwm: rcar: remove legacy APIs Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 4/4] pwm: rcar: improve calculation of divider Yoshihiro Shimoda
  3 siblings, 0 replies; 5+ messages in thread
From: Yoshihiro Shimoda @ 2019-01-09  8:19 UTC (permalink / raw)
  To: thierry.reding; +Cc: linux-pwm, linux-renesas-soc, Yoshihiro Shimoda

To remove legacy API related functions in the future, this patch
uses "atomic" related function instead. No change in behavior.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rcar.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index e3ab663..652a937 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -316,18 +316,16 @@ static int rcar_pwm_suspend(struct device *dev)
 static int rcar_pwm_resume(struct device *dev)
 {
 	struct pwm_device *pwm = rcar_pwm_dev_to_pwm_dev(dev);
+	struct pwm_state state;
 
 	if (!test_bit(PWMF_REQUESTED, &pwm->flags))
 		return 0;
 
 	pm_runtime_get_sync(dev);
 
-	rcar_pwm_config(pwm->chip, pwm, pwm->state.duty_cycle,
-			pwm->state.period);
-	if (pwm_is_enabled(pwm))
-		rcar_pwm_enable(pwm->chip, pwm);
+	pwm_get_state(pwm, &state);
 
-	return 0;
+	return rcar_pwm_apply(pwm->chip, pwm, &state);
 }
 #endif /* CONFIG_PM_SLEEP */
 static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops, rcar_pwm_suspend, rcar_pwm_resume);
-- 
1.9.1


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

* [PATCH v3 3/4] pwm: rcar: remove legacy APIs
  2019-01-09  8:19 [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 1/4] pwm: rcar: Add support "atomic" API Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 2/4] pwm: rcar: Use "atomic" API on rcar_pwm_resume() Yoshihiro Shimoda
@ 2019-01-09  8:19 ` Yoshihiro Shimoda
  2019-01-09  8:19 ` [PATCH v3 4/4] pwm: rcar: improve calculation of divider Yoshihiro Shimoda
  3 siblings, 0 replies; 5+ messages in thread
From: Yoshihiro Shimoda @ 2019-01-09  8:19 UTC (permalink / raw)
  To: thierry.reding; +Cc: linux-pwm, linux-renesas-soc, Yoshihiro Shimoda

This patch removes legacy APIs. Since rcar_pwm_{en,dis}able()
functions are reused on "atomic" API, this patch changes
the arguments of these functions. No change in behavior.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rcar.c | 44 ++++----------------------------------------
 1 file changed, 4 insertions(+), 40 deletions(-)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 652a937..1e13fbb 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -139,39 +139,8 @@ static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 	pm_runtime_put(chip->dev);
 }
 
-static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-			   int duty_ns, int period_ns)
+static int rcar_pwm_enable(struct rcar_pwm_chip *rp)
 {
-	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
-	int div, ret;
-
-	div = rcar_pwm_get_clock_division(rp, period_ns);
-	if (div < 0)
-		return div;
-
-	/*
-	 * Let the core driver set pwm->period if disabled and duty_ns == 0.
-	 * But, this driver should prevent to set the new duty_ns if current
-	 * duty_cycle is not set
-	 */
-	if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
-		return 0;
-
-	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
-
-	ret = rcar_pwm_set_counter(rp, div, duty_ns, period_ns);
-	if (!ret)
-		rcar_pwm_set_clock_control(rp, div);
-
-	/* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */
-	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR);
-
-	return ret;
-}
-
-static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
 	u32 value;
 
 	/* Don't enable the PWM device if CYC0 or PH0 is 0 */
@@ -185,10 +154,8 @@ static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	return 0;
 }
 
-static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+static void rcar_pwm_disable(struct rcar_pwm_chip *rp)
 {
-	struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
-
 	rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR);
 }
 
@@ -205,7 +172,7 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 		return -ENOTSUPP;
 
 	if (!state->enabled) {
-		rcar_pwm_disable(chip, pwm);
+		rcar_pwm_disable(rp);
 		return 0;
 	}
 
@@ -223,7 +190,7 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR);
 
 	if (!ret && state->enabled)
-		ret = rcar_pwm_enable(chip, pwm);
+		ret = rcar_pwm_enable(rp);
 
 	return ret;
 }
@@ -231,9 +198,6 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 static const struct pwm_ops rcar_pwm_ops = {
 	.request = rcar_pwm_request,
 	.free = rcar_pwm_free,
-	.config = rcar_pwm_config,
-	.enable = rcar_pwm_enable,
-	.disable = rcar_pwm_disable,
 	.apply = rcar_pwm_apply,
 	.owner = THIS_MODULE,
 };
-- 
1.9.1


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

* [PATCH v3 4/4] pwm: rcar: improve calculation of divider
  2019-01-09  8:19 [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation Yoshihiro Shimoda
                   ` (2 preceding siblings ...)
  2019-01-09  8:19 ` [PATCH v3 3/4] pwm: rcar: remove legacy APIs Yoshihiro Shimoda
@ 2019-01-09  8:19 ` Yoshihiro Shimoda
  3 siblings, 0 replies; 5+ messages in thread
From: Yoshihiro Shimoda @ 2019-01-09  8:19 UTC (permalink / raw)
  To: thierry.reding; +Cc: linux-pwm, linux-renesas-soc, Yoshihiro Shimoda

The rcar_pwm_get_clock_division() has a loop to calculate the divider,
but the value of div should be calculatable without a loop. So,
this patch improves it.

This algorithm is suggested by Uwe Kleine-König and Laurent Pinchart.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/pwm/pwm-rcar.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 1e13fbb..cfe7dd1 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -8,6 +8,8 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -68,19 +70,15 @@ static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data,
 static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
 {
 	unsigned long clk_rate = clk_get_rate(rp->clk);
-	unsigned long long max; /* max cycle / nanoseconds */
-	unsigned int div;
+	u64 div, tmp;
 
 	if (clk_rate == 0)
 		return -EINVAL;
 
-	for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
-		max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
-			(1 << div);
-		do_div(max, clk_rate);
-		if (period_ns <= max)
-			break;
-	}
+	div = (u64)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE;
+	tmp = (u64)period_ns * clk_rate + div - 1;
+	tmp = div64_u64(tmp, div);
+	div = ilog2(tmp - 1) + 1;
 
 	return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE;
 }
-- 
1.9.1


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

end of thread, back to index

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-09  8:19 [PATCH v3 0/4] pwm: rcar: Add support "atomic" API and improve calculation Yoshihiro Shimoda
2019-01-09  8:19 ` [PATCH v3 1/4] pwm: rcar: Add support "atomic" API Yoshihiro Shimoda
2019-01-09  8:19 ` [PATCH v3 2/4] pwm: rcar: Use "atomic" API on rcar_pwm_resume() Yoshihiro Shimoda
2019-01-09  8:19 ` [PATCH v3 3/4] pwm: rcar: remove legacy APIs Yoshihiro Shimoda
2019-01-09  8:19 ` [PATCH v3 4/4] pwm: rcar: improve calculation of divider Yoshihiro Shimoda

Linux-Renesas-SoC Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-renesas-soc/0 linux-renesas-soc/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-renesas-soc linux-renesas-soc/ https://lore.kernel.org/linux-renesas-soc \
		linux-renesas-soc@vger.kernel.org linux-renesas-soc@archiver.kernel.org
	public-inbox-index linux-renesas-soc


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-renesas-soc


AGPL code for this site: git clone https://public-inbox.org/ public-inbox