diff options
author | Iván Briano <ivan.briano@intel.com> | 2016-08-01 10:35:56 -0300 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 2016-08-02 06:48:21 +0000 |
commit | 1a47abe5bfdfbc9349aed87dbf667c95e0e86a67 (patch) | |
tree | 5539492609d18aba218ace3a1697bbf50ca98b05 | |
parent | dfc15d3a48500115b4948c584db7ced690aea6db (diff) |
pwm qmsi: Add suspend/resume
Implement saving and restoring context of the PWM controller when the
application goes to SYS_PM_DEEP_SLEEP. No action is taken for other
states at the moment.
This functionality is implemented in the shim driver first to enable
the feature, but will later be moved into QMSI.
Change-Id: I5784f6a2c63caaea5785ca5d92bb6cc3bc9fa4cc
Signed-off-by: Iván Briano <ivan.briano@intel.com>
-rw-r--r-- | drivers/pwm/pwm_qmsi.c | 70 |
1 files changed, 66 insertions, 4 deletions
diff --git a/drivers/pwm/pwm_qmsi.c b/drivers/pwm/pwm_qmsi.c index 2b3c41d0f..09b443065 100644 --- a/drivers/pwm/pwm_qmsi.c +++ b/drivers/pwm/pwm_qmsi.c @@ -20,6 +20,7 @@ #include <pwm.h> #include <device.h> #include <init.h> +#include <power.h> #include "qm_pwm.h" #include "clk.h" @@ -318,7 +319,68 @@ static int pwm_qmsi_init(struct device *dev) return 0; } -DEVICE_AND_API_INIT(pwm_qmsi_0, CONFIG_PWM_QMSI_DEV_NAME, pwm_qmsi_init, - PWM_CONTEXT, pwm_channel_period, SECONDARY, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - (void *)&pwm_qmsi_drv_api_funcs); +#ifdef CONFIG_DEVICE_POWER_MANAGEMENT +struct pwm_channel_ctx { + uint32_t loadcount1; + uint32_t loadcount2; + uint32_t controlreg; +}; + +struct pwm_ctx { + struct pwm_channel_ctx channels[CONFIG_PWM_QMSI_NUM_PORTS]; + uint32_t int_pwm_timer_mask; +}; + +static struct pwm_ctx pwm_ctx_save; + +static int pwm_qmsi_suspend(struct device *dev, int pm_policy) +{ + if (pm_policy == SYS_PM_DEEP_SLEEP) { + int i; + + pwm_ctx_save.int_pwm_timer_mask = + QM_SCSS_INT->int_pwm_timer_mask; + for (i = 0; i < CONFIG_PWM_QMSI_NUM_PORTS; i++) { + qm_pwm_channel_t *channel; + struct pwm_channel_ctx *channel_save; + + channel = &QM_PWM->timer[i]; + channel_save = &pwm_ctx_save.channels[i]; + channel_save->loadcount1 = channel->loadcount; + channel_save->controlreg = channel->controlreg; + channel_save->loadcount2 = QM_PWM->timer_loadcount2[i]; + } + } + + return 0; +} + +static int pwm_qmsi_resume(struct device *dev, int pm_policy) +{ + if (pm_policy == SYS_PM_DEEP_SLEEP) { + int i; + + for (i = 0; i < CONFIG_PWM_QMSI_NUM_PORTS; i++) { + qm_pwm_channel_t *channel; + struct pwm_channel_ctx *channel_save; + + channel = &QM_PWM->timer[i]; + channel_save = &pwm_ctx_save.channels[i]; + channel->loadcount = channel_save->loadcount1; + channel->controlreg = channel_save->controlreg; + QM_PWM->timer_loadcount2[i] = channel_save->loadcount2; + } + QM_SCSS_INT->int_pwm_timer_mask = + pwm_ctx_save.int_pwm_timer_mask; + } + + return 0; +} +#endif + +DEFINE_DEVICE_PM_OPS(pwm, pwm_qmsi_suspend, pwm_qmsi_resume); + +DEVICE_AND_API_INIT_PM(pwm_qmsi_0, CONFIG_PWM_QMSI_DEV_NAME, pwm_qmsi_init, + DEVICE_PM_OPS_GET(pwm), PWM_CONTEXT, pwm_channel_period, + SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + (void *)&pwm_qmsi_drv_api_funcs); |