]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91rm9200.c: use a variable for storing IMR
[karo-tx-linux.git] / drivers / rtc / rtc-at91rm9200.c
index 434ebc3a99dc089d10a6d27e5be99faebb28aace..0a9f27e094ea9ea122ec0658c673a3249eb6e04e 100644 (file)
@@ -44,6 +44,7 @@ static DECLARE_COMPLETION(at91_rtc_updated);
 static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
 static void __iomem *at91_rtc_regs;
 static int irq;
+static u32 at91_rtc_imr;
 
 /*
  * Decode time/date into rtc_time structure
@@ -108,9 +109,11 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
        cr = at91_rtc_read(AT91_RTC_CR);
        at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
 
+       at91_rtc_imr |= AT91_RTC_ACKUPD;
        at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
        wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+       at91_rtc_imr &= ~AT91_RTC_ACKUPD;
 
        at91_rtc_write(AT91_RTC_TIMR,
                          bin2bcd(tm->tm_sec) << 0
@@ -142,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
        tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
        tm->tm_year = at91_alarm_year - 1900;
 
-       alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
+       alrm->enabled = (at91_rtc_imr & AT91_RTC_ALARM)
                        ? 1 : 0;
 
        dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
@@ -168,6 +171,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        tm.tm_sec = alrm->time.tm_sec;
 
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+       at91_rtc_imr &= ~AT91_RTC_ALARM;
        at91_rtc_write(AT91_RTC_TIMALR,
                  bin2bcd(tm.tm_sec) << 0
                | bin2bcd(tm.tm_min) << 8
@@ -180,6 +184,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        if (alrm->enabled) {
                at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
+               at91_rtc_imr |= AT91_RTC_ALARM;
                at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
        }
 
@@ -196,9 +201,12 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        if (enabled) {
                at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
+               at91_rtc_imr |= AT91_RTC_ALARM;
                at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
-       } else
+       } else {
                at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+               at91_rtc_imr &= ~AT91_RTC_ALARM;
+       }
 
        return 0;
 }
@@ -207,12 +215,10 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  */
 static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
 {
-       unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
-
        seq_printf(seq, "update_IRQ\t: %s\n",
-                       (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+                       (at91_rtc_imr & AT91_RTC_ACKUPD) ? "yes" : "no");
        seq_printf(seq, "periodic_IRQ\t: %s\n",
-                       (imr & AT91_RTC_SECEV) ? "yes" : "no");
+                       (at91_rtc_imr & AT91_RTC_SECEV) ? "yes" : "no");
 
        return 0;
 }
@@ -227,7 +233,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
        unsigned int rtsr;
        unsigned long events = 0;
 
-       rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
+       rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_imr;
        if (rtsr) {             /* this interrupt is shared!  Is it ours? */
                if (rtsr & AT91_RTC_ALARM)
                        events |= (RTC_AF | RTC_IRQF);
@@ -291,6 +297,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
                                        AT91_RTC_SECEV | AT91_RTC_TIMEV |
                                        AT91_RTC_CALEV);
+       at91_rtc_imr = 0;
 
        ret = request_irq(irq, at91_rtc_interrupt,
                                IRQF_SHARED,
@@ -329,6 +336,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
                                        AT91_RTC_SECEV | AT91_RTC_TIMEV |
                                        AT91_RTC_CALEV);
+       at91_rtc_imr = 0;
        free_irq(irq, pdev);
 
        rtc_device_unregister(rtc);
@@ -341,31 +349,35 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
 
 /* AT91RM9200 RTC Power management control */
 
-static u32 at91_rtc_imr;
+static u32 at91_rtc_bkpimr;
+
 
 static int at91_rtc_suspend(struct device *dev)
 {
        /* this IRQ is shared with DBGU and other hardware which isn't
         * necessarily doing PM like we are...
         */
-       at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
-                       & (AT91_RTC_ALARM|AT91_RTC_SECEV);
-       if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+       at91_rtc_bkpimr = at91_rtc_imr & (AT91_RTC_ALARM|AT91_RTC_SECEV);
+       if (at91_rtc_bkpimr) {
+               if (device_may_wakeup(dev)) {
                        enable_irq_wake(irq);
-               else
-                       at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
-       }
+               } else {
+                       at91_rtc_write(AT91_RTC_IDR, at91_rtc_bkpimr);
+                       at91_rtc_imr &= ~at91_rtc_bkpimr;
+               }
+}
        return 0;
 }
 
 static int at91_rtc_resume(struct device *dev)
 {
-       if (at91_rtc_imr) {
-               if (device_may_wakeup(dev))
+       if (at91_rtc_bkpimr) {
+               if (device_may_wakeup(dev)) {
                        disable_irq_wake(irq);
-               else
-                       at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
+               } else {
+                       at91_rtc_imr |= at91_rtc_bkpimr;
+                       at91_rtc_write(AT91_RTC_IER, at91_rtc_bkpimr);
+               }
        }
        return 0;
 }