STR: fix suspend abort cause system resume by powerkey event [1/1]
authorQiufang Dai <qiufang.dai@amlogic.com>
Mon, 7 Jun 2021 12:58:00 +0000 (20:58 +0800)
committerNolen Johnson <johnsonnolen@gmail.com>
Tue, 21 Dec 2021 18:32:51 +0000 (13:32 -0500)
PD#SWPL-52156

Problem:
When suspend abort happens, device driver resume call back call
get_resume_method() which always feedback the last resume method.
It cause a wrong powerkey event report by driver resume call back.

Solution:
Clr resume method in suspend prepare notify.
Provide a stationary get_resume_reason() api.

Verify:
SC2_AH212

Change-Id: I4f6577201125af6ce93dfc36b24b4c80fd812e46
Signed-off-by: Qiufang Dai <qiufang.dai@amlogic.com>
drivers/amlogic/pm/gx_pm.c

index fee0f725f3d9486431bab03832a30484779b9077..539e3dff5c0762d60ef1e04d2cd9add24351fce4 100644 (file)
@@ -43,6 +43,7 @@
 #include <../kernel/power/power.h>
 #include <linux/amlogic/scpi_protocol.h>
 #include "vad_power.h"
+#include <linux/syscore_ops.h>
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
                                unsigned long, unsigned long);
@@ -70,6 +71,7 @@ static void __iomem *debug_reg;
 static void __iomem *exit_reg;
 static int max_idle_lvl;
 static suspend_state_t pm_state;
+static unsigned int resume_reason;
 
 
 /*
@@ -110,7 +112,11 @@ static void meson_pm_finish(void)
 {
        pr_info("enter meson_pm_finish!\n");
 }
-unsigned int get_resume_method(void)
+
+/*
+ * get_resume_reason always return last resume reason.
+ */
+unsigned int get_resume_reason(void)
 {
        unsigned int val = 0;
 
@@ -118,7 +124,36 @@ unsigned int get_resume_method(void)
                val = (readl(exit_reg) >> 28) & 0xf;
        return val;
 }
-EXPORT_SYMBOL(get_resume_method);
+EXPORT_SYMBOL_GPL(get_resume_reason);
+
+/*
+ * get_resume_method return last resume reason.
+ * It can be cleared by clr_resume_method().
+ */
+unsigned int get_resume_method(void)
+{
+       return resume_reason;
+}
+EXPORT_SYMBOL_GPL(get_resume_method);
+
+static void set_resume_method(unsigned int val)
+{
+       resume_reason = val;
+}
+
+static int clr_suspend_notify(struct notifier_block *nb,
+                                    unsigned long event, void *dummy)
+{
+       if (event == PM_SUSPEND_PREPARE)
+               set_resume_method(UDEFINED_WAKEUP);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block clr_suspend_notifier = {
+       .notifier_call = clr_suspend_notify,
+};
+
 
 static const struct platform_suspend_ops meson_gx_ops = {
        .enter = meson_gx_enter,
@@ -195,6 +230,7 @@ ssize_t time_out_show(struct device *dev, struct device_attribute *attr,
        return len;
 }
 
+static int sys_time_out;
 ssize_t time_out_store(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
@@ -204,6 +240,7 @@ ssize_t time_out_store(struct device *dev, struct device_attribute *attr,
        ret = kstrtouint(buf, 10, &time_out);
        switch (ret) {
        case 0:
+               sys_time_out = time_out;
                writel(time_out, debug_reg);
                break;
        default:
@@ -215,6 +252,30 @@ ssize_t time_out_store(struct device *dev, struct device_attribute *attr,
 
 DEVICE_ATTR(time_out, 0664, time_out_show, time_out_store);
 
+int gx_pm_syscore_suspend(void)
+{
+       if (sys_time_out)
+               writel_relaxed(sys_time_out, debug_reg);
+       return 0;
+}
+
+void gx_pm_syscore_resume(void)
+{
+       sys_time_out = 0;
+       set_resume_method(get_resume_reason());
+}
+
+static struct syscore_ops gx_pm_syscore_ops = {
+       .suspend = gx_pm_syscore_suspend,
+       .resume = gx_pm_syscore_resume,
+};
+
+static int __init gx_pm_init_ops(void)
+{
+       register_syscore_ops(&gx_pm_syscore_ops);
+       return 0;
+}
+
 static int meson_pm_probe(struct platform_device *pdev)
 {
        struct device_node *cpu_node;
@@ -282,6 +343,11 @@ static int meson_pm_probe(struct platform_device *pdev)
                return -1;
 #endif
        freeze_set_ops(&meson_gx_frz_ops);
+       gx_pm_init_ops();
+
+       ret = register_pm_notifier(&clr_suspend_notifier);
+       if (unlikely(ret))
+               return ret;
 
        pr_info("meson_pm_probe done\n");
        return 0;