diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/rtc-cmos.c | 38 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 15 | ||||
| -rw-r--r-- | drivers/rtc/rtc-lib.c | 5 |
3 files changed, 44 insertions, 14 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-dev.c b/drivers/rtc/rtc-dev.c index f118252f3a9f..52e2743b04ec 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c | |||
| @@ -422,6 +422,12 @@ done: | |||
| 422 | return err; | 422 | return err; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | static int rtc_dev_fasync(int fd, struct file *file, int on) | ||
| 426 | { | ||
| 427 | struct rtc_device *rtc = file->private_data; | ||
| 428 | return fasync_helper(fd, file, on, &rtc->async_queue); | ||
| 429 | } | ||
| 430 | |||
| 425 | static int rtc_dev_release(struct inode *inode, struct file *file) | 431 | static int rtc_dev_release(struct inode *inode, struct file *file) |
| 426 | { | 432 | { |
| 427 | struct rtc_device *rtc = file->private_data; | 433 | struct rtc_device *rtc = file->private_data; |
| @@ -434,16 +440,13 @@ static int rtc_dev_release(struct inode *inode, struct file *file) | |||
| 434 | if (rtc->ops->release) | 440 | if (rtc->ops->release) |
| 435 | rtc->ops->release(rtc->dev.parent); | 441 | rtc->ops->release(rtc->dev.parent); |
| 436 | 442 | ||
| 443 | if (file->f_flags & FASYNC) | ||
| 444 | rtc_dev_fasync(-1, file, 0); | ||
| 445 | |||
| 437 | clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); | 446 | clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); |
| 438 | return 0; | 447 | return 0; |
| 439 | } | 448 | } |
| 440 | 449 | ||
| 441 | static int rtc_dev_fasync(int fd, struct file *file, int on) | ||
| 442 | { | ||
| 443 | struct rtc_device *rtc = file->private_data; | ||
| 444 | return fasync_helper(fd, file, on, &rtc->async_queue); | ||
| 445 | } | ||
| 446 | |||
| 447 | static const struct file_operations rtc_dev_fops = { | 450 | static const struct file_operations rtc_dev_fops = { |
| 448 | .owner = THIS_MODULE, | 451 | .owner = THIS_MODULE, |
| 449 | .llseek = no_llseek, | 452 | .llseek = no_llseek, |
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; |
