rtc: rtc-sh: Zero out tm value for invalid rtc states.
[safe/jmp/linux-2.6] / drivers / rtc / rtc-sh.c
index 6abf481..8e8c8b8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SuperH On-Chip RTC Support
  *
- * Copyright (C) 2006  Paul Mundt
+ * Copyright (C) 2006, 2007  Paul Mundt
  * Copyright (C) 2006  Jamie Lenehan
  *
  * Based on the old arch/sh/kernel/cpu/rtc.c by:
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/io.h>
+#include <asm/rtc.h>
 
 #define DRV_NAME       "sh-rtc"
-#define DRV_VERSION    "0.1.2"
+#define DRV_VERSION    "0.1.3"
 
 #ifdef CONFIG_CPU_SH3
 #define rtc_reg_size           sizeof(u16)
 #define RTC_BIT_INVERTED       0       /* No bug on SH7708, SH7709A */
+#define RTC_DEF_CAPABILITIES   0UL
 #elif defined(CONFIG_CPU_SH4)
 #define rtc_reg_size           sizeof(u32)
 #define RTC_BIT_INVERTED       0x40    /* bug on SH7750, SH7750S */
+#define RTC_DEF_CAPABILITIES   RTC_CAP_4_DIGIT_YEAR
 #endif
 
 #define RTC_REG(r)     ((r) * rtc_reg_size)
@@ -80,6 +83,7 @@ struct sh_rtc {
        struct rtc_device *rtc_dev;
        spinlock_t lock;
        int rearm_aie;
+       unsigned long capabilities;     /* See asm-sh/rtc.h for cap bits */
 };
 
 static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
@@ -104,7 +108,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
 
        writeb(tmp, rtc->regbase + RCR1);
 
-       rtc_update_irq(&rtc->rtc_dev, 1, events);
+       rtc_update_irq(rtc->rtc_dev, 1, events);
 
        spin_unlock(&rtc->lock);
 
@@ -139,7 +143,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
 
                rtc->rearm_aie = 1;
 
-               rtc_update_irq(&rtc->rtc_dev, 1, events);
+               rtc_update_irq(rtc->rtc_dev, 1, events);
        }
 
        spin_unlock(&rtc->lock);
@@ -153,7 +157,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
 
        spin_lock(&rtc->lock);
 
-       rtc_update_irq(&rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
+       rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
 
        spin_unlock(&rtc->lock);
 
@@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_mday     = BCD2BIN(readb(rtc->regbase + RDAYCNT));
                tm->tm_mon      = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
 
-#if defined(CONFIG_CPU_SH4)
-               yr  = readw(rtc->regbase + RYRCNT);
-               yr100 = BCD2BIN(yr >> 8);
-               yr &= 0xff;
-#else
-               yr  = readb(rtc->regbase + RYRCNT);
-               yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
-#endif
+               if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+                       yr  = readw(rtc->regbase + RYRCNT);
+                       yr100 = BCD2BIN(yr >> 8);
+                       yr &= 0xff;
+               } else {
+                       yr  = readb(rtc->regbase + RYRCNT);
+                       yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+               }
 
                tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
 
@@ -341,14 +345,16 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
                tm->tm_sec--;
 #endif
 
-       dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
                "mday=%d, mon=%d, year=%d, wday=%d\n",
                __FUNCTION__,
                tm->tm_sec, tm->tm_min, tm->tm_hour,
                tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
 
-       if (rtc_valid_tm(tm) < 0)
+       if (rtc_valid_tm(tm) < 0) {
                dev_err(dev, "invalid date\n");
+               rtc_time_to_tm(0, tm);
+       }
 
        return 0;
 }
@@ -365,6 +371,7 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
        /* Reset pre-scaler & stop RTC */
        tmp = readb(rtc->regbase + RCR2);
        tmp |= RCR2_RESET;
+       tmp &= ~RCR2_START;
        writeb(tmp, rtc->regbase + RCR2);
 
        writeb(BIN2BCD(tm->tm_sec),  rtc->regbase + RSECCNT);
@@ -374,14 +381,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
        writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
        writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
 
-#ifdef CONFIG_CPU_SH3
-       year = tm->tm_year % 100;
-       writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
-#else
-       year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
-               BIN2BCD(tm->tm_year % 100);
-       writew(year, rtc->regbase + RYRCNT);
-#endif
+       if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+               year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+                       BIN2BCD(tm->tm_year % 100);
+               writew(year, rtc->regbase + RYRCNT);
+       } else {
+               year = tm->tm_year % 100;
+               writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+       }
 
        /* Start RTC */
        tmp = readb(rtc->regbase + RCR2);
@@ -583,11 +590,22 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
 
        rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
                                           &sh_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
+       if (IS_ERR(rtc->rtc_dev)) {
                ret = PTR_ERR(rtc->rtc_dev);
                goto err_badmap;
        }
 
+       rtc->capabilities = RTC_DEF_CAPABILITIES;
+       if (pdev->dev.platform_data) {
+               struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data;
+
+               /*
+                * Some CPUs have special capabilities in addition to the
+                * default set. Add those in here.
+                */
+               rtc->capabilities |= pinfo->capabilities;
+       }
+
        platform_set_drvdata(pdev, rtc);
 
        return 0;