Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH v5 02/46] backlight: pwm_bl: remove useless call to pwm_set_period()
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm
  Cc: Milo Kim, Kamil Debski, Heiko Stuebner, linux-doc, David Airlie,
	Mike Turquette, linux-fbdev, dri-devel, linux-kernel, linux-sunxi,
	Alexandre Belloni, Daniel Vetter, Lee Jones, linux-clk,
	linux-leds, Boris Brezillon, Krzysztof Kozlowski,
	linux-samsung-soc, Alexander Shiyan, Jonathan Corbet,
	Robert Jarzmik, lm-sensors, linux-rockchip, Chen-Yu Tsai,
	Tomi Valkeinen <tomi.valkeinen@
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon@free-electrons.com>

The PWM period will be set when calling pwm_config. Remove this useless
call to pwm_set_period(), which might mess up with the internal PWM state.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/video/backlight/pwm_bl.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 64f9e1b..a33a290 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -313,10 +313,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	 * via the PWM lookup table.
 	 */
 	pb->period = pwm_get_period(pb->pwm);
-	if (!pb->period && (data->pwm_period_ns > 0)) {
+	if (!pb->period && (data->pwm_period_ns > 0))
 		pb->period = data->pwm_period_ns;
-		pwm_set_period(pb->pwm, data->pwm_period_ns);
-	}
 
 	pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale);
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 03/46] backlight: lm3630a_bl: stop messing with the pwm->period field
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm
  Cc: Milo Kim, Kamil Debski, Heiko Stuebner, linux-doc, David Airlie,
	Mike Turquette, linux-fbdev, dri-devel, linux-kernel, linux-sunxi,
	Alexandre Belloni, Daniel Vetter, Lee Jones, linux-clk,
	linux-leds, Boris Brezillon, Krzysztof Kozlowski,
	linux-samsung-soc, Alexander Shiyan, Jonathan Corbet,
	Robert Jarzmik, lm-sensors, linux-rockchip, Chen-Yu Tsai,
	Tomi Valkeinen <tomi.valkeinen@
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon@free-electrons.com>

pwm->period field is not supposed to be changed by PWM users. The only
ones authorized to change it are the PWM core and PWM drivers.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/video/backlight/lm3630a_bl.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 35fe482..3d16bd6 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -162,7 +162,7 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip)
 
 static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
 {
-	unsigned int period = pwm_get_period(pchip->pwmd);
+	unsigned int period = pchip->pdata->pwm_period;
 	unsigned int duty = br * period / br_max;
 
 	pwm_config(pchip->pwmd, duty, period);
@@ -425,7 +425,6 @@ static int lm3630a_probe(struct i2c_client *client,
 			return PTR_ERR(pchip->pwmd);
 		}
 	}
-	pchip->pwmd->period = pdata->pwm_period;
 
 	/* interrupt enable  : irq 0 is not allowed */
 	pchip->irq = client->irq;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 04/46] pwm: get rid of pwm->lock
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

PWM devices are not protected against concurrent accesses. The lock in
pwm_device might let PWM users think it is, but it's actually only
protecting the enabled state.

Removing this lock should be fine as long as all PWM users are aware that
accesses to the PWM device have to be serialized, which seems to be the
case for all of them except the sysfs interface.
Patch the sysfs code by adding a lock to the pwm_export struct and making
sure it's taken for all accesses to the exported PWM device.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  | 19 ++++--------------
 drivers/pwm/sysfs.c | 57 ++++++++++++++++++++++++++++++++++++++++++-----------
 include/linux/pwm.h |  2 --
 3 files changed, 50 insertions(+), 28 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 7831bc6..7c330ff 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -269,7 +269,6 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
 		pwm->pwm = chip->base + i;
 		pwm->hwpwm = i;
 		pwm->polarity = polarity;
-		mutex_init(&pwm->lock);
 
 		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
 	}
@@ -474,22 +473,16 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
 	if (!pwm->chip->ops->set_polarity)
 		return -ENOSYS;
 
-	mutex_lock(&pwm->lock);
-
-	if (pwm_is_enabled(pwm)) {
-		err = -EBUSY;
-		goto unlock;
-	}
+	if (pwm_is_enabled(pwm))
+		return -EBUSY;
 
 	err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
 	if (err)
-		goto unlock;
+		return err;
 
 	pwm->polarity = polarity;
 
-unlock:
-	mutex_unlock(&pwm->lock);
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(pwm_set_polarity);
 
@@ -506,16 +499,12 @@ int pwm_enable(struct pwm_device *pwm)
 	if (!pwm)
 		return -EINVAL;
 
-	mutex_lock(&pwm->lock);
-
 	if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
 		err = pwm->chip->ops->enable(pwm->chip, pwm);
 		if (err)
 			clear_bit(PWMF_ENABLED, &pwm->flags);
 	}
 
-	mutex_unlock(&pwm->lock);
-
 	return err;
 }
 EXPORT_SYMBOL_GPL(pwm_enable);
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 9c90886..ab28c89 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -26,6 +26,7 @@
 struct pwm_export {
 	struct device child;
 	struct pwm_device *pwm;
+	struct mutex lock;
 };
 
 static struct pwm_export *child_to_pwm_export(struct device *child)
@@ -44,16 +45,23 @@ static ssize_t period_show(struct device *child,
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	const struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	const struct pwm_device *pwm = export->pwm;
+	unsigned int period;
+
+	mutex_lock(&export->lock);
+	period = pwm_get_period(pwm);
+	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%u\n", pwm_get_period(pwm));
+	return sprintf(buf, "%u\n", period);
 }
 
 static ssize_t period_store(struct device *child,
 			    struct device_attribute *attr,
 			    const char *buf, size_t size)
 {
-	struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	struct pwm_device *pwm = export->pwm;
 	unsigned int val;
 	int ret;
 
@@ -61,7 +69,9 @@ static ssize_t period_store(struct device *child,
 	if (ret)
 		return ret;
 
+	mutex_lock(&export->lock);
 	ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val);
+	mutex_unlock(&export->lock);
 
 	return ret ? : size;
 }
@@ -70,16 +80,23 @@ static ssize_t duty_cycle_show(struct device *child,
 			       struct device_attribute *attr,
 			       char *buf)
 {
-	const struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	const struct pwm_device *pwm = export->pwm;
+	unsigned int duty;
+
+	mutex_lock(&export->lock);
+	duty = pwm_get_duty_cycle(pwm);
+	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
+	return sprintf(buf, "%u\n", duty);
 }
 
 static ssize_t duty_cycle_store(struct device *child,
 				struct device_attribute *attr,
 				const char *buf, size_t size)
 {
-	struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	struct pwm_device *pwm = export->pwm;
 	unsigned int val;
 	int ret;
 
@@ -87,7 +104,9 @@ static ssize_t duty_cycle_store(struct device *child,
 	if (ret)
 		return ret;
 
+	mutex_lock(&export->lock);
 	ret = pwm_config(pwm, val, pwm_get_period(pwm));
+	mutex_unlock(&export->lock);
 
 	return ret ? : size;
 }
@@ -96,22 +115,30 @@ static ssize_t enable_show(struct device *child,
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	const struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	const struct pwm_device *pwm = export->pwm;
+	bool enabled;
+
+	mutex_lock(&export->lock);
+	enabled = pwm_is_enabled(pwm);
+	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%d\n", pwm_is_enabled(pwm));
+	return sprintf(buf, "%d\n", enabled);
 }
 
 static ssize_t enable_store(struct device *child,
 			    struct device_attribute *attr,
 			    const char *buf, size_t size)
 {
-	struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	struct pwm_device *pwm = export->pwm;
 	int val, ret;
 
 	ret = kstrtoint(buf, 0, &val);
 	if (ret)
 		return ret;
 
+	mutex_lock(&export->lock);
 	switch (val) {
 	case 0:
 		pwm_disable(pwm);
@@ -123,6 +150,7 @@ static ssize_t enable_store(struct device *child,
 		ret = -EINVAL;
 		break;
 	}
+	mutex_unlock(&export->lock);
 
 	return ret ? : size;
 }
@@ -131,9 +159,11 @@ static ssize_t polarity_show(struct device *child,
 			     struct device_attribute *attr,
 			     char *buf)
 {
-	const struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	const struct pwm_device *pwm = export->pwm;
 	const char *polarity = "unknown";
 
+	mutex_lock(&export->lock);
 	switch (pwm_get_polarity(pwm)) {
 	case PWM_POLARITY_NORMAL:
 		polarity = "normal";
@@ -143,6 +173,7 @@ static ssize_t polarity_show(struct device *child,
 		polarity = "inversed";
 		break;
 	}
+	mutex_unlock(&export->lock);
 
 	return sprintf(buf, "%s\n", polarity);
 }
@@ -151,7 +182,8 @@ static ssize_t polarity_store(struct device *child,
 			      struct device_attribute *attr,
 			      const char *buf, size_t size)
 {
-	struct pwm_device *pwm = child_to_pwm_device(child);
+	struct pwm_export *export = child_to_pwm_export(child);
+	struct pwm_device *pwm = export->pwm;
 	enum pwm_polarity polarity;
 	int ret;
 
@@ -162,7 +194,9 @@ static ssize_t polarity_store(struct device *child,
 	else
 		return -EINVAL;
 
+	mutex_lock(&export->lock);
 	ret = pwm_set_polarity(pwm, polarity);
+	mutex_unlock(&export->lock);
 
 	return ret ? : size;
 }
@@ -203,6 +237,7 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
 	}
 
 	export->pwm = pwm;
+	mutex_init(&export->lock);
 
 	export->child.release = pwm_export_release;
 	export->child.parent = parent;
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index cfc3ed4..6555f01 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -88,7 +88,6 @@ enum {
  * @pwm: global index of the PWM device
  * @chip: PWM chip providing this PWM device
  * @chip_data: chip-private data associated with the PWM device
- * @lock: used to serialize accesses to the PWM device where necessary
  * @period: period of the PWM signal (in nanoseconds)
  * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
  * @polarity: polarity of the PWM signal
@@ -100,7 +99,6 @@ struct pwm_device {
 	unsigned int pwm;
 	struct pwm_chip *chip;
 	void *chip_data;
-	struct mutex lock;
 
 	unsigned int period;
 	unsigned int duty_cycle;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 05/46] pwm: introduce the pwm_args concept
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Currently the PWM core mixes the current PWM state with the per-platform
reference config (specified through the PWM lookup table, DT definition or
directly hardcoded in PWM drivers).

Create a pwm_args struct to store this reference config, so that PWM users
can differentiate the current config from the reference one.

Patch all places where pwm->args should be initialized. We keep the
pwm_set_polarity/period() calls until all PWM users are patched to
use pwm_args instead of pwm_get_period/polarity().

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c         | 13 +++++++++----
 drivers/pwm/pwm-clps711x.c |  3 ++-
 drivers/pwm/pwm-pxa.c      |  1 +
 include/linux/pwm.h        | 26 ++++++++++++++++++++++++++
 4 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 7c330ff..cd55d61 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -146,12 +146,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
 	if (IS_ERR(pwm))
 		return pwm;
 
-	pwm_set_period(pwm, args->args[1]);
+	pwm->args.period = args->args[1];
+	pwm_set_period(pwm, pwm->args.period);
 
 	if (args->args[2] & PWM_POLARITY_INVERTED)
-		pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+		pwm->args.polarity = PWM_POLARITY_INVERSED;
 	else
-		pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+		pwm->args.polarity = PWM_POLARITY_NORMAL;
+	pwm_set_polarity(pwm, pwm->args.polarity);
 
 	return pwm;
 }
@@ -172,7 +174,8 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 	if (IS_ERR(pwm))
 		return pwm;
 
-	pwm_set_period(pwm, args->args[1]);
+	pwm->args.period = args->args[1];
+	pwm_set_period(pwm, pwm->args.period);
 
 	return pwm;
 }
@@ -740,6 +743,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
 	if (IS_ERR(pwm))
 		goto out;
 
+	pwm->args.period = chosen->period;
+	pwm->args.polarity = chosen->polarity;
 	pwm_set_period(pwm, chosen->period);
 	pwm_set_polarity(pwm, chosen->polarity);
 
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
index a80c108..807a48d 100644
--- a/drivers/pwm/pwm-clps711x.c
+++ b/drivers/pwm/pwm-clps711x.c
@@ -60,7 +60,8 @@ static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 		return -EINVAL;
 
 	/* Store constant period value */
-	pwm_set_period(pwm, DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq));
+	pwm->args.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq);
+	pwm_set_period(pwm, pwm->args.period);
 
 	return 0;
 }
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index cb2f702..3fcc886 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -160,6 +160,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 	if (IS_ERR(pwm))
 		return pwm;
 
