diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 107 |
2 files changed, 88 insertions, 21 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 50ac047cd136..f1598324344c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -640,7 +640,7 @@ config RTC_DRV_OMAP | |||
640 | 640 | ||
641 | config RTC_DRV_S3C | 641 | config RTC_DRV_S3C |
642 | tristate "Samsung S3C series SoC RTC" | 642 | tristate "Samsung S3C series SoC RTC" |
643 | depends on ARCH_S3C2410 | 643 | depends on ARCH_S3C2410 || ARCH_S3C64XX |
644 | help | 644 | help |
645 | RTC (Realtime Clock) driver for the clock inbuilt into the | 645 | RTC (Realtime Clock) driver for the clock inbuilt into the |
646 | Samsung S3C24XX series of SoCs. This can provide periodic | 646 | Samsung S3C24XX series of SoCs. This can provide periodic |
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 4969b6059c89..e5972b2c17b7 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -29,6 +29,11 @@ | |||
29 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
30 | #include <plat/regs-rtc.h> | 30 | #include <plat/regs-rtc.h> |
31 | 31 | ||
32 | enum s3c_cpu_type { | ||
33 | TYPE_S3C2410, | ||
34 | TYPE_S3C64XX, | ||
35 | }; | ||
36 | |||
32 | /* I have yet to find an S3C implementation with more than one | 37 | /* I have yet to find an S3C implementation with more than one |
33 | * of these rtc blocks in */ | 38 | * of these rtc blocks in */ |
34 | 39 | ||
@@ -37,6 +42,7 @@ static struct resource *s3c_rtc_mem; | |||
37 | static void __iomem *s3c_rtc_base; | 42 | static void __iomem *s3c_rtc_base; |
38 | static int s3c_rtc_alarmno = NO_IRQ; | 43 | static int s3c_rtc_alarmno = NO_IRQ; |
39 | static int s3c_rtc_tickno = NO_IRQ; | 44 | static int s3c_rtc_tickno = NO_IRQ; |
45 | static enum s3c_cpu_type s3c_rtc_cpu_type; | ||
40 | 46 | ||
41 | static DEFINE_SPINLOCK(s3c_rtc_pie_lock); | 47 | static DEFINE_SPINLOCK(s3c_rtc_pie_lock); |
42 | 48 | ||
@@ -80,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) | |||
80 | pr_debug("%s: pie=%d\n", __func__, enabled); | 86 | pr_debug("%s: pie=%d\n", __func__, enabled); |
81 | 87 | ||
82 | spin_lock_irq(&s3c_rtc_pie_lock); | 88 | spin_lock_irq(&s3c_rtc_pie_lock); |
83 | tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE; | ||
84 | 89 | ||
85 | if (enabled) | 90 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
86 | tmp |= S3C2410_TICNT_ENABLE; | 91 | tmp = readb(s3c_rtc_base + S3C2410_RTCCON); |
92 | tmp &= ~S3C64XX_RTCCON_TICEN; | ||
93 | |||
94 | if (enabled) | ||
95 | tmp |= S3C64XX_RTCCON_TICEN; | ||
96 | |||
97 | writeb(tmp, s3c_rtc_base + S3C2410_RTCCON); | ||
98 | } else { | ||
99 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); | ||
100 | tmp &= ~S3C2410_TICNT_ENABLE; | ||
101 | |||
102 | if (enabled) | ||
103 | tmp |= S3C2410_TICNT_ENABLE; | ||
104 | |||
105 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | ||
106 | } | ||
87 | 107 | ||
88 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | ||
89 | spin_unlock_irq(&s3c_rtc_pie_lock); | 108 | spin_unlock_irq(&s3c_rtc_pie_lock); |
90 | 109 | ||
91 | return 0; | 110 | return 0; |
@@ -93,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) | |||
93 | 112 | ||
94 | static int s3c_rtc_setfreq(struct device *dev, int freq) | 113 | static int s3c_rtc_setfreq(struct device *dev, int freq) |
95 | { | 114 | { |
96 | unsigned int tmp; | 115 | struct platform_device *pdev = to_platform_device(dev); |
116 | struct rtc_device *rtc_dev = platform_get_drvdata(pdev); | ||
117 | unsigned int tmp = 0; | ||
97 | 118 | ||
98 | if (!is_power_of_2(freq)) | 119 | if (!is_power_of_2(freq)) |
99 | return -EINVAL; | 120 | return -EINVAL; |
100 | 121 | ||
101 | spin_lock_irq(&s3c_rtc_pie_lock); | 122 | spin_lock_irq(&s3c_rtc_pie_lock); |
102 | 123 | ||
103 | tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; | 124 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { |
104 | tmp |= (128 / freq)-1; | 125 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); |
126 | tmp &= S3C2410_TICNT_ENABLE; | ||
127 | } | ||
128 | |||
129 | tmp |= (rtc_dev->max_user_freq / freq)-1; | ||
105 | 130 | ||
106 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | 131 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); |
107 | spin_unlock_irq(&s3c_rtc_pie_lock); | 132 | spin_unlock_irq(&s3c_rtc_pie_lock); |
@@ -283,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) | |||
283 | 308 | ||
284 | static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) | 309 | static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) |
285 | { | 310 | { |
286 | unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT); | 311 | unsigned int ticnt; |
287 | 312 | ||
288 | seq_printf(seq, "periodic_IRQ\t: %s\n", | 313 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { |
289 | (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" ); | 314 | ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); |
315 | ticnt &= S3C64XX_RTCCON_TICEN; | ||
316 | } else { | ||
317 | ticnt = readb(s3c_rtc_base + S3C2410_TICNT); | ||
318 | ticnt &= S3C2410_TICNT_ENABLE; | ||
319 | } | ||
320 | |||
321 | seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); | ||
290 | return 0; | 322 | return 0; |
291 | } | 323 | } |
292 | 324 | ||
@@ -353,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en) | |||
353 | 385 | ||
354 | if (!en) { | 386 | if (!en) { |
355 | tmp = readb(base + S3C2410_RTCCON); | 387 | tmp = readb(base + S3C2410_RTCCON); |
356 | writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); | 388 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
357 | 389 | tmp &= ~S3C64XX_RTCCON_TICEN; | |
358 | tmp = readb(base + S3C2410_TICNT); | 390 | tmp &= ~S3C2410_RTCCON_RTCEN; |
359 | writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT); | 391 | writeb(tmp, base + S3C2410_RTCCON); |
392 | |||
393 | if (s3c_rtc_cpu_type == TYPE_S3C2410) { | ||
394 | tmp = readb(base + S3C2410_TICNT); | ||
395 | tmp &= ~S3C2410_TICNT_ENABLE; | ||
396 | writeb(tmp, base + S3C2410_TICNT); | ||
397 | } | ||
360 | } else { | 398 | } else { |
361 | /* re-enable the device, and check it is ok */ | 399 | /* re-enable the device, and check it is ok */ |
362 | 400 | ||
@@ -472,7 +510,12 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
472 | goto err_nortc; | 510 | goto err_nortc; |
473 | } | 511 | } |
474 | 512 | ||
475 | rtc->max_user_freq = 128; | 513 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
514 | rtc->max_user_freq = 32768; | ||
515 | else | ||
516 | rtc->max_user_freq = 128; | ||
517 | |||
518 | s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; | ||
476 | 519 | ||
477 | platform_set_drvdata(pdev, rtc); | 520 | platform_set_drvdata(pdev, rtc); |
478 | return 0; | 521 | return 0; |
@@ -492,20 +535,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
492 | 535 | ||
493 | /* RTC Power management control */ | 536 | /* RTC Power management control */ |
494 | 537 | ||
495 | static int ticnt_save; | 538 | static int ticnt_save, ticnt_en_save; |
496 | 539 | ||
497 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) | 540 | static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) |
498 | { | 541 | { |
499 | /* save TICNT for anyone using periodic interrupts */ | 542 | /* save TICNT for anyone using periodic interrupts */ |
500 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); | 543 | ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); |
544 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) { | ||
545 | ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); | ||
546 | ticnt_en_save &= S3C64XX_RTCCON_TICEN; | ||
547 | } | ||
501 | s3c_rtc_enable(pdev, 0); | 548 | s3c_rtc_enable(pdev, 0); |
502 | return 0; | 549 | return 0; |
503 | } | 550 | } |
504 | 551 | ||
505 | static int s3c_rtc_resume(struct platform_device *pdev) | 552 | static int s3c_rtc_resume(struct platform_device *pdev) |
506 | { | 553 | { |
554 | unsigned int tmp; | ||
555 | |||
507 | s3c_rtc_enable(pdev, 1); | 556 | s3c_rtc_enable(pdev, 1); |
508 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); | 557 | writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); |
558 | if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { | ||
559 | tmp = readb(s3c_rtc_base + S3C2410_RTCCON); | ||
560 | writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); | ||
561 | } | ||
509 | return 0; | 562 | return 0; |
510 | } | 563 | } |
511 | #else | 564 | #else |
@@ -513,13 +566,27 @@ static int s3c_rtc_resume(struct platform_device *pdev) | |||
513 | #define s3c_rtc_resume NULL | 566 | #define s3c_rtc_resume NULL |
514 | #endif | 567 | #endif |
515 | 568 | ||
516 | static struct platform_driver s3c2410_rtc_driver = { | 569 | static struct platform_device_id s3c_rtc_driver_ids[] = { |
570 | { | ||
571 | .name = "s3c2410-rtc", | ||
572 | .driver_data = TYPE_S3C2410, | ||
573 | }, { | ||
574 | .name = "s3c64xx-rtc", | ||
575 | .driver_data = TYPE_S3C64XX, | ||
576 | }, | ||
577 | { } | ||
578 | }; | ||
579 | |||
580 | MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); | ||
581 | |||
582 | static struct platform_driver s3c_rtc_driver = { | ||
517 | .probe = s3c_rtc_probe, | 583 | .probe = s3c_rtc_probe, |
518 | .remove = __devexit_p(s3c_rtc_remove), | 584 | .remove = __devexit_p(s3c_rtc_remove), |
519 | .suspend = s3c_rtc_suspend, | 585 | .suspend = s3c_rtc_suspend, |
520 | .resume = s3c_rtc_resume, | 586 | .resume = s3c_rtc_resume, |
587 | .id_table = s3c_rtc_driver_ids, | ||
521 | .driver = { | 588 | .driver = { |
522 | .name = "s3c2410-rtc", | 589 | .name = "s3c-rtc", |
523 | .owner = THIS_MODULE, | 590 | .owner = THIS_MODULE, |
524 | }, | 591 | }, |
525 | }; | 592 | }; |
@@ -529,12 +596,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics | |||
529 | static int __init s3c_rtc_init(void) | 596 | static int __init s3c_rtc_init(void) |
530 | { | 597 | { |
531 | printk(banner); | 598 | printk(banner); |
532 | return platform_driver_register(&s3c2410_rtc_driver); | 599 | return platform_driver_register(&s3c_rtc_driver); |
533 | } | 600 | } |
534 | 601 | ||
535 | static void __exit s3c_rtc_exit(void) | 602 | static void __exit s3c_rtc_exit(void) |
536 | { | 603 | { |
537 | platform_driver_unregister(&s3c2410_rtc_driver); | 604 | platform_driver_unregister(&s3c_rtc_driver); |
538 | } | 605 | } |
539 | 606 | ||
540 | module_init(s3c_rtc_init); | 607 | module_init(s3c_rtc_init); |