All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] iio: trigger: stm32-timers fixes
@ 2017-09-18 10:05 ` Fabrice Gasnier
  0 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard, linux-iio, lars, knaack.h, pmeerw

This fixes misc corner cases observed when using stm32-timers:
- reload value is shadowed, after 1st write, or when doing successive 
  configurations (using sampling_frequency, then counter)
- clock needs to be enabled before using master->slave configuration

Fabrice Gasnier (3):
  iio: trigger: stm32-timer: preset shouldn't be buffered
  iio: trigger: stm32-timer: fix a corner case to write preset
  iio: trigger: stm32-timer: enable clock when in master mode

 drivers/iio/trigger/stm32-timer-trigger.c | 64 ++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 19 deletions(-)

-- 
1.9.1

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

* [PATCH 0/3] iio: trigger: stm32-timers fixes
@ 2017-09-18 10:05 ` Fabrice Gasnier
  0 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

This fixes misc corner cases observed when using stm32-timers:
- reload value is shadowed, after 1st write, or when doing successive 
  configurations (using sampling_frequency, then counter)
- clock needs to be enabled before using master->slave configuration

Fabrice Gasnier (3):
  iio: trigger: stm32-timer: preset shouldn't be buffered
  iio: trigger: stm32-timer: fix a corner case to write preset
  iio: trigger: stm32-timer: enable clock when in master mode

 drivers/iio/trigger/stm32-timer-trigger.c | 64 ++++++++++++++++++++++---------
 1 file changed, 45 insertions(+), 19 deletions(-)

-- 
1.9.1

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

* [PATCH 1/3] iio: trigger: stm32-timer: preset shouldn't be buffered
  2017-09-18 10:05 ` Fabrice Gasnier
@ 2017-09-18 10:05   ` Fabrice Gasnier
  -1 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard, linux-iio, lars, knaack.h, pmeerw

Currently, setting preset value (ARR) will update directly 'Auto reload
value' only on 1st write access. But then, ARPE is set. This makes
ARR a shadow register. Preset value should be updated upon each
write request: ensure ARPE is 0. This fixes successive writes to
preset attribute.

Fixes: 4adec7da0536 ("iio: stm32 trigger: Add quadrature encoder device")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 9b90534..34cc25b 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -715,8 +715,9 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
 	if (ret)
 		return ret;
 
+	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
+	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_write(priv->regmap, TIM_ARR, preset);
-	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
 
 	return len;
 }
-- 
1.9.1

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

* [PATCH 1/3] iio: trigger: stm32-timer: preset shouldn't be buffered
@ 2017-09-18 10:05   ` Fabrice Gasnier
  0 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, setting preset value (ARR) will update directly 'Auto reload
value' only on 1st write access. But then, ARPE is set. This makes
ARR a shadow register. Preset value should be updated upon each
write request: ensure ARPE is 0. This fixes successive writes to
preset attribute.

Fixes: 4adec7da0536 ("iio: stm32 trigger: Add quadrature encoder device")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 9b90534..34cc25b 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -715,8 +715,9 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
 	if (ret)
 		return ret;
 
+	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
+	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_write(priv->regmap, TIM_ARR, preset);
-	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
 
 	return len;
 }
-- 
1.9.1

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

* [PATCH 2/3] iio: trigger: stm32-timer: fix a corner case to write preset
  2017-09-18 10:05 ` Fabrice Gasnier
@ 2017-09-18 10:05   ` Fabrice Gasnier
  -1 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard, linux-iio, lars, knaack.h, pmeerw

Balance timer start routine that sets ARPE: clear it in stop routine.
This fixes a corner case, when timer is used successively as trigger
(with sampling_frequency start/stop routines), then as a counter
(with preset).

Fixes: 93fbe91b5521 ("iio: Add STM32 timer trigger driver")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 34cc25b..eb212f8c 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -174,6 +174,7 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 		clk_disable(priv->clk);
 
 	/* Stop timer */
+	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
 	regmap_write(priv->regmap, TIM_PSC, 0);
 	regmap_write(priv->regmap, TIM_ARR, 0);
-- 
1.9.1

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

* [PATCH 2/3] iio: trigger: stm32-timer: fix a corner case to write preset
@ 2017-09-18 10:05   ` Fabrice Gasnier
  0 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