+	pwm->args.period = args->args[0];
 	pwm_set_period(pwm, args->args[0]);
 
 	return pwm;
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 6555f01..ed65354 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -74,6 +74,23 @@ enum pwm_polarity {
 	PWM_POLARITY_INVERSED,
 };
 
+/**
+ * struct pwm_args - PWM arguments
+ * @period: reference period
+ * @polarity: reference polarity
+ *
+ * This structure describe board-dependent arguments attached to a PWM
+ * device. Those arguments are usually retrieved from the PWM lookup table or
+ * DT definition.
+ * This should not be confused with the PWM state: PWM args not representing
+ * the current PWM state, but the configuration the PWM user plan to use
+ * on this PWM device.
+ */
+struct pwm_args {
+	unsigned int period;
+	enum pwm_polarity polarity;
+};
+
 enum {
 	PWMF_REQUESTED = 1 << 0,
 	PWMF_ENABLED = 1 << 1,
@@ -91,6 +108,7 @@ enum {
  * @period: period of the PWM signal (in nanoseconds)
  * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
  * @polarity: polarity of the PWM signal
+ * @args: PWM arguments
  */
 struct pwm_device {
 	const char *label;
@@ -103,6 +121,8 @@ struct pwm_device {
 	unsigned int period;
 	unsigned int duty_cycle;
 	enum pwm_polarity polarity;
+
+	struct pwm_args args;
 };
 
 static inline bool pwm_is_enabled(const struct pwm_device *pwm)
@@ -142,6 +162,12 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
 	return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
 }
 
+static inline void pwm_get_args(const struct pwm_device *pwm,
+				struct pwm_args *args)
+{
+	*args = pwm->args;
+}
+
 /**
  * struct pwm_ops - PWM controller operations
  * @request: optional hook for requesting a PWM
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 06/46] pwm: use pwm_get/set_xxx() helpers where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Use pwm_get/set_xxx() helpers instead of directly accessing the pwm->xxx
field. Doing that will ease adaptation of the PWM framework to support
atomic update.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
Patch generated with the following coccinelle script:

--->8---
virtual patch

@@
struct pwm_device *p;
expression e;
@@
(
-(p)->polarity = e;
+pwm_set_polarity(p, e);
|
-(p)->polarity
+pwm_get_polarity(p)
|
-(p)->period = e;
+pwm_set_period(p, e);
|
-(p)->period
+pwm_get_period(p)
|
-(p)->duty_cycle = e;
+pwm_set_duty_cycle(p, e);
|
-(p)->duty_cycle
+pwm_get_duty_cycle(p)
)
--->8---
---
 drivers/pwm/pwm-crc.c          | 2 +-
 drivers/pwm/pwm-lpc18xx-sct.c  | 2 +-
 drivers/pwm/pwm-omap-dmtimer.c | 2 +-
 drivers/pwm/pwm-sun4i.c        | 3 ++-
 4 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 7101c70..bd0ebd0 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -75,7 +75,7 @@ static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
 		return -EINVAL;
 	}
 
-	if (pwm->period != period_ns) {
+	if (pwm_get_period(pwm) != period_ns) {
 		int clk_div;
 
 		/* changing the clk divisor, need to disable fisrt */
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index 9861fed..19dc64c 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -249,7 +249,7 @@ static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 			   LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event),
 			   LPC18XX_PWM_EVSTATEMSK_ALL);
 
