|
@@ -556,17 +556,24 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
|
|
|
rtc_control = CMOS_READ(RTC_CONTROL);
|
|
|
if (is_hpet_enabled())
|
|
|
irqstat = (unsigned long)irq & 0xF0;
|
|
|
- irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
|
|
|
+
|
|
|
+ /* If we were suspended, RTC_CONTROL may not be accurate since the
|
|
|
+ * bios may have cleared it.
|
|
|
+ */
|
|
|
+ if (!cmos_rtc.suspend_ctrl)
|
|
|
+ irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
|
|
|
+ else
|
|
|
+ irqstat &= (cmos_rtc.suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
|
|
|
|
|
|
/* All Linux RTC alarms should be treated as if they were oneshot.
|
|
|
* Similar code may be needed in system wakeup paths, in case the
|
|
|
* alarm woke the system.
|
|
|
*/
|
|
|
if (irqstat & RTC_AIE) {
|
|
|
+ cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
|
|
rtc_control &= ~RTC_AIE;
|
|
|
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
|
|
hpet_mask_rtc_irq_bit(RTC_AIE);
|
|
|
-
|
|
|
CMOS_READ(RTC_INTR_FLAGS);
|
|
|
}
|
|
|
spin_unlock(&rtc_lock);
|
|
@@ -839,21 +846,23 @@ static inline int cmos_poweroff(struct device *dev)
|
|
|
static int cmos_resume(struct device *dev)
|
|
|
{
|
|
|
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
|
|
- unsigned char tmp = cmos->suspend_ctrl;
|
|
|
+ unsigned char tmp;
|
|
|
+
|
|
|
+ if (cmos->enabled_wake) {
|
|
|
+ if (cmos->wake_off)
|
|
|
+ cmos->wake_off(dev);
|
|
|
+ else
|
|
|
+ disable_irq_wake(cmos->irq);
|
|
|
+ cmos->enabled_wake = 0;
|
|
|
+ }
|
|
|
|
|
|
+ spin_lock_irq(&rtc_lock);
|
|
|
+ tmp = cmos->suspend_ctrl;
|
|
|
+ cmos->suspend_ctrl = 0;
|
|
|
/* re-enable any irqs previously active */
|
|
|
if (tmp & RTC_IRQMASK) {
|
|
|
unsigned char mask;
|
|
|
|
|
|
- if (cmos->enabled_wake) {
|
|
|
- if (cmos->wake_off)
|
|
|
- cmos->wake_off(dev);
|
|
|
- else
|
|
|
- disable_irq_wake(cmos->irq);
|
|
|
- cmos->enabled_wake = 0;
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock_irq(&rtc_lock);
|
|
|
if (device_may_wakeup(dev))
|
|
|
hpet_rtc_timer_init();
|
|
|
|
|
@@ -873,8 +882,8 @@ static int cmos_resume(struct device *dev)
|
|
|
tmp &= ~RTC_AIE;
|
|
|
hpet_mask_rtc_irq_bit(RTC_AIE);
|
|
|
} while (mask & RTC_AIE);
|
|
|
- spin_unlock_irq(&rtc_lock);
|
|
|
}
|
|
|
+ spin_unlock_irq(&rtc_lock);
|
|
|
|
|
|
dev_dbg(dev, "resume, ctrl %02x\n", tmp);
|
|
|
|