summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Briano <ivan.briano@intel.com>2016-08-01 10:35:56 -0300
committerInaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>2016-08-02 06:48:21 +0000
commit1a47abe5bfdfbc9349aed87dbf667c95e0e86a67 (patch)
tree5539492609d18aba218ace3a1697bbf50ca98b05
parentdfc15d3a48500115b4948c584db7ced690aea6db (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.c70
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);