-	if (pwm->polarity = PWM_POLARITY_NORMAL) {
+	if (pwm_get_polarity(pwm) = PWM_POLARITY_NORMAL) {
 		set_event = lpc18xx_pwm->period_event;
 		clear_event = lpc18xx_data->duty_event;
 		res_action = LPC18XX_PWM_RES_SET;
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index b7e6ecb..3e95090 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -192,7 +192,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 		load_value, load_value,	match_value, match_value);
 
 	omap->pdata->set_pwm(omap->dm_timer,
-			      pwm->polarity = PWM_POLARITY_INVERSED,
+			      pwm_get_polarity(pwm) = PWM_POLARITY_INVERSED,
 			      true,
 			      PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
 
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 67af9f6..03a99a5 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -354,7 +354,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 	val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
 	for (i = 0; i < pwm->chip.npwm; i++)
 		if (!(val & BIT_CH(PWM_ACT_STATE, i)))
-			pwm->chip.pwms[i].polarity = PWM_POLARITY_INVERSED;
+			pwm_set_polarity(&pwm->chip.pwms[i],
+					 PWM_POLARITY_INVERSED);
 	clk_disable_unprepare(pwm->clk);
 
 	return 0;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 07/46] clk: pwm: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/clk/clk-pwm.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c
index 8830458..ebcd738 100644
--- a/drivers/clk/clk-pwm.c
+++ b/drivers/clk/clk-pwm.c
@@ -56,6 +56,7 @@ static const struct clk_ops clk_pwm_ops = {
 static int clk_pwm_probe(struct platform_device *pdev)
 {
 	struct device_node *node = pdev->dev.of_node;
+	struct pwm_args pargs = { };
 	struct clk_init_data init;
 	struct clk_pwm *clk_pwm;
 	struct pwm_device *pwm;
@@ -71,22 +72,23 @@ static int clk_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(pwm))
 		return PTR_ERR(pwm);
 
-	if (!pwm->period) {
+	pwm_get_args(pwm, &pargs);
+	if (!pargs.period) {
 		dev_err(&pdev->dev, "invalid PWM period\n");
 		return -EINVAL;
 	}
 
 	if (of_property_read_u32(node, "clock-frequency", &clk_pwm->fixed_rate))
-		clk_pwm->fixed_rate = NSEC_PER_SEC / pwm->period;
+		clk_pwm->fixed_rate = NSEC_PER_SEC / pargs.period;
 
-	if (pwm->period != NSEC_PER_SEC / clk_pwm->fixed_rate &&
-	    pwm->period != DIV_ROUND_UP(NSEC_PER_SEC, clk_pwm->fixed_rate)) {
+	if (pargs.period != NSEC_PER_SEC / clk_pwm->fixed_rate &&
+	    pargs.period != DIV_ROUND_UP(NSEC_PER_SEC, clk_pwm->fixed_rate)) {
 		dev_err(&pdev->dev,
 			"clock-frequency does not match PWM period\n");
 		return -EINVAL;
 	}
 
-	ret = pwm_config(pwm, (pwm->period + 1) >> 1, pwm->period);
+	ret = pwm_config(pwm, (pargs.period + 1) >> 1, pargs.period);
 	if (ret < 0)
 		return ret;
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 08/46] hwmon: pwm-fan: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm
  Cc: Mike Turquette, Stephen Boyd, linux-clk, Mark Brown,
	Liam Girdwood, Kamil Debski, lm-sensors, Jean Delvare,
	Guenter Roeck, Dmitry Torokhov, linux-input, Bryan Wu,
	Richard Purdie, Jacek Anaszewski, linux-leds, Maxime Ripard,
	Chen-Yu Tsai, linux-sunxi, Joachim Eastwood, Thomas Petazzoni,
	Heiko Stuebner, linux-rockchip, Jingoo Han, Lee Jones, linux-fbd
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon@free-electrons.com>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/hwmon/pwm-fan.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 3e23003..82c5656 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -40,15 +40,18 @@ struct pwm_fan_ctx {
 
 static int  __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
 {
+	struct pwm_args pargs = { };
 	unsigned long duty;
 	int ret = 0;
 
+	pwm_get_args(ctx->pwm, &pargs);
+
 	mutex_lock(&ctx->lock);
 	if (ctx->pwm_value = pwm)
 		goto exit_set_pwm_err;
 
-	duty = DIV_ROUND_UP(pwm * (ctx->pwm->period - 1), MAX_PWM);
-	ret = pwm_config(ctx->pwm, duty, ctx->pwm->period);
+	duty = DIV_ROUND_UP(pwm * (pargs.period - 1), MAX_PWM);
+	ret = pwm_config(ctx->pwm, duty, pargs.period);
 	if (ret)
 		goto exit_set_pwm_err;
 
@@ -214,6 +217,7 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
 static int pwm_fan_probe(struct platform_device *pdev)
 {
 	struct thermal_cooling_device *cdev;
+	struct pwm_args pargs = { };
 	struct pwm_fan_ctx *ctx;
 	struct device *hwmon;
 	int duty_cycle;
@@ -234,10 +238,11 @@ static int pwm_fan_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ctx);
 
 	/* Set duty cycle to maximum allowed */
-	duty_cycle = ctx->pwm->period - 1;
+	pwm_get_args(ctx->pwm, &pargs);
+	duty_cycle = pargs.period - 1;
 	ctx->pwm_value = MAX_PWM;
 
-	ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->period);
+	ret = pwm_config(ctx->pwm, duty_cycle, pargs.period);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to configure PWM\n");
 		return ret;
@@ -303,14 +308,16 @@ static int pwm_fan_suspend(struct device *dev)
 static int pwm_fan_resume(struct device *dev)
 {
 	struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	struct pwm_args pargs = { };
 	unsigned long duty;
 	int ret;
 
 	if (ctx->pwm_value = 0)
 		return 0;
 
-	duty = DIV_ROUND_UP(ctx->pwm_value * (ctx->pwm->period - 1), MAX_PWM);
-	ret = pwm_config(ctx->pwm, duty, ctx->pwm->period);
+	pwm_get_args(ctx->pwm, &pargs);
+	duty = DIV_ROUND_UP(ctx->pwm_value * (pargs.period - 1), MAX_PWM);
+	ret = pwm_config(ctx->pwm, duty, pargs.period);
 	if (ret)
 		return ret;
 	return pwm_enable(ctx->pwm);
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 09/46] misc: max77693-haptic: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/input/misc/max77693-haptic.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 6d96bff..cf6aac0 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -70,10 +70,13 @@ struct max77693_haptic {
 
 static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
 {
-	int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2;
+	struct pwm_args pargs = { };
+	int delta;
 	int error;
 
-	error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
+	pwm_get_args(haptic->pwm_dev, &pargs);
+	delta = (pargs.period + haptic->pwm_duty) / 2;
+	error = pwm_config(haptic->pwm_dev, delta, pargs.period);
 	if (error) {
 		dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
 		return error;
@@ -234,6 +237,7 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
 				       struct ff_effect *effect)
 {
 	struct max77693_haptic *haptic = input_get_drvdata(dev);
+	struct pwm_args pargs = { };
 	u64 period_mag_multi;
 
 	haptic->magnitude = effect->u.rumble.strong_magnitude;
@@ -245,7 +249,8 @@ static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
 	 * The formula to convert magnitude to pwm_duty as follows:
 	 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
 	 */
-	period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude;
+	pwm_get_args(haptic->pwm_dev, &pargs);
+	period_mag_multi = (u64)pargs.period * haptic->magnitude;
 	haptic->pwm_duty = (unsigned int)(period_mag_multi >>
 						MAX_MAGNITUDE_SHIFT);
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 10/46] leds: pwm: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/leds/leds-pwm.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 4783bac..b48231c 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -91,6 +91,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 		       struct led_pwm *led, struct device_node *child)
 {
 	struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
+	struct pwm_args pargs = { };
 	int ret;
 
 	led_data->active_low = led->active_low;
@@ -117,7 +118,8 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
 	else
 		led_data->cdev.brightness_set_blocking = led_pwm_set_blocking;
 
-	led_data->period = pwm_get_period(led_data->pwm);
+	pwm_get_args(led_data->pwm, &pargs);
+	led_data->period = pargs.period;
 	if (!led_data->period && (led->pwm_period_ns > 0))
 		led_data->period = led->pwm_period_ns;
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 11/46] regulator: pwm: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/regulator/pwm-regulator.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 4689d62..9154c47 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -59,16 +59,16 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
 					 unsigned selector)
 {
 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
-	unsigned int pwm_reg_period;
+	struct pwm_args pargs = { };
 	int dutycycle;
 	int ret;
 
-	pwm_reg_period = pwm_get_period(drvdata->pwm);
+	pwm_get_args(drvdata->pwm, &pargs);
 
-	dutycycle = (pwm_reg_period *
+	dutycycle = (pargs.period *
 		    drvdata->duty_cycle_table[selector].dutycycle) / 100;
 
-	ret = pwm_config(drvdata->pwm, dutycycle, pwm_reg_period);
+	ret = pwm_config(drvdata->pwm, dutycycle, pargs.period);
 	if (ret) {
 		dev_err(&rdev->dev, "Failed to configure PWM\n");
 		return ret;
@@ -138,13 +138,15 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
 {
 	struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
 	unsigned int ramp_delay = rdev->constraints->ramp_delay;
-	unsigned int period = pwm_get_period(drvdata->pwm);
+	struct pwm_args pargs = { };
 	int duty_cycle;
 	int ret;
 
+	pwm_get_args(drvdata->pwm, &pargs);
 	duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV);
 
-	ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period);
+	ret = pwm_config(drvdata->pwm, (pargs.period / 100) * duty_cycle,
+			 pargs.period);
 	if (ret) {
 		dev_err(&rdev->dev, "Failed to configure PWM\n");
 		return ret;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 12/46] fbdev: ssd1307fb: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm
  Cc: Mike Turquette, Stephen Boyd, linux-clk, Mark Brown,
	Liam Girdwood, Kamil Debski, lm-sensors, Jean Delvare,
	Guenter Roeck, Dmitry Torokhov, linux-input, Bryan Wu,
	Richard Purdie, Jacek Anaszewski, linux-leds, Maxime Ripard,
	Chen-Yu Tsai, linux-sunxi, Joachim Eastwood, Thomas Petazzoni,
	Heiko Stuebner, linux-rockchip, Jingoo Han, Lee Jones, linux-fbd
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon@free-electrons.com>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/video/fbdev/ssd1307fb.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index fa34808..df9c63a 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -286,6 +286,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
 {
 	int ret;
 	u32 precharge, dclk, com_invdir, compins;
+	struct pwm_args pargs = { };
 
 	if (par->device_info->need_pwm) {
 		par->pwm = pwm_get(&par->client->dev, NULL);
@@ -294,7 +295,8 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
 			return PTR_ERR(par->pwm);
 		}
 
-		par->pwm_period = pwm_get_period(par->pwm);
+		pwm_get_args(par->pwm, &pargs);
+		par->pwm_period = pargs.period;
 		/* Enable the PWM */
 		pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
 		pwm_enable(par->pwm);
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 13/46] backlight: pwm_bl: use pwm_get_args() where appropriate
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM framework has clarified the concept of reference PWM config
(the platform dependent config retrieved from the DT or the PWM
lookup table) and real PWM state.

Use pwm_get_args() when the PWM user wants to retrieve this reference
config and not the current state.

This is part of the rework allowing the PWM framework to support
hardware readout and expose real PWM state even when the PWM has
just been requested (before the user calls pwm_config/enable/disable()).

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/video/backlight/pwm_bl.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index a33a290..2479c11 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -201,6 +201,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	struct device_node *node = pdev->dev.of_node;
 	struct pwm_bl_data *pb;
 	int initial_blank = FB_BLANK_UNBLANK;
+	struct pwm_args pargs = { };
 	int ret;
 
 	if (!data) {
@@ -312,7 +313,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	 * set the period from platform data if it has not already been set
 	 * via the PWM lookup table.
 	 */
-	pb->period = pwm_get_period(pb->pwm);
+	pwm_get_args(pb->pwm, &pargs);
+	pb->period = pargs.period;
 	if (!pb->period && (data->pwm_period_ns > 0))
 		pb->period = data->pwm_period_ns;
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 14/46] pwm: keep PWM state in sync with hardware state
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Before the introduction of pwm_args, the core and some drivers were
resetting the PWM period and polarity states to the reference values
(those provided through the DT, a PWM lookup table or hardcoded in the
driver).

Now that all PWM users are correctly using pwm_args to configure their
PWM device, we can safely remove some pwm_set_period/polarity() calls.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c         | 5 -----
 drivers/pwm/pwm-clps711x.c | 1 -
 drivers/pwm/pwm-pxa.c      | 1 -
 3 files changed, 7 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index cd55d61..6433059 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -147,13 +147,11 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
 		return pwm;
 
 	pwm->args.period = args->args[1];
-	pwm_set_period(pwm, pwm->args.period);
 
 	if (args->args[2] & PWM_POLARITY_INVERTED)
 		pwm->args.polarity = PWM_POLARITY_INVERSED;
 	else
 		pwm->args.polarity = PWM_POLARITY_NORMAL;
-	pwm_set_polarity(pwm, pwm->args.polarity);
 
 	return pwm;
 }
@@ -175,7 +173,6 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 		return pwm;
 
 	pwm->args.period = args->args[1];
-	pwm_set_period(pwm, pwm->args.period);
 
 	return pwm;
 }
@@ -745,8 +742,6 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
 
 	pwm->args.period = chosen->period;
 	pwm->args.polarity = chosen->polarity;
-	pwm_set_period(pwm, chosen->period);
-	pwm_set_polarity(pwm, chosen->polarity);
 
 out:
 	mutex_unlock(&pwm_lookup_lock);
diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
index 807a48d..7d33542 100644
--- a/drivers/pwm/pwm-clps711x.c
+++ b/drivers/pwm/pwm-clps711x.c
@@ -61,7 +61,6 @@ static int clps711x_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	/* Store constant period value */
 	pwm->args.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, freq);
-	pwm_set_period(pwm, pwm->args.period);
 
 	return 0;
 }
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index 3fcc886..58b709f 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -161,7 +161,6 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
 		return pwm;
 
 	pwm->args.period = args->args[0];
-	pwm_set_period(pwm, args->args[0]);
 
 	return pwm;
 }
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 15/46] pwm: introduce the pwm_state concept
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The PWM state, represented by its period, duty_cycle and polarity,
is currently directly stored in the PWM device.
Declare a pwm_state structure embedding those field so that we can later
use this struct to atomically update all the PWM parameters at once.

