aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2014-10-13 18:52:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-13 20:18:17 -0400
commitae05c95074e0ead8a8fda4aca066e10270086e3f (patch)
treef6596bb217bd96544c67108122c6b9b495d774b0 /drivers
parentd67288da51b782f54dd3ae1455b997131160fd41 (diff)
rtc: s3c: add s3c_rtc_data structure to use variant data instead of s3c_cpu_type
Add s3c_rtc_data structure to variant data according to SoC type. The s3c_rtc_data structure includes some functions to control RTC operation and specific data dependent on SoC type. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/rtc-s3c.c461
1 files changed, 289 insertions, 172 deletions
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 4e95cca7615c..0d9089228bb0 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -32,17 +32,6 @@
32#include <asm/irq.h> 32#include <asm/irq.h>
33#include "rtc-s3c.h" 33#include "rtc-s3c.h"
34 34
35enum s3c_cpu_type {
36 TYPE_S3C2410,
37 TYPE_S3C2416,
38 TYPE_S3C2443,
39 TYPE_S3C64XX,
40};
41
42struct s3c_rtc_drv_data {
43 int cpu_type;
44};
45
46struct s3c_rtc { 35struct s3c_rtc {
47 struct device *dev; 36 struct device *dev;
48 struct rtc_device *rtc; 37 struct rtc_device *rtc;
@@ -51,7 +40,7 @@ struct s3c_rtc {
51 struct clk *rtc_clk; 40 struct clk *rtc_clk;
52 bool enabled; 41 bool enabled;
53 42
54 enum s3c_cpu_type cpu_type; 43 struct s3c_rtc_data *data;
55 44
56 int irq_alarm; 45 int irq_alarm;
57 int irq_tick; 46 int irq_tick;
@@ -63,6 +52,19 @@ struct s3c_rtc {
63 bool wake_en; 52 bool wake_en;
64}; 53};
65 54
55struct s3c_rtc_data {
56 int max_user_freq;
57
58 void (*irq_handler) (struct s3c_rtc *info, int mask);
59 void (*set_freq) (struct s3c_rtc *info, int freq);
60 void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
61 void (*select_tick_clk) (struct s3c_rtc *info);
62 void (*save_tick_cnt) (struct s3c_rtc *info);
63 void (*restore_tick_cnt) (struct s3c_rtc *info);
64 void (*enable) (struct s3c_rtc *info);
65 void (*disable) (struct s3c_rtc *info);
66};
67
66static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable) 68static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable)
67{ 69{
68 unsigned long irq_flags; 70 unsigned long irq_flags;
@@ -83,34 +85,22 @@ static void s3c_rtc_alarm_clk_enable(struct s3c_rtc *info, bool enable)
83} 85}
84 86
85/* IRQ Handlers */ 87/* IRQ Handlers */
86static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) 88static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
87{ 89{
88 struct s3c_rtc *info = (struct s3c_rtc *)id; 90 struct s3c_rtc *info = (struct s3c_rtc *)id;
89 91
90 clk_enable(info->rtc_clk); 92 if (info->data->irq_handler)
91 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 93 info->data->irq_handler(info, S3C2410_INTP_TIC);
92
93 if (info->cpu_type == TYPE_S3C64XX)
94 writeb(S3C2410_INTP_ALM, info->base + S3C2410_INTP);
95
96 clk_disable(info->rtc_clk);
97
98 s3c_rtc_alarm_clk_enable(info, false);
99 94
100 return IRQ_HANDLED; 95 return IRQ_HANDLED;
101} 96}
102 97
103static irqreturn_t s3c_rtc_tickirq(int irq, void *id) 98static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
104{ 99{
105 struct s3c_rtc *info = (struct s3c_rtc *)id; 100 struct s3c_rtc *info = (struct s3c_rtc *)id;
106 101
107 clk_enable(info->rtc_clk); 102 if (info->data->irq_handler)
108 rtc_update_irq(info->rtc, 1, RTC_PF | RTC_IRQF); 103 info->data->irq_handler(info, S3C2410_INTP_ALM);
109
110 if (info->cpu_type == TYPE_S3C64XX)
111 writeb(S3C2410_INTP_TIC, info->base + S3C2410_INTP);
112
113 clk_disable(info->rtc_clk);
114 104
115 return IRQ_HANDLED; 105 return IRQ_HANDLED;
116} 106}
@@ -137,36 +127,18 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
137 return 0; 127 return 0;
138} 128}
139 129
130/* Set RTC frequency */
140static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) 131static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
141{ 132{
142 unsigned int tmp = 0;
143 int val;
144
145 if (!is_power_of_2(freq)) 133 if (!is_power_of_2(freq))
146 return -EINVAL; 134 return -EINVAL;
147 135
148 clk_enable(info->rtc_clk); 136 clk_enable(info->rtc_clk);
149 spin_lock_irq(&info->pie_lock); 137 spin_lock_irq(&info->pie_lock);
150 138
151 if (info->cpu_type != TYPE_S3C64XX) { 139 if (info->data->set_freq)
152 tmp = readb(info->base + S3C2410_TICNT); 140 info->data->set_freq(info, freq);
153 tmp &= S3C2410_TICNT_ENABLE;
154 }
155
156 val = (info->rtc->max_user_freq / freq) - 1;
157
158 if (info->cpu_type == TYPE_S3C2416 || info->cpu_type == TYPE_S3C2443) {
159 tmp |= S3C2443_TICNT_PART(val);
160 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
161 141
162 if (info->cpu_type == TYPE_S3C2416)
163 writel(S3C2416_TICNT2_PART(val),
164 info->base + S3C2416_TICNT2);
165 } else {
166 tmp |= val;
167 }
168
169 writel(tmp, info->base + S3C2410_TICNT);
170 spin_unlock_irq(&info->pie_lock); 142 spin_unlock_irq(&info->pie_lock);
171 clk_disable(info->rtc_clk); 143 clk_disable(info->rtc_clk);
172 144
@@ -174,7 +146,6 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
174} 146}
175 147
176/* Time read/write */ 148/* Time read/write */
177
178static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) 149static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
179{ 150{
180 struct s3c_rtc *info = dev_get_drvdata(dev); 151 struct s3c_rtc *info = dev_get_drvdata(dev);
@@ -355,19 +326,14 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
355static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 326static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
356{ 327{
357 struct s3c_rtc *info = dev_get_drvdata(dev); 328 struct s3c_rtc *info = dev_get_drvdata(dev);
358 unsigned int ticnt;
359 329
360 clk_enable(info->rtc_clk); 330 clk_enable(info->rtc_clk);
361 if (info->cpu_type == TYPE_S3C64XX) {
362 ticnt = readw(info->base + S3C2410_RTCCON);
363 ticnt &= S3C64XX_RTCCON_TICEN;
364 } else {
365 ticnt = readb(info->base + S3C2410_TICNT);
366 ticnt &= S3C2410_TICNT_ENABLE;
367 }
368 331
369 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); 332 if (info->data->enable_tick)
333 info->data->enable_tick(info, seq);
334
370 clk_disable(info->rtc_clk); 335 clk_disable(info->rtc_clk);
336
371 return 0; 337 return 0;
372} 338}
373 339
@@ -380,50 +346,69 @@ static const struct rtc_class_ops s3c_rtcops = {
380 .alarm_irq_enable = s3c_rtc_setaie, 346 .alarm_irq_enable = s3c_rtc_setaie,
381}; 347};
382 348
383static void s3c_rtc_enable(struct s3c_rtc *info, int en) 349static void s3c24xx_rtc_enable(struct s3c_rtc *info)
384{ 350{
385 unsigned int con, tmp; 351 unsigned int con, tmp;
386 352
387 clk_enable(info->rtc_clk); 353 clk_enable(info->rtc_clk);
388 354
389 con = readw(info->base + S3C2410_RTCCON); 355 con = readw(info->base + S3C2410_RTCCON);
390 if (!en) { 356 /* re-enable the device, and check it is ok */
391 if (info->cpu_type == TYPE_S3C64XX) 357 if ((con & S3C2410_RTCCON_RTCEN) == 0) {
392 con &= ~S3C64XX_RTCCON_TICEN; 358 dev_info(info->dev, "rtc disabled, re-enabling\n");
393 con &= ~S3C2410_RTCCON_RTCEN;
394 writew(con, info->base + S3C2410_RTCCON);
395
396 if (info->cpu_type != TYPE_S3C64XX) {
397 con = readb(info->base + S3C2410_TICNT);
398 con &= ~S3C2410_TICNT_ENABLE;
399 writeb(con, info->base + S3C2410_TICNT);
400 }
401 } else {
402 /* re-enable the device, and check it is ok */
403 if ((con & S3C2410_RTCCON_RTCEN) == 0) {
404 dev_info(info->dev, "rtc disabled, re-enabling\n");
405 359
406 tmp = readw(info->base + S3C2410_RTCCON); 360 tmp = readw(info->base + S3C2410_RTCCON);
407 writew(tmp | S3C2410_RTCCON_RTCEN, 361 writew(tmp | S3C2410_RTCCON_RTCEN,
408 info->base + S3C2410_RTCCON); 362 info->base + S3C2410_RTCCON);
409 } 363 }
410 364
411 if (con & S3C2410_RTCCON_CNTSEL) { 365 if (con & S3C2410_RTCCON_CNTSEL) {
412 dev_info(info->dev, "removing RTCCON_CNTSEL\n"); 366 dev_info(info->dev, "removing RTCCON_CNTSEL\n");
413 367
414 tmp = readw(info->base + S3C2410_RTCCON); 368 tmp = readw(info->base + S3C2410_RTCCON);
415 writew(tmp & ~S3C2410_RTCCON_CNTSEL, 369 writew(tmp & ~S3C2410_RTCCON_CNTSEL,
416 info->base + S3C2410_RTCCON); 370 info->base + S3C2410_RTCCON);
417 } 371 }
418 372
419 if (con & S3C2410_RTCCON_CLKRST) { 373 if (con & S3C2410_RTCCON_CLKRST) {
420 dev_info(info->dev, "removing RTCCON_CLKRST\n"); 374 dev_info(info->dev, "removing RTCCON_CLKRST\n");
421 375
422 tmp = readw(info->base + S3C2410_RTCCON); 376 tmp = readw(info->base + S3C2410_RTCCON);
423 writew(tmp & ~S3C2410_RTCCON_CLKRST, 377 writew(tmp & ~S3C2410_RTCCON_CLKRST,
424 info->base + S3C2410_RTCCON); 378 info->base + S3C2410_RTCCON);
425 }
426 } 379 }
380
381 clk_disable(info->rtc_clk);
382}
383
384static void s3c24xx_rtc_disable(struct s3c_rtc *info)
385{
386 unsigned int con;
387
388 clk_enable(info->rtc_clk);
389
390 con = readw(info->base + S3C2410_RTCCON);
391 con &= ~S3C2410_RTCCON_RTCEN;
392 writew(con, info->base + S3C2410_RTCCON);
393
394 con = readb(info->base + S3C2410_TICNT);
395 con &= ~S3C2410_TICNT_ENABLE;
396 writeb(con, info->base + S3C2410_TICNT);
397
398 clk_disable(info->rtc_clk);
399}
400
401static void s3c6410_rtc_disable(struct s3c_rtc *info)
402{
403 unsigned int con;
404
405 clk_enable(info->rtc_clk);
406
407 con = readw(info->base + S3C2410_RTCCON);
408 con &= ~S3C64XX_RTCCON_TICEN;
409 con &= ~S3C2410_RTCCON_RTCEN;
410 writew(con, info->base + S3C2410_RTCCON);
411
427 clk_disable(info->rtc_clk); 412 clk_disable(info->rtc_clk);
428} 413}
429 414
@@ -441,20 +426,12 @@ static int s3c_rtc_remove(struct platform_device *pdev)
441 426
442static const struct of_device_id s3c_rtc_dt_match[]; 427static const struct of_device_id s3c_rtc_dt_match[];
443 428
444static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) 429static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
445{ 430{
446#ifdef CONFIG_OF 431 const struct of_device_id *match;
447 struct s3c_rtc_drv_data *data;
448 432
449 if (pdev->dev.of_node) { 433 match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
450 const struct of_device_id *match; 434 return (struct s3c_rtc_data *)match->data;
451
452 match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
453 data = (struct s3c_rtc_drv_data *) match->data;
454 return data->cpu_type;
455 }
456#endif
457 return platform_get_device_id(pdev)->driver_data;
458} 435}
459 436
460static int s3c_rtc_probe(struct platform_device *pdev) 437static int s3c_rtc_probe(struct platform_device *pdev)
@@ -463,7 +440,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
463 struct rtc_time rtc_tm; 440 struct rtc_time rtc_tm;
464 struct resource *res; 441 struct resource *res;
465 int ret; 442 int ret;
466 int tmp;
467 443
468 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 444 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
469 if (!info) 445 if (!info)
@@ -477,7 +453,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
477 } 453 }
478 454
479 info->dev = &pdev->dev; 455 info->dev = &pdev->dev;
480 info->cpu_type = s3c_rtc_get_driver_data(pdev); 456 info->data = s3c_rtc_get_data(pdev);
457 if (!info->data) {
458 dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
459 return -EINVAL;
460 }
481 spin_lock_init(&info->pie_lock); 461 spin_lock_init(&info->pie_lock);
482 spin_lock_init(&info->alarm_clk_lock); 462 spin_lock_init(&info->alarm_clk_lock);
483 463
@@ -506,7 +486,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
506 clk_prepare_enable(info->rtc_clk); 486 clk_prepare_enable(info->rtc_clk);
507 487
508 /* check to see if everything is setup correctly */ 488 /* check to see if everything is setup correctly */
509 s3c_rtc_enable(info, 1); 489 if (info->data->enable)
490 info->data->enable(info);
510 491
511 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", 492 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
512 readw(info->base + S3C2410_RTCCON)); 493 readw(info->base + S3C2410_RTCCON));
@@ -552,16 +533,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
552 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); 533 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
553 } 534 }
554 535
555 if (info->cpu_type != TYPE_S3C2410) 536 if (info->data->select_tick_clk)
556 info->rtc->max_user_freq = 32768; 537 info->data->select_tick_clk(info);
557 else
558 info->rtc->max_user_freq = 128;
559
560 if (info->cpu_type == TYPE_S3C2416 || info->cpu_type == TYPE_S3C2443) {
561 tmp = readw(info->base + S3C2410_RTCCON);
562 tmp |= S3C2443_RTCCON_TICSEL;
563 writew(tmp, info->base + S3C2410_RTCCON);
564 }
565 538
566 s3c_rtc_setfreq(info, 1); 539 s3c_rtc_setfreq(info, 1);
567 540
@@ -570,7 +543,8 @@ static int s3c_rtc_probe(struct platform_device *pdev)
570 return 0; 543 return 0;
571 544
572 err_nortc: 545 err_nortc:
573 s3c_rtc_enable(info, 0); 546 if (info->data->disable)
547 info->data->disable(info);
574 clk_disable_unprepare(info->rtc_clk); 548 clk_disable_unprepare(info->rtc_clk);
575 549
576 return ret; 550 return ret;
@@ -583,15 +557,13 @@ static int s3c_rtc_suspend(struct device *dev)
583 struct s3c_rtc *info = dev_get_drvdata(dev); 557 struct s3c_rtc *info = dev_get_drvdata(dev);
584 558
585 clk_enable(info->rtc_clk); 559 clk_enable(info->rtc_clk);
560
586 /* save TICNT for anyone using periodic interrupts */ 561 /* save TICNT for anyone using periodic interrupts */
587 if (info->cpu_type == TYPE_S3C64XX) { 562 if (info->data->save_tick_cnt)
588 info->ticnt_en_save = readw(info->base + S3C2410_RTCCON); 563 info->data->save_tick_cnt(info);
589 info->ticnt_en_save &= S3C64XX_RTCCON_TICEN; 564
590 info->ticnt_save = readl(info->base + S3C2410_TICNT); 565 if (info->data->disable)
591 } else { 566 info->data->disable(info);
592 info->ticnt_save = readb(info->base + S3C2410_TICNT);
593 }
594 s3c_rtc_enable(info, 0);
595 567
596 if (device_may_wakeup(dev) && !info->wake_en) { 568 if (device_may_wakeup(dev) && !info->wake_en) {
597 if (enable_irq_wake(info->irq_alarm) == 0) 569 if (enable_irq_wake(info->irq_alarm) == 0)
@@ -599,6 +571,7 @@ static int s3c_rtc_suspend(struct device *dev)
599 else 571 else
600 dev_err(dev, "enable_irq_wake failed\n"); 572 dev_err(dev, "enable_irq_wake failed\n");
601 } 573 }
574
602 clk_disable(info->rtc_clk); 575 clk_disable(info->rtc_clk);
603 576
604 return 0; 577 return 0;
@@ -607,25 +580,20 @@ static int s3c_rtc_suspend(struct device *dev)
607static int s3c_rtc_resume(struct device *dev) 580static int s3c_rtc_resume(struct device *dev)
608{ 581{
609 struct s3c_rtc *info = dev_get_drvdata(dev); 582 struct s3c_rtc *info = dev_get_drvdata(dev);
610 unsigned int tmp;
611 583
612 clk_enable(info->rtc_clk); 584 clk_enable(info->rtc_clk);
613 s3c_rtc_enable(info, 1); 585
614 if (info->cpu_type == TYPE_S3C64XX) { 586 if (info->data->enable)
615 writel(info->ticnt_save, info->base + S3C2410_TICNT); 587 info->data->enable(info);
616 if (info->ticnt_en_save) { 588
617 tmp = readw(info->base + S3C2410_RTCCON); 589 if (info->data->restore_tick_cnt)
618 writew(tmp | info->ticnt_en_save, 590 info->data->restore_tick_cnt(info);
619 info->base + S3C2410_RTCCON);
620 }
621 } else {
622 writeb(info->ticnt_save, info->base + S3C2410_TICNT);
623 }
624 591
625 if (device_may_wakeup(dev) && info->wake_en) { 592 if (device_may_wakeup(dev) && info->wake_en) {
626 disable_irq_wake(info->irq_alarm); 593 disable_irq_wake(info->irq_alarm);
627 info->wake_en = false; 594 info->wake_en = false;
628 } 595 }
596
629 clk_disable(info->rtc_clk); 597 clk_disable(info->rtc_clk);
630 598
631 return 0; 599 return 0;
@@ -633,56 +601,206 @@ static int s3c_rtc_resume(struct device *dev)
633#endif 601#endif
634static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); 602static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
635 603
636#ifdef CONFIG_OF 604static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
637static struct s3c_rtc_drv_data s3c_rtc_drv_data_array[] = { 605{
638 [TYPE_S3C2410] = { TYPE_S3C2410 }, 606 clk_enable(info->rtc_clk);
639 [TYPE_S3C2416] = { TYPE_S3C2416 }, 607 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
640 [TYPE_S3C2443] = { TYPE_S3C2443 }, 608 clk_disable(info->rtc_clk);
641 [TYPE_S3C64XX] = { TYPE_S3C64XX }, 609
610 s3c_rtc_alarm_clk_enable(info, false);
611}
612
613static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
614{
615 clk_enable(info->rtc_clk);
616 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
617 writeb(mask, info->base + S3C2410_INTP);
618 clk_disable(info->rtc_clk);
619
620 s3c_rtc_alarm_clk_enable(info, false);
621}
622
623static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
624{
625 unsigned int tmp = 0;
626 int val;
627
628 tmp = readb(info->base + S3C2410_TICNT);
629 tmp &= S3C2410_TICNT_ENABLE;
630
631 val = (info->rtc->max_user_freq / freq) - 1;
632 tmp |= val;
633
634 writel(tmp, info->base + S3C2410_TICNT);
635}
636
637static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
638{
639 unsigned int tmp = 0;
640 int val;
641
642 tmp = readb(info->base + S3C2410_TICNT);
643 tmp &= S3C2410_TICNT_ENABLE;
644
645 val = (info->rtc->max_user_freq / freq) - 1;
646
647 tmp |= S3C2443_TICNT_PART(val);
648 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
649
650 writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
651
652 writel(tmp, info->base + S3C2410_TICNT);
653}
654
655static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
656{
657 unsigned int tmp = 0;
658 int val;
659
660 tmp = readb(info->base + S3C2410_TICNT);
661 tmp &= S3C2410_TICNT_ENABLE;
662
663 val = (info->rtc->max_user_freq / freq) - 1;
664
665 tmp |= S3C2443_TICNT_PART(val);
666 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
667
668 writel(tmp, info->base + S3C2410_TICNT);
669}
670
671static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
672{
673 int val;
674
675 val = (info->rtc->max_user_freq / freq) - 1;
676 writel(val, info->base + S3C2410_TICNT);
677}
678
679static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
680{
681 unsigned int ticnt;
682
683 ticnt = readb(info->base + S3C2410_TICNT);
684 ticnt &= S3C2410_TICNT_ENABLE;
685
686 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
687}
688
689static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
690{
691 unsigned int con;
692
693 con = readw(info->base + S3C2410_RTCCON);
694 con |= S3C2443_RTCCON_TICSEL;
695 writew(con, info->base + S3C2410_RTCCON);
696}
697
698static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
699{
700 unsigned int ticnt;
701
702 ticnt = readw(info->base + S3C2410_RTCCON);
703 ticnt &= S3C64XX_RTCCON_TICEN;
704
705 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
706}
707
708static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
709{
710 info->ticnt_save = readb(info->base + S3C2410_TICNT);
711}
712
713static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
714{
715 writeb(info->ticnt_save, info->base + S3C2410_TICNT);
716}
717
718static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
719{
720 info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
721 info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
722 info->ticnt_save = readl(info->base + S3C2410_TICNT);
723}
724
725static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
726{
727 unsigned int con;
728
729 writel(info->ticnt_save, info->base + S3C2410_TICNT);
730 if (info->ticnt_en_save) {
731 con = readw(info->base + S3C2410_RTCCON);
732 writew(con | info->ticnt_en_save,
733 info->base + S3C2410_RTCCON);
734 }
735}
736
737static struct s3c_rtc_data const s3c2410_rtc_data = {
738 .max_user_freq = 128,
739 .irq_handler = s3c24xx_rtc_irq,
740 .set_freq = s3c2410_rtc_setfreq,
741 .enable_tick = s3c24xx_rtc_enable_tick,
742 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
743 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
744 .enable = s3c24xx_rtc_enable,
745 .disable = s3c24xx_rtc_disable,
746};
747
748static struct s3c_rtc_data const s3c2416_rtc_data = {
749 .max_user_freq = 32768,
750 .irq_handler = s3c24xx_rtc_irq,
751 .set_freq = s3c2416_rtc_setfreq,
752 .enable_tick = s3c24xx_rtc_enable_tick,
753 .select_tick_clk = s3c2416_rtc_select_tick_clk,
754 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
755 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
756 .enable = s3c24xx_rtc_enable,
757 .disable = s3c24xx_rtc_disable,
758};
759
760static struct s3c_rtc_data const s3c2443_rtc_data = {
761 .max_user_freq = 32768,
762 .irq_handler = s3c24xx_rtc_irq,
763 .set_freq = s3c2443_rtc_setfreq,
764 .enable_tick = s3c24xx_rtc_enable_tick,
765 .select_tick_clk = s3c2416_rtc_select_tick_clk,
766 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
767 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
768 .enable = s3c24xx_rtc_enable,
769 .disable = s3c24xx_rtc_disable,
770};
771
772static struct s3c_rtc_data const s3c6410_rtc_data = {
773 .max_user_freq = 32768,
774 .irq_handler = s3c6410_rtc_irq,
775 .set_freq = s3c6410_rtc_setfreq,
776 .enable_tick = s3c6410_rtc_enable_tick,
777 .save_tick_cnt = s3c6410_rtc_save_tick_cnt,
778 .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
779 .enable = s3c24xx_rtc_enable,
780 .disable = s3c6410_rtc_disable,
642}; 781};
643 782
644static const struct of_device_id s3c_rtc_dt_match[] = { 783static const struct of_device_id s3c_rtc_dt_match[] = {
645 { 784 {
646 .compatible = "samsung,s3c2410-rtc", 785 .compatible = "samsung,s3c2410-rtc",
647 .data = &s3c_rtc_drv_data_array[TYPE_S3C2410], 786 .data = (void *)&s3c2410_rtc_data,
648 }, { 787 }, {
649 .compatible = "samsung,s3c2416-rtc", 788 .compatible = "samsung,s3c2416-rtc",
650 .data = &s3c_rtc_drv_data_array[TYPE_S3C2416], 789 .data = (void *)&s3c2416_rtc_data,
651 }, { 790 }, {
652 .compatible = "samsung,s3c2443-rtc", 791 .compatible = "samsung,s3c2443-rtc",
653 .data = &s3c_rtc_drv_data_array[TYPE_S3C2443], 792 .data = (void *)&s3c2443_rtc_data,
654 }, { 793 }, {
655 .compatible = "samsung,s3c6410-rtc", 794 .compatible = "samsung,s3c6410-rtc",
656 .data = &s3c_rtc_drv_data_array[TYPE_S3C64XX], 795 .data = (void *)&s3c6410_rtc_data,
657 }, 796 },
658 {}, 797 { /* sentinel */ },
659}; 798};
660MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); 799MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
661#endif
662
663static struct platform_device_id s3c_rtc_driver_ids[] = {
664 {
665 .name = "s3c2410-rtc",
666 .driver_data = TYPE_S3C2410,
667 }, {
668 .name = "s3c2416-rtc",
669 .driver_data = TYPE_S3C2416,
670 }, {
671 .name = "s3c2443-rtc",
672 .driver_data = TYPE_S3C2443,
673 }, {
674 .name = "s3c64xx-rtc",
675 .driver_data = TYPE_S3C64XX,
676 },
677 { }
678};
679
680MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids);
681 800
682static struct platform_driver s3c_rtc_driver = { 801static struct platform_driver s3c_rtc_driver = {
683 .probe = s3c_rtc_probe, 802 .probe = s3c_rtc_probe,
684 .remove = s3c_rtc_remove, 803 .remove = s3c_rtc_remove,
685 .id_table = s3c_rtc_driver_ids,
686 .driver = { 804 .driver = {
687 .name = "s3c-rtc", 805 .name = "s3c-rtc",
688 .owner = THIS_MODULE, 806 .owner = THIS_MODULE,
@@ -690,7 +808,6 @@ static struct platform_driver s3c_rtc_driver = {
690 .of_match_table = of_match_ptr(s3c_rtc_dt_match), 808 .of_match_table = of_match_ptr(s3c_rtc_dt_match),
691 }, 809 },
692}; 810};
693
694module_platform_driver(s3c_rtc_driver); 811module_platform_driver(s3c_rtc_driver);
695 812
696MODULE_DESCRIPTION("Samsung S3C RTC Driver"); 813MODULE_DESCRIPTION("Samsung S3C RTC Driver");