rtc: add support for Epson RTC-9701JE V2
[linux-2.6.git] / drivers / rtc / rtc-sa1100.c
index 9c8ead4..2eb3852 100644 (file)
@@ -29,8 +29,8 @@
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/pm.h>
+#include <linux/bitops.h>
 
-#include <asm/bitops.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/rtc.h>
@@ -93,7 +93,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
        if (rtsr & RTSR_HZ)
                events |= RTC_UF | RTC_IRQF;
 
-       rtc_update_irq(&rtc->class_dev, 1, events);
+       rtc_update_irq(rtc, 1, events);
 
        if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
                rtc_update_alarm(&rtc_alarm);
@@ -119,7 +119,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
         */
        OSSR = OSSR_M1; /* clear match on timer1 */
 
-       rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
+       rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
 
        if (rtc_timer1_count == 1)
                rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
@@ -263,8 +263,12 @@ static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
 static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+       u32     rtsr;
+
        memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
-       alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+       rtsr = RTSR;
+       alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
+       alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
        return 0;
 }
 
@@ -275,12 +279,10 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        spin_lock_irq(&sa1100_rtc_lock);
        ret = rtc_update_alarm(&alrm->time);
        if (ret == 0) {
-               memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
-
                if (alrm->enabled)
-                       enable_irq_wake(IRQ_RTCAlrm);
+                       RTSR |= RTSR_ALE;
                else
-                       disable_irq_wake(IRQ_RTCAlrm);
+                       RTSR &= ~RTSR_ALE;
        }
        spin_unlock_irq(&sa1100_rtc_lock);
 
@@ -335,6 +337,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
+       device_init_wakeup(&pdev->dev, 1);
+
        platform_set_drvdata(pdev, rtc);
 
        return 0;
@@ -350,9 +354,38 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       if (pdev->dev.power.power_state.event != state.event) {
+               if (state.event == PM_EVENT_SUSPEND &&
+                   device_may_wakeup(&pdev->dev))
+                       enable_irq_wake(IRQ_RTCAlrm);
+
+               pdev->dev.power.power_state = state;
+       }
+       return 0;
+}
+
+static int sa1100_rtc_resume(struct platform_device *pdev)
+{
+       if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
+               if (device_may_wakeup(&pdev->dev))
+                       disable_irq_wake(IRQ_RTCAlrm);
+               pdev->dev.power.power_state = PMSG_ON;
+       }
+       return 0;
+}
+#else
+#define sa1100_rtc_suspend     NULL
+#define sa1100_rtc_resume      NULL
+#endif
+
 static struct platform_driver sa1100_rtc_driver = {
        .probe          = sa1100_rtc_probe,
        .remove         = sa1100_rtc_remove,
+       .suspend        = sa1100_rtc_suspend,
+       .resume         = sa1100_rtc_resume,
        .driver         = {
                .name           = "sa1100-rtc",
        },