All pwm_get_xxx() helpers are now implemented as wrappers around
pwm_get_state().

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  |  8 ++++----
 include/linux/pwm.h | 54 +++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 6433059..f3f91e7 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -268,7 +268,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
 		pwm->chip = chip;
 		pwm->pwm = chip->base + i;
 		pwm->hwpwm = i;
-		pwm->polarity = polarity;
+		pwm->state.polarity = polarity;
 
 		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
 	}
@@ -446,8 +446,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 	if (err)
 		return err;
 
-	pwm->duty_cycle = duty_ns;
-	pwm->period = period_ns;
+	pwm->state.duty_cycle = duty_ns;
+	pwm->state.period = period_ns;
 
 	return 0;
 }
@@ -480,7 +480,7 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
 	if (err)
 		return err;
 
-	pwm->polarity = polarity;
+	pwm->state.polarity = polarity;
 
 	return 0;
 }
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index ed65354..f0f0f37 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -97,6 +97,18 @@ enum {
 	PWMF_EXPORTED = 1 << 2,
 };
 
+/*
+ * struct pwm_state - state of a PWM channel
+ * @period: PWM period (in nanoseconds)
+ * @duty_cycle: PWM duty cycle (in nanoseconds)
+ * @polarity: PWM polarity
+ */
+struct pwm_state {
+	unsigned int period;
+	unsigned int duty_cycle;
+	enum pwm_polarity polarity;
+};
+
 /**
  * struct pwm_device - PWM channel object
  * @label: name of the PWM device
@@ -105,10 +117,8 @@ enum {
  * @pwm: global index of the PWM device
  * @chip: PWM chip providing this PWM device
  * @chip_data: chip-private data associated with the PWM device
- * @period: period of the PWM signal (in nanoseconds)
- * @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
- * @polarity: polarity of the PWM signal
  * @args: PWM arguments
+ * @state: curent PWM channel state
  */
 struct pwm_device {
 	const char *label;
@@ -118,13 +128,21 @@ struct pwm_device {
 	struct pwm_chip *chip;
 	void *chip_data;
 
-	unsigned int period;
-	unsigned int duty_cycle;
-	enum pwm_polarity polarity;
-
 	struct pwm_args args;
+	struct pwm_state state;
 };
 
+/**
+ * pwm_get_state() - retrieve the current PWM state
+ * @pwm: PWM device
+ * @state: state to fill with the current PWM state
+ */
+static inline void pwm_get_state(const struct pwm_device *pwm,
+				 struct pwm_state *state)
+{
+	*state = pwm->state;
+}
+
 static inline bool pwm_is_enabled(const struct pwm_device *pwm)
 {
 	return test_bit(PWMF_ENABLED, &pwm->flags);
@@ -133,23 +151,31 @@ static inline bool pwm_is_enabled(const struct pwm_device *pwm)
 static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
 {
 	if (pwm)
-		pwm->period = period;
+		pwm->state.period = period;
 }
 
 static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
 {
-	return pwm ? pwm->period : 0;
+	struct pwm_state pstate;
+
+	pwm_get_state(pwm, &pstate);
+
+	return pstate.period;
 }
 
 static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
 {
 	if (pwm)
-		pwm->duty_cycle = duty;
+		pwm->state.duty_cycle = duty;
 }
 
 static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
 {
-	return pwm ? pwm->duty_cycle : 0;
+	struct pwm_state pstate;
+
+	pwm_get_state(pwm, &pstate);
+
+	return pstate.duty_cycle;
 }
 
 /*
@@ -159,7 +185,11 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
 
 static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
 {
-	return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
+	struct pwm_state pstate;
+
+	pwm_get_state(pwm, &pstate);
+
+	return pstate.polarity;
 }
 
 static inline void pwm_get_args(const struct pwm_device *pwm,
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 16/46] pwm: move the enabled/disabled info into pwm_state
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Prepare the transition to PWM atomic update by moving the enabled/disabled
state into the pwm_state struct. This way we can easily update the whole
PWM state by copying the new state in the ->state field.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  | 13 +++++++++----
 include/linux/pwm.h | 11 ++++++++---
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index f3f91e7..c240b54 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -499,10 +499,10 @@ int pwm_enable(struct pwm_device *pwm)
 	if (!pwm)
 		return -EINVAL;
 
-	if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
+	if (!pwm_is_enabled(pwm)) {
 		err = pwm->chip->ops->enable(pwm->chip, pwm);
-		if (err)
-			clear_bit(PWMF_ENABLED, &pwm->flags);
+		if (!err)
+			pwm->state.enabled = true;
 	}
 
 	return err;
@@ -515,8 +515,13 @@ EXPORT_SYMBOL_GPL(pwm_enable);
  */
 void pwm_disable(struct pwm_device *pwm)
 {
-	if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+	if (!pwm)
+		return;
+
+	if (pwm_is_enabled(pwm)) {
 		pwm->chip->ops->disable(pwm->chip, pwm);
+		pwm->state.enabled = false;
+	}
 }
 EXPORT_SYMBOL_GPL(pwm_disable);
 
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index f0f0f37..55bf463 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -93,8 +93,7 @@ struct pwm_args {
 
 enum {
 	PWMF_REQUESTED = 1 << 0,
-	PWMF_ENABLED = 1 << 1,
-	PWMF_EXPORTED = 1 << 2,
+	PWMF_EXPORTED = 1 << 1,
 };
 
 /*
@@ -102,11 +101,13 @@ enum {
  * @period: PWM period (in nanoseconds)
  * @duty_cycle: PWM duty cycle (in nanoseconds)
  * @polarity: PWM polarity
+ * @enabled: PWM enabled status
  */
 struct pwm_state {
 	unsigned int period;
 	unsigned int duty_cycle;
 	enum pwm_polarity polarity;
+	bool enabled;
 };
 
 /**
@@ -145,7 +146,11 @@ static inline void pwm_get_state(const struct pwm_device *pwm,
 
 static inline bool pwm_is_enabled(const struct pwm_device *pwm)
 {
-	return test_bit(PWMF_ENABLED, &pwm->flags);
+	struct pwm_state pstate;
+
+	pwm_get_state(pwm, &pstate);
+
+	return pstate.enabled;
 }
 
 static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 17/46] pwm: add the PWM initial state retrieval infra
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Add a ->get_state() function to the pwm_ops struct to let PWM drivers
initialize the PWM state attached to a PWM device.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  | 3 +++
 include/linux/pwm.h | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c240b54..a909c64 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -270,6 +270,9 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
 		pwm->hwpwm = i;
 		pwm->state.polarity = polarity;
 
+		if (chip->ops->get_state)
+			chip->ops->get_state(chip, pwm, &pwm->state);
+
 		radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
 	}
 
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 55bf463..ceedcf8 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -211,6 +211,9 @@ static inline void pwm_get_args(const struct pwm_device *pwm,
  * @set_polarity: configure the polarity of this PWM
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
+ * @get_state: get the current PWM state. This function is only
+ *	       called once per PWM device when the PWM chip is
+ *	       registered.
  * @dbg_show: optional routine to show contents in debugfs
  * @owner: helps prevent removal of modules exporting active PWMs
  */
@@ -223,6 +226,8 @@ struct pwm_ops {
 			    enum pwm_polarity polarity);
 	int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
 	void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
+	void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
+			  struct pwm_state *pstate);
 #ifdef CONFIG_DEBUG_FS
 	void (*dbg_show)(struct pwm_chip *chip, struct seq_file *s);
 #endif
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 18/46] pwm: add the core infrastructure to allow atomic update
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Add an ->apply() method to the pwm_ops struct to allow PWM drivers to
implement atomic update.
This method will be preferred over the ->enable(), ->disable() and
->config() methods if available.

Add the pwm_apply_state() function to the PWM user API.

Note that the pwm_apply_state() does not guarantee the atomicity of the
update operation, it all depends on the availability and implementation
of the ->apply() method.

pwm_enable/disable/set_polarity/config() are now implemented as wrappers
around the pwm_apply_state() function.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  | 155 ++++++++++++++++++---------------------
 include/linux/pwm.h | 207 +++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 220 insertions(+), 142 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a909c64..62e6b3c 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -226,6 +226,19 @@ void *pwm_get_chip_data(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_get_chip_data);
 
+static bool pwm_ops_check(const struct pwm_ops *ops)
+{
+	/* driver supports legacy, non-atomic operation */
+	if (ops->config && ops->enable && ops->disable)
+		return true;
+
+	/* driver supports atomic operation */
+	if (ops->apply)
+		return true;
+
+	return false;
+}
+
 /**
  * pwmchip_add_with_polarity() - register a new PWM chip
  * @chip: the PWM chip to add
@@ -244,8 +257,10 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
 	unsigned int i;
 	int ret;
 
-	if (!chip || !chip->dev || !chip->ops || !chip->ops->config ||
-	    !chip->ops->enable || !chip->ops->disable || !chip->npwm)
+	if (!chip || !chip->dev || !chip->ops || !chip->npwm)
+		return -EINVAL;
+
+	if (!pwm_ops_check(chip->ops))
 		return -EINVAL;
 
 	mutex_lock(&pwm_lock);
@@ -431,102 +446,72 @@ void pwm_free(struct pwm_device *pwm)
 EXPORT_SYMBOL_GPL(pwm_free);
 
 /**
- * pwm_config() - change a PWM device configuration
+ * pwm_apply_state() - atomically apply a new state to a PWM device
  * @pwm: PWM device
- * @duty_ns: "on" time (in nanoseconds)
- * @period_ns: duration (in nanoseconds) of one cycle
- *
- * Returns: 0 on success or a negative error code on failure.
+ * @state: new state to apply. This can be adjusted by the PWM driver
+ *	   if the requested config is not achievable, for example,
+ *	   ->duty_cycle and ->period might be approximated.
  */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)
 {
 	int err;
 
-	if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
-		return -EINVAL;
-
-	err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
-	if (err)
-		return err;
-
-	pwm->state.duty_cycle = duty_ns;
-	pwm->state.period = period_ns;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(pwm_config);
-
-/**
- * pwm_set_polarity() - configure the polarity of a PWM signal
- * @pwm: PWM device
- * @polarity: new polarity of the PWM signal
- *
- * Note that the polarity cannot be configured while the PWM device is
- * enabled.
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
-{
-	int err;
-
-	if (!pwm || !pwm->chip->ops)
-		return -EINVAL;
-
-	if (!pwm->chip->ops->set_polarity)
-		return -ENOSYS;
-
-	if (pwm_is_enabled(pwm))
-		return -EBUSY;
-
-	err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
-	if (err)
-		return err;
-
-	pwm->state.polarity = polarity;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(pwm_set_polarity);
-
-/**
- * pwm_enable() - start a PWM output toggling
- * @pwm: PWM device
- *
- * Returns: 0 on success or a negative error code on failure.
- */
-int pwm_enable(struct pwm_device *pwm)
-{
-	int err = 0;
-
 	if (!pwm)
 		return -EINVAL;
 
-	if (!pwm_is_enabled(pwm)) {
-		err = pwm->chip->ops->enable(pwm->chip, pwm);
-		if (!err)
-			pwm->state.enabled = true;
-	}
+	if (!memcmp(state, &pwm->state, sizeof(*state)))
+		return 0;
 
-	return err;
-}
-EXPORT_SYMBOL_GPL(pwm_enable);
+	if (pwm->chip->ops->apply) {
+		err = pwm->chip->ops->apply(pwm->chip, pwm, state);
+		if (err)
+			return err;
+	} else {
+		/*
+		 * FIXME: restore the initial state in case of error.
+		 */
+		if (state->polarity != pwm->state.polarity) {
+			if (!pwm->chip->ops->set_polarity)
+				return -ENOTSUPP;
+
+			/*
+			 * Changing the polarity of a running PWM is
+			 * only allowed when the PWM driver implements
+			 * ->apply().
+			 */
+			if (pwm->state.enabled)
+				return -EBUSY;
+
+			err = pwm->chip->ops->set_polarity(pwm->chip, pwm,
+							   state->polarity);
+			if (err)
+				return err;
+		}
 
-/**
- * pwm_disable() - stop a PWM output toggling
- * @pwm: PWM device
- */
-void pwm_disable(struct pwm_device *pwm)
-{
-	if (!pwm)
-		return;
+		if (state->period != pwm->state.period ||
+		    state->duty_cycle != pwm->state.duty_cycle) {
+			err = pwm->chip->ops->config(pwm->chip, pwm,
+						     state->period,
+						     state->duty_cycle);
+			if (err)
+				return err;
+		}
 
-	if (pwm_is_enabled(pwm)) {
-		pwm->chip->ops->disable(pwm->chip, pwm);
-		pwm->state.enabled = false;
+		if (state->enabled != pwm->state.enabled) {
+			if (state->enabled) {
+				err = pwm->chip->ops->enable(pwm->chip, pwm);
+				if (err)
+					return err;
+			} else {
+				pwm->chip->ops->disable(pwm->chip, pwm);
+			}
+		}
 	}
+
+	pwm->state = *state;
+	return 0;
 }
-EXPORT_SYMBOL_GPL(pwm_disable);
+EXPORT_SYMBOL_GPL(pwm_apply_state);
 
 static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
 {
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index ceedcf8..4aad4eb 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -5,59 +5,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 
-struct pwm_device;
 struct seq_file;
-
-#if IS_ENABLED(CONFIG_PWM)
-/*
- * pwm_request - request a PWM device
- */
-struct pwm_device *pwm_request(int pwm_id, const char *label);
-
-/*
- * pwm_free - free a PWM device
- */
-void pwm_free(struct pwm_device *pwm);
-
-/*
- * pwm_config - change a PWM device configuration
- */
-int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
-
-/*
- * pwm_enable - start a PWM output toggling
- */
-int pwm_enable(struct pwm_device *pwm);
-
-/*
- * pwm_disable - stop a PWM output toggling
- */
-void pwm_disable(struct pwm_device *pwm);
-#else
-static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
-	return ERR_PTR(-ENODEV);
-}
-
-static inline void pwm_free(struct pwm_device *pwm)
-{
-}
-
-static inline int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
-{
-	return -EINVAL;
-}
-
-static inline int pwm_enable(struct pwm_device *pwm)
-{
-	return -EINVAL;
-}
-
-static inline void pwm_disable(struct pwm_device *pwm)
-{
-}
-#endif
-
 struct pwm_chip;
 
 /**
@@ -183,11 +131,6 @@ static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
 	return pstate.duty_cycle;
 }
 
-/*
- * pwm_set_polarity - configure the polarity of a PWM signal
- */
-int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
-
 static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
 {
 	struct pwm_state pstate;
@@ -211,6 +154,10 @@ static inline void pwm_get_args(const struct pwm_device *pwm,
  * @set_polarity: configure the polarity of this PWM
  * @enable: enable PWM output toggling
  * @disable: disable PWM output toggling
+ * @apply: atomically apply a new PWM config. The state argument
+ *	   should be adjusted with the real hardware config (if the
+ *	   approximate the period or duty_cycle value, state should
+ *	   reflect it)
  * @get_state: get the current PWM state. This function is only
  *	       called once per PWM device when the PWM chip is
  *	       registered.
@@ -226,6 +173,8 @@ struct pwm_ops {
 			    enum pwm_polarity polarity);
 	int (*enable)(struct pwm_chip *chip, struct pwm_device *pwm);
 	void (*disable)(struct pwm_chip *chip, struct pwm_device *pwm);
+	int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm,
+		     struct pwm_state *state);
 	void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
 			  struct pwm_state *pstate);
 #ifdef CONFIG_DEBUG_FS
@@ -263,6 +212,114 @@ struct pwm_chip {
 };
 
 #if IS_ENABLED(CONFIG_PWM)
+/* PWM user APIs */
+struct pwm_device *pwm_request(int pwm_id, const char *label);
+void pwm_free(struct pwm_device *pwm);
+int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
+
+/**
+ * pwm_config() - change a PWM device configuration
+ * @pwm: PWM device
+ * @duty_ns: "on" time (in nanoseconds)
+ * @period_ns: duration (in nanoseconds) of one cycle
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
+			     int period_ns)
+{
+	struct pwm_state pstate;
+
+	if (!pwm)
+		return -EINVAL;
+
+	pwm_get_state(pwm, &pstate);
+	if (pstate.duty_cycle = duty_ns && pstate.period = period_ns)
+		return 0;
+
+	pstate.duty_cycle = duty_ns;
+	pstate.period = period_ns;
+	return pwm_apply_state(pwm, &pstate);
+}
+
+/**
+ * pwm_set_polarity() - configure the polarity of a PWM signal
+ * @pwm: PWM device
+ * @polarity: new polarity of the PWM signal
+ *
+ * Note that the polarity cannot be configured while the PWM device is
+ * enabled.
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_set_polarity(struct pwm_device *pwm,
+				   enum pwm_polarity polarity)
+{
+	struct pwm_state pstate;
+
+	if (!pwm)
+		return -EINVAL;
+
+	pwm_get_state(pwm, &pstate);
+	if (pstate.polarity = polarity)
+		return 0;
+
+	/*
+	 * Changing the polarity of a running PWM without adjusting the
+	 * dutycycle/period value is a bit risky (can introduce glitches).
+	 * Return -EBUSY in this case.
+	 * Note that this is allowed when using pwm_apply_state() because
+	 * the user specifies all the parameters.
+	 */
+	if (pstate.enabled)
+		return -EBUSY;
+
+	pstate.polarity = polarity;
+	return pwm_apply_state(pwm, &pstate);
+}
+
+/**
+ * pwm_enable() - start a PWM output toggling
+ * @pwm: PWM device
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+	struct pwm_state pstate;
+
+	if (!pwm)
+		return -EINVAL;
+
+	pwm_get_state(pwm, &pstate);
+	if (pstate.enabled)
+		return 0;
+
+	pstate.enabled = true;
+	return pwm_apply_state(pwm, &pstate);
+}
+
+/**
+ * pwm_disable() - stop a PWM output toggling
+ * @pwm: PWM device
+ */
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+	struct pwm_state pstate;
+
+	if (!pwm)
+		return;
+
+	pwm_get_state(pwm, &pstate);
+	if (!pstate.enabled)
+		return;
+
+	pstate.enabled = false;
+	pwm_apply_state(pwm, &pstate);
+}
+
+
+/* PWM provider APIs */
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);
 void *pwm_get_chip_data(struct pwm_device *pwm);
 
