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