aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-s3c.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-08-06 13:13:54 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-08-06 13:13:54 -0400
commit11e4afb49b7fa1fc8e1ffd850c1806dd86a08204 (patch)
tree9e57efcb106ae912f7bec718feb3f8ec607559bb /drivers/rtc/rtc-s3c.c
parent162500b3a3ff39d941d29db49b41a16667ae44f0 (diff)
parent9b2a606d3898fcb2eedb6faded3bb37549590ac4 (diff)
Merge branches 'gemini' and 'misc' into devel
Diffstat (limited to 'drivers/rtc/rtc-s3c.c')
-rw-r--r--drivers/rtc/rtc-s3c.c113
1 files changed, 91 insertions, 22 deletions
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e0d7b9991505..70b68d35f969 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -21,6 +21,7 @@
21#include <linux/bcd.h> 21#include <linux/bcd.h>
22#include <linux/clk.h> 22#include <linux/clk.h>
23#include <linux/log2.h> 23#include <linux/log2.h>
24#include <linux/slab.h>
24 25
25#include <mach/hardware.h> 26#include <mach/hardware.h>
26#include <asm/uaccess.h> 27#include <asm/uaccess.h>
@@ -28,6 +29,11 @@
28#include <asm/irq.h> 29#include <asm/irq.h>
29#include <plat/regs-rtc.h> 30#include <plat/regs-rtc.h>
30 31
32enum s3c_cpu_type {
33 TYPE_S3C2410,
34 TYPE_S3C64XX,
35};
36
31/* 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
32 * of these rtc blocks in */ 38 * of these rtc blocks in */
33 39
@@ -36,6 +42,7 @@ static struct resource *s3c_rtc_mem;
36static void __iomem *s3c_rtc_base; 42static void __iomem *s3c_rtc_base;
37static int s3c_rtc_alarmno = NO_IRQ; 43static int s3c_rtc_alarmno = NO_IRQ;
38static int s3c_rtc_tickno = NO_IRQ; 44static int s3c_rtc_tickno = NO_IRQ;
45static enum s3c_cpu_type s3c_rtc_cpu_type;
39 46
40static DEFINE_SPINLOCK(s3c_rtc_pie_lock); 47static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
41 48
@@ -79,12 +86,25 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
79 pr_debug("%s: pie=%d\n", __func__, enabled); 86 pr_debug("%s: pie=%d\n", __func__, enabled);
80 87
81 spin_lock_irq(&s3c_rtc_pie_lock); 88 spin_lock_irq(&s3c_rtc_pie_lock);
82 tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
83 89
84 if (enabled) 90 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
85 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 }
86 107
87 writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
88 spin_unlock_irq(&s3c_rtc_pie_lock); 108 spin_unlock_irq(&s3c_rtc_pie_lock);
89 109
90 return 0; 110 return 0;
@@ -92,15 +112,21 @@ static int s3c_rtc_setpie(struct device *dev, int enabled)
92 112
93static int s3c_rtc_setfreq(struct device *dev, int freq) 113static int s3c_rtc_setfreq(struct device *dev, int freq)
94{ 114{
95 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;
96 118
97 if (!is_power_of_2(freq)) 119 if (!is_power_of_2(freq))
98 return -EINVAL; 120 return -EINVAL;
99 121
100 spin_lock_irq(&s3c_rtc_pie_lock); 122 spin_lock_irq(&s3c_rtc_pie_lock);
101 123
102 tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE; 124 if (s3c_rtc_cpu_type == TYPE_S3C2410) {
103 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;
104 130
105 writeb(tmp, s3c_rtc_base + S3C2410_TICNT); 131 writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
106 spin_unlock_irq(&s3c_rtc_pie_lock); 132 spin_unlock_irq(&s3c_rtc_pie_lock);
@@ -282,10 +308,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
282 308
283static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 309static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
284{ 310{
285 unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT); 311 unsigned int ticnt;
312
313 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
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 }
286 320
287 seq_printf(seq, "periodic_IRQ\t: %s\n", 321 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
288 (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
289 return 0; 322 return 0;
290} 323}
291 324
@@ -352,10 +385,16 @@ static void s3c_rtc_enable(struct platform_device *pdev, int en)
352 385
353 if (!en) { 386 if (!en) {
354 tmp = readb(base + S3C2410_RTCCON); 387 tmp = readb(base + S3C2410_RTCCON);
355 writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON); 388 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
356 389 tmp &= ~S3C64XX_RTCCON_TICEN;
357 tmp = readb(base + S3C2410_TICNT); 390 tmp &= ~S3C2410_RTCCON_RTCEN;
358 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 }
359 } else { 398 } else {
360 /* re-enable the device, and check it is ok */ 399 /* re-enable the device, and check it is ok */
361 400
@@ -456,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
456 pr_debug("s3c2410_rtc: RTCCON=%02x\n", 495 pr_debug("s3c2410_rtc: RTCCON=%02x\n",
457 readb(s3c_rtc_base + S3C2410_RTCCON)); 496 readb(s3c_rtc_base + S3C2410_RTCCON));
458 497
459 s3c_rtc_setfreq(&pdev->dev, 1);
460
461 device_init_wakeup(&pdev->dev, 1); 498 device_init_wakeup(&pdev->dev, 1);
462 499
463 /* register RTC and exit */ 500 /* register RTC and exit */
@@ -471,9 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
471 goto err_nortc; 508 goto err_nortc;
472 } 509 }
473 510
474 rtc->max_user_freq = 128; 511 s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
512
513 if (s3c_rtc_cpu_type == TYPE_S3C64XX)
514 rtc->max_user_freq = 32768;
515 else
516 rtc->max_user_freq = 128;
475 517
476 platform_set_drvdata(pdev, rtc); 518 platform_set_drvdata(pdev, rtc);
519
520 s3c_rtc_setfreq(&pdev->dev, 1);
521
477 return 0; 522 return 0;
478 523
479 err_nortc: 524 err_nortc:
@@ -491,20 +536,30 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
491 536
492/* RTC Power management control */ 537/* RTC Power management control */
493 538
494static int ticnt_save; 539static int ticnt_save, ticnt_en_save;
495 540
496static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) 541static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
497{ 542{
498 /* save TICNT for anyone using periodic interrupts */ 543 /* save TICNT for anyone using periodic interrupts */
499 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); 544 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
545 if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
546 ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON);
547 ticnt_en_save &= S3C64XX_RTCCON_TICEN;
548 }
500 s3c_rtc_enable(pdev, 0); 549 s3c_rtc_enable(pdev, 0);
501 return 0; 550 return 0;
502} 551}
503 552
504static int s3c_rtc_resume(struct platform_device *pdev) 553static int s3c_rtc_resume(struct platform_device *pdev)
505{ 554{
555 unsigned int tmp;
556
506 s3c_rtc_enable(pdev, 1); 557 s3c_rtc_enable(pdev, 1);
507 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); 558 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
559 if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
560 tmp = readb(s3c_rtc_base + S3C2410_RTCCON);
561 writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
562 }
508 return 0; 563 return 0;
509} 564}
510#else 565#else
@@ -512,13 +567,27 @@ static int s3c_rtc_resume(struct platform_device *pdev)
512#define s3c_rtc_resume NULL 567#define s3c_rtc_resume NULL
513#endif 568#endif
514 569
515static struct platform_driver s3c2410_rtc_driver = { 570static struct platform_device_id s3c_rtc_driver_ids[] = {
571 {
572 .name = "s3c2410-rtc",
573 .driver_data = TYPE_S3C2410,
574 }, {
575 .name = "s3c64xx-rtc",
576 .driver_data = TYPE_S3C64XX,
577 },
578 { }
579};
580
581MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
582
583static struct platform_driver s3c_rtc_driver = {
516 .probe = s3c_rtc_probe, 584 .probe = s3c_rtc_probe,
517 .remove = __devexit_p(s3c_rtc_remove), 585 .remove = __devexit_p(s3c_rtc_remove),
518 .suspend = s3c_rtc_suspend, 586 .suspend = s3c_rtc_suspend,
519 .resume = s3c_rtc_resume, 587 .resume = s3c_rtc_resume,
588 .id_table = s3c_rtc_driver_ids,
520 .driver = { 589 .driver = {
521 .name = "s3c2410-rtc", 590 .name = "s3c-rtc",
522 .owner = THIS_MODULE, 591 .owner = THIS_MODULE,
523 }, 592 },
524}; 593};
@@ -528,12 +597,12 @@ static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics
528static int __init s3c_rtc_init(void) 597static int __init s3c_rtc_init(void)
529{ 598{
530 printk(banner); 599 printk(banner);
531 return platform_driver_register(&s3c2410_rtc_driver); 600 return platform_driver_register(&s3c_rtc_driver);
532} 601}
533 602
534static void __exit s3c_rtc_exit(void) 603static void __exit s3c_rtc_exit(void)
535{ 604{
536 platform_driver_unregister(&s3c2410_rtc_driver); 605 platform_driver_unregister(&s3c_rtc_driver);
537} 606}
538 607
539module_init(s3c_rtc_init); 608module_init(s3c_rtc_init);