aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/interface.c')
-rw-r--r--drivers/rtc/interface.c122
1 files changed, 118 insertions, 4 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index ad66c6ecf365..de0da545c7a1 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -12,6 +12,7 @@
12*/ 12*/
13 13
14#include <linux/rtc.h> 14#include <linux/rtc.h>
15#include <linux/log2.h>
15 16
16int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 17int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
17{ 18{
@@ -99,7 +100,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
99} 100}
100EXPORT_SYMBOL_GPL(rtc_set_mmss); 101EXPORT_SYMBOL_GPL(rtc_set_mmss);
101 102
102int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 103static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
103{ 104{
104 int err; 105 int err;
105 106
@@ -119,6 +120,87 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
119 mutex_unlock(&rtc->ops_lock); 120 mutex_unlock(&rtc->ops_lock);
120 return err; 121 return err;
121} 122}
123
124int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
125{
126 int err;
127 struct rtc_time before, now;
128 int first_time = 1;
129
130 /* The lower level RTC driver may not be capable of filling
131 * in all fields of the rtc_time struct (eg. rtc-cmos),
132 * and so might instead return -1 in some fields.
133 * We deal with that here by grabbing a current RTC timestamp
134 * and using values from that for any missing (-1) values.
135 *
136 * But this can be racey, because some fields of the RTC timestamp
137 * may have wrapped in the interval since we read the RTC alarm,
138 * which would lead to us inserting inconsistent values in place
139 * of the -1 fields.
140 *
141 * Reading the alarm and timestamp in the reverse sequence
142 * would have the same race condition, and not solve the issue.
143 *
144 * So, we must first read the RTC timestamp,
145 * then read the RTC alarm value,
146 * and then read a second RTC timestamp.
147 *
148 * If any fields of the second timestamp have changed
149 * when compared with the first timestamp, then we know
150 * our timestamp may be inconsistent with that used by
151 * the low-level rtc_read_alarm_internal() function.
152 *
153 * So, when the two timestamps disagree, we just loop and do
154 * the process again to get a fully consistent set of values.
155 *
156 * This could all instead be done in the lower level driver,
157 * but since more than one lower level RTC implementation needs it,
158 * then it's probably best best to do it here instead of there..
159 */
160
161 /* Get the "before" timestamp */
162 err = rtc_read_time(rtc, &before);
163 if (err < 0)
164 return err;
165 do {
166 if (!first_time)
167 memcpy(&before, &now, sizeof(struct rtc_time));
168 first_time = 0;
169
170 /* get the RTC alarm values, which may be incomplete */
171 err = rtc_read_alarm_internal(rtc, alarm);
172 if (err)
173 return err;
174 if (!alarm->enabled)
175 return 0;
176
177 /* get the "after" timestamp, to detect wrapped fields */
178 err = rtc_read_time(rtc, &now);
179 if (err < 0)
180 return err;
181
182 /* note that tm_sec is a "don't care" value here: */
183 } while ( before.tm_min != now.tm_min
184 || before.tm_hour != now.tm_hour
185 || before.tm_mon != now.tm_mon
186 || before.tm_year != now.tm_year
187 || before.tm_isdst != now.tm_isdst);
188
189 /* Fill in any missing alarm fields using the timestamp */
190 if (alarm->time.tm_sec == -1)
191 alarm->time.tm_sec = now.tm_sec;
192 if (alarm->time.tm_min == -1)
193 alarm->time.tm_min = now.tm_min;
194 if (alarm->time.tm_hour == -1)
195 alarm->time.tm_hour = now.tm_hour;
196 if (alarm->time.tm_mday == -1)
197 alarm->time.tm_mday = now.tm_mday;
198 if (alarm->time.tm_mon == -1)
199 alarm->time.tm_mon = now.tm_mon;
200 if (alarm->time.tm_year == -1)
201 alarm->time.tm_year = now.tm_year;
202 return 0;
203}
122EXPORT_SYMBOL_GPL(rtc_read_alarm); 204EXPORT_SYMBOL_GPL(rtc_read_alarm);
123 205
124int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 206int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
@@ -210,6 +292,10 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
210 if (task == NULL || task->func == NULL) 292 if (task == NULL || task->func == NULL)
211 return -EINVAL; 293 return -EINVAL;
212 294
295 /* Cannot register while the char dev is in use */
296 if (!(mutex_trylock(&rtc->char_lock)))
297 return -EBUSY;
298
213 spin_lock_irq(&rtc->irq_task_lock); 299 spin_lock_irq(&rtc->irq_task_lock);
214 if (rtc->irq_task == NULL) { 300 if (rtc->irq_task == NULL) {
215 rtc->irq_task = task; 301 rtc->irq_task = task;
@@ -217,13 +303,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
217 } 303 }
218 spin_unlock_irq(&rtc->irq_task_lock); 304 spin_unlock_irq(&rtc->irq_task_lock);
219 305
306 mutex_unlock(&rtc->char_lock);
307
220 return retval; 308 return retval;
221} 309}
222EXPORT_SYMBOL_GPL(rtc_irq_register); 310EXPORT_SYMBOL_GPL(rtc_irq_register);
223 311
224void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) 312void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
225{ 313{
226
227 spin_lock_irq(&rtc->irq_task_lock); 314 spin_lock_irq(&rtc->irq_task_lock);
228 if (rtc->irq_task == task) 315 if (rtc->irq_task == task)
229 rtc->irq_task = NULL; 316 rtc->irq_task = NULL;
@@ -231,6 +318,16 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
231} 318}
232EXPORT_SYMBOL_GPL(rtc_irq_unregister); 319EXPORT_SYMBOL_GPL(rtc_irq_unregister);
233 320
321/**
322 * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
323 * @rtc: the rtc device
324 * @task: currently registered with rtc_irq_register()
325 * @enabled: true to enable periodic IRQs
326 * Context: any
327 *
328 * Note that rtc_irq_set_freq() should previously have been used to
329 * specify the desired frequency of periodic IRQ task->func() callbacks.
330 */
234int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) 331int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
235{ 332{
236 int err = 0; 333 int err = 0;
@@ -240,8 +337,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
240 return -ENXIO; 337 return -ENXIO;
241 338
242 spin_lock_irqsave(&rtc->irq_task_lock, flags); 339 spin_lock_irqsave(&rtc->irq_task_lock, flags);
340 if (rtc->irq_task != NULL && task == NULL)
341 err = -EBUSY;
243 if (rtc->irq_task != task) 342 if (rtc->irq_task != task)
244 err = -ENXIO; 343 err = -EACCES;
245 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 344 spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
246 345
247 if (err == 0) 346 if (err == 0)
@@ -251,6 +350,16 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
251} 350}
252EXPORT_SYMBOL_GPL(rtc_irq_set_state); 351EXPORT_SYMBOL_GPL(rtc_irq_set_state);
253 352
353/**
354 * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
355 * @rtc: the rtc device
356 * @task: currently registered with rtc_irq_register()
357 * @freq: positive frequency with which task->func() will be called
358 * Context: any
359 *
360 * Note that rtc_irq_set_state() is used to enable or disable the
361 * periodic IRQs.
362 */
254int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) 363int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
255{ 364{
256 int err = 0; 365 int err = 0;
@@ -259,9 +368,14 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
259 if (rtc->ops->irq_set_freq == NULL) 368 if (rtc->ops->irq_set_freq == NULL)
260 return -ENXIO; 369 return -ENXIO;
261 370
371 if (!is_power_of_2(freq))
372 return -EINVAL;
373
262 spin_lock_irqsave(&rtc->irq_task_lock, flags); 374 spin_lock_irqsave(&rtc->irq_task_lock, flags);
375 if (rtc->irq_task != NULL && task == NULL)
376 err = -EBUSY;
263 if (rtc->irq_task != task) 377 if (rtc->irq_task != task)
264 err = -ENXIO; 378 err = -EACCES;
265 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 379 spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
266 380
267 if (err == 0) { 381 if (err == 0) {