diff options
Diffstat (limited to 'drivers/rtc/rtc-s3c.c')
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 106 |
1 files changed, 65 insertions, 41 deletions
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e57d3ca70a78..db529733c9c4 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -127,10 +127,9 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) return ret; } -/* Time read/write */ -static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +/* Read time from RTC and convert it from BCD */ +static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm) { - struct s3c_rtc *info = dev_get_drvdata(dev); unsigned int have_retried = 0; int ret; @@ -139,54 +138,40 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) return ret; retry_get_time: - rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); - rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); - rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE); - rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON); - rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR); - rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC); - - /* the only way to work out whether the system was mid-update + tm->tm_min = readb(info->base + S3C2410_RTCMIN); + tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); + tm->tm_mday = readb(info->base + S3C2410_RTCDATE); + tm->tm_mon = readb(info->base + S3C2410_RTCMON); + tm->tm_year = readb(info->base + S3C2410_RTCYEAR); + tm->tm_sec = readb(info->base + S3C2410_RTCSEC); + + /* + * The only way to work out whether the system was mid-update * when we read it is to check the second counter, and if it * is zero, then we re-try the entire read */ - - if (rtc_tm->tm_sec == 0 && !have_retried) { + if (tm->tm_sec == 0 && !have_retried) { have_retried = 1; goto retry_get_time; } - rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); - rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); - rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); - rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); - rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); - rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); - s3c_rtc_disable_clk(info); - rtc_tm->tm_year += 100; - rtc_tm->tm_mon -= 1; + tm->tm_sec = bcd2bin(tm->tm_sec); + tm->tm_min = bcd2bin(tm->tm_min); + tm->tm_hour = bcd2bin(tm->tm_hour); + tm->tm_mday = bcd2bin(tm->tm_mday); + tm->tm_mon = bcd2bin(tm->tm_mon); + tm->tm_year = bcd2bin(tm->tm_year); - dev_dbg(dev, "read time %ptR\n", rtc_tm); return 0; } -static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) +/* Convert time to BCD and write it to RTC */ +static int s3c_rtc_write_time(struct s3c_rtc *info, const struct rtc_time *tm) { - struct s3c_rtc *info = dev_get_drvdata(dev); - int year = tm->tm_year - 100; int ret; - dev_dbg(dev, "set time %ptR\n", tm); - - /* we get around y2k by simply not supporting it */ - - if (year < 0 || year >= 100) { - dev_err(dev, "rtc only supports 100 years\n"); - return -EINVAL; - } - ret = s3c_rtc_enable_clk(info); if (ret) return ret; @@ -195,14 +180,48 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR); writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE); - writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON); - writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); + writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON); + writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR); s3c_rtc_disable_clk(info); return 0; } +static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm) +{ + struct s3c_rtc *info = dev_get_drvdata(dev); + int ret; + + ret = s3c_rtc_read_time(info, tm); + if (ret) + return ret; + + /* Convert internal representation to actual date/time */ + tm->tm_year += 100; + tm->tm_mon -= 1; + + dev_dbg(dev, "read time %ptR\n", tm); + return 0; +} + +static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct s3c_rtc *info = dev_get_drvdata(dev); + struct rtc_time rtc_tm = *tm; + + dev_dbg(dev, "set time %ptR\n", tm); + + /* + * Convert actual date/time to internal representation. + * We get around Y2K by simply not supporting it. + */ + rtc_tm.tm_year -= 100; + rtc_tm.tm_mon += 1; + + return s3c_rtc_write_time(info, &rtc_tm); +} + static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct s3c_rtc *info = dev_get_drvdata(dev); @@ -447,15 +466,20 @@ static int s3c_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - /* register RTC and exit */ - info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, - THIS_MODULE); + info->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(info->rtc)) { - dev_err(&pdev->dev, "cannot attach rtc\n"); ret = PTR_ERR(info->rtc); goto err_nortc; } + info->rtc->ops = &s3c_rtcops; + info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + info->rtc->range_max = RTC_TIMESTAMP_END_2099; + + ret = devm_rtc_register_device(info->rtc); + if (ret) + goto err_nortc; + ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq, 0, "s3c2410-rtc alarm", info); if (ret) { |