aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/time/alarmtimer.c137
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 */
46static ktime_t freezer_delta;
47static 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 */
47static struct rtc_timer rtctimer; 51static struct rtc_timer rtctimer;
48static struct rtc_device *rtcdev; 52static struct rtc_device *rtcdev;
49#endif 53static DEFINE_SPINLOCK(rtcdev_lock);
50 54
51/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ 55/**
52static ktime_t freezer_delta; 56 * has_wakealarm - check rtc device has wakealarm ability
53static 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 */
63static 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 */
83static 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}
639device_initcall(alarmtimer_init); 698device_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 */
650static 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 */
670static 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
695static 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
702late_initcall(alarmtimer_init_late);