This patch series adds power management support for STM32 LP Timer IIO
counter dt-bindings and driver.
Note: it's basically a resend of patches 3 & 4 as discussed in [1]
[1] https://patchwork.kernel.org/patch/10797425/
Fabrice Gasnier (2):
dt-bindings: iio: stm32-lptimer-counter: document pinctrl sleep state
iio: counter: stm32-lptimer: Add power management support
.../bindings/iio/counter/stm32-lptimer-cnt.txt | 8 ++--
drivers/iio/counter/stm32-lptimer-cnt.c | 55 ++++++++++++++++++++++
2 files changed, 60 insertions(+), 3 deletions(-)
--
2.7.4
Add documentation for optional pinctrl sleep state that can be used by
STM32 LPTimer encoder/counter.
Signed-off-by: Fabrice Gasnier <[email protected]>
---
.../devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
index a04aa5c..e90bc47 100644
--- a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
+++ b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
@@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node.
Required properties:
- compatible: Must be "st,stm32-lptimer-counter".
-- pinctrl-names: Set to "default".
-- pinctrl-0: List of phandles pointing to pin configuration nodes,
+- pinctrl-names: Set to "default". An additional "sleep" state can be
+ defined to set pins in sleep state.
+- pinctrl-n: List of phandles pointing to pin configuration nodes,
to set IN1/IN2 pins in mode of operation for Low-Power
Timer input on external pin.
@@ -21,7 +22,8 @@ Example:
...
counter {
compatible = "st,stm32-lptimer-counter";
- pinctrl-names = "default";
+ pinctrl-names = "default", "sleep";
pinctrl-0 = <&lptim1_in_pins>;
+ pinctrl-1 = <&lptim1_sleep_in_pins>;
};
};
--
2.7.4
Add suspend/resume PM sleep ops. When going to low power, disable
active counter. Only active counter should be resumed: don't touch
disabled counter, as it may be used by other LPTimer MFD child driver.
Signed-off-by: Fabrice Gasnier <[email protected]>
---
drivers/iio/counter/stm32-lptimer-cnt.c | 55 +++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c
index 42fb8ba..2a49cce 100644
--- a/drivers/iio/counter/stm32-lptimer-cnt.c
+++ b/drivers/iio/counter/stm32-lptimer-cnt.c
@@ -14,6 +14,7 @@
#include <linux/iio/iio.h>
#include <linux/mfd/stm32-lptimer.h>
#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
struct stm32_lptim_cnt {
@@ -23,6 +24,7 @@ struct stm32_lptim_cnt {
u32 preset;
u32 polarity;
u32 quadrature_mode;
+ bool enabled;
};
static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
@@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
if (!enable) {
clk_disable(priv->clk);
+ priv->enabled = false;
return 0;
}
@@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
return ret;
}
+ priv->enabled = true;
/* Start LP timer in continuous mode */
return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
@@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
return devm_iio_device_register(&pdev->dev, indio_dev);
}
+#ifdef CONFIG_PM_SLEEP
+static int stm32_lptim_cnt_suspend(struct device *dev)
+{
+ struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
+ int ret;
+
+ /* Only take care of enabled counter: don't disturb other MFD child */
+ if (priv->enabled) {
+ ret = stm32_lptim_setup(priv, 0);
+ if (ret)
+ return ret;
+
+ ret = stm32_lptim_set_enable_state(priv, 0);
+ if (ret)
+ return ret;
+
+ /* Force enable state for later resume */
+ priv->enabled = true;
+ }
+
+ return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int stm32_lptim_cnt_resume(struct device *dev)
+{
+ struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ return ret;
+
+ if (priv->enabled) {
+ priv->enabled = false;
+ ret = stm32_lptim_setup(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = stm32_lptim_set_enable_state(priv, 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
+ stm32_lptim_cnt_resume);
+
static const struct of_device_id stm32_lptim_cnt_of_match[] = {
{ .compatible = "st,stm32-lptimer-counter", },
{},
@@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = {
.driver = {
.name = "stm32-lptimer-counter",
.of_match_table = stm32_lptim_cnt_of_match,
+ .pm = &stm32_lptim_cnt_pm_ops,
},
};
module_platform_driver(stm32_lptim_cnt_driver);
--
2.7.4
On Mon, 25 Feb 2019 11:42:46 +0100
Fabrice Gasnier <[email protected]> wrote:
> Add documentation for optional pinctrl sleep state that can be used by
> STM32 LPTimer encoder/counter.
>
> Signed-off-by: Fabrice Gasnier <[email protected]>
Applied to the togreg branch of iio.git and pushed out as testing
for the autobuilders to play with it.
Note we are too late for the coming merge window so this will be
for the next one now.
Thanks,
Jonathan
> ---
> .../devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
> index a04aa5c..e90bc47 100644
> --- a/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
> +++ b/Documentation/devicetree/bindings/iio/counter/stm32-lptimer-cnt.txt
> @@ -10,8 +10,9 @@ See ../mfd/stm32-lptimer.txt for details about the parent node.
>
> Required properties:
> - compatible: Must be "st,stm32-lptimer-counter".
> -- pinctrl-names: Set to "default".
> -- pinctrl-0: List of phandles pointing to pin configuration nodes,
> +- pinctrl-names: Set to "default". An additional "sleep" state can be
> + defined to set pins in sleep state.
> +- pinctrl-n: List of phandles pointing to pin configuration nodes,
> to set IN1/IN2 pins in mode of operation for Low-Power
> Timer input on external pin.
>
> @@ -21,7 +22,8 @@ Example:
> ...
> counter {
> compatible = "st,stm32-lptimer-counter";
> - pinctrl-names = "default";
> + pinctrl-names = "default", "sleep";
> pinctrl-0 = <&lptim1_in_pins>;
> + pinctrl-1 = <&lptim1_sleep_in_pins>;
> };
> };
On Mon, 25 Feb 2019 11:42:47 +0100
Fabrice Gasnier <[email protected]> wrote:
> Add suspend/resume PM sleep ops. When going to low power, disable
> active counter. Only active counter should be resumed: don't touch
> disabled counter, as it may be used by other LPTimer MFD child driver.
>
> Signed-off-by: Fabrice Gasnier <[email protected]>
Applied. Thanks,
Jonathan
> ---
> drivers/iio/counter/stm32-lptimer-cnt.c | 55 +++++++++++++++++++++++++++++++++
> 1 file changed, 55 insertions(+)
>
> diff --git a/drivers/iio/counter/stm32-lptimer-cnt.c b/drivers/iio/counter/stm32-lptimer-cnt.c
> index 42fb8ba..2a49cce 100644
> --- a/drivers/iio/counter/stm32-lptimer-cnt.c
> +++ b/drivers/iio/counter/stm32-lptimer-cnt.c
> @@ -14,6 +14,7 @@
> #include <linux/iio/iio.h>
> #include <linux/mfd/stm32-lptimer.h>
> #include <linux/module.h>
> +#include <linux/pinctrl/consumer.h>
> #include <linux/platform_device.h>
>
> struct stm32_lptim_cnt {
> @@ -23,6 +24,7 @@ struct stm32_lptim_cnt {
> u32 preset;
> u32 polarity;
> u32 quadrature_mode;
> + bool enabled;
> };
>
> static int stm32_lptim_is_enabled(struct stm32_lptim_cnt *priv)
> @@ -50,6 +52,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
>
> if (!enable) {
> clk_disable(priv->clk);
> + priv->enabled = false;
> return 0;
> }
>
> @@ -79,6 +82,7 @@ static int stm32_lptim_set_enable_state(struct stm32_lptim_cnt *priv,
> regmap_write(priv->regmap, STM32_LPTIM_CR, 0);
> return ret;
> }
> + priv->enabled = true;
>
> /* Start LP timer in continuous mode */
> return regmap_update_bits(priv->regmap, STM32_LPTIM_CR,
> @@ -361,6 +365,56 @@ static int stm32_lptim_cnt_probe(struct platform_device *pdev)
> return devm_iio_device_register(&pdev->dev, indio_dev);
> }
>
> +#ifdef CONFIG_PM_SLEEP
> +static int stm32_lptim_cnt_suspend(struct device *dev)
> +{
> + struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
> + int ret;
> +
> + /* Only take care of enabled counter: don't disturb other MFD child */
> + if (priv->enabled) {
> + ret = stm32_lptim_setup(priv, 0);
> + if (ret)
> + return ret;
> +
> + ret = stm32_lptim_set_enable_state(priv, 0);
> + if (ret)
> + return ret;
> +
> + /* Force enable state for later resume */
> + priv->enabled = true;
> + }
> +
> + return pinctrl_pm_select_sleep_state(dev);
> +}
> +
> +static int stm32_lptim_cnt_resume(struct device *dev)
> +{
> + struct stm32_lptim_cnt *priv = dev_get_drvdata(dev);
> + int ret;
> +
> + ret = pinctrl_pm_select_default_state(dev);
> + if (ret)
> + return ret;
> +
> + if (priv->enabled) {
> + priv->enabled = false;
> + ret = stm32_lptim_setup(priv, 1);
> + if (ret)
> + return ret;
> +
> + ret = stm32_lptim_set_enable_state(priv, 1);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(stm32_lptim_cnt_pm_ops, stm32_lptim_cnt_suspend,
> + stm32_lptim_cnt_resume);
> +
> static const struct of_device_id stm32_lptim_cnt_of_match[] = {
> { .compatible = "st,stm32-lptimer-counter", },
> {},
> @@ -372,6 +426,7 @@ static struct platform_driver stm32_lptim_cnt_driver = {
> .driver = {
> .name = "stm32-lptimer-counter",
> .of_match_table = stm32_lptim_cnt_of_match,
> + .pm = &stm32_lptim_cnt_pm_ops,
> },
> };
> module_platform_driver(stm32_lptim_cnt_driver);