linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] iio: trigger: stm32-timer: add support for power management
@ 2020-03-03 14:59 Fabrice Gasnier
  2020-03-03 14:59 ` [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag Fabrice Gasnier
  2020-03-03 14:59 ` [PATCH 2/2] iio: trigger: stm32-timer: add power management support Fabrice Gasnier
  0 siblings, 2 replies; 5+ messages in thread
From: Fabrice Gasnier @ 2020-03-03 14:59 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	benjamin.gaignard, alexandre.torgue, fabrice.gasnier,
	olivier.moysan, linux-iio, lars, knaack.h, pmeerw, linux-stm32

This series adds power management support to stm32-timer-trigger driver,
it adds suspend/resume routines. A small precursor patch is used to rename
"enabled" flag.

Fabrice Gasnier (2):
  iio: trigger: stm32-timer: rename enabled flag
  iio: trigger: stm32-timer: add power management support

 drivers/iio/trigger/stm32-timer-trigger.c | 91 ++++++++++++++++++++++++++-----
 1 file changed, 77 insertions(+), 14 deletions(-)

-- 
2.7.4


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

* [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag
  2020-03-03 14:59 [PATCH 0/2] iio: trigger: stm32-timer: add support for power management Fabrice Gasnier
@ 2020-03-03 14:59 ` Fabrice Gasnier
  2020-03-07 15:20   ` Jonathan Cameron
  2020-03-03 14:59 ` [PATCH 2/2] iio: trigger: stm32-timer: add power management support Fabrice Gasnier
  1 sibling, 1 reply; 5+ messages in thread
From: Fabrice Gasnier @ 2020-03-03 14:59 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	benjamin.gaignard, alexandre.torgue, fabrice.gasnier,
	olivier.moysan, linux-iio, lars, knaack.h, pmeerw, linux-stm32

"clk_enabled" flag reflects enabled state of the timer, for master mode,
slave mode or trigger (with sampling_frequency). So rename it to "enabled".

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

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 16a3b6b..32e1249 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -79,7 +79,7 @@ struct stm32_timer_trigger {
 	struct device *dev;
 	struct regmap *regmap;
 	struct clk *clk;
-	bool clk_enabled;
+	bool enabled;
 	u32 max_arr;
 	const void *triggers;
 	const void *valids;
@@ -140,8 +140,8 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 		return -EBUSY;
 
 	mutex_lock(&priv->lock);
-	if (!priv->clk_enabled) {
-		priv->clk_enabled = true;
+	if (!priv->enabled) {
+		priv->enabled = true;
 		clk_enable(priv->clk);
 	}
 
@@ -185,8 +185,8 @@ 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;
+	if (priv->enabled) {
+		priv->enabled = false;
 		clk_disable(priv->clk);
 	}
 	mutex_unlock(&priv->lock);
@@ -305,9 +305,9 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
 		if (!strncmp(master_mode_table[i], buf,
 			     strlen(master_mode_table[i]))) {
 			mutex_lock(&priv->lock);
-			if (!priv->clk_enabled) {
+			if (!priv->enabled) {
 				/* Clock should be enabled first */
-				priv->clk_enabled = true;
+				priv->enabled = true;
 				clk_enable(priv->clk);
 			}
 			regmap_update_bits(priv->regmap, TIM_CR2, mask,
@@ -476,8 +476,8 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 	case IIO_CHAN_INFO_ENABLE:
 		mutex_lock(&priv->lock);
 		if (val) {
-			if (!priv->clk_enabled) {
-				priv->clk_enabled = true;
+			if (!priv->enabled) {
+				priv->enabled = true;
 				clk_enable(priv->clk);
 			}
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
@@ -485,8 +485,8 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
 		} else {
 			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
 					   0);
-			if (priv->clk_enabled) {
-				priv->clk_enabled = false;
+			if (priv->enabled) {
+				priv->enabled = false;
 				clk_disable(priv->clk);
 			}
 		}
@@ -594,9 +594,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
 	 */
 	mutex_lock(&priv->lock);
-	if (sms == 6 && !priv->clk_enabled) {
+	if (sms == 6 && !priv->enabled) {
 		clk_enable(priv->clk);
-		priv->clk_enabled = true;
+		priv->enabled = true;
 	}
 	mutex_unlock(&priv->lock);
 
@@ -806,7 +806,7 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
 	if (!(val & TIM_CCER_CCXE))
 		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
 
-	if (priv->clk_enabled)
+	if (priv->enabled)
 		clk_disable(priv->clk);
 
 	return 0;
-- 
2.7.4


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

* [PATCH 2/2] iio: trigger: stm32-timer: add power management support
  2020-03-03 14:59 [PATCH 0/2] iio: trigger: stm32-timer: add support for power management Fabrice Gasnier
  2020-03-03 14:59 ` [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag Fabrice Gasnier
@ 2020-03-03 14:59 ` Fabrice Gasnier
  2020-03-07 15:21   ` Jonathan Cameron
  1 sibling, 1 reply; 5+ messages in thread
From: Fabrice Gasnier @ 2020-03-03 14:59 UTC (permalink / raw)
  To: jic23
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	benjamin.gaignard, alexandre.torgue, fabrice.gasnier,
	olivier.moysan, linux-iio, lars, knaack.h, pmeerw, linux-stm32

Add suspend/resume PM sleep ops to stm32-timer-trigger driver.
Register contents may be lost depending on low power modes.
When going to low power, enforce the timer isn't active. Gracefully
restore its state upon resume in case it's been left enabled prior to
suspend.

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

diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
index 32e1249..37545a8 100644
--- a/drivers/iio/trigger/stm32-timer-trigger.c
+++ b/drivers/iio/trigger/stm32-timer-trigger.c
@@ -75,6 +75,15 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = {
 	{ }, /* timer 17 */
 };
 
+struct stm32_timer_trigger_regs {
+	u32 cr1;
+	u32 cr2;
+	u32 psc;
+	u32 arr;
+	u32 cnt;
+	u32 smcr;
+};
+
 struct stm32_timer_trigger {
 	struct device *dev;
 	struct regmap *regmap;
@@ -86,6 +95,7 @@ struct stm32_timer_trigger {
 	bool has_trgo2;
 	struct mutex lock; /* concurrent sysfs configuration */
 	struct list_head tr_list;
+	struct stm32_timer_trigger_regs bak;
 };
 
 struct stm32_timer_trigger_cfg {
@@ -812,6 +822,58 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev)
+{
+	struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+
+	/* Only take care of enabled timer: don't disturb other MFD child */
+	if (priv->enabled) {
+		/* Backup registers that may get lost in low power mode */
+		regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1);
+		regmap_read(priv->regmap, TIM_CR2, &priv->bak.cr2);
+		regmap_read(priv->regmap, TIM_PSC, &priv->bak.psc);
+		regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr);
+		regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt);
+		regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
+
+		/* Disable the timer */
+		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+		clk_disable(priv->clk);
+	}
+
+	return 0;
+}
+
+static int __maybe_unused stm32_timer_trigger_resume(struct device *dev)
+{
+	struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+	int ret;
+
+	if (priv->enabled) {
+		ret = clk_enable(priv->clk);
+		if (ret)
+			return ret;
+
+		/* restore master/slave modes */
+		regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr);
+		regmap_write(priv->regmap, TIM_CR2, priv->bak.cr2);
+
+		/* restore sampling_frequency (trgo / trgo2 triggers) */
+		regmap_write(priv->regmap, TIM_PSC, priv->bak.psc);
+		regmap_write(priv->regmap, TIM_ARR, priv->bak.arr);
+		regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt);
+
+		/* Also re-enables the timer */
+		regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops,
+			 stm32_timer_trigger_suspend,
+			 stm32_timer_trigger_resume);
+
 static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
 	.valids_table = valids_table,
 	.num_valids_table = ARRAY_SIZE(valids_table),
