[v2] iio: adc: stm32-adc: fix runtime autosuspend delay when slow polling
diff mbox series

Message ID 1588163348-31640-1-git-send-email-fabrice.gasnier@st.com
State Accepted
Commit c537d3457542a398caa1fe58e0976c5f83cf7281
Headers show
Series
  • [v2] iio: adc: stm32-adc: fix runtime autosuspend delay when slow polling
Related show

Commit Message

Fabrice Gasnier April 29, 2020, 12:29 p.m. UTC
When the ADC is runtime suspended and starting a conversion, the stm32-adc
driver calls pm_runtime_get_sync() that gets cascaded to the parent
(e.g. runtime resume of stm32-adc-core driver). This also kicks the
autosuspend delay (e.g. 2s) of the parent.
Once the ADC is active, calling pm_runtime_get_sync() again (upon a new
capture) won't kick the autosuspend delay for the parent (stm32-adc-core
driver) as already active.

Currently, this makes the stm32-adc-core driver go in suspend state
every 2s when doing slow polling. As an example, doing a capture, e.g.
cat in_voltageY_raw at a 0.2s rate, the auto suspend delay for the parent
isn't refreshed. Once it expires, the parent immediately falls into
runtime suspended state, in between two captures, as soon as the child
driver falls into runtime suspend state:
- e.g. after 2s, + child calls pm_runtime_put_autosuspend() + 100ms
  autosuspend delay of the child.
- stm32-adc-core switches off regulators, clocks and so on.
- They get switched on back again 100ms later in this example (at 2.2s).

So, use runtime_idle() callback in stm32-adc-core driver to call
pm_runtime_mark_last_busy() for the parent driver (stm32-adc-core),
to avoid this.

Fixes: 9bdbb1139ca1 ("iio: adc: stm32-adc: add power management support")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- Use runtime_idle callback in stm32-adc-core driver, instead of refreshing
  last_busy from the child (for the parent) at many place. Initial patch v1
  looked like "somewhat adhoc solution" as commented by Jonathan.
---
 drivers/iio/adc/stm32-adc-core.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Comments

Jonathan Cameron May 3, 2020, 11:48 a.m. UTC | #1
On Wed, 29 Apr 2020 14:29:08 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> When the ADC is runtime suspended and starting a conversion, the stm32-adc
> driver calls pm_runtime_get_sync() that gets cascaded to the parent
> (e.g. runtime resume of stm32-adc-core driver). This also kicks the
> autosuspend delay (e.g. 2s) of the parent.
> Once the ADC is active, calling pm_runtime_get_sync() again (upon a new
> capture) won't kick the autosuspend delay for the parent (stm32-adc-core
> driver) as already active.
> 
> Currently, this makes the stm32-adc-core driver go in suspend state
> every 2s when doing slow polling. As an example, doing a capture, e.g.
> cat in_voltageY_raw at a 0.2s rate, the auto suspend delay for the parent
> isn't refreshed. Once it expires, the parent immediately falls into
> runtime suspended state, in between two captures, as soon as the child
> driver falls into runtime suspend state:
> - e.g. after 2s, + child calls pm_runtime_put_autosuspend() + 100ms
>   autosuspend delay of the child.
> - stm32-adc-core switches off regulators, clocks and so on.
> - They get switched on back again 100ms later in this example (at 2.2s).
> 
> So, use runtime_idle() callback in stm32-adc-core driver to call
> pm_runtime_mark_last_busy() for the parent driver (stm32-adc-core),
> to avoid this.
> 
> Fixes: 9bdbb1139ca1 ("iio: adc: stm32-adc: add power management support")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Whilst this seems 'sensible' to me, I really don't have a good enough grasp
of runtime pm to be sure. 

I see something similar looking in the greybus driver, but not sure on the
reason it is there.

Hence, ideally looking for an ack from Rafael on this one!

Thanks,

Jonathan

