diff options
Diffstat (limited to 'drivers/rtc/alarm.c')
-rw-r--r-- | drivers/rtc/alarm.c | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c new file mode 100644 index 00000000000..28b0df836a3 --- /dev/null +++ b/drivers/rtc/alarm.c | |||
@@ -0,0 +1,590 @@ | |||
1 | /* drivers/rtc/alarm.c | ||
2 | * | ||
3 | * Copyright (C) 2007-2009 Google, Inc. | ||
4 | * | ||
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. | ||
8 | * | ||
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. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <asm/mach/time.h> | ||
17 | #include <linux/android_alarm.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/miscdevice.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/rtc.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/sysdev.h> | ||
25 | #include <linux/wakelock.h> | ||
26 | |||
27 | #define ANDROID_ALARM_PRINT_ERROR (1U << 0) | ||
28 | #define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1) | ||
29 | #define ANDROID_ALARM_PRINT_TSET (1U << 2) | ||
30 | #define ANDROID_ALARM_PRINT_CALL (1U << 3) | ||
31 | #define ANDROID_ALARM_PRINT_SUSPEND (1U << 4) | ||
32 | #define ANDROID_ALARM_PRINT_INT (1U << 5) | ||
33 | #define ANDROID_ALARM_PRINT_FLOW (1U << 6) | ||
34 | |||
35 | static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \ | ||
36 | ANDROID_ALARM_PRINT_INIT_STATUS; | ||
37 | module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP); | ||
38 | |||
39 | #define pr_alarm(debug_level_mask, args...) \ | ||
40 | do { \ | ||
41 | if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \ | ||
42 | pr_info(args); \ | ||
43 | } \ | ||
44 | } while (0) | ||
45 | |||
46 | #define ANDROID_ALARM_WAKEUP_MASK ( \ | ||
47 | ANDROID_ALARM_RTC_WAKEUP_MASK | \ | ||
48 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) | ||
49 | |||
50 | /* support old usespace code */ | ||
51 | #define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */ | ||
52 | #define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t) | ||
53 | |||
54 | struct alarm_queue { | ||
55 | struct rb_root alarms; | ||
56 | struct rb_node *first; | ||
57 | struct hrtimer timer; | ||
58 | ktime_t delta; | ||
59 | bool stopped; | ||
60 | ktime_t stopped_time; | ||
61 | }; | ||
62 | |||
63 | static struct rtc_device *alarm_rtc_dev; | ||
64 | static DEFINE_SPINLOCK(alarm_slock); | ||
65 | static DEFINE_MUTEX(alarm_setrtc_mutex); | ||
66 | static struct wake_lock alarm_rtc_wake_lock; | ||
67 | static struct platform_device *alarm_platform_dev; | ||
68 | struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT]; | ||
69 | static bool suspended; | ||
70 | |||
71 | static void update_timer_locked(struct alarm_queue *base, bool head_removed) | ||
72 | { | ||
73 | struct alarm *alarm; | ||
74 | bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] || | ||
75 | base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; | ||
76 | |||
77 | if (base->stopped) { | ||
78 | pr_alarm(FLOW, "changed alarm while setting the wall time\n"); | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | if (is_wakeup && !suspended && head_removed) | ||
83 | wake_unlock(&alarm_rtc_wake_lock); | ||
84 | |||
85 | if (!base->first) | ||
86 | return; | ||
87 | |||
88 | alarm = container_of(base->first, struct alarm, node); | ||
89 | |||
90 | pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n", | ||
91 | alarm->type, alarm->function, ktime_to_ns(alarm->expires)); | ||
92 | |||
93 | if (is_wakeup && suspended) { | ||
94 | pr_alarm(FLOW, "changed alarm while suspened\n"); | ||
95 | wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | hrtimer_try_to_cancel(&base->timer); | ||
100 | base->timer.node.expires = ktime_add(base->delta, alarm->expires); | ||
101 | base->timer._softexpires = ktime_add(base->delta, alarm->softexpires); | ||
102 | hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS); | ||
103 | } | ||
104 | |||
105 | static void alarm_enqueue_locked(struct alarm *alarm) | ||
106 | { | ||
107 | struct alarm_queue *base = &alarms[alarm->type]; | ||
108 | struct rb_node **link = &base->alarms.rb_node; | ||
109 | struct rb_node *parent = NULL; | ||
110 | struct alarm *entry; | ||
111 | int leftmost = 1; | ||
112 | bool was_first = false; | ||
113 | |||
114 | pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n", | ||
115 | alarm->type, alarm->function, ktime_to_ns(alarm->expires)); | ||
116 | |||
117 | if (base->first == &alarm->node) { | ||
118 | base->first = rb_next(&alarm->node); | ||
119 | was_first = true; | ||
120 | } | ||
121 | if (!RB_EMPTY_NODE(&alarm->node)) { | ||
122 | rb_erase(&alarm->node, &base->alarms); | ||
123 | RB_CLEAR_NODE(&alarm->node); | ||
124 | } | ||
125 | |||
126 | while (*link) { | ||
127 | parent = *link; | ||
128 | entry = rb_entry(parent, struct alarm, node); | ||
129 | /* | ||
130 | * We dont care about collisions. Nodes with | ||
131 | * the same expiry time stay together. | ||
132 | */ | ||
133 | if (alarm->expires.tv64 < entry->expires.tv64) { | ||
134 | link = &(*link)->rb_left; | ||
135 | } else { | ||
136 | link = &(*link)->rb_right; | ||
137 | leftmost = 0; | ||
138 | } | ||
139 | } | ||
140 | if (leftmost) | ||
141 | base->first = &alarm->node; | ||
142 | if (leftmost || was_first) | ||
143 | update_timer_locked(base, was_first); | ||
144 | |||
145 | rb_link_node(&alarm->node, parent, link); | ||
146 | rb_insert_color(&alarm->node, &base->alarms); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * alarm_init - initialize an alarm | ||
151 | * @alarm: the alarm to be initialized | ||
152 | * @type: the alarm type to be used | ||
153 | * @function: alarm callback function | ||
154 | */ | ||
155 | void alarm_init(struct alarm *alarm, | ||
156 | enum android_alarm_type type, void (*function)(struct alarm *)) | ||
157 | { | ||
158 | RB_CLEAR_NODE(&alarm->node); | ||
159 | alarm->type = type; | ||
160 | alarm->function = function; | ||
161 | |||
162 | pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * alarm_start_range - (re)start an alarm | ||
168 | * @alarm: the alarm to be added | ||
169 | * @start: earliest expiry time | ||
170 | * @end: expiry time | ||
171 | */ | ||
172 | void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end) | ||
173 | { | ||
174 | unsigned long flags; | ||
175 | |||
176 | spin_lock_irqsave(&alarm_slock, flags); | ||
177 | alarm->softexpires = start; | ||
178 | alarm->expires = end; | ||
179 | alarm_enqueue_locked(alarm); | ||
180 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * alarm_try_to_cancel - try to deactivate an alarm | ||
185 | * @alarm: alarm to stop | ||
186 | * | ||
187 | * Returns: | ||
188 | * 0 when the alarm was not active | ||
189 | * 1 when the alarm was active | ||
190 | * -1 when the alarm may currently be excuting the callback function and | ||
191 | * cannot be stopped (it may also be inactive) | ||
192 | */ | ||
193 | int alarm_try_to_cancel(struct alarm *alarm) | ||
194 | { | ||
195 | struct alarm_queue *base = &alarms[alarm->type]; | ||
196 | unsigned long flags; | ||
197 | bool first = false; | ||
198 | int ret = 0; | ||
199 | |||
200 | spin_lock_irqsave(&alarm_slock, flags); | ||
201 | if (!RB_EMPTY_NODE(&alarm->node)) { | ||
202 | pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n", | ||
203 | alarm->type, alarm->function, | ||
204 | ktime_to_ns(alarm->expires)); | ||
205 | ret = 1; | ||
206 | if (base->first == &alarm->node) { | ||
207 | base->first = rb_next(&alarm->node); | ||
208 | first = true; | ||
209 | } | ||
210 | rb_erase(&alarm->node, &base->alarms); | ||
211 | RB_CLEAR_NODE(&alarm->node); | ||
212 | if (first) | ||
213 | update_timer_locked(base, true); | ||
214 | } else | ||
215 | pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n", | ||
216 | alarm->type, alarm->function); | ||
217 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
218 | if (!ret && hrtimer_callback_running(&base->timer)) | ||
219 | ret = -1; | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * alarm_cancel - cancel an alarm and wait for the handler to finish. | ||
225 | * @alarm: the alarm to be cancelled | ||
226 | * | ||
227 | * Returns: | ||
228 | * 0 when the alarm was not active | ||
229 | * 1 when the alarm was active | ||
230 | */ | ||
231 | int alarm_cancel(struct alarm *alarm) | ||
232 | { | ||
233 | for (;;) { | ||
234 | int ret = alarm_try_to_cancel(alarm); | ||
235 | if (ret >= 0) | ||
236 | return ret; | ||
237 | cpu_relax(); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * alarm_set_rtc - set the kernel and rtc walltime | ||
243 | * @new_time: timespec value containing the new time | ||
244 | */ | ||
245 | int alarm_set_rtc(struct timespec new_time) | ||
246 | { | ||
247 | int i; | ||
248 | int ret; | ||
249 | unsigned long flags; | ||
250 | struct rtc_time rtc_new_rtc_time; | ||
251 | struct timespec tmp_time; | ||
252 | |||
253 | rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time); | ||
254 | |||
255 | pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n", | ||
256 | new_time.tv_sec, new_time.tv_nsec, | ||
257 | rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min, | ||
258 | rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1, | ||
259 | rtc_new_rtc_time.tm_mday, | ||
260 | rtc_new_rtc_time.tm_year + 1900); | ||
261 | |||
262 | mutex_lock(&alarm_setrtc_mutex); | ||
263 | spin_lock_irqsave(&alarm_slock, flags); | ||
264 | wake_lock(&alarm_rtc_wake_lock); | ||
265 | getnstimeofday(&tmp_time); | ||
266 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { | ||
267 | hrtimer_try_to_cancel(&alarms[i].timer); | ||
268 | alarms[i].stopped = true; | ||
269 | alarms[i].stopped_time = timespec_to_ktime(tmp_time); | ||
270 | } | ||
271 | alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = | ||
272 | alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = | ||
273 | ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta, | ||
274 | timespec_to_ktime(timespec_sub(tmp_time, new_time))); | ||
275 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
276 | ret = do_settimeofday(&new_time); | ||
277 | spin_lock_irqsave(&alarm_slock, flags); | ||
278 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { | ||
279 | alarms[i].stopped = false; | ||
280 | update_timer_locked(&alarms[i], false); | ||
281 | } | ||
282 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
283 | if (ret < 0) { | ||
284 | pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n"); | ||
285 | goto err; | ||
286 | } | ||
287 | if (!alarm_rtc_dev) { | ||
288 | pr_alarm(ERROR, | ||
289 | "alarm_set_rtc: no RTC, time will be lost on reboot\n"); | ||
290 | goto err; | ||
291 | } | ||
292 | ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time); | ||
293 | if (ret < 0) | ||
294 | pr_alarm(ERROR, "alarm_set_rtc: " | ||
295 | "Failed to set RTC, time will be lost on reboot\n"); | ||
296 | err: | ||
297 | wake_unlock(&alarm_rtc_wake_lock); | ||
298 | mutex_unlock(&alarm_setrtc_mutex); | ||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format | ||
304 | * | ||
305 | * returns the time in ktime_t format | ||
306 | */ | ||
307 | ktime_t alarm_get_elapsed_realtime(void) | ||
308 | { | ||
309 | ktime_t now; | ||
310 | unsigned long flags; | ||
311 | struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME]; | ||
312 | |||
313 | spin_lock_irqsave(&alarm_slock, flags); | ||
314 | now = base->stopped ? base->stopped_time : ktime_get_real(); | ||
315 | now = ktime_sub(now, base->delta); | ||
316 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
317 | return now; | ||
318 | } | ||
319 | |||
320 | static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer) | ||
321 | { | ||
322 | struct alarm_queue *base; | ||
323 | struct alarm *alarm; | ||
324 | unsigned long flags; | ||
325 | ktime_t now; | ||
326 | |||
327 | spin_lock_irqsave(&alarm_slock, flags); | ||
328 | |||
329 | base = container_of(timer, struct alarm_queue, timer); | ||
330 | now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer); | ||
331 | now = ktime_sub(now, base->delta); | ||
332 | |||
333 | pr_alarm(INT, "alarm_timer_triggered type %d at %lld\n", | ||
334 | base - alarms, ktime_to_ns(now)); | ||
335 | |||
336 | while (base->first) { | ||
337 | alarm = container_of(base->first, struct alarm, node); | ||
338 | if (alarm->softexpires.tv64 > now.tv64) { | ||
339 | pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n", | ||
340 | alarm->function, ktime_to_ns(alarm->expires), | ||
341 | ktime_to_ns(alarm->softexpires)); | ||
342 | break; | ||
343 | } | ||
344 | base->first = rb_next(&alarm->node); | ||
345 | rb_erase(&alarm->node, &base->alarms); | ||
346 | RB_CLEAR_NODE(&alarm->node); | ||
347 | pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n", | ||
348 | alarm->type, alarm->function, | ||
349 | ktime_to_ns(alarm->expires), | ||
350 | ktime_to_ns(alarm->softexpires)); | ||
351 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
352 | alarm->function(alarm); | ||
353 | spin_lock_irqsave(&alarm_slock, flags); | ||
354 | } | ||
355 | if (!base->first) | ||
356 | pr_alarm(FLOW, "no more alarms of type %d\n", base - alarms); | ||
357 | update_timer_locked(base, true); | ||
358 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
359 | return HRTIMER_NORESTART; | ||
360 | } | ||
361 | |||
362 | static void alarm_triggered_func(void *p) | ||
363 | { | ||
364 | struct rtc_device *rtc = alarm_rtc_dev; | ||
365 | if (!(rtc->irq_data & RTC_AF)) | ||
366 | return; | ||
367 | pr_alarm(INT, "rtc alarm triggered\n"); | ||
368 | wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); | ||
369 | } | ||
370 | |||
371 | static int alarm_suspend(struct platform_device *pdev, pm_message_t state) | ||
372 | { | ||
373 | int err = 0; | ||
374 | unsigned long flags; | ||
375 | struct rtc_wkalrm rtc_alarm; | ||
376 | struct rtc_time rtc_current_rtc_time; | ||
377 | unsigned long rtc_current_time; | ||
378 | unsigned long rtc_alarm_time; | ||
379 | struct timespec rtc_delta; | ||
380 | struct timespec wall_time; | ||
381 | struct alarm_queue *wakeup_queue = NULL; | ||
382 | struct alarm_queue *tmp_queue = NULL; | ||
383 | |||
384 | pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event); | ||
385 | |||
386 | spin_lock_irqsave(&alarm_slock, flags); | ||
387 | suspended = true; | ||
388 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
389 | |||
390 | hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer); | ||
391 | hrtimer_cancel(&alarms[ | ||
392 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer); | ||
393 | |||
394 | tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP]; | ||
395 | if (tmp_queue->first) | ||
396 | wakeup_queue = tmp_queue; | ||
397 | tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]; | ||
398 | if (tmp_queue->first && (!wakeup_queue || | ||
399 | hrtimer_get_expires(&tmp_queue->timer).tv64 < | ||
400 | hrtimer_get_expires(&wakeup_queue->timer).tv64)) | ||
401 | wakeup_queue = tmp_queue; | ||
402 | if (wakeup_queue) { | ||
403 | rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); | ||
404 | getnstimeofday(&wall_time); | ||
405 | rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); | ||
406 | set_normalized_timespec(&rtc_delta, | ||
407 | wall_time.tv_sec - rtc_current_time, | ||
408 | wall_time.tv_nsec); | ||
409 | |||
410 | rtc_alarm_time = timespec_sub(ktime_to_timespec( | ||
411 | hrtimer_get_expires(&wakeup_queue->timer)), | ||
412 | rtc_delta).tv_sec; | ||
413 | |||
414 | rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time); | ||
415 | rtc_alarm.enabled = 1; | ||
416 | rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); | ||
417 | rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time); | ||
418 | rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time); | ||
419 | pr_alarm(SUSPEND, | ||
420 | "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n", | ||
421 | rtc_alarm_time, rtc_current_time, | ||
422 | rtc_delta.tv_sec, rtc_delta.tv_nsec); | ||
423 | if (rtc_current_time + 1 >= rtc_alarm_time) { | ||
424 | pr_alarm(SUSPEND, "alarm about to go off\n"); | ||
425 | memset(&rtc_alarm, 0, sizeof(rtc_alarm)); | ||
426 | rtc_alarm.enabled = 0; | ||
427 | rtc_set_alarm(alarm_rtc_dev, &rtc_alarm); | ||
428 | |||
429 | spin_lock_irqsave(&alarm_slock, flags); | ||
430 | suspended = false; | ||
431 | wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ); | ||
432 | update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], | ||
433 | false); | ||
434 | update_timer_locked(&alarms[ | ||
435 | ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false); | ||
436 | err = -EBUSY; | ||
437 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
438 | } | ||
439 | } | ||
440 | return err; | ||
441 | } | ||
442 | |||
443 | static int alarm_resume(struct platform_device *pdev) | ||
444 | { | ||
445 | struct rtc_wkalrm alarm; | ||
446 | unsigned long flags; | ||
447 | |||
448 | pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev); | ||
449 | |||
450 | memset(&alarm, 0, sizeof(alarm)); | ||
451 | alarm.enabled = 0; | ||
452 | rtc_set_alarm(alarm_rtc_dev, &alarm); | ||
453 | |||
454 | spin_lock_irqsave(&alarm_slock, flags); | ||
455 | suspended = false; | ||
456 | update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false); | ||
457 | update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], | ||
458 | false); | ||
459 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static struct rtc_task alarm_rtc_task = { | ||
465 | .func = alarm_triggered_func | ||
466 | }; | ||
467 | |||
468 | static int rtc_alarm_add_device(struct device *dev, | ||
469 | struct class_interface *class_intf) | ||
470 | { | ||
471 | int err; | ||
472 | struct rtc_device *rtc = to_rtc_device(dev); | ||
473 | |||
474 | mutex_lock(&alarm_setrtc_mutex); | ||
475 | |||
476 | if (alarm_rtc_dev) { | ||
477 | err = -EBUSY; | ||
478 | goto err1; | ||
479 | } | ||
480 | |||
481 | alarm_platform_dev = | ||
482 | platform_device_register_simple("alarm", -1, NULL, 0); | ||
483 | if (IS_ERR(alarm_platform_dev)) { | ||
484 | err = PTR_ERR(alarm_platform_dev); | ||
485 | goto err2; | ||
486 | } | ||
487 | err = rtc_irq_register(rtc, &alarm_rtc_task); | ||
488 | if (err) | ||
489 | goto err3; | ||
490 | alarm_rtc_dev = rtc; | ||
491 | pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name); | ||
492 | mutex_unlock(&alarm_setrtc_mutex); | ||
493 | |||
494 | return 0; | ||
495 | |||
496 | err3: | ||
497 | platform_device_unregister(alarm_platform_dev); | ||
498 | err2: | ||
499 | err1: | ||
500 | mutex_unlock(&alarm_setrtc_mutex); | ||
501 | return err; | ||
502 | } | ||
503 | |||
504 | static void rtc_alarm_remove_device(struct device *dev, | ||
505 | struct class_interface *class_intf) | ||
506 | { | ||
507 | if (dev == &alarm_rtc_dev->dev) { | ||
508 | pr_alarm(INIT_STATUS, "lost rtc device for alarms"); | ||
509 | rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task); | ||
510 | platform_device_unregister(alarm_platform_dev); | ||
511 | alarm_rtc_dev = NULL; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | static struct class_interface rtc_alarm_interface = { | ||
516 | .add_dev = &rtc_alarm_add_device, | ||
517 | .remove_dev = &rtc_alarm_remove_device, | ||
518 | }; | ||
519 | |||
520 | static struct platform_driver alarm_driver = { | ||
521 | .suspend = alarm_suspend, | ||
522 | .resume = alarm_resume, | ||
523 | .driver = { | ||
524 | .name = "alarm" | ||
525 | } | ||
526 | }; | ||
527 | |||
528 | static int __init alarm_late_init(void) | ||
529 | { | ||
530 | unsigned long flags; | ||
531 | struct timespec tmp_time, system_time; | ||
532 | |||
533 | /* this needs to run after the rtc is read at boot */ | ||
534 | spin_lock_irqsave(&alarm_slock, flags); | ||
535 | /* We read the current rtc and system time so we can later calulate | ||
536 | * elasped realtime to be (boot_systemtime + rtc - boot_rtc) == | ||
537 | * (rtc - (boot_rtc - boot_systemtime)) | ||
538 | */ | ||
539 | getnstimeofday(&tmp_time); | ||
540 | ktime_get_ts(&system_time); | ||
541 | alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta = | ||
542 | alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta = | ||
543 | timespec_to_ktime(timespec_sub(tmp_time, system_time)); | ||
544 | |||
545 | spin_unlock_irqrestore(&alarm_slock, flags); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int __init alarm_driver_init(void) | ||
550 | { | ||
551 | int err; | ||
552 | int i; | ||
553 | |||
554 | for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { | ||
555 | hrtimer_init(&alarms[i].timer, | ||
556 | CLOCK_REALTIME, HRTIMER_MODE_ABS); | ||
557 | alarms[i].timer.function = alarm_timer_triggered; | ||
558 | } | ||
559 | hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer, | ||
560 | CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
561 | alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered; | ||
562 | err = platform_driver_register(&alarm_driver); | ||
563 | if (err < 0) | ||
564 | goto err1; | ||
565 | wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); | ||
566 | rtc_alarm_interface.class = rtc_class; | ||
567 | err = class_interface_register(&rtc_alarm_interface); | ||
568 | if (err < 0) | ||
569 | goto err2; | ||
570 | |||
571 | return 0; | ||
572 | |||
573 | err2: | ||
574 | wake_lock_destroy(&alarm_rtc_wake_lock); | ||
575 | platform_driver_unregister(&alarm_driver); | ||
576 | err1: | ||
577 | return err; | ||
578 | } | ||
579 | |||
580 | static void __exit alarm_exit(void) | ||
581 | { | ||
582 | class_interface_unregister(&rtc_alarm_interface); | ||
583 | wake_lock_destroy(&alarm_rtc_wake_lock); | ||
584 | platform_driver_unregister(&alarm_driver); | ||
585 | } | ||
586 | |||
587 | late_initcall(alarm_late_init); | ||
588 | module_init(alarm_driver_init); | ||
589 | module_exit(alarm_exit); | ||
590 | |||