aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/rtc-cmos.c37
-rw-r--r--include/linux/mc146818rtc.h7
2 files changed, 34 insertions, 10 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 4e8c373f78e3..3fbfdd16191d 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -46,6 +46,10 @@ struct cmos_rtc {
46 int irq; 46 int irq;
47 struct resource *iomem; 47 struct resource *iomem;
48 48
49 void (*wake_on)(struct device *);
50 void (*wake_off)(struct device *);
51
52 u8 enabled_wake;
49 u8 suspend_ctrl; 53 u8 suspend_ctrl;
50 54
51 /* newer hardware extends the original register set */ 55 /* newer hardware extends the original register set */
@@ -405,13 +409,20 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
405 cmos_rtc.irq = rtc_irq; 409 cmos_rtc.irq = rtc_irq;
406 cmos_rtc.iomem = ports; 410 cmos_rtc.iomem = ports;
407 411
408 /* For ACPI systems the info comes from the FADT. On others, 412 /* For ACPI systems extension info comes from the FADT. On others,
409 * board specific setup provides it as appropriate. 413 * board specific setup provides it as appropriate. Systems where
414 * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
415 * some almost-clones) can provide hooks to make that behave.
410 */ 416 */
411 if (info) { 417 if (info) {
412 cmos_rtc.day_alrm = info->rtc_day_alarm; 418 cmos_rtc.day_alrm = info->rtc_day_alarm;
413 cmos_rtc.mon_alrm = info->rtc_mon_alarm; 419 cmos_rtc.mon_alrm = info->rtc_mon_alarm;
414 cmos_rtc.century = info->rtc_century; 420 cmos_rtc.century = info->rtc_century;
421
422 if (info->wake_on && info->wake_off) {
423 cmos_rtc.wake_on = info->wake_on;
424 cmos_rtc.wake_off = info->wake_off;
425 }
415 } 426 }
416 427
417 cmos_rtc.rtc = rtc_device_register(driver_name, dev, 428 cmos_rtc.rtc = rtc_device_register(driver_name, dev,
@@ -559,9 +570,13 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
559 } 570 }
560 spin_unlock_irq(&rtc_lock); 571 spin_unlock_irq(&rtc_lock);
561 572
562 /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE) 573 if (tmp & RTC_AIE) {
563 * ... it'd be best if we could do that under rtc_lock. 574 cmos->enabled_wake = 1;
564 */ 575 if (cmos->wake_on)
576 cmos->wake_on(dev);
577 else
578 enable_irq_wake(cmos->irq);
579 }
565 580
566 pr_debug("%s: suspend%s, ctrl %02x\n", 581 pr_debug("%s: suspend%s, ctrl %02x\n",
567 cmos_rtc.rtc->dev.bus_id, 582 cmos_rtc.rtc->dev.bus_id,
@@ -576,14 +591,16 @@ static int cmos_resume(struct device *dev)
576 struct cmos_rtc *cmos = dev_get_drvdata(dev); 591 struct cmos_rtc *cmos = dev_get_drvdata(dev);
577 unsigned char tmp = cmos->suspend_ctrl; 592 unsigned char tmp = cmos->suspend_ctrl;
578 593
579 /* REVISIT: a mechanism to resync the system clock (jiffies)
580 * on resume should be portable between platforms ...
581 */
582
583 /* re-enable any irqs previously active */ 594 /* re-enable any irqs previously active */
584 if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { 595 if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
585 596
586 /* ACPI HOOK: disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */ 597 if (cmos->enabled_wake) {
598 if (cmos->wake_off)
599 cmos->wake_off(dev);
600 else
601 disable_irq_wake(cmos->irq);
602 cmos->enabled_wake = 0;
603 }
587 604
588 spin_lock_irq(&rtc_lock); 605 spin_lock_irq(&rtc_lock);
589 CMOS_WRITE(tmp, RTC_CONTROL); 606 CMOS_WRITE(tmp, RTC_CONTROL);
diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h
index bdc01127dced..580b3f4956ee 100644
--- a/include/linux/mc146818rtc.h
+++ b/include/linux/mc146818rtc.h
@@ -22,8 +22,15 @@ extern spinlock_t rtc_lock; /* serialize CMOS RAM access */
22/* Some RTCs extend the mc146818 register set to support alarms of more 22/* Some RTCs extend the mc146818 register set to support alarms of more
23 * than 24 hours in the future; or dates that include a century code. 23 * than 24 hours in the future; or dates that include a century code.
24 * This platform_data structure can pass this information to the driver. 24 * This platform_data structure can pass this information to the driver.
25 *
26 * Also, some platforms need suspend()/resume() hooks to kick in special
27 * handling of wake alarms, e.g. activating ACPI BIOS hooks or setting up
28 * a separate wakeup alarm used by some almost-clone chips.
25 */ 29 */
26struct cmos_rtc_board_info { 30struct cmos_rtc_board_info {
31 void (*wake_on)(struct device *dev);
32 void (*wake_off)(struct device *dev);
33
27 u8 rtc_day_alarm; /* zero, or register index */ 34 u8 rtc_day_alarm; /* zero, or register index */
28 u8 rtc_mon_alarm; /* zero, or register index */ 35 u8 rtc_mon_alarm; /* zero, or register index */
29 u8 rtc_century; /* zero, or register index */ 36 u8 rtc_century; /* zero, or register index */