aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-s3c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-s3c.c')
-rw-r--r--drivers/rtc/rtc-s3c.c139
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 @@
1/* drivers/rtc/rtc-s3c.c 1/* drivers/rtc/rtc-s3c.c
2 * 2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
3 * Copyright (c) 2004,2006 Simtec Electronics 6 * Copyright (c) 2004,2006 Simtec Electronics
4 * Ben Dooks, <ben@simtec.co.uk> 7 * Ben Dooks, <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/ 8 * http://armlinux.simtec.co.uk/
@@ -39,6 +42,7 @@ enum s3c_cpu_type {
39 42
40static struct resource *s3c_rtc_mem; 43static struct resource *s3c_rtc_mem;
41 44
45static struct clk *rtc_clk;
42static void __iomem *s3c_rtc_base; 46static void __iomem *s3c_rtc_base;
43static int s3c_rtc_alarmno = NO_IRQ; 47static int s3c_rtc_alarmno = NO_IRQ;
44static int s3c_rtc_tickno = NO_IRQ; 48static int s3c_rtc_tickno = NO_IRQ;
@@ -53,6 +57,10 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
53 struct rtc_device *rdev = id; 57 struct rtc_device *rdev = id;
54 58
55 rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); 59 rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
60
61 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
62 writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP);
63
56 return IRQ_HANDLED; 64 return IRQ_HANDLED;
57} 65}
58 66
@@ -61,6 +69,10 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
61 struct rtc_device *rdev = id; 69 struct rtc_device *rdev = id;
62 70
63 rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); 71 rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
72
73 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
74 writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP);
75
64 return IRQ_HANDLED; 76 return IRQ_HANDLED;
65} 77}
66 78
@@ -88,13 +100,13 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
88 spin_lock_irq(&s3c_rtc_pie_lock); 100 spin_lock_irq(&s3c_rtc_pie_lock);
89 101
90 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 102 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
91 tmp = readb(s3c_rtc_base + S3C2410_RTCCON); 103 tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
92 tmp &= ~S3C64XX_RTCCON_TICEN; 104 tmp &= ~S3C64XX_RTCCON_TICEN;
93 105
94 if (enabled) 106 if (enabled)
95 tmp |= S3C64XX_RTCCON_TICEN; 107 tmp |= S3C64XX_RTCCON_TICEN;
96 108
97 writeb(tmp, s3c_rtc_base + S3C2410_RTCCON); 109 writew(tmp, s3c_rtc_base + S3C2410_RTCCON);
98 } else { 110 } else {
99 tmp = readb(s3c_rtc_base + S3C2410_TICNT); 111 tmp = readb(s3c_rtc_base + S3C2410_TICNT);
100 tmp &= ~S3C2410_TICNT_ENABLE; 112 tmp &= ~S3C2410_TICNT_ENABLE;
@@ -128,7 +140,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq)
128 140
129 tmp |= (rtc_dev->max_user_freq / freq)-1; 141 tmp |= (rtc_dev->max_user_freq / freq)-1;
130 142
131 writeb(tmp, s3c_rtc_base + S3C2410_TICNT); 143 writel(tmp, s3c_rtc_base + S3C2410_TICNT);
132 spin_unlock_irq(&s3c_rtc_pie_lock); 144 spin_unlock_irq(&s3c_rtc_pie_lock);
133 145
134 return 0; 146 return 0;
@@ -159,8 +171,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
159 goto retry_get_time; 171 goto retry_get_time;
160 } 172 }
161 173
162 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", 174 pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
163 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, 175 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
164 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); 176 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
165 177
166 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); 178 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)
173 rtc_tm->tm_year += 100; 185 rtc_tm->tm_year += 100;
174 rtc_tm->tm_mon -= 1; 186 rtc_tm->tm_mon -= 1;
175 187
176 return 0; 188 return rtc_valid_tm(rtc_tm);
177} 189}
178 190
179static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) 191static 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)
181 void __iomem *base = s3c_rtc_base; 193 void __iomem *base = s3c_rtc_base;
182 int year = tm->tm_year - 100; 194 int year = tm->tm_year - 100;
183 195
184 pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", 196 pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
185 tm->tm_year, tm->tm_mon, tm->tm_mday, 197 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
186 tm->tm_hour, tm->tm_min, tm->tm_sec); 198 tm->tm_hour, tm->tm_min, tm->tm_sec);
187 199
188 /* we get around y2k by simply not supporting it */ 200 /* 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)
219 231
220 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; 232 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
221 233
222 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", 234 pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
223 alm_en, 235 alm_en,
224 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, 236 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
225 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); 237 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
226 238
227 239
@@ -230,34 +242,34 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
230 if (alm_en & S3C2410_RTCALM_SECEN) 242 if (alm_en & S3C2410_RTCALM_SECEN)
231 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); 243 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
232 else 244 else
233 alm_tm->tm_sec = 0xff; 245 alm_tm->tm_sec = -1;
234 246
235 if (alm_en & S3C2410_RTCALM_MINEN) 247 if (alm_en & S3C2410_RTCALM_MINEN)
236 alm_tm->tm_min = bcd2bin(alm_tm->tm_min); 248 alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
237 else 249 else
238 alm_tm->tm_min = 0xff; 250 alm_tm->tm_min = -1;
239 251
240 if (alm_en & S3C2410_RTCALM_HOUREN) 252 if (alm_en & S3C2410_RTCALM_HOUREN)
241 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); 253 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
242 else 254 else
243 alm_tm->tm_hour = 0xff; 255 alm_tm->tm_hour = -1;
244 256
245 if (alm_en & S3C2410_RTCALM_DAYEN) 257 if (alm_en & S3C2410_RTCALM_DAYEN)
246 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); 258 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
247 else 259 else
248 alm_tm->tm_mday = 0xff; 260 alm_tm->tm_mday = -1;
249 261
250 if (alm_en & S3C2410_RTCALM_MONEN) { 262 if (alm_en & S3C2410_RTCALM_MONEN) {
251 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); 263 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
252 alm_tm->tm_mon -= 1; 264 alm_tm->tm_mon -= 1;
253 } else { 265 } else {
254 alm_tm->tm_mon = 0xff; 266 alm_tm->tm_mon = -1;
255 } 267 }
256 268
257 if (alm_en & S3C2410_RTCALM_YEAREN) 269 if (alm_en & S3C2410_RTCALM_YEAREN)
258 alm_tm->tm_year = bcd2bin(alm_tm->tm_year); 270 alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
259 else 271 else
260 alm_tm->tm_year = 0xffff; 272 alm_tm->tm_year = -1;
261 273
262 return 0; 274 return 0;
263} 275}
@@ -268,10 +280,10 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
268 void __iomem *base = s3c_rtc_base; 280 void __iomem *base = s3c_rtc_base;
269 unsigned int alrm_en; 281 unsigned int alrm_en;
270 282
271 pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", 283 pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
272 alrm->enabled, 284 alrm->enabled,
273 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, 285 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
274 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); 286 tm->tm_hour, tm->tm_min, tm->tm_sec);
275 287
276 288
277 alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; 289 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)
298 310
299 s3c_rtc_setaie(alrm->enabled); 311 s3c_rtc_setaie(alrm->enabled);
300 312
301 if (alrm->enabled)
302 enable_irq_wake(s3c_rtc_alarmno);
303 else
304 disable_irq_wake(s3c_rtc_alarmno);
305
306 return 0; 313 return 0;
307} 314}
308 315
@@ -311,7 +318,7 @@ static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
311 unsigned int ticnt; 318 unsigned int ticnt;
312 319
313 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 320 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
314 ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); 321 ticnt = readw(s3c_rtc_base + S3C2410_RTCCON);
315 ticnt &= S3C64XX_RTCCON_TICEN; 322 ticnt &= S3C64XX_RTCCON_TICEN;
316 } else { 323 } else {
317 ticnt = readb(s3c_rtc_base + S3C2410_TICNT); 324 ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
@@ -372,7 +379,8 @@ static const struct rtc_class_ops s3c_rtcops = {
372 .set_alarm = s3c_rtc_setalarm, 379 .set_alarm = s3c_rtc_setalarm,
373 .irq_set_freq = s3c_rtc_setfreq, 380 .irq_set_freq = s3c_rtc_setfreq,
374 .irq_set_state = s3c_rtc_setpie, 381 .irq_set_state = s3c_rtc_setpie,
375 .proc = s3c_rtc_proc, 382 .proc = s3c_rtc_proc,
383 .alarm_irq_enable = s3c_rtc_setaie,
376}; 384};
377 385
378static void s3c_rtc_enable(struct platform_device *pdev, int en) 386static 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)
384 return; 392 return;
385 393
386 if (!en) { 394 if (!en) {
387 tmp = readb(base + S3C2410_RTCCON); 395 tmp = readw(base + S3C2410_RTCCON);
388 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 396 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
389 tmp &= ~S3C64XX_RTCCON_TICEN; 397 tmp &= ~S3C64XX_RTCCON_TICEN;
390 tmp &= ~S3C2410_RTCCON_RTCEN; 398 tmp &= ~S3C2410_RTCCON_RTCEN;
391 writeb(tmp, base + S3C2410_RTCCON); 399 writew(tmp, base + S3C2410_RTCCON);
392 400
393 if (s3c_rtc_cpu_type == TYPE_S3C2410) { 401 if (s3c_rtc_cpu_type == TYPE_S3C2410) {
394 tmp = readb(base + S3C2410_TICNT); 402 tmp = readb(base + S3C2410_TICNT);
@@ -398,25 +406,28 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
398 } else { 406 } else {
399 /* re-enable the device, and check it is ok */ 407 /* re-enable the device, and check it is ok */
400 408
401 if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ 409 if ((readw(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0) {
402 dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); 410 dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
403 411
404 tmp = readb(base + S3C2410_RTCCON); 412 tmp = readw(base + S3C2410_RTCCON);
405 writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); 413 writew(tmp | S3C2410_RTCCON_RTCEN,
414 base + S3C2410_RTCCON);
406 } 415 }
407 416
408 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ 417 if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)) {
409 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); 418 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
410 419
411 tmp = readb(base + S3C2410_RTCCON); 420 tmp = readw(base + S3C2410_RTCCON);
412 writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); 421 writew(tmp & ~S3C2410_RTCCON_CNTSEL,
422 base + S3C2410_RTCCON);
413 } 423 }
414 424
415 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ 425 if ((readw(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)) {
416 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); 426 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
417 427
418 tmp = readb(base + S3C2410_RTCCON); 428 tmp = readw(base + S3C2410_RTCCON);
419 writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); 429 writew(tmp & ~S3C2410_RTCCON_CLKRST,
430 base + S3C2410_RTCCON);
420 } 431 }
421 } 432 }
422} 433}
@@ -431,6 +442,10 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
431 s3c_rtc_setpie(&dev->dev, 0); 442 s3c_rtc_setpie(&dev->dev, 0);
432 s3c_rtc_setaie(0); 443 s3c_rtc_setaie(0);
433 444
445 clk_disable(rtc_clk);
446 clk_put(rtc_clk);
447 rtc_clk = NULL;
448
434 iounmap(s3c_rtc_base); 449 iounmap(s3c_rtc_base);
435 release_resource(s3c_rtc_mem); 450 release_resource(s3c_rtc_mem);
436 kfree(s3c_rtc_mem); 451 kfree(s3c_rtc_mem);
@@ -441,6 +456,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
441static int __devinit s3c_rtc_probe(struct platform_device *pdev) 456static int __devinit s3c_rtc_probe(struct platform_device *pdev)
442{ 457{
443 struct rtc_device *rtc; 458 struct rtc_device *rtc;
459 struct rtc_time rtc_tm;
444 struct resource *res; 460 struct resource *res;
445 int ret; 461 int ret;
446 462
@@ -488,12 +504,22 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
488 goto err_nomap; 504 goto err_nomap;
489 } 505 }
490 506
507 rtc_clk = clk_get(&pdev->dev, "rtc");
508 if (IS_ERR(rtc_clk)) {
509 dev_err(&pdev->dev, "failed to find rtc clock source\n");
510 ret = PTR_ERR(rtc_clk);
511 rtc_clk = NULL;
512 goto err_clk;
513 }
514
515 clk_enable(rtc_clk);
516
491 /* check to see if everything is setup correctly */ 517 /* check to see if everything is setup correctly */
492 518
493 s3c_rtc_enable(pdev, 1); 519 s3c_rtc_enable(pdev, 1);
494 520
495 pr_debug("s3c2410_rtc: RTCCON=%02x\n", 521 pr_debug("s3c2410_rtc: RTCCON=%02x\n",
496 readb(s3c_rtc_base + S3C2410_RTCCON)); 522 readw(s3c_rtc_base + S3C2410_RTCCON));
497 523
498 device_init_wakeup(&pdev->dev, 1); 524 device_init_wakeup(&pdev->dev, 1);
499 525
@@ -510,6 +536,23 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
510 536
511 s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; 537 s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
512 538
539 /* Check RTC Time */
540
541 s3c_rtc_gettime(NULL, &rtc_tm);
542
543 if (rtc_valid_tm(&rtc_tm)) {
544 rtc_tm.tm_year = 100;
545 rtc_tm.tm_mon = 0;
546 rtc_tm.tm_mday = 1;
547 rtc_tm.tm_hour = 0;
548 rtc_tm.tm_min = 0;
549 rtc_tm.tm_sec = 0;
550
551 s3c_rtc_settime(NULL, &rtc_tm);
552
553 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
554 }
555
513 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 556 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
514 rtc->max_user_freq = 32768; 557 rtc->max_user_freq = 32768;
515 else 558 else
@@ -523,6 +566,10 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
523 566
524 err_nortc: 567 err_nortc:
525 s3c_rtc_enable(pdev, 0); 568 s3c_rtc_enable(pdev, 0);
569 clk_disable(rtc_clk);
570 clk_put(rtc_clk);
571
572 err_clk:
526 iounmap(s3c_rtc_base); 573 iounmap(s3c_rtc_base);
527 574
528 err_nomap: 575 err_nomap:
@@ -543,10 +590,14 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
543 /* save TICNT for anyone using periodic interrupts */ 590 /* save TICNT for anyone using periodic interrupts */
544 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); 591 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
545 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 592 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
546 ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); 593 ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
547 ticnt_en_save &= S3C64XX_RTCCON_TICEN; 594 ticnt_en_save &= S3C64XX_RTCCON_TICEN;
548 } 595 }
549 s3c_rtc_enable(pdev, 0); 596 s3c_rtc_enable(pdev, 0);
597
598 if (device_may_wakeup(&pdev->dev))
599 enable_irq_wake(s3c_rtc_alarmno);
600
550 return 0; 601 return 0;
551} 602}
552 603
@@ -557,9 +608,13 @@ static int s3c_rtc_resume(struct platform_device *pdev)
557 s3c_rtc_enable(pdev, 1); 608 s3c_rtc_enable(pdev, 1);
558 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); 609 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
559 if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { 610 if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
560 tmp = readb(s3c_rtc_base + S3C2410_RTCCON); 611 tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
561 writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); 612 writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
562 } 613 }
614
615 if (device_may_wakeup(&pdev->dev))
616 disable_irq_wake(s3c_rtc_alarmno);
617
563 return 0; 618 return 0;
564} 619}
565#else 620#else