@@ -288,6 +345,42 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
 
 bool pwm_can_sleep(struct pwm_device *pwm);
 #else
+static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void pwm_free(struct pwm_device *pwm)
+{
+}
+
+static inline int pwm_apply_state(struct pwm_device *pwm,
+				  const struct pwm_state *state)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
+			     int period_ns)
+{
+	return -EINVAL;
+}
+
+static inline int pwm_set_polarity(struct pwm_device *pwm,
+				   enum pwm_polarity polarity)
+{
+	return -ENOTSUPP;
+}
+
+static inline int pwm_enable(struct pwm_device *pwm)
+{
+	return -EINVAL;
+}
+
+static inline void pwm_disable(struct pwm_device *pwm)
+{
+}
+
 static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
 {
 	return -EINVAL;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 19/46] pwm: switch to the atomic API
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Replace legacy pwm_get/set_xxx() and pwm_config/enable/disable() calls
by pwm_get/apply_state().

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c  |  5 ++++-
 drivers/pwm/sysfs.c | 61 +++++++++++++++++++++++++++++++----------------------
 2 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 62e6b3c..c2b1569 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -882,13 +882,16 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
 
 	for (i = 0; i < chip->npwm; i++) {
 		struct pwm_device *pwm = &chip->pwms[i];
+		struct pwm_state pstate;
+
+		pwm_get_state(pwm, &pstate);
 
 		seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label);
 
 		if (test_bit(PWMF_REQUESTED, &pwm->flags))
 			seq_puts(s, " requested");
 
