diff options
author | John Stultz <john.stultz@linaro.org> | 2011-07-14 21:35:13 -0400 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2011-08-10 17:55:30 -0400 |
commit | 8bc0dafb5cf38a19484dfb16e2c6d29e85820046 (patch) | |
tree | af2f0000b9cc95567cc4bab5966ef6fd887c6f1f /kernel/time | |
parent | 9082c465a5403f4a98734193e078552991a2e283 (diff) |
alarmtimers: Rework RTC device selection using class interface
This allows cleaner detection of the RTC device being registered, rather
then probing any time someone calls alarmtimer_get_rtcdev.
CC: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/alarmtimer.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index bdb7342b6896..154d5563ab1b 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c | |||
@@ -53,27 +53,6 @@ static struct rtc_device *rtcdev; | |||
53 | static DEFINE_SPINLOCK(rtcdev_lock); | 53 | static DEFINE_SPINLOCK(rtcdev_lock); |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * has_wakealarm - check rtc device has wakealarm ability | ||
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 | 56 | * alarmtimer_get_rtcdev - Return selected rtcdevice |
78 | * | 57 | * |
79 | * This function returns the rtc device to use for wakealarms. | 58 | * This function returns the rtc device to use for wakealarms. |
@@ -82,37 +61,58 @@ static int has_wakealarm(struct device *dev, void *name_ptr) | |||
82 | */ | 61 | */ |
83 | static struct rtc_device *alarmtimer_get_rtcdev(void) | 62 | static struct rtc_device *alarmtimer_get_rtcdev(void) |
84 | { | 63 | { |
85 | struct device *dev; | ||
86 | char *str; | ||
87 | unsigned long flags; | 64 | unsigned long flags; |
88 | struct rtc_device *ret; | 65 | struct rtc_device *ret; |
89 | 66 | ||
90 | spin_lock_irqsave(&rtcdev_lock, flags); | 67 | 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; | 68 | ret = rtcdev; |
106 | spin_unlock_irqrestore(&rtcdev_lock, flags); | 69 | spin_unlock_irqrestore(&rtcdev_lock, flags); |
107 | 70 | ||
108 | return ret; | 71 | return ret; |
109 | } | 72 | } |
73 | |||
74 | |||
75 | static int alarmtimer_rtc_add_device(struct device *dev, | ||
76 | struct class_interface *class_intf) | ||
77 | { | ||
78 | unsigned long flags; | ||
79 | struct rtc_device *rtc = to_rtc_device(dev); | ||
80 | |||
81 | if (rtcdev) | ||
82 | return -EBUSY; | ||
83 | |||
84 | if (!rtc->ops->set_alarm) | ||
85 | return -1; | ||
86 | if (!device_may_wakeup(rtc->dev.parent)) | ||
87 | return -1; | ||
88 | |||
89 | spin_lock_irqsave(&rtcdev_lock, flags); | ||
90 | if (!rtcdev) { | ||
91 | rtcdev = rtc; | ||
92 | /* hold a reference so it doesn't go away */ | ||
93 | get_device(dev); | ||
94 | } | ||
95 | spin_unlock_irqrestore(&rtcdev_lock, flags); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static struct class_interface alarmtimer_rtc_interface = { | ||
100 | .add_dev = &alarmtimer_rtc_add_device, | ||
101 | }; | ||
102 | |||
103 | static void alarmtimer_rtc_interface_setup(void) | ||
104 | { | ||
105 | alarmtimer_rtc_interface.class = rtc_class; | ||
106 | class_interface_register(&alarmtimer_rtc_interface); | ||
107 | } | ||
110 | #else | 108 | #else |
111 | #define alarmtimer_get_rtcdev() (0) | 109 | #define alarmtimer_get_rtcdev() (0) |
112 | #define rtcdev (0) | 110 | #define rtcdev (0) |
111 | #define alarmtimer_rtc_interface_setup() | ||
113 | #endif | 112 | #endif |
114 | 113 | ||
115 | 114 | ||
115 | |||
116 | /** | 116 | /** |
117 | * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue | 117 | * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue |
118 | * @base: pointer to the base where the timer is being run | 118 | * @base: pointer to the base where the timer is being run |
@@ -244,7 +244,7 @@ static int alarmtimer_suspend(struct device *dev) | |||
244 | freezer_delta = ktime_set(0, 0); | 244 | freezer_delta = ktime_set(0, 0); |
245 | spin_unlock_irqrestore(&freezer_delta_lock, flags); | 245 | spin_unlock_irqrestore(&freezer_delta_lock, flags); |
246 | 246 | ||
247 | rtc = rtcdev; | 247 | rtc = alarmtimer_get_rtcdev(); |
248 | /* If we have no rtcdev, just return */ | 248 | /* If we have no rtcdev, just return */ |
249 | if (!rtc) | 249 | if (!rtc) |
250 | return 0; | 250 | return 0; |
@@ -792,6 +792,8 @@ static int __init alarmtimer_init(void) | |||
792 | HRTIMER_MODE_ABS); | 792 | HRTIMER_MODE_ABS); |
793 | alarm_bases[i].timer.function = alarmtimer_fired; | 793 | alarm_bases[i].timer.function = alarmtimer_fired; |
794 | } | 794 | } |
795 | |||
796 | alarmtimer_rtc_interface_setup(); | ||
795 | error = platform_driver_register(&alarmtimer_driver); | 797 | error = platform_driver_register(&alarmtimer_driver); |
796 | platform_device_register_simple("alarmtimer", -1, NULL, 0); | 798 | platform_device_register_simple("alarmtimer", -1, NULL, 0); |
797 | 799 | ||