diff options
Diffstat (limited to 'drivers/rtc/interface.c')
-rw-r--r-- | drivers/rtc/interface.c | 451 |
1 files changed, 406 insertions, 45 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c816238aa9..df68618f6dbb 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; | ||
34 | 39 | ||
40 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
41 | if (err) | ||
42 | return err; | ||
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 | static 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,18 +348,75 @@ 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 | } |
314 | EXPORT_SYMBOL_GPL(rtc_set_alarm); | 376 | EXPORT_SYMBOL_GPL(rtc_set_alarm); |
315 | 377 | ||
378 | /* Called once per device from rtc_device_register */ | ||
379 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | ||
380 | { | ||
381 | int err; | ||
382 | |||
383 | err = rtc_valid_tm(&alarm->time); | ||
384 | if (err != 0) | ||
385 | return err; | ||
386 | |||
387 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
388 | if (err) | ||
389 | return err; | ||
390 | |||
391 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); | ||
392 | rtc->aie_timer.period = ktime_set(0, 0); | ||
393 | if (alarm->enabled) { | ||
394 | rtc->aie_timer.enabled = 1; | ||
395 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); | ||
396 | } | ||
397 | mutex_unlock(&rtc->ops_lock); | ||
398 | return err; | ||
399 | } | ||
400 | EXPORT_SYMBOL_GPL(rtc_initialize_alarm); | ||
401 | |||
402 | |||
403 | |||
316 | int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) | 404 | int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) |
317 | { | 405 | { |
318 | int err = mutex_lock_interruptible(&rtc->ops_lock); | 406 | int err = mutex_lock_interruptible(&rtc->ops_lock); |
319 | if (err) | 407 | if (err) |
320 | return err; | 408 | return err; |
321 | 409 | ||
322 | if (!rtc->ops) | 410 | if (rtc->aie_timer.enabled != enabled) { |
411 | if (enabled) | ||
412 | err = rtc_timer_enqueue(rtc, &rtc->aie_timer); | ||
413 | else | ||
414 | rtc_timer_remove(rtc, &rtc->aie_timer); | ||
415 | } | ||
416 | |||
417 | if (err) | ||
418 | /* nothing */; | ||
419 | else if (!rtc->ops) | ||
323 | err = -ENODEV; | 420 | err = -ENODEV; |
324 | else if (!rtc->ops->alarm_irq_enable) | 421 | else if (!rtc->ops->alarm_irq_enable) |
325 | err = -EINVAL; | 422 | err = -EINVAL; |
@@ -340,19 +437,28 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
340 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 437 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
341 | if (enabled == 0 && rtc->uie_irq_active) { | 438 | if (enabled == 0 && rtc->uie_irq_active) { |
342 | mutex_unlock(&rtc->ops_lock); | 439 | mutex_unlock(&rtc->ops_lock); |
343 | return rtc_dev_update_irq_enable_emul(rtc, enabled); | 440 | return rtc_dev_update_irq_enable_emul(rtc, 0); |
344 | } | 441 | } |
345 | #endif | 442 | #endif |
443 | /* make sure we're changing state */ | ||
444 | if (rtc->uie_rtctimer.enabled == enabled) | ||
445 | goto out; | ||
446 | |||
447 | if (enabled) { | ||
448 | struct rtc_time tm; | ||
449 | ktime_t now, onesec; | ||
450 | |||
451 | __rtc_read_time(rtc, &tm); | ||
452 | onesec = ktime_set(1, 0); | ||
453 | now = rtc_tm_to_ktime(tm); | ||
454 | rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); | ||
455 | rtc->uie_rtctimer.period = ktime_set(1, 0); | ||
456 | err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); | ||
457 | } else | ||
458 | rtc_timer_remove(rtc, &rtc->uie_rtctimer); | ||
346 | 459 | ||
347 | if (!rtc->ops) | 460 | 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); | 461 | mutex_unlock(&rtc->ops_lock); |
355 | |||
356 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 462 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL |
357 | /* | 463 | /* |
358 | * Enable emulation if the driver did not provide | 464 | * Enable emulation if the driver did not provide |
@@ -364,25 +470,30 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
364 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); | 470 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); |
365 | #endif | 471 | #endif |
366 | return err; | 472 | return err; |
473 | |||
367 | } | 474 | } |
368 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); | 475 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); |
369 | 476 | ||
477 | |||
370 | /** | 478 | /** |
371 | * rtc_update_irq - report RTC periodic, alarm, and/or update irqs | 479 | * rtc_handle_legacy_irq - AIE, UIE and PIE event hook |
372 | * @rtc: the rtc device | 480 | * @rtc: pointer to the rtc device |
373 | * @num: how many irqs are being reported (usually one) | 481 | * |
374 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | 482 | * This function is called when an AIE, UIE or PIE mode interrupt |
375 | * Context: any | 483 | * has occurred (or been emulated). |
484 | * | ||
485 | * Triggers the registered irq_task function callback. | ||
376 | */ | 486 | */ |
377 | void rtc_update_irq(struct rtc_device *rtc, | 487 | void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) |
378 | unsigned long num, unsigned long events) | ||
379 | { | 488 | { |
380 | unsigned long flags; | 489 | unsigned long flags; |
381 | 490 | ||
491 | /* mark one irq of the appropriate mode */ | ||
382 | spin_lock_irqsave(&rtc->irq_lock, flags); | 492 | spin_lock_irqsave(&rtc->irq_lock, flags); |
383 | rtc->irq_data = (rtc->irq_data + (num << 8)) | events; | 493 | rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); |
384 | spin_unlock_irqrestore(&rtc->irq_lock, flags); | 494 | spin_unlock_irqrestore(&rtc->irq_lock, flags); |
385 | 495 | ||
496 | /* call the task func */ | ||
386 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 497 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
387 | if (rtc->irq_task) | 498 | if (rtc->irq_task) |
388 | rtc->irq_task->func(rtc->irq_task->private_data); | 499 | rtc->irq_task->func(rtc->irq_task->private_data); |
@@ -391,6 +502,69 @@ void rtc_update_irq(struct rtc_device *rtc, | |||
391 | wake_up_interruptible(&rtc->irq_queue); | 502 | wake_up_interruptible(&rtc->irq_queue); |
392 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); | 503 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); |
393 | } | 504 | } |
505 | |||
506 | |||
507 | /** | ||
508 | * rtc_aie_update_irq - AIE mode rtctimer hook | ||
509 | * @private: pointer to the rtc_device | ||
510 | * | ||
511 | * This functions is called when the aie_timer expires. | ||
512 | */ | ||
513 | void rtc_aie_update_irq(void *private) | ||
514 | { | ||
515 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
516 | rtc_handle_legacy_irq(rtc, 1, RTC_AF); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * rtc_uie_update_irq - UIE mode rtctimer hook | ||
522 | * @private: pointer to the rtc_device | ||
523 | * | ||
524 | * This functions is called when the uie_timer expires. | ||
525 | */ | ||
526 | void rtc_uie_update_irq(void *private) | ||
527 | { | ||
528 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
529 | rtc_handle_legacy_irq(rtc, 1, RTC_UF); | ||
530 | } | ||
531 | |||
532 | |||
533 | /** | ||
534 | * rtc_pie_update_irq - PIE mode hrtimer hook | ||
535 | * @timer: pointer to the pie mode hrtimer | ||
536 | * | ||
537 | * This function is used to emulate PIE mode interrupts | ||
538 | * using an hrtimer. This function is called when the periodic | ||
539 | * hrtimer expires. | ||
540 | */ | ||
541 | enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) | ||
542 | { | ||
543 | struct rtc_device *rtc; | ||
544 | ktime_t period; | ||
545 | int count; | ||
546 | rtc = container_of(timer, struct rtc_device, pie_timer); | ||
547 | |||
548 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
549 | count = hrtimer_forward_now(timer, period); | ||
550 | |||
551 | rtc_handle_legacy_irq(rtc, count, RTC_PF); | ||
552 | |||
553 | return HRTIMER_RESTART; | ||
554 | } | ||
555 | |||
556 | /** | ||
557 | * rtc_update_irq - Triggered when a RTC interrupt occurs. | ||
558 | * @rtc: the rtc device | ||
559 | * @num: how many irqs are being reported (usually one) | ||
560 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | ||
561 | * Context: any | ||
562 | */ | ||
563 | void rtc_update_irq(struct rtc_device *rtc, | ||
564 | unsigned long num, unsigned long events) | ||
565 | { | ||
566 | schedule_work(&rtc->irqwork); | ||
567 | } | ||
394 | EXPORT_SYMBOL_GPL(rtc_update_irq); | 568 | EXPORT_SYMBOL_GPL(rtc_update_irq); |
395 | 569 | ||
396 | static int __rtc_match(struct device *dev, void *data) | 570 | static int __rtc_match(struct device *dev, void *data) |
@@ -477,18 +651,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
477 | int err = 0; | 651 | int err = 0; |
478 | unsigned long flags; | 652 | unsigned long flags; |
479 | 653 | ||
480 | if (rtc->ops->irq_set_state == NULL) | ||
481 | return -ENXIO; | ||
482 | |||
483 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 654 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
484 | if (rtc->irq_task != NULL && task == NULL) | 655 | if (rtc->irq_task != NULL && task == NULL) |
485 | err = -EBUSY; | 656 | err = -EBUSY; |
486 | if (rtc->irq_task != task) | 657 | if (rtc->irq_task != task) |
487 | err = -EACCES; | 658 | err = -EACCES; |
488 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
489 | 659 | ||
490 | if (err == 0) | 660 | if (enabled) { |
491 | err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); | 661 | ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); |
662 | hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); | ||
663 | } else { | ||
664 | hrtimer_cancel(&rtc->pie_timer); | ||
665 | } | ||
666 | rtc->pie_enabled = enabled; | ||
667 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
492 | 668 | ||
493 | return err; | 669 | return err; |
494 | } | 670 | } |
@@ -509,21 +685,206 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
509 | int err = 0; | 685 | int err = 0; |
510 | unsigned long flags; | 686 | unsigned long flags; |
511 | 687 | ||
512 | if (rtc->ops->irq_set_freq == NULL) | 688 | if (freq <= 0) |
513 | return -ENXIO; | 689 | return -EINVAL; |
514 | 690 | ||
515 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 691 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
516 | if (rtc->irq_task != NULL && task == NULL) | 692 | if (rtc->irq_task != NULL && task == NULL) |
517 | err = -EBUSY; | 693 | err = -EBUSY; |
518 | if (rtc->irq_task != task) | 694 | if (rtc->irq_task != task) |
519 | err = -EACCES; | 695 | err = -EACCES; |
520 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
521 | |||
522 | if (err == 0) { | 696 | if (err == 0) { |
523 | err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); | 697 | rtc->irq_freq = freq; |
524 | if (err == 0) | 698 | if (rtc->pie_enabled) { |
525 | rtc->irq_freq = freq; | 699 | ktime_t period; |
700 | hrtimer_cancel(&rtc->pie_timer); | ||
701 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
702 | hrtimer_start(&rtc->pie_timer, period, | ||
703 | HRTIMER_MODE_REL); | ||
704 | } | ||
526 | } | 705 | } |
706 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
527 | return err; | 707 | return err; |
528 | } | 708 | } |
529 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); | 709 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); |
710 | |||
711 | /** | ||
712 | * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue | ||
713 | * @rtc rtc device | ||
714 | * @timer timer being added. | ||
715 | * | ||
716 | * Enqueues a timer onto the rtc devices timerqueue and sets | ||
717 | * the next alarm event appropriately. | ||
718 | * | ||
719 | * Sets the enabled bit on the added timer. | ||
720 | * | ||
721 | * Must hold ops_lock for proper serialization of timerqueue | ||
722 | */ | ||
723 | static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) | ||
724 | { | ||
725 | timer->enabled = 1; | ||
726 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
727 | if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { | ||
728 | struct rtc_wkalrm alarm; | ||
729 | int err; | ||
730 | alarm.time = rtc_ktime_to_tm(timer->node.expires); | ||
731 | alarm.enabled = 1; | ||
732 | err = __rtc_set_alarm(rtc, &alarm); | ||
733 | if (err == -ETIME) | ||
734 | schedule_work(&rtc->irqwork); | ||
735 | else if (err) { | ||
736 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
737 | timer->enabled = 0; | ||
738 | return err; | ||
739 | } | ||
740 | } | ||
741 | return 0; | ||
742 | } | ||
743 | |||
744 | /** | ||
745 | * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue | ||
746 | * @rtc rtc device | ||
747 | * @timer timer being removed. | ||
748 | * | ||
749 | * Removes a timer onto the rtc devices timerqueue and sets | ||
750 | * the next alarm event appropriately. | ||
751 | * | ||
752 | * Clears the enabled bit on the removed timer. | ||
753 | * | ||
754 | * Must hold ops_lock for proper serialization of timerqueue | ||
755 | */ | ||
756 | static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) | ||
757 | { | ||
758 | struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); | ||
759 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
760 | timer->enabled = 0; | ||
761 | if (next == &timer->node) { | ||
762 | struct rtc_wkalrm alarm; | ||
763 | int err; | ||
764 | next = timerqueue_getnext(&rtc->timerqueue); | ||
765 | if (!next) | ||
766 | return; | ||
767 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
768 | alarm.enabled = 1; | ||
769 | err = __rtc_set_alarm(rtc, &alarm); | ||
770 | if (err == -ETIME) | ||
771 | schedule_work(&rtc->irqwork); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /** | ||
776 | * rtc_timer_do_work - Expires rtc timers | ||
777 | * @rtc rtc device | ||
778 | * @timer timer being removed. | ||
779 | * | ||
780 | * Expires rtc timers. Reprograms next alarm event if needed. | ||
781 | * Called via worktask. | ||
782 | * | ||
783 | * Serializes access to timerqueue via ops_lock mutex | ||
784 | */ | ||
785 | void rtc_timer_do_work(struct work_struct *work) | ||
786 | { | ||
787 | struct rtc_timer *timer; | ||
788 | struct timerqueue_node *next; | ||
789 | ktime_t now; | ||
790 | struct rtc_time tm; | ||
791 | |||
792 | struct rtc_device *rtc = | ||
793 | container_of(work, struct rtc_device, irqwork); | ||
794 | |||
795 | mutex_lock(&rtc->ops_lock); | ||
796 | again: | ||
797 | __rtc_read_time(rtc, &tm); | ||
798 | now = rtc_tm_to_ktime(tm); | ||
799 | while ((next = timerqueue_getnext(&rtc->timerqueue))) { | ||
800 | if (next->expires.tv64 > now.tv64) | ||
801 | break; | ||
802 | |||
803 | /* expire timer */ | ||
804 | timer = container_of(next, struct rtc_timer, node); | ||
805 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
806 | timer->enabled = 0; | ||
807 | if (timer->task.func) | ||
808 | timer->task.func(timer->task.private_data); | ||
809 | |||
810 | /* Re-add/fwd periodic timers */ | ||
811 | if (ktime_to_ns(timer->period)) { | ||
812 | timer->node.expires = ktime_add(timer->node.expires, | ||
813 | timer->period); | ||
814 | timer->enabled = 1; | ||
815 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | /* Set next alarm */ | ||
820 | if (next) { | ||
821 | struct rtc_wkalrm alarm; | ||
822 | int err; | ||
823 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
824 | alarm.enabled = 1; | ||
825 | err = __rtc_set_alarm(rtc, &alarm); | ||
826 | if (err == -ETIME) | ||
827 | goto again; | ||
828 | } | ||
829 | |||
830 | mutex_unlock(&rtc->ops_lock); | ||
831 | } | ||
832 | |||
833 | |||
834 | /* rtc_timer_init - Initializes an rtc_timer | ||
835 | * @timer: timer to be intiialized | ||
836 | * @f: function pointer to be called when timer fires | ||
837 | * @data: private data passed to function pointer | ||
838 | * | ||
839 | * Kernel interface to initializing an rtc_timer. | ||
840 | */ | ||
841 | void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) | ||
842 | { | ||
843 | timerqueue_init(&timer->node); | ||
844 | timer->enabled = 0; | ||
845 | timer->task.func = f; | ||
846 | timer->task.private_data = data; | ||
847 | } | ||
848 | |||
849 | /* rtc_timer_start - Sets an rtc_timer to fire in the future | ||
850 | * @ rtc: rtc device to be used | ||
851 | * @ timer: timer being set | ||
852 | * @ expires: time at which to expire the timer | ||
853 | * @ period: period that the timer will recur | ||
854 | * | ||
855 | * Kernel interface to set an rtc_timer | ||
856 | */ | ||
857 | int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, | ||
858 | ktime_t expires, ktime_t period) | ||
859 | { | ||
860 | int ret = 0; | ||
861 | mutex_lock(&rtc->ops_lock); | ||
862 | if (timer->enabled) | ||
863 | rtc_timer_remove(rtc, timer); | ||
864 | |||
865 | timer->node.expires = expires; | ||
866 | timer->period = period; | ||
867 | |||
868 | ret = rtc_timer_enqueue(rtc, timer); | ||
869 | |||
870 | mutex_unlock(&rtc->ops_lock); | ||
871 | return ret; | ||
872 | } | ||
873 | |||
874 | /* rtc_timer_cancel - Stops an rtc_timer | ||
875 | * @ rtc: rtc device to be used | ||
876 | * @ timer: timer being set | ||
877 | * | ||
878 | * Kernel interface to cancel an rtc_timer | ||
879 | */ | ||
880 | int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) | ||
881 | { | ||
882 | int ret = 0; | ||
883 | mutex_lock(&rtc->ops_lock); | ||
884 | if (timer->enabled) | ||
885 | rtc_timer_remove(rtc, timer); | ||
886 | mutex_unlock(&rtc->ops_lock); | ||
887 | return ret; | ||
888 | } | ||
889 | |||
890 | |||