-		if (pwm_is_enabled(pwm))
+		if (pstate.enabled)
 			seq_puts(s, " enabled");
 
 		seq_puts(s, "\n");
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index ab28c89..7ec1747 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -47,13 +47,13 @@ static ssize_t period_show(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	const struct pwm_device *pwm = export->pwm;
-	unsigned int period;
+	struct pwm_state pstate;
 
 	mutex_lock(&export->lock);
-	period = pwm_get_period(pwm);
+	pwm_get_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%u\n", period);
+	return sprintf(buf, "%u\n", pstate.period);
 }
 
 static ssize_t period_store(struct device *child,
@@ -62,6 +62,7 @@ static ssize_t period_store(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	struct pwm_device *pwm = export->pwm;
+	struct pwm_state pstate;
 	unsigned int val;
 	int ret;
 
@@ -70,7 +71,9 @@ static ssize_t period_store(struct device *child,
 		return ret;
 
 	mutex_lock(&export->lock);
-	ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val);
+	pwm_get_state(pwm, &pstate);
+	pstate.period = val;
+	ret = pwm_apply_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
 	return ret ? : size;
@@ -82,13 +85,13 @@ static ssize_t duty_cycle_show(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	const struct pwm_device *pwm = export->pwm;
-	unsigned int duty;
+	struct pwm_state pstate;
 
 	mutex_lock(&export->lock);
-	duty = pwm_get_duty_cycle(pwm);
+	pwm_get_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%u\n", duty);
+	return sprintf(buf, "%u\n", pstate.duty_cycle);
 }
 
 static ssize_t duty_cycle_store(struct device *child,
@@ -97,6 +100,7 @@ static ssize_t duty_cycle_store(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	struct pwm_device *pwm = export->pwm;
+	struct pwm_state pstate;
 	unsigned int val;
 	int ret;
 
@@ -105,7 +109,9 @@ static ssize_t duty_cycle_store(struct device *child,
 		return ret;
 
 	mutex_lock(&export->lock);
-	ret = pwm_config(pwm, val, pwm_get_period(pwm));
+	pwm_get_state(pwm, &pstate);
+	pstate.duty_cycle = val;
+	ret = pwm_apply_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
 	return ret ? : size;
@@ -117,13 +123,13 @@ static ssize_t enable_show(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	const struct pwm_device *pwm = export->pwm;
-	bool enabled;
+	struct pwm_state pstate;
 
 	mutex_lock(&export->lock);
-	enabled = pwm_is_enabled(pwm);
+	pwm_get_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
-	return sprintf(buf, "%d\n", enabled);
+	return sprintf(buf, "%d\n", pstate.enabled);
 }
 
 static ssize_t enable_store(struct device *child,
@@ -132,24 +138,20 @@ static ssize_t enable_store(struct device *child,
 {
 	struct pwm_export *export = child_to_pwm_export(child);
 	struct pwm_device *pwm = export->pwm;
+	struct pwm_state pstate;
 	int val, ret;
 
 	ret = kstrtoint(buf, 0, &val);
 	if (ret)
 		return ret;
 
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
 	mutex_lock(&export->lock);
-	switch (val) {
-	case 0:
-		pwm_disable(pwm);
-		break;
-	case 1:
-		ret = pwm_enable(pwm);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
+	pwm_get_state(pwm, &pstate);
+	pstate.enabled = val;
+	ret = pwm_apply_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
 	return ret ? : size;
@@ -162,9 +164,13 @@ static ssize_t polarity_show(struct device *child,
 	struct pwm_export *export = child_to_pwm_export(child);
 	const struct pwm_device *pwm = export->pwm;
 	const char *polarity = "unknown";
+	struct pwm_state pstate;
 
 	mutex_lock(&export->lock);
-	switch (pwm_get_polarity(pwm)) {
+	pwm_get_state(pwm, &pstate);
+	mutex_unlock(&export->lock);
+
+	switch (pstate.polarity) {
 	case PWM_POLARITY_NORMAL:
 		polarity = "normal";
 		break;
@@ -173,7 +179,6 @@ static ssize_t polarity_show(struct device *child,
 		polarity = "inversed";
 		break;
 	}
-	mutex_unlock(&export->lock);
 
 	return sprintf(buf, "%s\n", polarity);
 }
@@ -185,6 +190,7 @@ static ssize_t polarity_store(struct device *child,
 	struct pwm_export *export = child_to_pwm_export(child);
 	struct pwm_device *pwm = export->pwm;
 	enum pwm_polarity polarity;
+	struct pwm_state pstate;
 	int ret;
 
 	if (sysfs_streq(buf, "normal"))
@@ -195,7 +201,12 @@ static ssize_t polarity_store(struct device *child,
 		return -EINVAL;
 
 	mutex_lock(&export->lock);
-	ret = pwm_set_polarity(pwm, polarity);
+	pwm_get_state(pwm, &pstate);
+	pstate.polarity = polarity;
+	if (pstate.enabled)
+		ret = -EBUSY;
+	else
+		ret = pwm_apply_state(pwm, &pstate);
 	mutex_unlock(&export->lock);
 
 	return ret ? : size;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 20/46] pwm: add information about polarity, duty cycle and period to debugfs
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

From: Heiko Stübner <heiko@sntech.de>

The pwm-states make it possible to also output the polarity, duty cycle
and period information in the debugfs pwm summary-outout.
This makes it easier to gather overview information about pwms without
needing to walk through the sysfs attributes of every pwm.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/core.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index c2b1569..9a83840 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -894,6 +894,11 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
 		if (pstate.enabled)
 			seq_puts(s, " enabled");
 
+		seq_printf(s, " period:%uns", pstate.period);
+		seq_printf(s, " duty:%uns", pstate.duty_cycle);
+		seq_printf(s, " polarity:%s",
+			   pstate.polarity ? "inverse" : "normal");
+
 		seq_puts(s, "\n");
 	}
 }
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 21/46] pwm: rockchip: add initial state retrieval
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Implement the ->get_state() function to expose initial state.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/pwm-rockchip.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 7d9cc90..6a1087c 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -51,6 +51,8 @@ struct rockchip_pwm_data {
 
 	void (*set_enable)(struct pwm_chip *chip,
 			   struct pwm_device *pwm, bool enable);
+	void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
+			  struct pwm_state *pstate);
 };
 
 static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
@@ -75,6 +77,19 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
 	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
 }
 
+static void rockchip_pwm_get_state_v1(struct pwm_chip *chip,
+				      struct pwm_device *pwm,
+				      struct pwm_state *pstate)
+{
+	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+	u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
+	u32 val;
+
+	val = readl(pc->base + pc->data->regs.ctrl);
+	if ((val & enable_conf) = enable_conf)
+		pstate->enabled = true;
+}
+
 static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
 				       struct pwm_device *pwm, bool enable)
 {
@@ -98,6 +113,55 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
 	writel_relaxed(val, pc->base + pc->data->regs.ctrl);
 }
 
+static void rockchip_pwm_get_state_v2(struct pwm_chip *chip,
+				      struct pwm_device *pwm,
+				      struct pwm_state *pstate)
+{
+	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+	u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+			  PWM_CONTINUOUS;
+	u32 val;
+
+	val = readl(pc->base + pc->data->regs.ctrl);
+	if ((val & enable_conf) != enable_conf)
+		return;
+
+	pstate->enabled = true;
+
+	if (!(val & PWM_DUTY_POSITIVE))
+		pstate->polarity = PWM_POLARITY_INVERSED;
+}
+
+static void rockchip_pwm_get_state(struct pwm_chip *chip,
+				   struct pwm_device *pwm,
+				   struct pwm_state *pstate)
+{
+	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+	unsigned long clk_rate;
+	u64 tmp;
+	int ret;
+
+	ret = clk_enable(pc->clk);
+	if (ret)
+		return;
+
+	clk_rate = clk_get_rate(pc->clk);
+
+	tmp = readl(pc->base + pc->data->regs.period);
+	tmp *= pc->data->prescaler * NSEC_PER_SEC;
+	do_div(tmp, clk_rate);
+	pstate->period = tmp;
+
+	tmp = readl(pc->base + pc->data->regs.duty);
+	tmp *= pc->data->prescaler * NSEC_PER_SEC;
+	do_div(tmp, clk_rate);
+	pstate->duty_cycle = tmp;
+
+	pc->data->get_state(chip, pwm, pstate);
+
+	clk_disable(pc->clk);
+}
+
 static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			       int duty_ns, int period_ns)
 {
@@ -171,6 +235,7 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 }
 
 static const struct pwm_ops rockchip_pwm_ops_v1 = {
+	.get_state = rockchip_pwm_get_state,
 	.config = rockchip_pwm_config,
 	.enable = rockchip_pwm_enable,
 	.disable = rockchip_pwm_disable,
@@ -178,6 +243,7 @@ static const struct pwm_ops rockchip_pwm_ops_v1 = {
 };
 
 static const struct pwm_ops rockchip_pwm_ops_v2 = {
+	.get_state = rockchip_pwm_get_state,
 	.config = rockchip_pwm_config,
 	.set_polarity = rockchip_pwm_set_polarity,
 	.enable = rockchip_pwm_enable,
@@ -195,6 +261,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
 	.prescaler = 2,
 	.ops = &rockchip_pwm_ops_v1,
 	.set_enable = rockchip_pwm_set_enable_v1,
+	.get_state = rockchip_pwm_get_state_v1,
 };
 
 static const struct rockchip_pwm_data pwm_data_v2 = {
@@ -207,6 +274,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
 	.prescaler = 1,
 	.ops = &rockchip_pwm_ops_v2,
 	.set_enable = rockchip_pwm_set_enable_v2,
+	.get_state = rockchip_pwm_get_state_v2,
 };
 
 static const struct rockchip_pwm_data pwm_data_vop = {
@@ -219,6 +287,7 @@ static const struct rockchip_pwm_data pwm_data_vop = {
 	.prescaler = 1,
 	.ops = &rockchip_pwm_ops_v2,
 	.set_enable = rockchip_pwm_set_enable_v2,
+	.get_state = rockchip_pwm_get_state_v2,
 };
 
 static const struct of_device_id rockchip_pwm_dt_ids[] = {
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 22/46] pwm: rockchip: avoid glitches on already running PWMs
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The current logic will disable the PWM clk even if the PWM was left
enabled by the bootloader (because it's controlling a critical device
like a regulator for example).
Keep the PWM clk enabled if the PWM is enabled to avoid any glitches.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/pwm-rockchip.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 6a1087c..5c7e79c 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -302,6 +302,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *id;
 	struct rockchip_pwm_chip *pc;
+	struct pwm_state pstate;
 	struct resource *r;
 	int ret;
 
@@ -322,7 +323,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 	if (IS_ERR(pc->clk))
 		return PTR_ERR(pc->clk);
 
-	ret = clk_prepare(pc->clk);
+	ret = clk_prepare_enable(pc->clk);
 	if (ret)
 		return ret;
 
@@ -345,12 +346,33 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
 	}
 
+	/* Keep the PWM clk enabled if the PWM appears to be up and running. */
+	pwm_get_state(pc->chip.pwms, &pstate);
+	if (!pstate.enabled)
+		clk_disable(pc->clk);
+
 	return ret;
 }
 
 static int rockchip_pwm_remove(struct platform_device *pdev)
 {
 	struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
+	struct pwm_state pstate;
+
+	/*
+	 * Disable the PWM clk before unpreparing it if the PWM device is still
+	 * running. This should only happen when the last PWM user left it
+	 * enabled, or when nobody requested a PWM that was previously enabled
+	 * by the bootloader.
+	 *
+	 * FIXME: Maybe the core should disable all PWM devices in
+	 * pwmchip_remove(). In this case we'd only have to call
+	 * clk_unprepare() after pwmchip_remove().
+	 *
+	 */
+	pwm_get_state(pc->chip.pwms, &pstate);
+	if (pstate.enabled)
+		clk_disable(pc->clk);
 
 	clk_unprepare(pc->clk);
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 23/46] pwm: rockchip: add support for atomic update
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Implement the ->apply() function to add support for atomic update.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Heiko Stuebner <heiko@sntech.de>
---
 drivers/pwm/pwm-rockchip.c | 63 ++++++++++++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 24 deletions(-)

diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 5c7e79c..ed27740 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -50,7 +50,8 @@ struct rockchip_pwm_data {
 	const struct pwm_ops *ops;
 
 	void (*set_enable)(struct pwm_chip *chip,
-			   struct pwm_device *pwm, bool enable);
+			   struct pwm_device *pwm, bool enable,
+			   enum pwm_polarity polarity);
 	void (*get_state)(struct pwm_chip *chip, struct pwm_device *pwm,
 			  struct pwm_state *pstate);
 };
@@ -61,7 +62,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
 }
 
 static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
-				       struct pwm_device *pwm, bool enable)
+				       struct pwm_device *pwm, bool enable,
+				       enum pwm_polarity polarity)
 {
 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 	u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
@@ -91,14 +93,15 @@ static void rockchip_pwm_get_state_v1(struct pwm_chip *chip,
 }
 
 static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
-				       struct pwm_device *pwm, bool enable)
+				       struct pwm_device *pwm, bool enable,
+				       enum pwm_polarity polarity)
 {
 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 	u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
 			  PWM_CONTINUOUS;
 	u32 val;
 
-	if (pwm_get_polarity(pwm) = PWM_POLARITY_INVERSED)
+	if (polarity = PWM_POLARITY_INVERSED)
 		enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
 	else
 		enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
@@ -168,7 +171,6 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
 	unsigned long period, duty;
 	u64 clk_rate, div;
-	int ret;
 
 	clk_rate = clk_get_rate(pc->clk);
 
@@ -185,15 +187,8 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	do_div(div, pc->data->prescaler * NSEC_PER_SEC);
 	duty = div;
 
-	ret = clk_enable(pc->clk);
-	if (ret)
-		return ret;
-
 	writel(period, pc->base + pc->data->regs.period);
 	writel(duty, pc->base + pc->data->regs.duty);
-	writel(0, pc->base + pc->data->regs.cntr);
-
-	clk_disable(pc->clk);
 
 	return 0;
 }
