diff options
Diffstat (limited to 'drivers/rtc/rtc-cmos.c')
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 04ecfd2e7c88..b23af0c2a869 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -801,7 +801,6 @@ static void __exit cmos_do_remove(struct device *dev) | |||
801 | static int cmos_suspend(struct device *dev, pm_message_t mesg) | 801 | static int cmos_suspend(struct device *dev, pm_message_t mesg) |
802 | { | 802 | { |
803 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 803 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
804 | int do_wake = device_may_wakeup(dev); | ||
805 | unsigned char tmp; | 804 | unsigned char tmp; |
806 | 805 | ||
807 | /* only the alarm might be a wakeup event source */ | 806 | /* only the alarm might be a wakeup event source */ |
@@ -810,7 +809,7 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) | |||
810 | if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { | 809 | if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) { |
811 | unsigned char mask; | 810 | unsigned char mask; |
812 | 811 | ||
813 | if (do_wake) | 812 | if (device_may_wakeup(dev)) |
814 | mask = RTC_IRQMASK & ~RTC_AIE; | 813 | mask = RTC_IRQMASK & ~RTC_AIE; |
815 | else | 814 | else |
816 | mask = RTC_IRQMASK; | 815 | mask = RTC_IRQMASK; |
@@ -838,6 +837,17 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) | |||
838 | return 0; | 837 | return 0; |
839 | } | 838 | } |
840 | 839 | ||
840 | /* We want RTC alarms to wake us from e.g. ACPI G2/S5 "soft off", even | ||
841 | * after a detour through G3 "mechanical off", although the ACPI spec | ||
842 | * says wakeup should only work from G1/S4 "hibernate". To most users, | ||
843 | * distinctions between S4 and S5 are pointless. So when the hardware | ||
844 | * allows, don't draw that distinction. | ||
845 | */ | ||
846 | static inline int cmos_poweroff(struct device *dev) | ||
847 | { | ||
848 | return cmos_suspend(dev, PMSG_HIBERNATE); | ||
849 | } | ||
850 | |||
841 | static int cmos_resume(struct device *dev) | 851 | static int cmos_resume(struct device *dev) |
842 | { | 852 | { |
843 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 853 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
@@ -885,6 +895,12 @@ static int cmos_resume(struct device *dev) | |||
885 | #else | 895 | #else |
886 | #define cmos_suspend NULL | 896 | #define cmos_suspend NULL |
887 | #define cmos_resume NULL | 897 | #define cmos_resume NULL |
898 | |||
899 | static inline int cmos_poweroff(struct device *dev) | ||
900 | { | ||
901 | return -ENOSYS; | ||
902 | } | ||
903 | |||
888 | #endif | 904 | #endif |
889 | 905 | ||
890 | /*----------------------------------------------------------------*/ | 906 | /*----------------------------------------------------------------*/ |
@@ -904,10 +920,6 @@ static int cmos_resume(struct device *dev) | |||
904 | static int __devinit | 920 | static int __devinit |
905 | cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | 921 | cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) |
906 | { | 922 | { |
907 | /* REVISIT paranoia argues for a shutdown notifier, since PNP | ||
908 | * drivers can't provide shutdown() methods to disable IRQs. | ||
909 | * Or better yet, fix PNP to allow those methods... | ||
910 | */ | ||
911 | if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0)) | 923 | if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0)) |
912 | /* Some machines contain a PNP entry for the RTC, but | 924 | /* Some machines contain a PNP entry for the RTC, but |
913 | * don't define the IRQ. It should always be safe to | 925 | * don't define the IRQ. It should always be safe to |
@@ -943,6 +955,13 @@ static int cmos_pnp_resume(struct pnp_dev *pnp) | |||
943 | #define cmos_pnp_resume NULL | 955 | #define cmos_pnp_resume NULL |
944 | #endif | 956 | #endif |
945 | 957 | ||
958 | static void cmos_pnp_shutdown(struct device *pdev) | ||
959 | { | ||
960 | if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(pdev)) | ||
961 | return; | ||
962 | |||
963 | cmos_do_shutdown(); | ||
964 | } | ||
946 | 965 | ||
947 | static const struct pnp_device_id rtc_ids[] = { | 966 | static const struct pnp_device_id rtc_ids[] = { |
948 | { .id = "PNP0b00", }, | 967 | { .id = "PNP0b00", }, |
@@ -962,6 +981,10 @@ static struct pnp_driver cmos_pnp_driver = { | |||
962 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | 981 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, |
963 | .suspend = cmos_pnp_suspend, | 982 | .suspend = cmos_pnp_suspend, |
964 | .resume = cmos_pnp_resume, | 983 | .resume = cmos_pnp_resume, |
984 | .driver = { | ||
985 | .name = (char *)driver_name, | ||
986 | .shutdown = cmos_pnp_shutdown, | ||
987 | } | ||
965 | }; | 988 | }; |
966 | 989 | ||
967 | #endif /* CONFIG_PNP */ | 990 | #endif /* CONFIG_PNP */ |
@@ -987,6 +1010,9 @@ static int __exit cmos_platform_remove(struct platform_device *pdev) | |||
987 | 1010 | ||
988 | static void cmos_platform_shutdown(struct platform_device *pdev) | 1011 | static void cmos_platform_shutdown(struct platform_device *pdev) |
989 | { | 1012 | { |
1013 | if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) | ||
1014 | return; | ||
1015 | |||
990 | cmos_do_shutdown(); | 1016 | cmos_do_shutdown(); |
991 | } | 1017 | } |
992 | 1018 | ||