diff options
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 37 | ||||
-rw-r--r-- | include/linux/mc146818rtc.h | 7 |
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 | */ |
26 | struct cmos_rtc_board_info { | 30 | struct 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 */ |