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:
Родитель
0f9d2ecba8
Коммит
2d3aa06b5d
|
@ -12,6 +12,7 @@
|
|||
#include <linux/mfd/stm32-timers.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
|
@ -659,6 +660,42 @@ static int stm32_pwm_remove(struct platform_device *pdev)
|
|||
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[] = {
|
||||
{ .compatible = "st,stm32-pwm", },
|
||||
{ /* end node */ },
|
||||
|
@ -671,6 +708,7 @@ static struct platform_driver stm32_pwm_driver = {
|
|||
.driver = {
|
||||
.name = "stm32-pwm",
|
||||
.of_match_table = stm32_pwm_of_match,
|
||||
.pm = &stm32_pwm_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(stm32_pwm_driver);
|
||||
|
|
Загрузка…
Ссылка в новой задаче