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); | ||
