msm: rpm-smd: call SMD API to mask/unmask SMD interrupt.
When the system goes to sleep, the power management code sends a sleep
set to RPM. The code executes with interrupts disabled so the power
management code polls for ack message from RPM. Since the SMD interrupt
is in a triggered state and irq handler hasn't had a chance to run, the
pending interrupt prevent the Core from entering a low power mode.
To prevent interrupt from waking the system up, disable/enable the RPM to
SMD interrupt while entering/exiting sleep mode, by calling into the SMD
API.
Change-Id: I38faa18e6b1d7f4cc92d72c3da4ac8ca29275444
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index ea368ae..be59d7c 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -20,6 +20,7 @@
#include <mach/mpm.h>
#include "lpm_resources.h"
#include "pm.h"
+#include "rpm-notifier.h"
static struct msm_rpmrs_level *msm_lpm_levels;
static int msm_lpm_level_count;
@@ -41,14 +42,22 @@
{
int ret = 0;
+ ret = msm_rpm_enter_sleep();
+ if (ret) {
+ pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+ __func__, ret);
+ goto bail;
+ }
ret = msm_lpmrs_enter_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm);
+bail:
return ret;
}
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
bool notify_rpm, bool collapsed)
{
+ msm_rpm_exit_sleep();
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
}
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index df8d9b3..33086c6 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -20,8 +20,31 @@
uint32_t size;
uint8_t *value;
};
-
+/**
+ * msm_rpm_register_notifier - Register for sleep set notifications
+ *
+ * @nb - notifier block to register
+ *
+ * return 0 on success, errno on failure.
+ */
int msm_rpm_register_notifier(struct notifier_block *nb);
+
+/**
+ * msm_rpm_unregister_notifier - Unregister previously registered notifications
+ *
+ * @nb - notifier block to unregister
+ *
+ * return 0 on success, errno on failure.
+ */
int msm_rpm_unregister_notifier(struct notifier_block *nb);
+/**
+ * msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ */
+int msm_rpm_enter_sleep(void);
+
+/**
+ * msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
+ */
+void msm_rpm_exit_sleep(void);
#endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 697d504..0faafc8 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -886,6 +886,27 @@
return rc;
}
EXPORT_SYMBOL(msm_rpm_send_message_noirq);
+
+/**
+ * During power collapse, the rpm driver disables the SMD interrupts to make
+ * sure that the interrupt doesn't wakes us from sleep.
+ */
+int msm_rpm_enter_sleep(void)
+{
+ return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
+}
+EXPORT_SYMBOL(msm_rpm_enter_sleep);
+
+/**
+ * When the system resumes from power collapse, the SMD interrupt disabled by
+ * enter function has to reenabled to continue processing SMD message.
+ */
+void msm_rpm_exit_sleep(void)
+{
+ smd_mask_receive_interrupt(msm_rpm_data.ch_info, false);
+}
+EXPORT_SYMBOL(msm_rpm_exit_sleep);
+
static bool msm_rpm_set_standalone(void)
{
if (machine_is_msm8974()) {