Commit 2d3aa06b authored by Fabrice Gasnier's avatar Fabrice Gasnier Committed by Thierry Reding

pwm: stm32: Add power management support

Add suspend/resume PM sleep ops. When going to low power, enforce the PWM
channel isn't active. Let the PWM consumers disable it during their own
suspend sequence, see [1]. So, perform a check here, and handle the
pinctrl states. Also restore the break inputs upon resume, as registers
content may be lost when going to low power mode.

[1] https://lkml.org/lkml/2019/2/5/770Signed-off-by: default avatarFabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent 0f9d2ecb
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/mfd/stm32-timers.h> #include <linux/mfd/stm32-timers.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pwm.h> #include <linux/pwm.h>
...@@ -659,6 +660,42 @@ static int stm32_pwm_remove(struct platform_device *pdev) ...@@ -659,6 +660,42 @@ static int stm32_pwm_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused stm32_pwm_suspend(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
unsigned int i;
u32 ccer, mask;
/* Look for active channels */
ccer = active_channels(priv);
for (i = 0; i < priv->chip.npwm; i++) {
mask = TIM_CCER_CC1E << (i * 4);
if (ccer & mask) {
dev_err(dev, "PWM %u still in use by consumer %s\n",
i, priv->chip.pwms[i].label);
return -EBUSY;
}
}
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused stm32_pwm_resume(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
int ret;
ret = pinctrl_pm_select_default_state(dev);
if (ret)
return ret;
/* restore breakinput registers that may have been lost in low power */
return stm32_pwm_apply_breakinputs(priv);
}
static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
static const struct of_device_id stm32_pwm_of_match[] = { static const struct of_device_id stm32_pwm_of_match[] = {
{ .compatible = "st,stm32-pwm", }, { .compatible = "st,stm32-pwm", },
{ /* end node */ }, { /* end node */ },
...@@ -671,6 +708,7 @@ static struct platform_driver stm32_pwm_driver = { ...@@ -671,6 +708,7 @@ static struct platform_driver stm32_pwm_driver = {
.driver = { .driver = {
.name = "stm32-pwm", .name = "stm32-pwm",
.of_match_table = stm32_pwm_of_match, .of_match_table = stm32_pwm_of_match,
.pm = &stm32_pwm_pm_ops,
}, },
}; };
module_platform_driver(stm32_pwm_driver); module_platform_driver(stm32_pwm_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment