diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/rtc-cmos.c | 38 | ||||
| -rw-r--r-- | drivers/rtc/rtc-lib.c | 5 |
2 files changed, 35 insertions, 8 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 | ||
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 9f996ec881ce..dd70bf73ce9d 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c | |||
| @@ -51,10 +51,11 @@ EXPORT_SYMBOL(rtc_year_days); | |||
| 51 | */ | 51 | */ |
| 52 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) | 52 | void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) |
| 53 | { | 53 | { |
| 54 | unsigned int days, month, year; | 54 | unsigned int month, year; |
| 55 | int days; | ||
| 55 | 56 | ||
| 56 | days = time / 86400; | 57 | days = time / 86400; |
| 57 | time -= days * 86400; | 58 | time -= (unsigned int) days * 86400; |
| 58 | 59 | ||
| 59 | /* day of the week, 1970-01-01 was a Thursday */ | 60 | /* day of the week, 1970-01-01 was a Thursday */ |
| 60 | tm->tm_wday = (days + 4) % 7; | 61 | tm->tm_wday = (days + 4) % 7; |
