2 * kernel/power/autosleep.c
4 * Opportunistic sleep support.
6 * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
9 #include <linux/device.h>
10 #include <linux/mutex.h>
11 #include <linux/pm_wakeup.h>
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__)
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__);
25 #define hib_autoslp_log(fmt, ...)
27 #define hib_autoslp_warn(fmt, ...) pr_warn("[%s][%s]" fmt, _TAG_HIB_M, __func__, ##__VA_ARGS__);
30 static suspend_state_t autosleep_state
;
31 static struct workqueue_struct
*autosleep_wq
;
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.
38 static DEFINE_MUTEX(autosleep_lock
);
39 static struct wakeup_source
*autosleep_ws
;
41 #ifdef CONFIG_MTK_HIBERNATION
42 extern bool system_is_hibernating
;
43 extern int mtk_hibernate_via_autosleep(suspend_state_t
*autoslp_state
);
45 static void try_to_suspend(struct work_struct
*work
)
47 unsigned int initial_count
, final_count
;
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))
54 mutex_lock(&autosleep_lock
);
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
);
64 if (autosleep_state
== PM_SUSPEND_ON
) {
65 #ifdef CONFIG_MTK_HIBERNATION
66 system_is_hibernating
= false;
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
);
73 #ifdef CONFIG_MTK_HIBERNATION
74 if (autosleep_state
>= PM_SUSPEND_MAX
) {
75 mtk_hibernate_via_autosleep(&autosleep_state
);
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
);
84 hib_autoslp_warn("system is hibernating: so changing state(%d->%d)\n", autosleep_state
, PM_SUSPEND_MAX
);
85 autosleep_state
= PM_SUSPEND_MAX
;
88 #else // !CONFIG_MTK_HIBERNATION
89 if (autosleep_state
>= PM_SUSPEND_MAX
)
93 //<20130327> <marc.huang> add autosleep dubug log
94 autosleep_log("pm_suspend, autosleep_state: %d\n", autosleep_state
);
95 pm_suspend(autosleep_state
);
97 #endif // CONFIG_MTK_HIBERNATION
98 mutex_unlock(&autosleep_lock
);
100 if (!pm_get_wakeup_count(&final_count
, false))
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.
107 if (final_count
== initial_count
)
108 schedule_timeout_uninterruptible(HZ
/ 2);
111 //<20130327> <marc.huang> add autosleep dubug log
112 autosleep_log("queue_up_suspend_work again\n");
113 queue_up_suspend_work();
116 static DECLARE_WORK(suspend_work
, try_to_suspend
);
118 void queue_up_suspend_work(void)
120 if (autosleep_state
> PM_SUSPEND_ON
)
122 //<20130327> <marc.huang> add autosleep dubug log
123 autosleep_log("autosleep_state: %d\n", autosleep_state
);
124 queue_work(autosleep_wq
, &suspend_work
);
128 suspend_state_t
pm_autosleep_state(void)
130 return autosleep_state
;
133 int pm_autosleep_lock(void)
135 return mutex_lock_interruptible(&autosleep_lock
);
138 void pm_autosleep_unlock(void)
140 mutex_unlock(&autosleep_lock
);
143 int pm_autosleep_set_state(suspend_state_t state
)
146 #ifndef CONFIG_HIBERNATION
147 if (state
>= PM_SUSPEND_MAX
)
151 __pm_stay_awake(autosleep_ws
);
153 mutex_lock(&autosleep_lock
);
155 autosleep_state
= state
;
157 __pm_relax(autosleep_ws
);
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();
165 //<20130327> <marc.huang> add autosleep dubug log
166 autosleep_log("pm_wakep_autosleep_enabled(false)\n");
167 pm_wakep_autosleep_enabled(false);
170 mutex_unlock(&autosleep_lock
);
174 int __init
pm_autosleep_init(void)
176 autosleep_ws
= wakeup_source_register("autosleep");
180 autosleep_wq
= alloc_ordered_workqueue("autosleep", 0);
184 wakeup_source_unregister(autosleep_ws
);