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/770 Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
parent
0f9d2ecba8
commit
2d3aa06b5d
|
@ -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)
|
||||||
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 = {
|
||||||
.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);
|
||||||
|
|
Loading…
Reference in New Issue