@@ -840,6 +902,7 @@ static struct platform_driver stm32_timer_trigger_driver = {
 	.driver = {
 		.name = "stm32-timer-trigger",
 		.of_match_table = stm32_trig_of_match,
+		.pm = &stm32_timer_trigger_pm_ops,
 	},
 };
 module_platform_driver(stm32_timer_trigger_driver);
-- 
2.7.4


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

* Re: [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag
  2020-03-03 14:59 ` [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag Fabrice Gasnier
@ 2020-03-07 15:20   ` Jonathan Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2020-03-07 15:20 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	benjamin.gaignard, alexandre.torgue, olivier.moysan, linux-iio,
	lars, knaack.h, pmeerw, linux-stm32

On Tue, 3 Mar 2020 15:59:44 +0100
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> "clk_enabled" flag reflects enabled state of the timer, for master mode,
> slave mode or trigger (with sampling_frequency). So rename it to "enabled".
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan

> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 28 ++++++++++++++--------------
>  1 file changed, 14 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 16a3b6b..32e1249 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -79,7 +79,7 @@ struct stm32_timer_trigger {
>  	struct device *dev;
>  	struct regmap *regmap;
>  	struct clk *clk;
> -	bool clk_enabled;
> +	bool enabled;
>  	u32 max_arr;
>  	const void *triggers;
>  	const void *valids;
> @@ -140,8 +140,8 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
>  		return -EBUSY;
>  
>  	mutex_lock(&priv->lock);
> -	if (!priv->clk_enabled) {
> -		priv->clk_enabled = true;
> +	if (!priv->enabled) {
> +		priv->enabled = true;
>  		clk_enable(priv->clk);
>  	}
>  
> @@ -185,8 +185,8 @@ 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;
> +	if (priv->enabled) {
> +		priv->enabled = false;
>  		clk_disable(priv->clk);
>  	}
>  	mutex_unlock(&priv->lock);
> @@ -305,9 +305,9 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
>  		if (!strncmp(master_mode_table[i], buf,
>  			     strlen(master_mode_table[i]))) {
>  			mutex_lock(&priv->lock);
> -			if (!priv->clk_enabled) {
> +			if (!priv->enabled) {
>  				/* Clock should be enabled first */
> -				priv->clk_enabled = true;
> +				priv->enabled = true;
>  				clk_enable(priv->clk);
>  			}
>  			regmap_update_bits(priv->regmap, TIM_CR2, mask,
> @@ -476,8 +476,8 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  	case IIO_CHAN_INFO_ENABLE:
>  		mutex_lock(&priv->lock);
>  		if (val) {
> -			if (!priv->clk_enabled) {
> -				priv->clk_enabled = true;
> +			if (!priv->enabled) {
> +				priv->enabled = true;
>  				clk_enable(priv->clk);
>  			}
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
> @@ -485,8 +485,8 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
>  		} else {
>  			regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
>  					   0);
> -			if (priv->clk_enabled) {
> -				priv->clk_enabled = false;
> +			if (priv->enabled) {
> +				priv->enabled = false;
>  				clk_disable(priv->clk);
>  			}
>  		}
> @@ -594,9 +594,9 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
>  	 * enable counter clock, so it can use it. Keeps it in sync with CEN.
>  	 */
>  	mutex_lock(&priv->lock);
> -	if (sms == 6 && !priv->clk_enabled) {
> +	if (sms == 6 && !priv->enabled) {
>  		clk_enable(priv->clk);
> -		priv->clk_enabled = true;
> +		priv->enabled = true;
>  	}
>  	mutex_unlock(&priv->lock);
>  
> @@ -806,7 +806,7 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
>  	if (!(val & TIM_CCER_CCXE))
>  		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
>  
> -	if (priv->clk_enabled)
> +	if (priv->enabled)
>  		clk_disable(priv->clk);
>  
>  	return 0;


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

* Re: [PATCH 2/2] iio: trigger: stm32-timer: add power management support
  2020-03-03 14:59 ` [PATCH 2/2] iio: trigger: stm32-timer: add power management support Fabrice Gasnier
@ 2020-03-07 15:21   ` Jonathan Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2020-03-07 15:21 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: linux-arm-kernel, linux-kernel, mcoquelin.stm32,
	benjamin.gaignard, alexandre.torgue, olivier.moysan, linux-iio,
	lars, knaack.h, pmeerw, linux-stm32

On Tue, 3 Mar 2020 15:59:45 +0100
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Add suspend/resume PM sleep ops to stm32-timer-trigger driver.
> Register contents may be lost depending on low power modes.
> When going to low power, enforce the timer isn't active. Gracefully
> restore its state upon resume in case it's been left enabled prior to
> suspend.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Seems sensible. Applied,

Thanks,

Jonathan

> ---
>  drivers/iio/trigger/stm32-timer-trigger.c | 63 +++++++++++++++++++++++++++++++
>  1 file changed, 63 insertions(+)
> 
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> index 32e1249..37545a8 100644
> --- a/drivers/iio/trigger/stm32-timer-trigger.c
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -75,6 +75,15 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = {
>  	{ }, /* timer 17 */
>  };
>  
> +struct stm32_timer_trigger_regs {
> +	u32 cr1;
> +	u32 cr2;
> +	u32 psc;
> +	u32 arr;
> +	u32 cnt;
> +	u32 smcr;
> +};
> +
>  struct stm32_timer_trigger {
>  	struct device *dev;
>  	struct regmap *regmap;
> @@ -86,6 +95,7 @@ struct stm32_timer_trigger {
>  	bool has_trgo2;
>  	struct mutex lock; /* concurrent sysfs configuration */
>  	struct list_head tr_list;
> +	struct stm32_timer_trigger_regs bak;
>  };
>  
>  struct stm32_timer_trigger_cfg {
> @@ -812,6 +822,58 @@ static int stm32_timer_trigger_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev)
> +{
> +	struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
> +
> +	/* Only take care of enabled timer: don't disturb other MFD child */
> +	if (priv->enabled) {
> +		/* Backup registers that may get lost in low power mode */
> +		regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1);
> +		regmap_read(priv->regmap, TIM_CR2, &priv->bak.cr2);
> +		regmap_read(priv->regmap, TIM_PSC, &priv->bak.psc);
> +		regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr);
> +		regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt);
> +		regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
> +
> +		/* Disable the timer */
> +		regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> +		clk_disable(priv->clk);
> +	}
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused stm32_timer_trigger_resume(struct device *dev)
> +{
> +	struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
> +	int ret;
> +
> +	if (priv->enabled) {
> +		ret = clk_enable(priv->clk);
> +		if (ret)
> +			return ret;
> +
> +		/* restore master/slave modes */
> +		regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr);
> +		regmap_write(priv->regmap, TIM_CR2, priv->bak.cr2);
> +
> +		/* restore sampling_frequency (trgo / trgo2 triggers) */
> +		regmap_write(priv->regmap, TIM_PSC, priv->bak.psc);
> +		regmap_write(priv->regmap, TIM_ARR, priv->bak.arr);
> +		regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt);
> +
> +		/* Also re-enables the timer */
> +		regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1);
> +	}
> +
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops,
> +			 stm32_timer_trigger_suspend,
> +			 stm32_timer_trigger_resume);
> +
>  static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
>  	.valids_table = valids_table,
>  	.num_valids_table = ARRAY_SIZE(valids_table),
> @@ -840,6 +902,7 @@ static struct platform_driver stm32_timer_trigger_driver = {
>  	.driver = {
>  		.name = "stm32-timer-trigger",
>  		.of_match_table = stm32_trig_of_match,
> +		.pm = &stm32_timer_trigger_pm_ops,
>  	},
>  };
>  module_platform_driver(stm32_timer_trigger_driver);


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

end of thread, other threads:[~2020-03-07 15:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-03 14:59 [PATCH 0/2] iio: trigger: stm32-timer: add support for power management Fabrice Gasnier
2020-03-03 14:59 ` [PATCH 1/2] iio: trigger: stm32-timer: rename enabled flag Fabrice Gasnier
2020-03-07 15:20   ` Jonathan Cameron
2020-03-03 14:59 ` [PATCH 2/2] iio: trigger: stm32-timer: add power management support Fabrice Gasnier
2020-03-07 15:21   ` Jonathan Cameron

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