> ---
> Changes in v2:
> - Use runtime_idle callback in stm32-adc-core driver, instead of refreshing
>   last_busy from the child (for the parent) at many place. Initial patch v1
>   looked like "somewhat adhoc solution" as commented by Jonathan.
> ---
>  drivers/iio/adc/stm32-adc-core.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
> index 2df88d2..ebe5dbc 100644
> --- a/drivers/iio/adc/stm32-adc-core.c
> +++ b/drivers/iio/adc/stm32-adc-core.c
> @@ -803,6 +803,13 @@ static int stm32_adc_core_runtime_resume(struct device *dev)
>  {
>  	return stm32_adc_core_hw_start(dev);
>  }
> +
> +static int stm32_adc_core_runtime_idle(struct device *dev)
> +{
> +	pm_runtime_mark_last_busy(dev);
> +
> +	return 0;
> +}
>  #endif
>  
>  static const struct dev_pm_ops stm32_adc_core_pm_ops = {
> @@ -810,7 +817,7 @@ static const struct dev_pm_ops stm32_adc_core_pm_ops = {
>  				pm_runtime_force_resume)
>  	SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
>  			   stm32_adc_core_runtime_resume,
> -			   NULL)
> +			   stm32_adc_core_runtime_idle)
>  };
>  
>  static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
Fabrice Gasnier June 11, 2020, 10:09 a.m. UTC | #2
On 5/3/20 1:48 PM, Jonathan Cameron wrote:
> On Wed, 29 Apr 2020 14:29:08 +0200
> Fabrice Gasnier <fabrice.gasnier@st.com> wrote:
> 
>> When the ADC is runtime suspended and starting a conversion, the stm32-adc
>> driver calls pm_runtime_get_sync() that gets cascaded to the parent
>> (e.g. runtime resume of stm32-adc-core driver). This also kicks the
>> autosuspend delay (e.g. 2s) of the parent.
>> Once the ADC is active, calling pm_runtime_get_sync() again (upon a new
>> capture) won't kick the autosuspend delay for the parent (stm32-adc-core
>> driver) as already active.
>>
>> Currently, this makes the stm32-adc-core driver go in suspend state
>> every 2s when doing slow polling. As an example, doing a capture, e.g.
>> cat in_voltageY_raw at a 0.2s rate, the auto suspend delay for the parent
>> isn't refreshed. Once it expires, the parent immediately falls into
>> runtime suspended state, in between two captures, as soon as the child
>> driver falls into runtime suspend state:
>> - e.g. after 2s, + child calls pm_runtime_put_autosuspend() + 100ms
>>   autosuspend delay of the child.
>> - stm32-adc-core switches off regulators, clocks and so on.
>> - They get switched on back again 100ms later in this example (at 2.2s).
>>
>> So, use runtime_idle() callback in stm32-adc-core driver to call
>> pm_runtime_mark_last_busy() for the parent driver (stm32-adc-core),
>> to avoid this.
>>
>> Fixes: 9bdbb1139ca1 ("iio: adc: stm32-adc: add power management support")
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> 
> Whilst this seems 'sensible' to me, I really don't have a good enough grasp
> of runtime pm to be sure. 
> 
> I see something similar looking in the greybus driver, but not sure on the
> reason it is there.
> 
> Hence, ideally looking for an ack from Rafael on this one!

Hi,

Gentle reminder, I'm not sure how to progress on this patch.

Rafael, or maybe Ulf, could take a look at it ?

Thanks in advance,
Best Regards,
Fabrice

> 
> Thanks,
> 
> Jonathan
> 
>> ---
>> Changes in v2:
>> - Use runtime_idle callback in stm32-adc-core driver, instead of refreshing
>>   last_busy from the child (for the parent) at many place. Initial patch v1
>>   looked like "somewhat adhoc solution" as commented by Jonathan.
>> ---
>>  drivers/iio/adc/stm32-adc-core.c | 9 ++++++++-
>>  1 file changed, 8 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
>> index 2df88d2..ebe5dbc 100644
>> --- a/drivers/iio/adc/stm32-adc-core.c
>> +++ b/drivers/iio/adc/stm32-adc-core.c
>> @@ -803,6 +803,13 @@ static int stm32_adc_core_runtime_resume(struct device *dev)
>>  {
>>  	return stm32_adc_core_hw_start(dev);
>>  }
>> +
>> +static int stm32_adc_core_runtime_idle(struct device *dev)
>> +{
>> +	pm_runtime_mark_last_busy(dev);
>> +
>> +	return 0;
>> +}
>>  #endif
>>  
>>  static const struct dev_pm_ops stm32_adc_core_pm_ops = {
>> @@ -810,7 +817,7 @@ static const struct dev_pm_ops stm32_adc_core_pm_ops = {
>>  				pm_runtime_force_resume)
>>  	SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
>>  			   stm32_adc_core_runtime_resume,
>> -			   NULL)
>> +			   stm32_adc_core_runtime_idle)
>>  };
>>  
>>  static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
>

Patch
diff mbox series

diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 2df88d2..ebe5dbc 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -803,6 +803,13 @@  static int stm32_adc_core_runtime_resume(struct device *dev)
 {
 	return stm32_adc_core_hw_start(dev);
 }
+
+static int stm32_adc_core_runtime_idle(struct device *dev)
+{
+	pm_runtime_mark_last_busy(dev);
+
+	return 0;
+}
 #endif
 
 static const struct dev_pm_ops stm32_adc_core_pm_ops = {
@@ -810,7 +817,7 @@  static const struct dev_pm_ops stm32_adc_core_pm_ops = {
 				pm_runtime_force_resume)
 	SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend,
 			   stm32_adc_core_runtime_resume,
-			   NULL)
+			   stm32_adc_core_runtime_idle)
 };
 
 static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {