Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[firefly-linux-kernel-4.4.55.git] / drivers / rtc / rtc-cmos.c
index a6727d9773305fca6c8e5db196de7a42539b47e0..be06d7150de5d4b81f6c84e9c5cc874e26360e70 100644 (file)
@@ -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);