@@ -211,43 +206,63 @@ static int rockchip_pwm_set_polarity(struct pwm_chip *chip,
 	return 0;
 }
 
-static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			      struct pwm_state *state)
 {
 	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+	struct pwm_state curstate;
+	bool enabled;
 	int ret;
 
+	pwm_get_state(pwm, &curstate);
+	enabled = curstate.enabled;
+
 	ret = clk_enable(pc->clk);
 	if (ret)
 		return ret;
 
-	pc->data->set_enable(chip, pwm, true);
+	if (state->polarity != curstate.polarity && enabled) {
+		pc->data->set_enable(chip, pwm, false, state->polarity);
+		enabled = false;
+	}
 
-	return 0;
-}
+	ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period);
+	if (ret) {
+		if (enabled != curstate.enabled)
+			pc->data->set_enable(chip, pwm, !enabled,
+					     state->polarity);
 
-static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
-	struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+		goto out;
+	}
 
-	pc->data->set_enable(chip, pwm, false);
+	if (state->enabled != enabled)
+		pc->data->set_enable(chip, pwm, state->enabled,
+				     state->polarity);
 
+	/*
+	 * Update the state with the real hardware, which can differ a bit
+	 * because of period/duty_cycle approximation.
+	 */
+	rockchip_pwm_get_state(chip, pwm, state);
+
+out:
 	clk_disable(pc->clk);
