/*
* 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)
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)
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);
rtc->rearm_aie = 1;
- rtc_update_irq(&rtc->rtc_dev, 1, events);
+ rtc_update_irq(rtc->rtc_dev, 1, events);
}
spin_unlock(&rtc->lock);
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);
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;
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;
}
/* 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);
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);
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;