diff options
author | Gabriele Mazzotta <gabriele.mzt@gmail.com> | 2016-09-19 19:12:43 -0400 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2016-09-21 16:08:42 -0400 |
commit | 983bf1256edb477a376b6ce95adf36e13bc88f9a (patch) | |
tree | 87339d47fde88ccc10a8a42c25c2c3875617c8d7 | |
parent | 97ea1906b3c2201273ea6bb40c43c611c056ddb3 (diff) |
rtc: cmos: Clear ACPI-driven alarms upon resume
Currently ACPI-driven alarms are not cleared when they wake the
system. As consequence, expired alarms must be manually cleared to
program a new alarm. Fix this by correctly handling ACPI-driven
alarms.
More specifically, the ACPI specification [1] provides for two
alternative implementations of the RTC. Depending on the
implementation, the driver either clear the alarm from the resume
callback or from ACPI interrupt handler:
- The platform has the RTC wakeup status fixed in hardware
(ACPI_FADT_FIXED_RTC is 0). In this case the driver can determine
if the RTC was the reason of the wakeup from the resume callback
by reading the RTC status register.
- The platform has no fixed hardware feature event bits. In this
case a GPE is used to wake the system and the driver clears the
alarm from its handler.
[1] http://www.acpi.info/DOWNLOADS/ACPI_5_Errata%20A.pdf
Signed-off-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index fddde655cbd4..e8f3a212d09a 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -899,6 +899,9 @@ static inline int cmos_poweroff(struct device *dev) | |||
899 | 899 | ||
900 | #ifdef CONFIG_PM_SLEEP | 900 | #ifdef CONFIG_PM_SLEEP |
901 | 901 | ||
902 | static void cmos_check_acpi_rtc_status(struct device *dev, | ||
903 | unsigned char *rtc_control); | ||
904 | |||
902 | static int cmos_resume(struct device *dev) | 905 | static int cmos_resume(struct device *dev) |
903 | { | 906 | { |
904 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 907 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
@@ -938,6 +941,9 @@ static int cmos_resume(struct device *dev) | |||
938 | tmp &= ~RTC_AIE; | 941 | tmp &= ~RTC_AIE; |
939 | hpet_mask_rtc_irq_bit(RTC_AIE); | 942 | hpet_mask_rtc_irq_bit(RTC_AIE); |
940 | } while (mask & RTC_AIE); | 943 | } while (mask & RTC_AIE); |
944 | |||
945 | if (tmp & RTC_AIE) | ||
946 | cmos_check_acpi_rtc_status(dev, &tmp); | ||
941 | } | 947 | } |
942 | spin_unlock_irq(&rtc_lock); | 948 | spin_unlock_irq(&rtc_lock); |
943 | 949 | ||
@@ -975,6 +981,20 @@ static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); | |||
975 | static u32 rtc_handler(void *context) | 981 | static u32 rtc_handler(void *context) |
976 | { | 982 | { |
977 | struct device *dev = context; | 983 | struct device *dev = context; |
984 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | ||
985 | unsigned char rtc_control = 0; | ||
986 | unsigned char rtc_intr; | ||
987 | |||
988 | spin_lock_irq(&rtc_lock); | ||
989 | if (cmos_rtc.suspend_ctrl) | ||
990 | rtc_control = CMOS_READ(RTC_CONTROL); | ||
991 | if (rtc_control & RTC_AIE) { | ||
992 | cmos_rtc.suspend_ctrl &= ~RTC_AIE; | ||
993 | CMOS_WRITE(rtc_control, RTC_CONTROL); | ||
994 | rtc_intr = CMOS_READ(RTC_INTR_FLAGS); | ||
995 | rtc_update_irq(cmos->rtc, 1, rtc_intr); | ||
996 | } | ||
997 | spin_unlock_irq(&rtc_lock); | ||
978 | 998 | ||
979 | pm_wakeup_event(dev, 0); | 999 | pm_wakeup_event(dev, 0); |
980 | acpi_clear_event(ACPI_EVENT_RTC); | 1000 | acpi_clear_event(ACPI_EVENT_RTC); |
@@ -1041,12 +1061,39 @@ static void cmos_wake_setup(struct device *dev) | |||
1041 | device_init_wakeup(dev, 1); | 1061 | device_init_wakeup(dev, 1); |
1042 | } | 1062 | } |
1043 | 1063 | ||
1064 | static void cmos_check_acpi_rtc_status(struct device *dev, | ||
1065 | unsigned char *rtc_control) | ||
1066 | { | ||
1067 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | ||
1068 | acpi_event_status rtc_status; | ||
1069 | acpi_status status; | ||
1070 | |||
1071 | if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC) | ||
1072 | return; | ||
1073 | |||
1074 | status = acpi_get_event_status(ACPI_EVENT_RTC, &rtc_status); | ||
1075 | if (ACPI_FAILURE(status)) { | ||
1076 | dev_err(dev, "Could not get RTC status\n"); | ||
1077 | } else if (rtc_status & ACPI_EVENT_FLAG_SET) { | ||
1078 | unsigned char mask; | ||
1079 | *rtc_control &= ~RTC_AIE; | ||
1080 | CMOS_WRITE(*rtc_control, RTC_CONTROL); | ||
1081 | mask = CMOS_READ(RTC_INTR_FLAGS); | ||
1082 | rtc_update_irq(cmos->rtc, 1, mask); | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1044 | #else | 1086 | #else |
1045 | 1087 | ||
1046 | static void cmos_wake_setup(struct device *dev) | 1088 | static void cmos_wake_setup(struct device *dev) |
1047 | { | 1089 | { |
1048 | } | 1090 | } |
1049 | 1091 | ||
1092 | static void cmos_check_acpi_rtc_status(struct device *dev, | ||
1093 | unsigned char *rtc_control) | ||
1094 | { | ||
1095 | } | ||
1096 | |||
1050 | #endif | 1097 | #endif |
1051 | 1098 | ||
1052 | #ifdef CONFIG_PNP | 1099 | #ifdef CONFIG_PNP |