diff options
-rw-r--r-- | kernel/time/alarmtimer.c | 137 |
1 files changed, 67 insertions, 70 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index 2d966244ea60..98ecf4e36f2f 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
@@ -42,15 +42,72 @@ static struct alarm_base { | |||
42 | clockid_t base_clockid; | 42 | clockid_t base_clockid; |
43 | } alarm_bases[ALARM_NUMTYPE]; | 43 | } alarm_bases[ALARM_NUMTYPE]; |
44 | 44 | ||
45 | /* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ | ||
46 | static ktime_t freezer_delta; | ||
47 | static DEFINE_SPINLOCK(freezer_delta_lock); | ||
48 | |||
45 | #ifdef CONFIG_RTC_CLASS | 49 | #ifdef CONFIG_RTC_CLASS |
46 | /* rtc timer and device for setting alarm wakeups at suspend */ | 50 | /* rtc timer and device for setting alarm wakeups at suspend */ |
47 | static struct rtc_timer rtctimer; | 51 | static struct rtc_timer rtctimer; |
48 | static struct rtc_device *rtcdev; | 52 | static struct rtc_device *rtcdev; |
49 | #endif | 53 | static DEFINE_SPINLOCK(rtcdev_lock); |
50 | 54 | ||
51 | /* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ | 55 | /** |
52 | static ktime_t freezer_delta; | 56 | * has_wakealarm - check rtc device has wakealarm ability |
53 | static DEFINE_SPINLOCK(freezer_delta_lock); | 57 | * @dev: current device |
58 | * @name_ptr: name to be returned | ||
59 | * | ||
60 | * This helper function checks to see if the rtc device can wake | ||
61 | * from suspend. | ||
62 | */ | ||
63 | static int has_wakealarm(struct device *dev, void *name_ptr) | ||
64 | { | ||
65 | struct rtc_device *candidate = to_rtc_device(dev); | ||
66 | |||
67 | if (!candidate->ops->set_alarm) | ||
68 | return 0; | ||
69 | if (!device_may_wakeup(candidate->dev.parent)) | ||
70 | return 0; | ||
71 | |||
72 | *(const char **)name_ptr = dev_name(dev); | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * alarmtimer_get_rtcdev - Return selected rtcdevice | ||
78 | * | ||
79 | * This function returns the rtc device to use for wakealarms. | ||
80 | * If one has not already been chosen, it checks to see if a | ||
81 | * functional rtc device is available. | ||
82 | */ | ||
83 | static struct rtc_device *alarmtimer_get_rtcdev(void) | ||
84 | { | ||
85 | struct device *dev; | ||
86 | char *str; | ||
87 | unsigned long flags; | ||
88 | struct rtc_device *ret; | ||
89 | |||
90 | spin_lock_irqsave(&rtcdev_lock, flags); | ||
91 | if (!rtcdev) { | ||
92 | /* Find an rtc device and init the rtc_timer */ | ||
93 | dev = class_find_device(rtc_class, NULL, &str, has_wakealarm); | ||
94 | /* If we have a device then str is valid. See has_wakealarm() */ | ||
95 | if (dev) { | ||
96 | rtcdev = rtc_class_open(str); | ||
97 | /* | ||
98 | * Drop the reference we got in class_find_device, | ||
99 | * rtc_open takes its own. | ||
100 | */ | ||
101 | put_device(dev); | ||
102 | rtc_timer_init(&rtctimer, NULL, NULL); | ||
103 | } | ||
104 | } | ||
105 | ret = rtcdev; | ||
106 | spin_unlock_irqrestore(&rtcdev_lock, flags); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | #endif | ||
54 | 111 | ||
55 | 112 | ||
56 | /** | 113 | /** |
@@ -166,6 +223,7 @@ static int alarmtimer_suspend(struct device *dev) | |||
166 | struct rtc_time tm; | 223 | struct rtc_time tm; |
167 | ktime_t min, now; | 224 | ktime_t min, now; |
168 | unsigned long flags; | 225 | unsigned long flags; |
226 | struct rtc_device *rtc; | ||
169 | int i; | 227 | int i; |
170 | 228 | ||
171 | spin_lock_irqsave(&freezer_delta_lock, flags); | 229 | spin_lock_irqsave(&freezer_delta_lock, flags); |
@@ -173,8 +231,9 @@ static int alarmtimer_suspend(struct device *dev) | |||
173 | freezer_delta = ktime_set(0, 0); | 231 | freezer_delta = ktime_set(0, 0); |
174 | spin_unlock_irqrestore(&freezer_delta_lock, flags); | 232 | spin_unlock_irqrestore(&freezer_delta_lock, flags); |
175 | 233 | ||
234 | rtc = alarmtimer_get_rtcdev(); | ||
176 | /* If we have no rtcdev, just return */ | 235 | /* If we have no rtcdev, just return */ |
177 | if (!rtcdev) | 236 | if (!rtc) |
178 | return 0; | 237 | return 0; |
179 | 238 | ||
180 | /* Find the soonest timer to expire*/ | 239 | /* Find the soonest timer to expire*/ |
@@ -199,12 +258,12 @@ static int alarmtimer_suspend(struct device *dev) | |||
199 | WARN_ON(min.tv64 < NSEC_PER_SEC); | 258 | WARN_ON(min.tv64 < NSEC_PER_SEC); |
200 | 259 | ||
201 | /* Setup an rtc timer to fire that far in the future */ | 260 | /* Setup an rtc timer to fire that far in the future */ |
202 | rtc_timer_cancel(rtcdev, &rtctimer); | 261 | rtc_timer_cancel(rtc, &rtctimer); |
203 | rtc_read_time(rtcdev, &tm); | 262 | rtc_read_time(rtc, &tm); |
204 | now = rtc_tm_to_ktime(tm); | 263 | now = rtc_tm_to_ktime(tm); |
205 | now = ktime_add(now, min); | 264 | now = ktime_add(now, min); |
206 | 265 | ||
207 | rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0)); | 266 | rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); |
208 | 267 | ||
209 | return 0; | 268 | return 0; |
210 | } | 269 | } |
@@ -638,65 +697,3 @@ static int __init alarmtimer_init(void) | |||
638 | } | 697 | } |
639 | device_initcall(alarmtimer_init); | 698 | device_initcall(alarmtimer_init); |
640 | 699 | ||
641 | #ifdef CONFIG_RTC_CLASS | ||
642 | /** | ||
643 | * has_wakealarm - check rtc device has wakealarm ability | ||
644 | * @dev: current device | ||
645 | * @name_ptr: name to be returned | ||
646 | * | ||
647 | * This helper function checks to see if the rtc device can wake | ||
648 | * from suspend. | ||
649 | */ | ||
650 | static int __init has_wakealarm(struct device *dev, void *name_ptr) | ||
651 | { | ||
652 | struct rtc_device *candidate = to_rtc_device(dev); | ||
653 | |||
654 | if (!candidate->ops->set_alarm) | ||
655 | return 0; | ||
656 | if (!device_may_wakeup(candidate->dev.parent)) | ||
657 | return 0; | ||
658 | |||
659 | *(const char **)name_ptr = dev_name(dev); | ||
660 | return 1; | ||
661 | } | ||
662 | |||
663 | /** | ||
664 | * alarmtimer_init_late - Late initializing of alarmtimer code | ||
665 | * | ||
666 | * This function locates a rtc device to use for wakealarms. | ||
667 | * Run as late_initcall to make sure rtc devices have been | ||
668 | * registered. | ||
669 | */ | ||
670 | static int __init alarmtimer_init_late(void) | ||
671 | { | ||
672 | struct device *dev; | ||
673 | char *str; | ||
674 | |||
675 | /* Find an rtc device and init the rtc_timer */ | ||
676 | dev = class_find_device(rtc_class, NULL, &str, has_wakealarm); | ||
677 | /* If we have a device then str is valid. See has_wakealarm() */ | ||
678 | if (dev) { | ||
679 | rtcdev = rtc_class_open(str); | ||
680 | /* | ||
681 | * Drop the reference we got in class_find_device, | ||
682 | * rtc_open takes its own. | ||
683 | */ | ||
684 | put_device(dev); | ||
685 | } | ||
686 | if (!rtcdev) { | ||
687 | printk(KERN_WARNING "No RTC device found, ALARM timers will" | ||
688 | " not wake from suspend"); | ||
689 | } | ||
690 | rtc_timer_init(&rtctimer, NULL, NULL); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | #else | ||
695 | static int __init alarmtimer_init_late(void) | ||
696 | { | ||
697 | printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers" | ||
698 | " will not wake from suspend"); | ||
699 | return 0; | ||
700 | } | ||
701 | #endif | ||
702 | late_initcall(alarmtimer_init_late); | ||