drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / autosleep.c
1 /*
2 * kernel/power/autosleep.c
3 *
4 * Opportunistic sleep support.
5 *
6 * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
7 */
8
9 #include <linux/device.h>
10 #include <linux/mutex.h>
11 #include <linux/pm_wakeup.h>
12
13 #include "power.h"
14
15 //<20130327> <marc.huang> add autosleep dubug log
16 #define _TAG_AUTOSLEEP "AUTOSLEEP"
17 #define autosleep_log(fmt, ...) pr_debug("[%s][%s]" fmt, _TAG_AUTOSLEEP, __func__, ##__VA_ARGS__)
18 #define autosleep_warn(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_AUTOSLEEP, __func__, ##__VA_ARGS__)
19
20 #define HIB_AUTOSLEEP_DEBUG 1
21 #define _TAG_HIB_M "HIB/AUTOSLEEP"
22 #if (HIB_AUTOSLEEP_DEBUG)
23 #define hib_autoslp_log(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
24 #else
25 #define hib_autoslp_log(fmt, ...)
26 #endif
27 #define hib_autoslp_warn(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
28
29
30 static suspend_state_t autosleep_state;
31 static struct workqueue_struct *autosleep_wq;
32 /*
33 * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
34 * is active, otherwise a deadlock with try_to_suspend() is possible.
35 * Alternatively mutex_lock_interruptible() can be used. This will then fail
36 * if an auto_sleep cycle tries to freeze processes.
37 */
38 static DEFINE_MUTEX(autosleep_lock);
39 static struct wakeup_source *autosleep_ws;
40
41 #ifdef CONFIG_MTK_HIBERNATION
42 extern bool system_is_hibernating;
43 extern int mtk_hibernate_via_autosleep(suspend_state_t *autoslp_state);
44 #endif
45 static void try_to_suspend(struct work_struct *work)
46 {
47 unsigned int initial_count, final_count;
48
49 //<20130327> <marc.huang> add autosleep dubug log
50 autosleep_log("pm_get_wakeup_count\n");
51 if (!pm_get_wakeup_count(&initial_count, true))
52 goto out;
53
54 mutex_lock(&autosleep_lock);
55
56 //<20130327> <marc.huang> add autosleep dubug log
57 autosleep_log("pm_save_wakeup_count\n");
58 if (!pm_save_wakeup_count(initial_count) ||
59 system_state != SYSTEM_RUNNING) {
60 mutex_unlock(&autosleep_lock);
61 goto out;
62 }
63
64 if (autosleep_state == PM_SUSPEND_ON) {
65 #ifdef CONFIG_MTK_HIBERNATION
66 system_is_hibernating = false;
67 #endif
68 //<20130327> <marc.huang> add autosleep dubug log
69 autosleep_warn("abort due to autosleep_state: %d\n", autosleep_state);
70 mutex_unlock(&autosleep_lock);
71 return;
72 }
73 #ifdef CONFIG_MTK_HIBERNATION
74 if (autosleep_state >= PM_SUSPEND_MAX) {
75 mtk_hibernate_via_autosleep(&autosleep_state);
76 }
77 else {
78 hib_autoslp_log("pm_suspend: state(%d)\n", autosleep_state);
79 if (!system_is_hibernating) {
80 hib_autoslp_warn("calling pm_suspend() state(%d)\n", autosleep_state);
81 pm_suspend(autosleep_state);
82 }
83 else {
84 hib_autoslp_warn("system is hibernating: so changing state(%d->%d)\n", autosleep_state, PM_SUSPEND_MAX);
85 autosleep_state = PM_SUSPEND_MAX;
86 }
87 }
88 #else // !CONFIG_MTK_HIBERNATION
89 if (autosleep_state >= PM_SUSPEND_MAX)
90 hibernate();
91 else
92 {
93 //<20130327> <marc.huang> add autosleep dubug log
94 autosleep_log("pm_suspend, autosleep_state: %d\n", autosleep_state);
95 pm_suspend(autosleep_state);
96 }
97 #endif // CONFIG_MTK_HIBERNATION
98 mutex_unlock(&autosleep_lock);
99
100 if (!pm_get_wakeup_count(&final_count, false))
101 goto out;
102
103 /*
104 * If the wakeup occured for an unknown reason, wait to prevent the
105 * system from trying to suspend and waking up in a tight loop.
106 */
107 if (final_count == initial_count)
108 schedule_timeout_uninterruptible(HZ / 2);
109
110 out:
111 //<20130327> <marc.huang> add autosleep dubug log
112 autosleep_log("queue_up_suspend_work again\n");
113 queue_up_suspend_work();
114 }
115
116 static DECLARE_WORK(suspend_work, try_to_suspend);
117
118 void queue_up_suspend_work(void)
119 {
120 if (autosleep_state > PM_SUSPEND_ON)
121 {
122 //<20130327> <marc.huang> add autosleep dubug log
123 autosleep_log("autosleep_state: %d\n", autosleep_state);
124 queue_work(autosleep_wq, &suspend_work);
125 }
126 }
127
128 suspend_state_t pm_autosleep_state(void)
129 {
130 return autosleep_state;
131 }
132
133 int pm_autosleep_lock(void)
134 {
135 return mutex_lock_interruptible(&autosleep_lock);
136 }
137
138 void pm_autosleep_unlock(void)
139 {
140 mutex_unlock(&autosleep_lock);
141 }
142
143 int pm_autosleep_set_state(suspend_state_t state)
144 {
145
146 #ifndef CONFIG_HIBERNATION
147 if (state >= PM_SUSPEND_MAX)
148 return -EINVAL;
149 #endif
150
151 __pm_stay_awake(autosleep_ws);
152
153 mutex_lock(&autosleep_lock);
154
155 autosleep_state = state;
156
157 __pm_relax(autosleep_ws);
158
159 if (state > PM_SUSPEND_ON) {
160 //<20130327> <marc.huang> add autosleep dubug log
161 autosleep_log("pm_wakep_autosleep_enabled(true)\n");
162 pm_wakep_autosleep_enabled(true);
163 queue_up_suspend_work();
164 } else {
165 //<20130327> <marc.huang> add autosleep dubug log
166 autosleep_log("pm_wakep_autosleep_enabled(false)\n");
167 pm_wakep_autosleep_enabled(false);
168 }
169
170 mutex_unlock(&autosleep_lock);
171 return 0;
172 }
173
174 int __init pm_autosleep_init(void)
175 {
176 autosleep_ws = wakeup_source_register("autosleep");
177 if (!autosleep_ws)
178 return -ENOMEM;
179
180 autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
181 if (autosleep_wq)
182 return 0;
183
184 wakeup_source_unregister(autosleep_ws);
185 return -ENOMEM;
186 }