diff options
Diffstat (limited to 'drivers/rtc/interface.c')
-rw-r--r-- | drivers/rtc/interface.c | 425 |
1 files changed, 380 insertions, 45 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c816238aa..8ec6b069a7f 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -14,15 +14,14 @@ | |||
14 | #include <linux/rtc.h> | 14 | #include <linux/rtc.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/log2.h> | 16 | #include <linux/log2.h> |
17 | #include <linux/workqueue.h> | ||
17 | 18 | ||
18 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | 19 | static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer); |
20 | static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer); | ||
21 | |||
22 | static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | ||
19 | { | 23 | { |
20 | int err; | 24 | int err; |
21 | |||
22 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
23 | if (err) | ||
24 | return err; | ||
25 | |||
26 | if (!rtc->ops) | 25 | if (!rtc->ops) |
27 | err = -ENODEV; | 26 | err = -ENODEV; |
28 | else if (!rtc->ops->read_time) | 27 | else if (!rtc->ops->read_time) |
@@ -31,7 +30,18 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
31 | memset(tm, 0, sizeof(struct rtc_time)); | 30 | memset(tm, 0, sizeof(struct rtc_time)); |
32 | err = rtc->ops->read_time(rtc->dev.parent, tm); | 31 | err = rtc->ops->read_time(rtc->dev.parent, tm); |
33 | } | 32 | } |
33 | return err; | ||
34 | } | ||
35 | |||
36 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | ||
37 | { | ||
38 | int err; | ||
39 | |||
40 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
41 | if (err) | ||
42 | return err; | ||
34 | 43 | ||
44 | err = __rtc_read_time(rtc, tm); | ||
35 | mutex_unlock(&rtc->ops_lock); | 45 | mutex_unlock(&rtc->ops_lock); |
36 | return err; | 46 | return err; |
37 | } | 47 | } |
@@ -127,7 +137,7 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al | |||
127 | return err; | 137 | return err; |
128 | } | 138 | } |
129 | 139 | ||
130 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 140 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
131 | { | 141 | { |
132 | int err; | 142 | int err; |
133 | struct rtc_time before, now; | 143 | struct rtc_time before, now; |
@@ -190,8 +200,6 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
190 | err = rtc_read_alarm_internal(rtc, alarm); | 200 | err = rtc_read_alarm_internal(rtc, alarm); |
191 | if (err) | 201 | if (err) |
192 | return err; | 202 | return err; |
193 | if (!alarm->enabled) | ||
194 | return 0; | ||
195 | 203 | ||
196 | /* full-function RTCs won't have such missing fields */ | 204 | /* full-function RTCs won't have such missing fields */ |
197 | if (rtc_valid_tm(&alarm->time) == 0) | 205 | if (rtc_valid_tm(&alarm->time) == 0) |
@@ -287,19 +295,51 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
287 | done: | 295 | done: |
288 | return 0; | 296 | return 0; |
289 | } | 297 | } |
290 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | ||
291 | 298 | ||
292 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 299 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
293 | { | 300 | { |
294 | int err; | 301 | int err; |
295 | 302 | ||
296 | err = rtc_valid_tm(&alarm->time); | 303 | err = mutex_lock_interruptible(&rtc->ops_lock); |
297 | if (err != 0) | 304 | if (err) |
298 | return err; | 305 | return err; |
306 | if (rtc->ops == NULL) | ||
307 | err = -ENODEV; | ||
308 | else if (!rtc->ops->read_alarm) | ||
309 | err = -EINVAL; | ||
310 | else { | ||
311 | memset(alarm, 0, sizeof(struct rtc_wkalrm)); | ||
312 | alarm->enabled = rtc->aie_timer.enabled; | ||
313 | alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); | ||
314 | } | ||
315 | mutex_unlock(&rtc->ops_lock); | ||
299 | 316 | ||
300 | err = mutex_lock_interruptible(&rtc->ops_lock); | 317 | return err; |
318 | } | ||
319 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | ||
320 | |||
321 | int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
322 | { | ||
323 | struct rtc_time tm; | ||
324 | long now, scheduled; | ||
325 | int err; | ||
326 | |||
327 | err = rtc_valid_tm(&alarm->time); | ||
301 | if (err) | 328 | if (err) |
302 | return err; | 329 | return err; |
330 | rtc_tm_to_time(&alarm->time, &scheduled); | ||
331 | |||
332 | /* Make sure we're not setting alarms in the past */ | ||
333 | err = __rtc_read_time(rtc, &tm); | ||
334 | rtc_tm_to_time(&tm, &now); | ||
335 | if (scheduled <= now) | ||
336 | return -ETIME; | ||
337 | /* | ||
338 | * XXX - We just checked to make sure the alarm time is not | ||
339 | * in the past, but there is still a race window where if | ||
340 | * the is alarm set for the next second and the second ticks | ||
341 | * over right here, before we set the alarm. | ||
342 | */ | ||
303 | 343 | ||
304 | if (!rtc->ops) | 344 | if (!rtc->ops) |
305 | err = -ENODEV; | 345 | err = -ENODEV; |
@@ -308,6 +348,28 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
308 | else | 348 | else |
309 | err = rtc->ops->set_alarm(rtc->dev.parent, alarm); | 349 | err = rtc->ops->set_alarm(rtc->dev.parent, alarm); |
310 | 350 | ||
351 | return err; | ||
352 | } | ||
353 | |||
354 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
355 | { | ||
356 | int err; | ||
357 | |||
358 | err = rtc_valid_tm(&alarm->time); | ||
359 | if (err != 0) | ||
360 | return err; | ||
361 | |||
362 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
363 | if (err) | ||
364 | return err; | ||
365 | if (rtc->aie_timer.enabled) { | ||
366 | rtc_timer_remove(rtc, &rtc->aie_timer); | ||
367 | } | ||
368 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); | ||
369 | rtc->aie_timer.period = ktime_set(0, 0); | ||
370 | if (alarm->enabled) { | ||
371 | err = rtc_timer_enqueue(rtc, &rtc->aie_timer); | ||
372 | } | ||
311 | mutex_unlock(&rtc->ops_lock); | 373 | mutex_unlock(&rtc->ops_lock); |
312 | return err; | 374 | return err; |
313 | } | 375 | } |
@@ -319,7 +381,16 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
319 | if (err) | 381 | if (err) |
320 | return err; | 382 | return err; |
321 | 383 | ||
322 | if (!rtc->ops) | 384 | if (rtc->aie_timer.enabled != enabled) { |
385 | if (enabled) | ||
386 | err = rtc_timer_enqueue(rtc, &rtc->aie_timer); | ||
387 | else | ||
388 | rtc_timer_remove(rtc, &rtc->aie_timer); | ||
389 | } | ||
390 | |||
391 | if (err) | ||
392 | /* nothing */; | ||
393 | else if (!rtc->ops) | ||
323 | err = -ENODEV; | 394 | err = -ENODEV; |
324 | else if (!rtc->ops->alarm_irq_enable) | 395 | else if (!rtc->ops->alarm_irq_enable) |
325 | err = -EINVAL; | 396 | err = -EINVAL; |
@@ -340,19 +411,28 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
340 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 411 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
341 | if (enabled == 0 && rtc->uie_irq_active) { | 412 | if (enabled == 0 && rtc->uie_irq_active) { |
342 | mutex_unlock(&rtc->ops_lock); | 413 | mutex_unlock(&rtc->ops_lock); |
343 | return rtc_dev_update_irq_enable_emul(rtc, enabled); | 414 | return rtc_dev_update_irq_enable_emul(rtc, 0); |
344 | } | 415 | } |
345 | #endif | 416 | #endif |
417 | /* make sure we're changing state */ | ||
418 | if (rtc->uie_rtctimer.enabled == enabled) | ||
419 | goto out; | ||
420 | |||
421 | if (enabled) { | ||
422 | struct rtc_time tm; | ||
423 | ktime_t now, onesec; | ||
424 | |||
425 | __rtc_read_time(rtc, &tm); | ||
426 | onesec = ktime_set(1, 0); | ||
427 | now = rtc_tm_to_ktime(tm); | ||
428 | rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); | ||
429 | rtc->uie_rtctimer.period = ktime_set(1, 0); | ||
430 | err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); | ||
431 | } else | ||
432 | rtc_timer_remove(rtc, &rtc->uie_rtctimer); | ||
346 | 433 | ||
347 | if (!rtc->ops) | 434 | out: |
348 | err = -ENODEV; | ||
349 | else if (!rtc->ops->update_irq_enable) | ||
350 | err = -EINVAL; | ||
351 | else | ||
352 | err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); | ||
353 | |||
354 | mutex_unlock(&rtc->ops_lock); | 435 | mutex_unlock(&rtc->ops_lock); |
355 | |||
356 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 436 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
357 | /* | 437 | /* |
358 | * Enable emulation if the driver did not provide | 438 | * Enable emulation if the driver did not provide |
@@ -364,25 +444,30 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
364 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); | 444 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); |
365 | #endif | 445 | #endif |
366 | return err; | 446 | return err; |
447 | |||
367 | } | 448 | } |
368 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); | 449 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); |
369 | 450 | ||
451 | |||
370 | /** | 452 | /** |
371 | * rtc_update_irq - report RTC periodic, alarm, and/or update irqs | 453 | * rtc_handle_legacy_irq - AIE, UIE and PIE event hook |
372 | * @rtc: the rtc device | 454 | * @rtc: pointer to the rtc device |
373 | * @num: how many irqs are being reported (usually one) | 455 | * |
374 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | 456 | * This function is called when an AIE, UIE or PIE mode interrupt |
375 | * Context: any | 457 | * has occured (or been emulated). |
458 | * | ||
459 | * Triggers the registered irq_task function callback. | ||
376 | */ | 460 | */ |
377 | void rtc_update_irq(struct rtc_device *rtc, | 461 | void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) |
378 | unsigned long num, unsigned long events) | ||
379 | { | 462 | { |
380 | unsigned long flags; | 463 | unsigned long flags; |
381 | 464 | ||
465 | /* mark one irq of the appropriate mode */ | ||
382 | spin_lock_irqsave(&rtc->irq_lock, flags); | 466 | spin_lock_irqsave(&rtc->irq_lock, flags); |
383 | rtc->irq_data = (rtc->irq_data + (num << 8)) | events; | 467 | rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); |
384 | spin_unlock_irqrestore(&rtc->irq_lock, flags); | 468 | spin_unlock_irqrestore(&rtc->irq_lock, flags); |
385 | 469 | ||
470 | /* call the task func */ | ||
386 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 471 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
387 | if (rtc->irq_task) | 472 | if (rtc->irq_task) |
388 | rtc->irq_task->func(rtc->irq_task->private_data); | 473 | rtc->irq_task->func(rtc->irq_task->private_data); |
@@ -391,6 +476,69 @@ void rtc_update_irq(struct rtc_device *rtc, | |||
391 | wake_up_interruptible(&rtc->irq_queue); | 476 | wake_up_interruptible(&rtc->irq_queue); |
392 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); | 477 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); |
393 | } | 478 | } |
479 | |||
480 | |||
481 | /** | ||
482 | * rtc_aie_update_irq - AIE mode rtctimer hook | ||
483 | * @private: pointer to the rtc_device | ||
484 | * | ||
485 | * This functions is called when the aie_timer expires. | ||
486 | */ | ||
487 | void rtc_aie_update_irq(void *private) | ||
488 | { | ||
489 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
490 | rtc_handle_legacy_irq(rtc, 1, RTC_AF); | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * rtc_uie_update_irq - UIE mode rtctimer hook | ||
496 | * @private: pointer to the rtc_device | ||
497 | * | ||
498 | * This functions is called when the uie_timer expires. | ||
499 | */ | ||
500 | void rtc_uie_update_irq(void *private) | ||
501 | { | ||
502 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
503 | rtc_handle_legacy_irq(rtc, 1, RTC_UF); | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * rtc_pie_update_irq - PIE mode hrtimer hook | ||
509 | * @timer: pointer to the pie mode hrtimer | ||
510 | * | ||
511 | * This function is used to emulate PIE mode interrupts | ||
512 | * using an hrtimer. This function is called when the periodic | ||
513 | * hrtimer expires. | ||
514 | */ | ||
515 | enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) | ||
516 | { | ||
517 | struct rtc_device *rtc; | ||
518 | ktime_t period; | ||
519 | int count; | ||
520 | rtc = container_of(timer, struct rtc_device, pie_timer); | ||
521 | |||
522 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
523 | count = hrtimer_forward_now(timer, period); | ||
524 | |||
525 | rtc_handle_legacy_irq(rtc, count, RTC_PF); | ||
526 | |||
527 | return HRTIMER_RESTART; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * rtc_update_irq - Triggered when a RTC interrupt occurs. | ||
532 | * @rtc: the rtc device | ||
533 | * @num: how many irqs are being reported (usually one) | ||
534 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | ||
535 | * Context: any | ||
536 | */ | ||
537 | void rtc_update_irq(struct rtc_device *rtc, | ||
538 | unsigned long num, unsigned long events) | ||
539 | { | ||
540 | schedule_work(&rtc->irqwork); | ||
541 | } | ||
394 | EXPORT_SYMBOL_GPL(rtc_update_irq); | 542 | EXPORT_SYMBOL_GPL(rtc_update_irq); |
395 | 543 | ||
396 | static int __rtc_match(struct device *dev, void *data) | 544 | static int __rtc_match(struct device *dev, void *data) |
@@ -477,18 +625,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
477 | int err = 0; | 625 | int err = 0; |
478 | unsigned long flags; | 626 | unsigned long flags; |
479 | 627 | ||
480 | if (rtc->ops->irq_set_state == NULL) | ||
481 | return -ENXIO; | ||
482 | |||
483 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 628 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
484 | if (rtc->irq_task != NULL && task == NULL) | 629 | if (rtc->irq_task != NULL && task == NULL) |
485 | err = -EBUSY; | 630 | err = -EBUSY; |
486 | if (rtc->irq_task != task) | 631 | if (rtc->irq_task != task) |
487 | err = -EACCES; | 632 | err = -EACCES; |
488 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
489 | 633 | ||
490 | if (err == 0) | 634 | if (enabled) { |
491 | err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); | 635 | ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); |
636 | hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); | ||
637 | } else { | ||
638 | hrtimer_cancel(&rtc->pie_timer); | ||
639 | } | ||
640 | rtc->pie_enabled = enabled; | ||
641 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
492 | 642 | ||
493 | return err; | 643 | return err; |
494 | } | 644 | } |
@@ -509,21 +659,206 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
509 | int err = 0; | 659 | int err = 0; |
510 | unsigned long flags; | 660 | unsigned long flags; |
511 | 661 | ||
512 | if (rtc->ops->irq_set_freq == NULL) | 662 | if (freq <= 0) |
513 | return -ENXIO; | 663 | return -EINVAL; |
514 | 664 | ||
515 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 665 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
516 | if (rtc->irq_task != NULL && task == NULL) | 666 | if (rtc->irq_task != NULL && task == NULL) |
517 | err = -EBUSY; | 667 | err = -EBUSY; |
518 | if (rtc->irq_task != task) | 668 | if (rtc->irq_task != task) |
519 | err = -EACCES; | 669 | err = -EACCES; |
520 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
521 | |||
522 | if (err == 0) { | 670 | if (err == 0) { |
523 | err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); | 671 | rtc->irq_freq = freq; |
524 | if (err == 0) | 672 | if (rtc->pie_enabled) { |
525 | rtc->irq_freq = freq; | 673 | ktime_t period; |
674 | hrtimer_cancel(&rtc->pie_timer); | ||
675 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
676 | hrtimer_start(&rtc->pie_timer, period, | ||
677 | HRTIMER_MODE_REL); | ||
678 | } | ||
526 | } | 679 | } |
680 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
527 | return err; | 681 | return err; |
528 | } | 682 | } |
529 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); | 683 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); |
684 | |||
685 | /** | ||
686 | * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue | ||
687 | * @rtc rtc device | ||
688 | * @timer timer being added. | ||
689 | * | ||
690 | * Enqueues a timer onto the rtc devices timerqueue and sets | ||
691 | * the next alarm event appropriately. | ||
692 | * | ||
693 | * Sets the enabled bit on the added timer. | ||
694 | * | ||
695 | * Must hold ops_lock for proper serialization of timerqueue | ||
696 | */ | ||
697 | static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) | ||
698 | { | ||
699 | timer->enabled = 1; | ||
700 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
701 | if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { | ||
702 | struct rtc_wkalrm alarm; | ||
703 | int err; | ||
704 | alarm.time = rtc_ktime_to_tm(timer->node.expires); | ||
705 | alarm.enabled = 1; | ||
706 | err = __rtc_set_alarm(rtc, &alarm); | ||
707 | if (err == -ETIME) | ||
708 | schedule_work(&rtc->irqwork); | ||
709 | else if (err) { | ||
710 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
711 | timer->enabled = 0; | ||
712 | return err; | ||
713 | } | ||
714 | } | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | /** | ||
719 | * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue | ||
720 | * @rtc rtc device | ||
721 | * @timer timer being removed. | ||
722 | * | ||
723 | * Removes a timer onto the rtc devices timerqueue and sets | ||
724 | * the next alarm event appropriately. | ||
725 | * | ||
726 | * Clears the enabled bit on the removed timer. | ||
727 | * | ||
728 | * Must hold ops_lock for proper serialization of timerqueue | ||
729 | */ | ||
730 | static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) | ||
731 | { | ||
732 | struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); | ||
733 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
734 | timer->enabled = 0; | ||
735 | if (next == &timer->node) { | ||
736 | struct rtc_wkalrm alarm; | ||
737 | int err; | ||
738 | next = timerqueue_getnext(&rtc->timerqueue); | ||
739 | if (!next) | ||
740 | return; | ||
741 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
742 | alarm.enabled = 1; | ||
743 | err = __rtc_set_alarm(rtc, &alarm); | ||
744 | if (err == -ETIME) | ||
745 | schedule_work(&rtc->irqwork); | ||
746 | } | ||
747 | } | ||
748 | |||
749 | /** | ||
750 | * rtc_timer_do_work - Expires rtc timers | ||
751 | * @rtc rtc device | ||
752 | * @timer timer being removed. | ||
753 | * | ||
754 | * Expires rtc timers. Reprograms next alarm event if needed. | ||
755 | * Called via worktask. | ||
756 | * | ||
757 | * Serializes access to timerqueue via ops_lock mutex | ||
758 | */ | ||
759 | void rtc_timer_do_work(struct work_struct *work) | ||
760 | { | ||
761 | struct rtc_timer *timer; | ||
762 | struct timerqueue_node *next; | ||
763 | ktime_t now; | ||
764 | struct rtc_time tm; | ||
765 | |||
766 | struct rtc_device *rtc = | ||
767 | container_of(work, struct rtc_device, irqwork); | ||
768 | |||
769 | mutex_lock(&rtc->ops_lock); | ||
770 | again: | ||
771 | __rtc_read_time(rtc, &tm); | ||
772 | now = rtc_tm_to_ktime(tm); | ||
773 | while ((next = timerqueue_getnext(&rtc->timerqueue))) { | ||
774 | if (next->expires.tv64 > now.tv64) | ||
775 | break; | ||
776 | |||
777 | /* expire timer */ | ||
778 | timer = container_of(next, struct rtc_timer, node); | ||
779 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
780 | timer->enabled = 0; | ||
781 | if (timer->task.func) | ||
782 | timer->task.func(timer->task.private_data); | ||
783 | |||
784 | /* Re-add/fwd periodic timers */ | ||
785 | if (ktime_to_ns(timer->period)) { | ||
786 | timer->node.expires = ktime_add(timer->node.expires, | ||
787 | timer->period); | ||
788 | timer->enabled = 1; | ||
789 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | /* Set next alarm */ | ||
794 | if (next) { | ||
795 | struct rtc_wkalrm alarm; | ||
796 | int err; | ||
797 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
798 | alarm.enabled = 1; | ||
799 | err = __rtc_set_alarm(rtc, &alarm); | ||
800 | if (err == -ETIME) | ||
801 | goto again; | ||
802 | } | ||
803 | |||
804 | mutex_unlock(&rtc->ops_lock); | ||
805 | } | ||
806 | |||
807 | |||
808 | /* rtc_timer_init - Initializes an rtc_timer | ||
809 | * @timer: timer to be intiialized | ||
810 | * @f: function pointer to be called when timer fires | ||
811 | * @data: private data passed to function pointer | ||
812 | * | ||
813 | * Kernel interface to initializing an rtc_timer. | ||
814 | */ | ||
815 | void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) | ||
816 | { | ||
817 | timerqueue_init(&timer->node); | ||
818 | timer->enabled = 0; | ||
819 | timer->task.func = f; | ||
820 | timer->task.private_data = data; | ||
821 | } | ||
822 | |||
823 | /* rtc_timer_start - Sets an rtc_timer to fire in the future | ||
824 | * @ rtc: rtc device to be used | ||
825 | * @ timer: timer being set | ||
826 | * @ expires: time at which to expire the timer | ||
827 | * @ period: period that the timer will recur | ||
828 | * | ||
829 | * Kernel interface to set an rtc_timer | ||
830 | */ | ||
831 | int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, | ||
832 | ktime_t expires, ktime_t period) | ||
833 | { | ||
834 | int ret = 0; | ||
835 | mutex_lock(&rtc->ops_lock); | ||
836 | if (timer->enabled) | ||
837 | rtc_timer_remove(rtc, timer); | ||
838 | |||
839 | timer->node.expires = expires; | ||
840 | timer->period = period; | ||
841 | |||
842 | ret = rtc_timer_enqueue(rtc, timer); | ||
843 | |||
844 | mutex_unlock(&rtc->ops_lock); | ||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | /* rtc_timer_cancel - Stops an rtc_timer | ||
849 | * @ rtc: rtc device to be used | ||
850 | * @ timer: timer being set | ||
851 | * | ||
852 | * Kernel interface to cancel an rtc_timer | ||
853 | */ | ||
854 | int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) | ||
855 | { | ||
856 | int ret = 0; | ||
857 | mutex_lock(&rtc->ops_lock); | ||
858 | if (timer->enabled) | ||
859 | rtc_timer_remove(rtc, timer); | ||
860 | mutex_unlock(&rtc->ops_lock); | ||
861 | return ret; | ||
862 | } | ||
863 | |||
864 | |||