Balance timer start routine that sets ARPE: clear it in stop routine.
This fixes a corner case, when timer is used successively as trigger
(with sampling_frequency start/stop routines), then as a counter
(with preset).

Fixes: 93fbe91b5521 ("iio: Add STM32 timer trigger driver")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 34cc25b..eb212f8c 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -174,6 +174,7 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 		clk_disable(priv->clk);
 
 	/* Stop timer */
+	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
 	regmap_write(priv->regmap, TIM_PSC, 0);
 	regmap_write(priv->regmap, TIM_ARR, 0);
-- 
1.9.1

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

* [PATCH 3/3] iio: trigger: stm32-timer: enable clock when in master mode
  2017-09-18 10:05 ` Fabrice Gasnier
@ 2017-09-18 10:05   ` Fabrice Gasnier
  -1 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard, linux-iio, lars, knaack.h, pmeerw

Clock should be enabled as soon as using master mode, even before
enabling timer. Or, this may provoke bad behavior on the other end
(slave timer). Then, introduce 'clk_enabled' flag, instead of relying
on CR1 EN bit, to keep track of clock being enabled.
Propagate this anywhere else in the driver.

Also add 'remove' routine to stop timer and disable clock in case it
has been left enabled.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 60 +++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 18 deletions(-)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index eb212f8c..5a6509c 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -79,6 +79,7 @@ struct stm32_timer_trigger {
 	struct device *dev;
 	struct regmap *regmap;
 	struct clk *clk;
+	bool clk_enabled;
 	u32 max_arr;
 	const void *triggers;
 	const void *valids;
@@ -106,7 +107,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 {
 	unsigned long long prd, div;
 	int prescaler = 0;
-	u32 ccer, cr1;
+	u32 ccer;
 
 	/* Period and prescaler values depends of clock rate */
 	div = (unsigned long long)clk_get_rate(priv->clk);
@@ -136,9 +137,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 	if (ccer & TIM_CCER_CCXE)
 		return -EBUSY;
 
-	regmap_read(priv->regmap, TIM_CR1, &cr1);
-	if (!(cr1 & TIM_CR1_CEN))
+	if (!priv->clk_enabled) {
+		priv->clk_enabled = true;
 		clk_enable(priv->clk);
+	}
 
 	regmap_write(priv->regmap, TIM_PSC, prescaler);
 	regmap_write(priv->regmap, TIM_ARR, prd - 1);
@@ -163,16 +165,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 
 static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 {
-	u32 ccer, cr1;
+	u32 ccer;
 
 	regmap_read(priv->regmap, TIM_CCER, &ccer);
 	if (ccer & TIM_CCER_CCXE)
 		return;
 
-	regmap_read(priv->regmap, TIM_CR1, &cr1);
-	if (cr1 & TIM_CR1_CEN)
-		clk_disable(priv->clk);
-
 	/* Stop timer */
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
@@ -181,6 +179,11 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 
 	/* Make sure that registers are updated */
 	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	if (priv->clk_enabled) {
+		priv->clk_enabled = false;
+		clk_disable(priv->clk);
+	}
 }
 
 static ssize_t stm32_tt_store_frequency(struct device *dev,
@@ -295,6 +298,11 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
 	for (i = 0; i <= master_mode_max; i++) {
 		if (!strncmp(master_mode_table[i], buf,
 			     strlen(master_mode_table[i]))) {
+			if (!priv->clk_enabled) {
+				/* Clock should be enabled first */
+				priv->clk_enabled = true;
+				clk_enable(priv->clk);
+			}
 			regmap_update_bits(priv->regmap, TIM_CR2, mask,
 					   i << shift);
 			/* Make sure that registers are updated */
@@ -438,7 +446,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 				   int val, int val2, long mask)
 {
 	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
-	u32 dat;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
@@ -450,17 +457,19 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 
 	case IIO_CHAN_INFO_ENABLE:
 		if (val) {
-			regmap_read(priv->regmap, TIM_CR1, &dat);
-			if (!(dat & TIM_CR1_CEN))
+			if (!priv->clk_enabled) {
+				priv->clk_enabled = true;
 				clk_enable(priv->clk);
+			}
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
 					   TIM_CR1_CEN);
 		} else {
-			regmap_read(priv->regmap, TIM_CR1, &dat);
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
 					   0);
-			if (dat & TIM_CR1_CEN)
+			if (priv->clk_enabled) {
+				priv->clk_enabled = false;
 				clk_disable(priv->clk);
+			}
 		}
 		return 0;
 	}
@@ -558,7 +567,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 {
 	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
 	int sms = stm32_enable_mode2sms(mode);
-	u32 val;
 
 	if (sms < 0)
 		return sms;
@@ -566,10 +574,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 	 * Triggered mode sets CEN bit automatically by hardware. So, first
 	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
 	 */
-	if (sms == 6) {
-		regmap_read(priv->regmap, TIM_CR1, &val);
-		if (!(val & TIM_CR1_CEN))
-			clk_enable(priv->clk);
+	if (sms == 6 && !priv->clk_enabled) {
+		clk_enable(priv->clk);
+		priv->clk_enabled = true;
 	}
 
 	regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
@@ -848,6 +855,22 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static int stm32_timer_trigger_remove(struct platform_device *pdev)
+{
+	struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
+	u32 val;
+
+	/* Check if nobody else use the timer, then disable it */
+	regmap_read(priv->regmap, TIM_CCER, &val);
+	if (!(val & TIM_CCER_CCXE))
+		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+	if (priv->clk_enabled)
+		clk_disable(priv->clk);
+
+	return 0;
+}
+
 static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
 	.valids_table = valids_table,
 	.num_valids_table = ARRAY_SIZE(valids_table),
@@ -872,6 +895,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
 
 static struct platform_driver stm32_timer_trigger_driver = {
 	.probe = stm32_timer_trigger_probe,
+	.remove = stm32_timer_trigger_remove,
 	.driver = {
 		.name = "stm32-timer-trigger",
 		.of_match_table = stm32_trig_of_match,
-- 
1.9.1

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

* [PATCH 3/3] iio: trigger: stm32-timer: enable clock when in master mode
@ 2017-09-18 10:05   ` Fabrice Gasnier
  0 siblings, 0 replies; 14+ messages in thread
From: Fabrice Gasnier @ 2017-09-18 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

Clock should be enabled as soon as using master mode, even before
enabling timer. Or, this may provoke bad behavior on the other end
(slave timer). Then, introduce 'clk_enabled' flag, instead of relying
on CR1 EN bit, to keep track of clock being enabled.
Propagate this anywhere else in the driver.

Also add 'remove' routine to stop timer and disable clock in case it
has been left enabled.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/trigger/stm32-timer-trigger.c | 60 +++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 18 deletions(-)

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index eb212f8c..5a6509c 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -79,6 +79,7 @@ struct stm32_timer_trigger {
 	struct device *dev;
 	struct regmap *regmap;
 	struct clk *clk;
+	bool clk_enabled;
 	u32 max_arr;
 	const void *triggers;
 	const void *valids;
@@ -106,7 +107,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 {
 	unsigned long long prd, div;
 	int prescaler = 0;
-	u32 ccer, cr1;
+	u32 ccer;
 
 	/* Period and prescaler values depends of clock rate */
 	div = (unsigned long long)clk_get_rate(priv->clk);
@@ -136,9 +137,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 	if (ccer & TIM_CCER_CCXE)
 		return -EBUSY;
 
-	regmap_read(priv->regmap, TIM_CR1, &cr1);
-	if (!(cr1 & TIM_CR1_CEN))
+	if (!priv->clk_enabled) {
+		priv->clk_enabled = true;
 		clk_enable(priv->clk);
+	}
 
 	regmap_write(priv->regmap, TIM_PSC, prescaler);
 	regmap_write(priv->regmap, TIM_ARR, prd - 1);
@@ -163,16 +165,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 
 static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 {
-	u32 ccer, cr1;
+	u32 ccer;
 
 	regmap_read(priv->regmap, TIM_CCER, &ccer);
 	if (ccer & TIM_CCER_CCXE)
 		return;
 
-	regmap_read(priv->regmap, TIM_CR1, &cr1);
-	if (cr1 & TIM_CR1_CEN)
-		clk_disable(priv->clk);
-
 	/* Stop timer */
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
 	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
@@ -181,6 +179,11 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
 
 	/* Make sure that registers are updated */
 	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+	if (priv->clk_enabled) {
+		priv->clk_enabled = false;
+		clk_disable(priv->clk);
+	}
 }
 
 static ssize_t stm32_tt_store_frequency(struct device *dev,
@@ -295,6 +298,11 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
 	for (i = 0; i <= master_mode_max; i++) {
 		if (!strncmp(master_mode_table[i], buf,
 			     strlen(master_mode_table[i]))) {
+			if (!priv->clk_enabled) {
+				/* Clock should be enabled first */
+				priv->clk_enabled = true;
+				clk_enable(priv->clk);
+			}
 			regmap_update_bits(priv->regmap, TIM_CR2, mask,
 					   i << shift);
 			/* Make sure that registers are updated */
@@ -438,7 +446,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 				   int val, int val2, long mask)
 {
 	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
-	u32 dat;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
@@ -450,17 +457,19 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 
 	case IIO_CHAN_INFO_ENABLE:
 		if (val) {
-			regmap_read(priv->regmap, TIM_CR1, &dat);
-			if (!(dat & TIM_CR1_CEN))
+			if (!priv->clk_enabled) {
+				priv->clk_enabled = true;
 				clk_enable(priv->clk);
+			}
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
 					   TIM_CR1_CEN);
 		} else {
-			regmap_read(priv->regmap, TIM_CR1, &dat);
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
 					   0);
-			if (dat & TIM_CR1_CEN)
+			if (priv->clk_enabled) {
+				priv->clk_enabled = false;
 				clk_disable(priv->clk);
+			}
 		}
 		return 0;
 	}
@@ -558,7 +567,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 {
 	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
 	int sms = stm32_enable_mode2sms(mode);
-	u32 val;
 
 	if (sms < 0)
 		return sms;
@@ -566,10 +574,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 	 * Triggered mode sets CEN bit automatically by hardware. So, first
 	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
 	 */
-	if (sms == 6) {
-		regmap_read(priv->regmap, TIM_CR1, &val);
-		if (!(val & TIM_CR1_CEN))
-			clk_enable(priv->clk);
+	if (sms == 6 && !priv->clk_enabled) {
+		clk_enable(priv->clk);
+		priv->clk_enabled = true;
 	}
 
 	regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
@@ -848,6 +855,22 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static int stm32_timer_trigger_remove(struct platform_device *pdev)
+{
+	struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
+	u32 val;
+
+	/* Check if nobody else use the timer, then disable it */
+	regmap_read(priv->regmap, TIM_CCER, &val);
+	if (!(val & TIM_CCER_CCXE))
+		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+	if (priv->clk_enabled)
+		clk_disable(priv->clk);
+
+	return 0;
+}
+
 static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
 	.valids_table = valids_table,
 	.num_valids_table = ARRAY_SIZE(valids_table),
@@ -872,6 +895,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
 
 static struct platform_driver stm32_timer_trigger_driver = {
 	.probe = stm32_timer_trigger_probe,
+	.remove = stm32_timer_trigger_remove,
 	.driver = {
 		.name = "stm32-timer-trigger",
 		.of_match_table = stm32_trig_of_match,
-- 
1.9.1

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

* Re: [PATCH 1/3] iio: trigger: stm32-timer: preset shouldn't be buffered
  2017-09-18 10:05   ` Fabrice Gasnier
@ 2017-09-24 12:09     ` Jonathan Cameron
  -1 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:09 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, benjamin.gaignard, benjamin.gaignard,
	linux-iio, lars, knaack.h, pmeerw

On Mon, 18 Sep 2017 12:05:30 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Currently, setting preset value (ARR) will update directly 'Auto reload
> value' only on 1st write access. But then, ARPE is set. This makes
> ARR a shadow register. Preset value should be updated upon each
> write request: ensure ARPE is 0. This fixes successive writes to
> preset attribute.
> 
> Fixes: 4adec7da0536 ("iio: stm32 trigger: Add quadrature encoder device")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Applied to the fixes-togreg-post-rc1 branch of iio.git and marked
for stable.

Thanks,

Jonathan

> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 9b90534..34cc25b 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -715,8 +715,9 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
>  	if (ret)
>  		return ret;
>  
> +	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_write(priv->regmap, TIM_ARR, preset);
> -	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
>  
>  	return len;
>  }

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

* [PATCH 1/3] iio: trigger: stm32-timer: preset shouldn't be buffered
@ 2017-09-24 12:09     ` Jonathan Cameron
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 18 Sep 2017 12:05:30 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Currently, setting preset value (ARR) will update directly 'Auto reload
> value' only on 1st write access. But then, ARPE is set. This makes
> ARR a shadow register. Preset value should be updated upon each
> write request: ensure ARPE is 0. This fixes successive writes to
> preset attribute.
> 
> Fixes: 4adec7da0536 ("iio: stm32 trigger: Add quadrature encoder device")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Applied to the fixes-togreg-post-rc1 branch of iio.git and marked
for stable.

Thanks,

Jonathan

> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 9b90534..34cc25b 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -715,8 +715,9 @@ static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
>  	if (ret)
>  		return ret;
>  
> +	/* TIMx_ARR register shouldn't be buffered (ARPE=0) */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_write(priv->regmap, TIM_ARR, preset);
> -	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
>  
>  	return len;
>  }

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

* Re: [PATCH 2/3] iio: trigger: stm32-timer: fix a corner case to write preset
  2017-09-18 10:05   ` Fabrice Gasnier
@ 2017-09-24 12:10     ` Jonathan Cameron
  -1 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:10 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, benjamin.gaignard, benjamin.gaignard,
	linux-iio, lars, knaack.h, pmeerw

On Mon, 18 Sep 2017 12:05:31 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Balance timer start routine that sets ARPE: clear it in stop routine.
> This fixes a corner case, when timer is used successively as trigger
> (with sampling_frequency start/stop routines), then as a counter
> (with preset).
> 
> Fixes: 93fbe91b5521 ("iio: Add STM32 timer trigger driver")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Applied to the fixes-togreg-post-rc1 branch of iio.git and
marked for stable.

Thanks,

Jonathan
> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 34cc25b..eb212f8c 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -174,6 +174,7 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  		clk_disable(priv->clk);
>  
>  	/* Stop timer */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
>  	regmap_write(priv->regmap, TIM_PSC, 0);
>  	regmap_write(priv->regmap, TIM_ARR, 0);

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

* [PATCH 2/3] iio: trigger: stm32-timer: fix a corner case to write preset
@ 2017-09-24 12:10     ` Jonathan Cameron
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 18 Sep 2017 12:05:31 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Balance timer start routine that sets ARPE: clear it in stop routine.
> This fixes a corner case, when timer is used successively as trigger
> (with sampling_frequency start/stop routines), then as a counter
> (with preset).
> 
> Fixes: 93fbe91b5521 ("iio: Add STM32 timer trigger driver")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Applied to the fixes-togreg-post-rc1 branch of iio.git and
marked for stable.

Thanks,

Jonathan
> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 34cc25b..eb212f8c 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -174,6 +174,7 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  		clk_disable(priv->clk);
>  
>  	/* Stop timer */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
>  	regmap_write(priv->regmap, TIM_PSC, 0);
>  	regmap_write(priv->regmap, TIM_ARR, 0);

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

* Re: [PATCH 3/3] iio: trigger: stm32-timer: enable clock when in master mode
  2017-09-18 10:05   ` Fabrice Gasnier
@ 2017-09-24 12:22     ` Jonathan Cameron
  -1 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:22 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	alexandre.torgue, benjamin.gaignard, benjamin.gaignard,
	linux-iio, lars, knaack.h, pmeerw

On Mon, 18 Sep 2017 12:05:32 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Clock should be enabled as soon as using master mode, even before
> enabling timer. Or, this may provoke bad behavior on the other end
> (slave timer). Then, introduce 'clk_enabled' flag, instead of relying
> on CR1 EN bit, to keep track of clock being enabled.
> Propagate this anywhere else in the driver.
> 
> Also add 'remove' routine to stop timer and disable clock in case it
> has been left enabled.

This last bit leaves us open to some nasty race conditions I think.
I'm not sure of a clean way to avoid them, but turning this off
before we remove the userspace interfaces doesn't strike me as a good
idea!

More detail inline.

Jonathan

> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 60 +++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index eb212f8c..5a6509c 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -79,6 +79,7 @@ struct stm32_timer_trigger {
>  	struct device *dev;
>  	struct regmap *regmap;
>  	struct clk *clk;
> +	bool clk_enabled;
>  	u32 max_arr;
>  	const void *triggers;
>  	const void *valids;
> @@ -106,7 +107,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  {
>  	unsigned long long prd, div;
>  	int prescaler = 0;
> -	u32 ccer, cr1;
> +	u32 ccer;
>  
>  	/* Period and prescaler values depends of clock rate */
>  	div = (unsigned long long)clk_get_rate(priv->clk);
> @@ -136,9 +137,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  	if (ccer & TIM_CCER_CCXE)
>  		return -EBUSY;
>  
> -	regmap_read(priv->regmap, TIM_CR1, &cr1);
> -	if (!(cr1 & TIM_CR1_CEN))
> +	if (!priv->clk_enabled) {
> +		priv->clk_enabled = true;
>  		clk_enable(priv->clk);
> +	}
>  
>  	regmap_write(priv->regmap, TIM_PSC, prescaler);
>  	regmap_write(priv->regmap, TIM_ARR, prd - 1);
> @@ -163,16 +165,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  
>  static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  {
> -	u32 ccer, cr1;
> +	u32 ccer;
>  
>  	regmap_read(priv->regmap, TIM_CCER, &ccer);
>  	if (ccer & TIM_CCER_CCXE)
>  		return;
>  
> -	regmap_read(priv->regmap, TIM_CR1, &cr1);
> -	if (cr1 & TIM_CR1_CEN)
> -		clk_disable(priv->clk);
> -
>  	/* Stop timer */
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> @@ -181,6 +179,11 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  
>  	/* Make sure that registers are updated */
>  	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> +
> +	if (priv->clk_enabled) {
> +		priv->clk_enabled = false;
> +		clk_disable(priv->clk);
> +	}
>  }
>  
>  static ssize_t stm32_tt_store_frequency(struct device *dev,
> @@ -295,6 +298,11 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
>  	for (i = 0; i <= master_mode_max; i++) {
>  		if (!strncmp(master_mode_table[i], buf,
>  			     strlen(master_mode_table[i]))) {
> +			if (!priv->clk_enabled) {
> +				/* Clock should be enabled first */
> +				priv->clk_enabled = true;
> +				clk_enable(priv->clk);
> +			}
>  			regmap_update_bits(priv->regmap, TIM_CR2, mask,
>  					   i << shift);
>  			/* Make sure that registers are updated */
> @@ -438,7 +446,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  				   int val, int val2, long mask)
>  {
>  	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
> -	u32 dat;
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> @@ -450,17 +457,19 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  
>  	case IIO_CHAN_INFO_ENABLE:
>  		if (val) {
> -			regmap_read(priv->regmap, TIM_CR1, &dat);
> -			if (!(dat & TIM_CR1_CEN))
> +			if (!priv->clk_enabled) {
> +				priv->clk_enabled = true;
>  				clk_enable(priv->clk);
> +			}
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
>  					   TIM_CR1_CEN);
>  		} else {
> -			regmap_read(priv->regmap, TIM_CR1, &dat);
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
>  					   0);
> -			if (dat & TIM_CR1_CEN)
> +			if (priv->clk_enabled) {
> +				priv->clk_enabled = false;
>  				clk_disable(priv->clk);
> +			}
>  		}
>  		return 0;
>  	}
> @@ -558,7 +567,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
>  {
>  	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
>  	int sms = stm32_enable_mode2sms(mode);
> -	u32 val;
>  
>  	if (sms < 0)
>  		return sms;
> @@ -566,10 +574,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
>  	 * Triggered mode sets CEN bit automatically by hardware. So, first
>  	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
>  	 */
> -	if (sms == 6) {
> -		regmap_read(priv->regmap, TIM_CR1, &val);
> -		if (!(val & TIM_CR1_CEN))
> -			clk_enable(priv->clk);
> +	if (sms == 6 && !priv->clk_enabled) {
> +		clk_enable(priv->clk);
> +		priv->clk_enabled = true;
>  	}
>  
>  	regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
> @@ -848,6 +855,22 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int stm32_timer_trigger_remove(struct platform_device *pdev)
> +{
> +	struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
> +	u32 val;
> +
> +	/* Check if nobody else use the timer, then disable it */
> +	regmap_read(priv->regmap, TIM_CCER, &val);
> +	if (!(val & TIM_CCER_CCXE))
> +		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> +
> +	if (priv->clk_enabled)
> +		clk_disable(priv->clk);
> +
> +	return 0;
> +}

This looks racy to me.  Given we did everything previously with devm
calls, which will run after this time, we are turning the timer off
before the userspace interfaces are removed.  If you need to do
this you probably also need to unwind the use of devm for anything
that needs this clock.

It's not immediately obvious how to clean up these timers cleanly
though as they seem to only be enabled on userspace configuration.

Any attempt to prevent removal of the driver until a manual unwind
is done by userspace would be risk prone, but that might be one
approach.  It's not as though anyone can force a removal of
one of these by pulling the cable out or anything.

> +
>  static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
>  	.valids_table = valids_table,
>  	.num_valids_table = ARRAY_SIZE(valids_table),
> @@ -872,6 +895,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
>  
>  static struct platform_driver stm32_timer_trigger_driver = {
>  	.probe = stm32_timer_trigger_probe,
> +	.remove = stm32_timer_trigger_remove,
>  	.driver = {
>  		.name = "stm32-timer-trigger",
>  		.of_match_table = stm32_trig_of_match,

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

* [PATCH 3/3] iio: trigger: stm32-timer: enable clock when in master mode
@ 2017-09-24 12:22     ` Jonathan Cameron
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2017-09-24 12:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 18 Sep 2017 12:05:32 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Clock should be enabled as soon as using master mode, even before
> enabling timer. Or, this may provoke bad behavior on the other end
> (slave timer). Then, introduce 'clk_enabled' flag, instead of relying
> on CR1 EN bit, to keep track of clock being enabled.
> Propagate this anywhere else in the driver.
> 
> Also add 'remove' routine to stop timer and disable clock in case it
> has been left enabled.

This last bit leaves us open to some nasty race conditions I think.
I'm not sure of a clean way to avoid them, but turning this off
before we remove the userspace interfaces doesn't strike me as a good
idea!

More detail inline.

Jonathan

> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 60 +++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index eb212f8c..5a6509c 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -79,6 +79,7 @@ struct stm32_timer_trigger {
>  	struct device *dev;
>  	struct regmap *regmap;
>  	struct clk *clk;
> +	bool clk_enabled;
>  	u32 max_arr;
>  	const void *triggers;
>  	const void *valids;
> @@ -106,7 +107,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  {
>  	unsigned long long prd, div;
>  	int prescaler = 0;
> -	u32 ccer, cr1;
> +	u32 ccer;
>  
>  	/* Period and prescaler values depends of clock rate */
>  	div = (unsigned long long)clk_get_rate(priv->clk);
> @@ -136,9 +137,10 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  	if (ccer & TIM_CCER_CCXE)
>  		return -EBUSY;
>  
> -	regmap_read(priv->regmap, TIM_CR1, &cr1);
> -	if (!(cr1 & TIM_CR1_CEN))
> +	if (!priv->clk_enabled) {
> +		priv->clk_enabled = true;
>  		clk_enable(priv->clk);
> +	}
>  
>  	regmap_write(priv->regmap, TIM_PSC, prescaler);
>  	regmap_write(priv->regmap, TIM_ARR, prd - 1);
> @@ -163,16 +165,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  
>  static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  {
> -	u32 ccer, cr1;
> +	u32 ccer;
>  
>  	regmap_read(priv->regmap, TIM_CCER, &ccer);
>  	if (ccer & TIM_CCER_CCXE)
>  		return;
>  
> -	regmap_read(priv->regmap, TIM_CR1, &cr1);
> -	if (cr1 & TIM_CR1_CEN)
> -		clk_disable(priv->clk);
> -
>  	/* Stop timer */
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
>  	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> @@ -181,6 +179,11 @@ static void stm32_timer_stop(struct stm32_timer_trigger *priv)
>  
>  	/* Make sure that registers are updated */
>  	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> +
> +	if (priv->clk_enabled) {
> +		priv->clk_enabled = false;
> +		clk_disable(priv->clk);
> +	}
>  }
>  
>  static ssize_t stm32_tt_store_frequency(struct device *dev,
> @@ -295,6 +298,11 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
>  	for (i = 0; i <= master_mode_max; i++) {
>  		if (!strncmp(master_mode_table[i], buf,
>  			     strlen(master_mode_table[i]))) {
> +			if (!priv->clk_enabled) {
> +				/* Clock should be enabled first */
> +				priv->clk_enabled = true;
> +				clk_enable(priv->clk);
> +			}
>  			regmap_update_bits(priv->regmap, TIM_CR2, mask,
>  					   i << shift);
>  			/* Make sure that registers are updated */
> @@ -438,7 +446,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  				   int val, int val2, long mask)
>  {
>  	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
> -	u32 dat;
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> @@ -450,17 +457,19 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  
>  	case IIO_CHAN_INFO_ENABLE:
>  		if (val) {
> -			regmap_read(priv->regmap, TIM_CR1, &dat);
> -			if (!(dat & TIM_CR1_CEN))
> +			if (!priv->clk_enabled) {
> +				priv->clk_enabled = true;
>  				clk_enable(priv->clk);
> +			}
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
>  					   TIM_CR1_CEN);
>  		} else {
> -			regmap_read(priv->regmap, TIM_CR1, &dat);
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
>  					   0);
> -			if (dat & TIM_CR1_CEN)
> +			if (priv->clk_enabled) {
> +				priv->clk_enabled = false;
>  				clk_disable(priv->clk);
> +			}
>  		}
>  		return 0;
>  	}
> @@ -558,7 +567,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
>  {
>  	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
>  	int sms = stm32_enable_mode2sms(mode);
> -	u32 val;
>  
>  	if (sms < 0)
>  		return sms;
> @@ -566,10 +574,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
>  	 * Triggered mode sets CEN bit automatically by hardware. So, first
>  	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
>  	 */
> -	if (sms == 6) {
> -		regmap_read(priv->regmap, TIM_CR1, &val);
> -		if (!(val & TIM_CR1_CEN))
> -			clk_enable(priv->clk);
> +	if (sms == 6 && !priv->clk_enabled) {
> +		clk_enable(priv->clk);
> +		priv->clk_enabled = true;
>  	}
>  
>  	regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
> @@ -848,6 +855,22 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int stm32_timer_trigger_remove(struct platform_device *pdev)
> +{
> +	struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
> +	u32 val;
> +
> +	/* Check if nobody else use the timer, then disable it */
> +	regmap_read(priv->regmap, TIM_CCER, &val);
> +	if (!(val & TIM_CCER_CCXE))
> +		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> +
> +	if (priv->clk_enabled)
> +		clk_disable(priv->clk);
> +
> +	return 0;
> +}

This looks racy to me.  Given we did everything previously with devm
calls, which will run after this time, we are turning the timer off
before the userspace interfaces are removed.  If you need to do
this you probably also need to unwind the use of devm for anything
that needs this clock.

It's not immediately obvious how to clean up these timers cleanly
though as they seem to only be enabled on userspace configuration.

Any attempt to prevent removal of the driver until a manual unwind
is done by userspace would be risk prone, but that might be one
approach.  It's not as though anyone can force a removal of
one of these by pulling the cable out or anything.

> +
>  static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
>  	.valids_table = valids_table,
>  	.num_valids_table = ARRAY_SIZE(valids_table),
> @@ -872,6 +895,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
>  
>  static struct platform_driver stm32_timer_trigger_driver = {
>  	.probe = stm32_timer_trigger_probe,
> +	.remove = stm32_timer_trigger_remove,
>  	.driver = {
>  		.name = "stm32-timer-trigger",
>  		.of_match_table = stm32_trig_of_match,

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

end of thread, other threads:[~2017-09-24 12:22 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-18 10:05 [PATCH 0/3] iio: trigger: stm32-timers fixes Fabrice Gasnier
2017-09-18 10:05 ` Fabrice Gasnier
2017-09-18 10:05 ` [PATCH 1/3] iio: trigger: stm32-timer: preset shouldn't be buffered Fabrice Gasnier
2017-09-18 10:05   ` Fabrice Gasnier
2017-09-24 12:09   ` Jonathan Cameron
2017-09-24 12:09     ` Jonathan Cameron
2017-09-18 10:05 ` [PATCH 2/3] iio: trigger: stm32-timer: fix a corner case to write preset Fabrice Gasnier
2017-09-18 10:05   ` Fabrice Gasnier
2017-09-24 12:10   ` Jonathan Cameron
2017-09-24 12:10     ` Jonathan Cameron
2017-09-18 10:05 ` [PATCH 3/3] iio: trigger: stm32-timer: enable clock when in master mode Fabrice Gasnier
2017-09-18 10:05   ` Fabrice Gasnier
2017-09-24 12:22   ` Jonathan Cameron
2017-09-24 12:22     ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.