aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorMaurus Cuelenaere <mcuelenaere@gmail.com>2010-05-24 17:33:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-25 11:07:07 -0400
commit9f4123b78d02ba48e7e6e3cd9de789c9b85b557a (patch)
tree0faf7f318bd90af043c8e9e056697ca38a1281e4 /drivers/rtc
parent337bbfdbffa5c893e80f96a3bf117743ceb0fefc (diff)
s3c rtc driver: add support for S3C64xx
Add support for the S3C64xx SoC to the generic S3C RTC driver. Signed-off-by: Maurus Cuelenaere <mcuelenaere@gmail.com> Acked-by: Ben Dooks <ben-linux@fluff.org> Cc: Frans Pop <elendil@planet.nl> Cc: Paul Gortmaker <p_gortmaker@yahoo.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/rtc-s3c.c107
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
641config RTC_DRV_S3C 641config 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
32enum 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;
37static void __iomem *s3c_rtc_base; 42static void __iomem *s3c_rtc_base;
38static int s3c_rtc_alarmno = NO_IRQ; 43static int s3c_rtc_alarmno = NO_IRQ;
39static int s3c_rtc_tickno = NO_IRQ; 44static int s3c_rtc_tickno = NO_IRQ;
45static enum s3c_cpu_type s3c_rtc_cpu_type;
40 46
41static DEFINE_SPINLOCK(s3c_rtc_pie_lock); 47static 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
94static int s3c_rtc_setfreq(struct device *dev, int freq) 113static 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
284static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 309static 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
495static int ticnt_save; 538static int ticnt_save, ticnt_en_save;
496 539
497static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) 540static 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
505static int s3c_rtc_resume(struct platform_device *pdev) 552static 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
516static struct platform_driver s3c2410_rtc_driver = { 569static 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
580MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
581
582static 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
529static int __init s3c_rtc_init(void) 596static 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
535static void __exit s3c_rtc_exit(void) 602static 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
540module_init(s3c_rtc_init); 607module_init(s3c_rtc_init);