1 /* kernel/power/earlysuspend.c
3 * Copyright (C) 2005-2008 Google, Inc.
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/earlysuspend.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/rtc.h>
20 #include <linux/syscalls.h> /* sys_sync */
21 #include <linux/wakelock.h>
22 #include <linux/workqueue.h>
27 DEBUG_USER_STATE
= 1U << 0,
28 DEBUG_SUSPEND
= 1U << 2,
30 static int debug_mask
= DEBUG_USER_STATE
;
31 module_param_named(debug_mask
, debug_mask
, int, S_IRUGO
| S_IWUSR
| S_IWGRP
);
33 static DEFINE_MUTEX(early_suspend_lock
);
34 static LIST_HEAD(early_suspend_handlers
);
35 static void early_suspend(struct work_struct
*work
);
36 static void late_resume(struct work_struct
*work
);
37 static DECLARE_WORK(early_suspend_work
, early_suspend
);
38 static DECLARE_WORK(late_resume_work
, late_resume
);
39 static DEFINE_SPINLOCK(state_lock
);
41 SUSPEND_REQUESTED
= 0x1,
43 SUSPEND_REQUESTED_AND_SUSPENDED
= SUSPEND_REQUESTED
| SUSPENDED
,
47 void register_early_suspend(struct early_suspend
*handler
)
49 struct list_head
*pos
;
51 mutex_lock(&early_suspend_lock
);
52 list_for_each(pos
, &early_suspend_handlers
) {
53 struct early_suspend
*e
;
54 e
= list_entry(pos
, struct early_suspend
, link
);
55 if (e
->level
> handler
->level
)
58 list_add_tail(&handler
->link
, pos
);
59 if ((state
& SUSPENDED
) && handler
->suspend
)
60 handler
->suspend(handler
);
61 mutex_unlock(&early_suspend_lock
);
63 EXPORT_SYMBOL(register_early_suspend
);
65 void unregister_early_suspend(struct early_suspend
*handler
)
67 mutex_lock(&early_suspend_lock
);
68 list_del(&handler
->link
);
69 mutex_unlock(&early_suspend_lock
);
71 EXPORT_SYMBOL(unregister_early_suspend
);
73 static void early_suspend(struct work_struct
*work
)
75 struct early_suspend
*pos
;
76 unsigned long irqflags
;
79 pr_info("[R] early_suspend start\n");
80 mutex_lock(&early_suspend_lock
);
81 spin_lock_irqsave(&state_lock
, irqflags
);
82 if (state
== SUSPEND_REQUESTED
)
86 spin_unlock_irqrestore(&state_lock
, irqflags
);
89 if (debug_mask
& DEBUG_SUSPEND
)
90 pr_info("early_suspend: abort, state %d\n", state
);
91 mutex_unlock(&early_suspend_lock
);
95 if (debug_mask
& DEBUG_SUSPEND
)
96 pr_info("early_suspend: call handlers\n");
97 list_for_each_entry(pos
, &early_suspend_handlers
, link
) {
98 if (pos
->suspend
!= NULL
)
101 mutex_unlock(&early_suspend_lock
);
103 if (debug_mask
& DEBUG_SUSPEND
)
104 pr_info("early_suspend: sync\n");
106 pr_info("[R] early_suspend: sync\n");
109 spin_lock_irqsave(&state_lock
, irqflags
);
110 if (state
== SUSPEND_REQUESTED_AND_SUSPENDED
)
111 wake_unlock(&main_wake_lock
);
112 spin_unlock_irqrestore(&state_lock
, irqflags
);
113 pr_info("[R] early_suspend end\n");
116 static void late_resume(struct work_struct
*work
)
118 struct early_suspend
*pos
;
119 unsigned long irqflags
;
122 pr_info("[R] late_resume start\n");
123 mutex_lock(&early_suspend_lock
);
124 spin_lock_irqsave(&state_lock
, irqflags
);
125 if (state
== SUSPENDED
)
129 spin_unlock_irqrestore(&state_lock
, irqflags
);
132 if (debug_mask
& DEBUG_SUSPEND
)
133 pr_info("late_resume: abort, state %d\n", state
);
136 if (debug_mask
& DEBUG_SUSPEND
)
137 pr_info("late_resume: call handlers\n");
138 list_for_each_entry_reverse(pos
, &early_suspend_handlers
, link
)
139 if (pos
->resume
!= NULL
)
141 if (debug_mask
& DEBUG_SUSPEND
)
142 pr_info("late_resume: done\n");
144 mutex_unlock(&early_suspend_lock
);
145 pr_info("[R] late_resume end\n");
148 void request_suspend_state(suspend_state_t new_state
)
150 unsigned long irqflags
;
153 spin_lock_irqsave(&state_lock
, irqflags
);
154 old_sleep
= state
& SUSPEND_REQUESTED
;
155 if (debug_mask
& DEBUG_USER_STATE
) {
159 rtc_time_to_tm(ts
.tv_sec
, &tm
);
160 pr_info("request_suspend_state: %s (%d->%d) at %lld "
161 "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
162 new_state
!= PM_SUSPEND_ON
? "sleep" : "wakeup",
163 requested_suspend_state
, new_state
,
164 ktime_to_ns(ktime_get()),
165 tm
.tm_year
+ 1900, tm
.tm_mon
+ 1, tm
.tm_mday
,
166 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, ts
.tv_nsec
);
168 if (!old_sleep
&& new_state
!= PM_SUSPEND_ON
) {
169 state
|= SUSPEND_REQUESTED
;
170 queue_work(suspend_work_queue
, &early_suspend_work
);
171 } else if (old_sleep
&& new_state
== PM_SUSPEND_ON
) {
172 state
&= ~SUSPEND_REQUESTED
;
173 wake_lock(&main_wake_lock
);
174 queue_work(suspend_work_queue
, &late_resume_work
);
176 requested_suspend_state
= new_state
;
177 spin_unlock_irqrestore(&state_lock
, irqflags
);
180 suspend_state_t
get_suspend_state(void)
182 return requested_suspend_state
;