diff options
Diffstat (limited to 'drivers/rtc/rtc-s3c.c')
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 139 |
1 files changed, 97 insertions, 42 deletions
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 70b68d35f969..cf953ecbfca9 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -1,5 +1,8 @@ /* drivers/rtc/rtc-s3c.c * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * * Copyright (c) 2004,2006 Simtec Electronics * Ben Dooks, <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ @@ -39,6 +42,7 @@ enum s3c_cpu_type { static struct resource *s3c_rtc_mem; +static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; @@ -53,6 +57,10 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) struct rtc_device *rdev = id; rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); + + if (s3c_rtc_cpu_type == TYPE_S3C64XX) + writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); + return IRQ_HANDLED; } @@ -61,6 +69,10 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) struct rtc_device *rdev = id; rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); + + if (s3c_rtc_cpu_type == TYPE_S3C64XX) + writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); + return IRQ_HANDLED; } @@ -88,13 +100,13 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) spin_lock_irq(&s3c_rtc_pie_lock); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); tmp &= ~S3C64XX_RTCCON_TICEN; if (enabled) tmp |= S3C64XX_RTCCON_TICEN; - writeb(tmp, s3c_rtc_base + S3C2410_RTCCON); + writew(tmp, s3c_rtc_base + S3C2410_RTCCON); } else { tmp = readb(s3c_rtc_base + S3C2410_TICNT); tmp &= ~S3C2410_TICNT_ENABLE; @@ -128,7 +140,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) tmp |= (rtc_dev->max_user_freq / freq)-1; - writeb(tmp, s3c_rtc_base + S3C2410_TICNT); + writel(tmp, s3c_rtc_base + S3C2410_TICNT); spin_unlock_irq(&s3c_rtc_pie_lock); return 0; @@ -159,8 +171,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) goto retry_get_time; } - pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", - rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, + pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); @@ -173,7 +185,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) rtc_tm->tm_year += 100; rtc_tm->tm_mon -= 1; - return 0; + return rtc_valid_tm(rtc_tm); } static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) @@ -181,8 +193,8 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = s3c_rtc_base; int year = tm->tm_year - 100; - pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, + pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* we get around y2k by simply not supporting it */ @@ -219,9 +231,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; - pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", + pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", alm_en, - alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, + 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -230,34 +242,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alm_en & S3C2410_RTCALM_SECEN) alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); else - alm_tm->tm_sec = 0xff; + alm_tm->tm_sec = -1; if (alm_en & S3C2410_RTCALM_MINEN) alm_tm->tm_min = bcd2bin(alm_tm->tm_min); else - alm_tm->tm_min = 0xff; + alm_tm->tm_min = -1; if (alm_en & S3C2410_RTCALM_HOUREN) alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); else - alm_tm->tm_hour = 0xff; + alm_tm->tm_hour = -1; if (alm_en & S3C2410_RTCALM_DAYEN) alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); else - alm_tm->tm_mday = 0xff; + alm_tm->tm_mday = -1; if (alm_en & S3C2410_RTCALM_MONEN) { alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); alm_tm->tm_mon -= 1; } else { - alm_tm->tm_mon = 0xff; + alm_tm->tm_mon = -1; } if (alm_en & S3C2410_RTCALM_YEAREN) alm_tm->tm_year = bcd2bin(alm_tm->tm_year); else - alm_tm->tm_year = 0xffff; + alm_tm->tm_year = -1; return 0; } @@ -268,10 +280,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) void __iomem *base = s3c_rtc_base; unsigned int alrm_en; - pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", + pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, - tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, - tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; @@ -298,11 +310,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) s3c_rtc_setaie(alrm->enabled); - if (alrm->enabled) - enable_irq_wake(s3c_rtc_alarmno); - else - disable_irq_wake(s3c_rtc_alarmno); - return 0; } @@ -311,7 +318,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) unsigned int ticnt; if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt &= S3C64XX_RTCCON_TICEN; } else { ticnt = readb(s3c_rtc_base + S3C2410_TICNT); @@ -372,7 +379,8 @@ static const struct rtc_class_ops s3c_rtcops = { .set_alarm = s3c_rtc_setalarm, .irq_set_freq = s3c_rtc_setfreq, .irq_set_state = s3c_rtc_setpie, - .proc = s3c_rtc_proc, + .proc = s3c_rtc_proc, + .alarm_irq_enable = s3c_rtc_setaie, }; static void s3c_rtc_enable(struct platform_device *pdev, int en) @@ -384,11 +392,11 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) return; if (!en) { - tmp = readb(base + S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C64XX) tmp &= ~S3C64XX_RTCCON_TICEN; tmp &= ~S3C2410_RTCCON_RTCEN; - writeb(tmp, base + S3C2410_RTCCON); + writew(tmp, base + S3C2410_RTCCON); if (s3c_rtc_cpu_type == TYPE_S3C2410) { tmp = readb(base + S3C2410_TICNT); @@ -398,25 +406,28 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) } else { /* re-enable the device, and check it is ok */ - if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ + if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) { dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp | S3C2410_RTCCON_RTCEN, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) { dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CNTSEL, + base + S3C2410_RTCCON); } - if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ + if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) { dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); - tmp = readb(base + S3C2410_RTCCON); - writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); + tmp = readw(base + S3C2410_RTCCON); + writew(tmp & ~S3C2410_RTCCON_CLKRST, + base + S3C2410_RTCCON); } } } @@ -431,6 +442,10 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) s3c_rtc_setpie(&dev->dev, 0); s3c_rtc_setaie(0); + clk_disable(rtc_clk); + clk_put(rtc_clk); + rtc_clk = NULL; + iounmap(s3c_rtc_base); release_resource(s3c_rtc_mem); kfree(s3c_rtc_mem); @@ -441,6 +456,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) static int __devinit s3c_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; + struct rtc_time rtc_tm; struct resource *res; int ret; @@ -488,12 +504,22 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) goto err_nomap; } + rtc_clk = clk_get(&pdev->dev, "rtc"); + if (IS_ERR(rtc_clk)) { + dev_err(&pdev->dev, "failed to find rtc clock source\n"); + ret = PTR_ERR(rtc_clk); + rtc_clk = NULL; + goto err_clk; + } + + clk_enable(rtc_clk); + /* check to see if everything is setup correctly */ s3c_rtc_enable(pdev, 1); - pr_debug("s3c2410_rtc: RTCCON=%02x\n", - readb(s3c_rtc_base + S3C2410_RTCCON)); + pr_debug("s3c2410_rtc: RTCCON=%02x\n", + readw(s3c_rtc_base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, 1); @@ -510,6 +536,23 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; + /* Check RTC Time */ + + s3c_rtc_gettime(NULL, &rtc_tm); + + if (rtc_valid_tm(&rtc_tm)) { + rtc_tm.tm_year = 100; + rtc_tm.tm_mon = 0; + rtc_tm.tm_mday = 1; + rtc_tm.tm_hour = 0; + rtc_tm.tm_min = 0; + rtc_tm.tm_sec = 0; + + s3c_rtc_settime(NULL, &rtc_tm); + + dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); + } + if (s3c_rtc_cpu_type == TYPE_S3C64XX) rtc->max_user_freq = 32768; else @@ -523,6 +566,10 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) err_nortc: s3c_rtc_enable(pdev, 0); + clk_disable(rtc_clk); + clk_put(rtc_clk); + + err_clk: iounmap(s3c_rtc_base); err_nomap: @@ -543,10 +590,14 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) /* save TICNT for anyone using periodic interrupts */ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { - ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); + ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt_en_save &= S3C64XX_RTCCON_TICEN; } s3c_rtc_enable(pdev, 0); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(s3c_rtc_alarmno); + return 0; } @@ -557,9 +608,13 @@ static int s3c_rtc_resume(struct platform_device *pdev) s3c_rtc_enable(pdev, 1); writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { - tmp = readb(s3c_rtc_base + S3C2410_RTCCON); - writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(s3c_rtc_alarmno); + return 0; } #else |