blob: 9caddfd9084b2fa419f4139b27fee109f038e27c [file] [log] [blame]
yuezonghe824eb0c2024-06-27 02:32:26 -07001/* drivers/base/power/zx-suspend.c
2 *
3 * ZTE suspend manager
4 *
5 * Copyright (C) 2013 ZTE Ltd.
6 * by zxp
7 *
8 */
9
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/rtc.h>
13#include <linux/suspend.h>
14#include <linux/syscalls.h> /* sys_sync */
15#include <linux/wakelock.h>
16#include "power.h"
17
18//#define CONFIG_LINUX_AUTOSLEEP /* may like MTK code to use linux autosleep interface */
19
20static struct workqueue_struct *sync_work_queue;
21static struct wake_lock sync_wake_lock;
22
23static struct workqueue_struct *suspend_work_queue;
24static struct wake_lock main_wake_lock;
25static struct wake_lock wakeup_irq_lock;
26static suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
27static bool zx_pm_init = false;
28static unsigned int suspend_state = 0;
29static DEFINE_MUTEX(suspend_lock);
30static DEFINE_SPINLOCK(zx_suspend_lock);
31
32
33extern void pm_debug_wakelocks(void);
34extern bool pm_disable_suspend(void);
35
36enum {
37 DEBUG_EXIT_SUSPEND = 1U << 0,
38 DEBUG_WAKE_LOCK = 1U << 1,
39 DEBUG_SUSPEND = 1U << 2,
40};
41
42static int debug_mask = DEBUG_EXIT_SUSPEND | /* DEBUG_WAKE_LOCK |*/ DEBUG_SUSPEND;
43/* /sys/module/zx-suspend/parameters/debug_mask */
44module_param(debug_mask, int, 0644);
45
46
47static void sync_system(struct work_struct *work)
48{
49 sys_sync();
50 wake_unlock(&sync_wake_lock);
51
52 if (debug_mask & DEBUG_SUSPEND)
53 pr_info("[SLP]: sync done\n");
54}
55
56static DECLARE_WORK(sync_system_work, sync_system);
57
58void test_wakelock(void)
59{
60#ifndef CONFIG_ZX_AUTOSLEEP
61 wake_lock(&sync_wake_lock);
62 queue_work(sync_work_queue, &sync_system_work);
63#endif
64
65 wake_unlock(&main_wake_lock);
66}
67
68#ifdef CONFIG_ZX_AUTOSLEEP
69void app_start_done(void)
70{
71 wake_unlock(&main_wake_lock);
72}
73EXPORT_SYMBOL_GPL(app_start_done);
74#endif
75
76extern volatile int wakelock_current_event_num;
77static void suspend(struct work_struct *work)
78{
79 int ret;
80 int entry_event_num;
81 struct timespec ts_entry, ts_exit;
82
83 mutex_lock(&suspend_lock);
84 suspend_state = 1;
85 entry_event_num = wakelock_current_event_num;
86#ifdef CONFIG_ZX_AUTOSLEEP
87 sys_sync();
88#endif
89
90 getnstimeofday(&ts_entry);
91 ret = pm_suspend(requested_suspend_state);
92 getnstimeofday(&ts_exit);
93
94 if (debug_mask & DEBUG_EXIT_SUSPEND) {
95 struct rtc_time tm;
96 rtc_time_to_tm(ts_exit.tv_sec, &tm);
97 pr_info("[SLP]: exit suspend, ret = %d "
98 "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
99 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
100 tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
101 }
102#ifdef CONFIG_ZX_AUTOSLEEP
103// wake_lock_timeout(&main_wake_lock, 2 ); /* 2 jiffies */
104 if(wakelock_current_event_num == entry_event_num)
105 wake_lock_timeout(&main_wake_lock, msecs_to_jiffies(1*1000));
106#else
107 wake_lock(&main_wake_lock);
108#endif
109
110 suspend_state = 0;
111 mutex_unlock(&suspend_lock);
112
113}
114
115static DECLARE_WORK(suspend_work, suspend);
116
117/**
118 * zx_pm_suspend
119 *
120 * try suspend when wakelock is unlocked or expired anytime.
121 *
122 */
123void zx_pm_suspend(void)
124{
125
126#if 1
127 //if(!zx_pm_init)
128 return ;
129#else
130 unsigned int temp_count;
131 unsigned long flags;
132
133 if(!zx_pm_init)
134 return ;
135
136 if(pm_disable_suspend())
137 return;
138
139 if (debug_mask & DEBUG_WAKE_LOCK)
140 pm_debug_wakelocks();
141
142 spin_lock_irqsave(&zx_suspend_lock, flags);
143 if(pm_get_wakeup_count(&temp_count, false))
144 {
145 if (pm_save_wakeup_count(temp_count))
146 {
147 spin_unlock_irqrestore(&zx_suspend_lock, flags);
148 if (!suspend_state)
149 queue_work(suspend_work_queue, &suspend_work);
150
151 pm_get_wakeup_count(&temp_count, false);
152 }
153 else
154 {
155 spin_unlock_irqrestore(&zx_suspend_lock, flags);
156 //error save the count, why?
157 if (debug_mask & DEBUG_SUSPEND)
158 {
159 pr_info("suspend: error save wakeup_count: %d ", temp_count);
160 }
161 }
162 }
163 else
164 {
165 spin_unlock_irqrestore(&zx_suspend_lock, flags);
166 }
167#endif
168
169}
170EXPORT_SYMBOL_GPL(zx_pm_suspend);
171
172void zx_pm_wakeup_irq_timeout(void)
173{
174 if (!zx_pm_init)
175 return;
176 wake_lock_timeout(&wakeup_irq_lock, msecs_to_jiffies(1*1000));
177}
178EXPORT_SYMBOL_GPL(zx_pm_wakeup_irq_timeout);
179static int __init zx_suspend_init(void)
180{
181 int ret;
182
183 /* we init a main wakelock for maintain system on until app start ok! */
184 wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
185 wake_lock_init(&sync_wake_lock, WAKE_LOCK_SUSPEND, "sync_system");
186 wake_lock_init(&wakeup_irq_lock, WAKE_LOCK_SUSPEND, "wakeup_irq");
187// wake_lock(&main_wake_lock);
188 wake_lock_timeout(&main_wake_lock, msecs_to_jiffies(60*1000));
189
190 suspend_work_queue = create_singlethread_workqueue("suspend");
191 if (suspend_work_queue == NULL)
192 {
193 ret = -ENOMEM;
194 goto err_suspend_work_queue;
195 }
196
197 sync_work_queue = create_singlethread_workqueue("sync_system_work");
198 if (sync_work_queue == NULL) {
199 pr_err("%s: failed to create sync_work_queue\n", __func__);
200 ret = -ENOMEM;
201 goto err_sync_work_queue;
202 }
203
204 zx_pm_init = true;
205
206 return 0;
207
208err_sync_work_queue:
209 destroy_workqueue(suspend_work_queue);
210
211err_suspend_work_queue:
212 wake_lock_destroy(&main_wake_lock);
213 wake_lock_destroy(&sync_wake_lock);
214
215 return ret;
216}
217
218static void __exit zx_suspend_exit(void)
219{
220 destroy_workqueue(sync_work_queue);
221 destroy_workqueue(suspend_work_queue);
222
223 wake_lock_destroy(&sync_wake_lock);
224 wake_lock_destroy(&main_wake_lock);
225}
226
227late_initcall(zx_suspend_init);
228module_exit(zx_suspend_exit);
229