+
+	return ret;
 }
 
 static const struct pwm_ops rockchip_pwm_ops_v1 = {
 	.get_state = rockchip_pwm_get_state,
 	.config = rockchip_pwm_config,
-	.enable = rockchip_pwm_enable,
-	.disable = rockchip_pwm_disable,
+	.apply = rockchip_pwm_apply,
 	.owner = THIS_MODULE,
 };
 
 static const struct pwm_ops rockchip_pwm_ops_v2 = {
 	.get_state = rockchip_pwm_get_state,
 	.config = rockchip_pwm_config,
+	.apply = rockchip_pwm_apply,
 	.set_polarity = rockchip_pwm_set_polarity,
-	.enable = rockchip_pwm_enable,
-	.disable = rockchip_pwm_disable,
 	.owner = THIS_MODULE,
 };
 
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 24/46] pwm: sti: add support for initial state retrieval
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Implement ->get_state() to provide support for initial state retrieval.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/pwm-sti.c | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index 92abbd5..0fbca94 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -238,6 +238,46 @@ static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	mutex_unlock(&pc->sti_pwm_lock);
 }
 
+static void sti_pwm_get_state(struct pwm_chip *chip,
+			      struct pwm_device *pwm,
+			      struct pwm_state *pstate)
+{
+	struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
+	unsigned int regval, prescaler;
+	u64 timens;
+	int ret;
+
+	/* The clock has to be enabled to access PWM registers */
+	ret = clk_enable(pc->clk);
+	if (ret) {
+		dev_err(chip->dev, "Failed to enable PWM clk");
+		return;
+	}
+
+	regmap_field_read(pc->prescale_high, &regval);
+	prescaler = regval << 4;
+	regmap_field_read(pc->prescale_low, &regval);
+	prescaler |= regval;
+
+	timens = (u64)(prescaler + 1) * NSEC_PER_SEC *
+		 (pc->cdata->max_pwm_cnt + 1);
+	do_div(timens, pc->clk_rate);
+
+	pstate->period = timens;
+
+	regmap_read(pc->regmap, STI_DS_REG(pwm->hwpwm), &regval);
+	timens = (u64)(regval + 1) * pstate->period;
+	do_div(timens, pc->cdata->max_pwm_cnt + 1);
+	pstate->duty_cycle = timens;
+
+	regmap_field_read(pc->pwm_en, &regval);
+	pstate->enabled = regval;
+
+	pstate->polarity = PWM_POLARITY_NORMAL;
+
+	clk_disable(pc->clk);
+}
+
 static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
@@ -249,6 +289,7 @@ static const struct pwm_ops sti_pwm_ops = {
 	.config = sti_pwm_config,
 	.enable = sti_pwm_enable,
 	.disable = sti_pwm_disable,
+	.get_state = sti_pwm_get_state,
 	.free = sti_pwm_free,
 	.owner = THIS_MODULE,
 };
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 25/46] pwm: sti: avoid glitches on already running PWMs
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The current logic will disable the PWM clk even if a PWM was left
enabled by the bootloader (because it's controlling a critical device
like a regulator for example).
Keep the PWM clk enabled if at least one PWM is enabled to avoid any
glitches.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/pwm-sti.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index 0fbca94..bea1d17 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -343,7 +343,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
 	struct sti_pwm_compat_data *cdata;
 	struct sti_pwm_chip *pc;
 	struct resource *res;
-	int ret;
+	int i, ret;
 
 	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
 	if (!pc)
@@ -394,7 +394,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	ret = clk_prepare(pc->clk);
+	ret = clk_prepare_enable(pc->clk);
 	if (ret) {
 		dev_err(dev, "failed to prepare clock\n");
 		return ret;
@@ -412,6 +412,19 @@ static int sti_pwm_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	/*
+	 * Keep the PWM clk enabled if some PWMs appear to be up and
+	 * running.
+	 */
+	for (i = 0; i < pc->chip.npwm; i++) {
+		struct pwm_state pstate;
+
+		pwm_get_state(&pc->chip.pwms[i], &pstate);
+		if (pstate.enabled)
+			clk_enable(pc->clk);
+	}
+	clk_disable(pc->clk);
+
 	platform_set_drvdata(pdev, pc);
 
 	return 0;
-- 
2.5.0


^ permalink raw reply related

* [PATCH v5 26/46] pwm: sun4i: implement hardware readout
From: Boris Brezillon @ 2016-03-30 20:03 UTC (permalink / raw)
  To: Thierry Reding, linux-pwm-u79uwXL29TY76Z2rM5mHXA
  Cc: Mike Turquette, Stephen Boyd, linux-clk-u79uwXL29TY76Z2rM5mHXA,
	Mark Brown, Liam Girdwood, Kamil Debski,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA, Jean Delvare, Guenter Roeck,
	Dmitry Torokhov, linux-input-u79uwXL29TY76Z2rM5mHXA, Bryan Wu,
	Richard Purdie, Jacek Anaszewski,
	linux-leds-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Chen-Yu Tsai,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Joachim Eastwood,
	Thomas Petazzoni, Heiko Stuebner,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jingoo Han,
	Lee Jones
In-Reply-To: <1459368249-13241-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Implement ->get_state() instead of only initializing the polarity in
the probe function.

This implementation also takes care of keeping the PWM clk enabled if at
least one of the PWM exported by the PWM chip is already enabled, which
should prevent glitches.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/pwm/pwm-sun4i.c | 74 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 55 insertions(+), 19 deletions(-)

diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index 03a99a5..34cb296 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -252,11 +252,65 @@ static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 	clk_disable_unprepare(sun4i_pwm->clk);
 }
 
+static void sun4i_pwm_get_state(struct pwm_chip *chip,
+				struct pwm_device *pwm,
+				struct pwm_state *pstate)
+{
+	struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+	unsigned int clk_rate = clk_get_rate(sun4i_pwm->clk);
+	int prescaler, prescalerid;
+	int ret;
+	u32 val;
+
+	ret = clk_prepare_enable(sun4i_pwm->clk);
+	if (ret) {
+		dev_err(chip->dev, "Failed to enable PWM clock");
+		return;
+	}
+
+	val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+	if (val & BIT_CH(PWM_ACT_STATE, pwm->hwpwm))
+		pstate->polarity = PWM_POLARITY_INVERSED;
+	else
+		pstate->polarity = PWM_POLARITY_NORMAL;
+
+	if ((val & BIT_CH(PWM_EN, pwm->hwpwm)) &&
+	    (val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm)))
+		pstate->enabled = true;
+	else
+		pstate->enabled = false;
+
+	pstate->period = 0;
+	pstate->duty_cycle = 0;
+	prescalerid = (val >> (PWMCH_OFFSET * pwm->hwpwm)) & PWM_PRESCAL_MASK;
+	prescaler = prescaler_table[prescalerid];
+	if (prescaler) {
+		u64 timens;
+
+		clk_rate /= prescaler;
+
+		val = sun4i_pwm_readl(sun4i_pwm, PWM_CH_PRD(pwm->hwpwm));
+
+		timens = ((val >> 16) & PWM_PRD_MASK) + 1;
+		timens *= NSEC_PER_SEC;
+		do_div(timens, clk_rate);
+		pstate->period = timens;
+
+		timens = val & PWM_DTY_MASK;
+		timens *= NSEC_PER_SEC;
+		do_div(timens, clk_rate);
+		pstate->duty_cycle = timens;
+	}
+
+	clk_disable_unprepare(sun4i_pwm->clk);
+}
+
 static const struct pwm_ops sun4i_pwm_ops = {
 	.config = sun4i_pwm_config,
 	.set_polarity = sun4i_pwm_set_polarity,
 	.enable = sun4i_pwm_enable,
 	.disable = sun4i_pwm_disable,
+	.get_state = sun4i_pwm_get_state,
 	.owner = THIS_MODULE,
 };
 
@@ -307,8 +361,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 {
 	struct sun4i_pwm_chip *pwm;
 	struct resource *res;
-	u32 val;
-	int i, ret;
+	int ret;
 	const struct of_device_id *match;
 
 	match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev);
@@ -345,24 +398,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pwm);
 
-	ret = clk_prepare_enable(pwm->clk);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to enable PWM clock\n");
-		goto clk_error;
-	}
-
-	val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
-	for (i = 0; i < pwm->chip.npwm; i++)
-		if (!(val & BIT_CH(PWM_ACT_STATE, i)))
-			pwm_set_polarity(&pwm->chip.pwms[i],
-					 PWM_POLARITY_INVERSED);
-	clk_disable_unprepare(pwm->clk);
-
 	return 0;
-
-clk_error:
-	pwmchip_remove(&pwm->chip);
-	return ret;
 }
 
 static int sun4i_pwm_remove(struct platform_device *pdev)
-- 
2.5.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox