perf intel-pt: Factor out intel_pt_8b_tsc()
[linux/fpc-iii.git] / drivers / rtc / rtc-s3c.c
blobe81a2b22a5c374451ddfd06818c0f36df2c5d135
1 /* drivers/rtc/rtc-s3c.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * Copyright (c) 2004,2006 Simtec Electronics
7 * Ben Dooks, <ben@simtec.co.uk>
8 * http://armlinux.simtec.co.uk/
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * S3C2410/S3C2440/S3C24XX Internal RTC Driver
17 #include <linux/module.h>
18 #include <linux/fs.h>
19 #include <linux/string.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
22 #include <linux/interrupt.h>
23 #include <linux/rtc.h>
24 #include <linux/bcd.h>
25 #include <linux/clk.h>
26 #include <linux/log2.h>
27 #include <linux/slab.h>
28 #include <linux/of.h>
29 #include <linux/of_device.h>
30 #include <linux/uaccess.h>
31 #include <linux/io.h>
33 #include <asm/irq.h>
34 #include "rtc-s3c.h"
36 struct s3c_rtc {
37 struct device *dev;
38 struct rtc_device *rtc;
40 void __iomem *base;
41 struct clk *rtc_clk;
42 struct clk *rtc_src_clk;
43 bool alarm_enabled;
45 const struct s3c_rtc_data *data;
47 int irq_alarm;
48 int irq_tick;
50 spinlock_t pie_lock;
51 spinlock_t alarm_lock;
53 int ticnt_save;
54 int ticnt_en_save;
55 bool wake_en;
58 struct s3c_rtc_data {
59 int max_user_freq;
60 bool needs_src_clk;
62 void (*irq_handler) (struct s3c_rtc *info, int mask);
63 void (*set_freq) (struct s3c_rtc *info, int freq);
64 void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
65 void (*select_tick_clk) (struct s3c_rtc *info);
66 void (*save_tick_cnt) (struct s3c_rtc *info);
67 void (*restore_tick_cnt) (struct s3c_rtc *info);
68 void (*enable) (struct s3c_rtc *info);
69 void (*disable) (struct s3c_rtc *info);
72 static int s3c_rtc_enable_clk(struct s3c_rtc *info)
74 int ret;
76 ret = clk_enable(info->rtc_clk);
77 if (ret)
78 return ret;
80 if (info->data->needs_src_clk) {
81 ret = clk_enable(info->rtc_src_clk);
82 if (ret) {
83 clk_disable(info->rtc_clk);
84 return ret;
87 return 0;
90 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
92 if (info->data->needs_src_clk)
93 clk_disable(info->rtc_src_clk);
94 clk_disable(info->rtc_clk);
97 /* IRQ Handlers */
98 static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
100 struct s3c_rtc *info = (struct s3c_rtc *)id;
102 if (info->data->irq_handler)
103 info->data->irq_handler(info, S3C2410_INTP_TIC);
105 return IRQ_HANDLED;
108 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
110 struct s3c_rtc *info = (struct s3c_rtc *)id;
112 if (info->data->irq_handler)
113 info->data->irq_handler(info, S3C2410_INTP_ALM);
115 return IRQ_HANDLED;
118 /* Update control registers */
119 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
121 struct s3c_rtc *info = dev_get_drvdata(dev);
122 unsigned long flags;
123 unsigned int tmp;
124 int ret;
126 dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
128 ret = s3c_rtc_enable_clk(info);
129 if (ret)
130 return ret;
132 tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
134 if (enabled)
135 tmp |= S3C2410_RTCALM_ALMEN;
137 writeb(tmp, info->base + S3C2410_RTCALM);
139 spin_lock_irqsave(&info->alarm_lock, flags);
141 if (info->alarm_enabled && !enabled)
142 s3c_rtc_disable_clk(info);
143 else if (!info->alarm_enabled && enabled)
144 ret = s3c_rtc_enable_clk(info);
146 info->alarm_enabled = enabled;
147 spin_unlock_irqrestore(&info->alarm_lock, flags);
149 s3c_rtc_disable_clk(info);
151 return ret;
154 /* Set RTC frequency */
155 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
157 int ret;
159 if (!is_power_of_2(freq))
160 return -EINVAL;
162 ret = s3c_rtc_enable_clk(info);
163 if (ret)
164 return ret;
165 spin_lock_irq(&info->pie_lock);
167 if (info->data->set_freq)
168 info->data->set_freq(info, freq);
170 spin_unlock_irq(&info->pie_lock);
171 s3c_rtc_disable_clk(info);
173 return 0;
176 /* Time read/write */
177 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
179 struct s3c_rtc *info = dev_get_drvdata(dev);
180 unsigned int have_retried = 0;
181 int ret;
183 ret = s3c_rtc_enable_clk(info);
184 if (ret)
185 return ret;
187 retry_get_time:
188 rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
189 rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
190 rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
191 rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON);
192 rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
193 rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC);
195 /* the only way to work out whether the system was mid-update
196 * when we read it is to check the second counter, and if it
197 * is zero, then we re-try the entire read
200 if (rtc_tm->tm_sec == 0 && !have_retried) {
201 have_retried = 1;
202 goto retry_get_time;
205 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
206 rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
207 rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
208 rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
209 rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
210 rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
212 s3c_rtc_disable_clk(info);
214 rtc_tm->tm_year += 100;
215 rtc_tm->tm_mon -= 1;
217 dev_dbg(dev, "read time %ptR\n", rtc_tm);
218 return 0;
221 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
223 struct s3c_rtc *info = dev_get_drvdata(dev);
224 int year = tm->tm_year - 100;
225 int ret;
227 dev_dbg(dev, "set time %ptR\n", tm);
229 /* we get around y2k by simply not supporting it */
231 if (year < 0 || year >= 100) {
232 dev_err(dev, "rtc only supports 100 years\n");
233 return -EINVAL;
236 ret = s3c_rtc_enable_clk(info);
237 if (ret)
238 return ret;
240 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
241 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
242 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
243 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
244 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
245 writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
247 s3c_rtc_disable_clk(info);
249 return 0;
252 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
254 struct s3c_rtc *info = dev_get_drvdata(dev);
255 struct rtc_time *alm_tm = &alrm->time;
256 unsigned int alm_en;
257 int ret;
259 ret = s3c_rtc_enable_clk(info);
260 if (ret)
261 return ret;
263 alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
264 alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
265 alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
266 alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON);
267 alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
268 alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
270 alm_en = readb(info->base + S3C2410_RTCALM);
272 s3c_rtc_disable_clk(info);
274 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
276 dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
278 /* decode the alarm enable field */
279 if (alm_en & S3C2410_RTCALM_SECEN)
280 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
282 if (alm_en & S3C2410_RTCALM_MINEN)
283 alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
285 if (alm_en & S3C2410_RTCALM_HOUREN)
286 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
288 if (alm_en & S3C2410_RTCALM_DAYEN)
289 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
291 if (alm_en & S3C2410_RTCALM_MONEN) {
292 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
293 alm_tm->tm_mon -= 1;
296 if (alm_en & S3C2410_RTCALM_YEAREN)
297 alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
299 return 0;
302 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
304 struct s3c_rtc *info = dev_get_drvdata(dev);
305 struct rtc_time *tm = &alrm->time;
306 unsigned int alrm_en;
307 int ret;
309 dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
311 ret = s3c_rtc_enable_clk(info);
312 if (ret)
313 return ret;
315 alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
316 writeb(0x00, info->base + S3C2410_RTCALM);
318 if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
319 alrm_en |= S3C2410_RTCALM_SECEN;
320 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
323 if (tm->tm_min < 60 && tm->tm_min >= 0) {
324 alrm_en |= S3C2410_RTCALM_MINEN;
325 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
328 if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
329 alrm_en |= S3C2410_RTCALM_HOUREN;
330 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
333 if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
334 alrm_en |= S3C2410_RTCALM_MONEN;
335 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
338 if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
339 alrm_en |= S3C2410_RTCALM_DAYEN;
340 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
343 dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
345 writeb(alrm_en, info->base + S3C2410_RTCALM);
347 s3c_rtc_setaie(dev, alrm->enabled);
349 s3c_rtc_disable_clk(info);
351 return 0;
354 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
356 struct s3c_rtc *info = dev_get_drvdata(dev);
357 int ret;
359 ret = s3c_rtc_enable_clk(info);
360 if (ret)
361 return ret;
363 if (info->data->enable_tick)
364 info->data->enable_tick(info, seq);
366 s3c_rtc_disable_clk(info);
368 return 0;
371 static const struct rtc_class_ops s3c_rtcops = {
372 .read_time = s3c_rtc_gettime,
373 .set_time = s3c_rtc_settime,
374 .read_alarm = s3c_rtc_getalarm,
375 .set_alarm = s3c_rtc_setalarm,
376 .proc = s3c_rtc_proc,
377 .alarm_irq_enable = s3c_rtc_setaie,
380 static void s3c24xx_rtc_enable(struct s3c_rtc *info)
382 unsigned int con, tmp;
384 con = readw(info->base + S3C2410_RTCCON);
385 /* re-enable the device, and check it is ok */
386 if ((con & S3C2410_RTCCON_RTCEN) == 0) {
387 dev_info(info->dev, "rtc disabled, re-enabling\n");
389 tmp = readw(info->base + S3C2410_RTCCON);
390 writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
393 if (con & S3C2410_RTCCON_CNTSEL) {
394 dev_info(info->dev, "removing RTCCON_CNTSEL\n");
396 tmp = readw(info->base + S3C2410_RTCCON);
397 writew(tmp & ~S3C2410_RTCCON_CNTSEL,
398 info->base + S3C2410_RTCCON);
401 if (con & S3C2410_RTCCON_CLKRST) {
402 dev_info(info->dev, "removing RTCCON_CLKRST\n");
404 tmp = readw(info->base + S3C2410_RTCCON);
405 writew(tmp & ~S3C2410_RTCCON_CLKRST,
406 info->base + S3C2410_RTCCON);
410 static void s3c24xx_rtc_disable(struct s3c_rtc *info)
412 unsigned int con;
414 con = readw(info->base + S3C2410_RTCCON);
415 con &= ~S3C2410_RTCCON_RTCEN;
416 writew(con, info->base + S3C2410_RTCCON);
418 con = readb(info->base + S3C2410_TICNT);
419 con &= ~S3C2410_TICNT_ENABLE;
420 writeb(con, info->base + S3C2410_TICNT);
423 static void s3c6410_rtc_disable(struct s3c_rtc *info)
425 unsigned int con;
427 con = readw(info->base + S3C2410_RTCCON);
428 con &= ~S3C64XX_RTCCON_TICEN;
429 con &= ~S3C2410_RTCCON_RTCEN;
430 writew(con, info->base + S3C2410_RTCCON);
433 static int s3c_rtc_remove(struct platform_device *pdev)
435 struct s3c_rtc *info = platform_get_drvdata(pdev);
437 s3c_rtc_setaie(info->dev, 0);
439 if (info->data->needs_src_clk)
440 clk_unprepare(info->rtc_src_clk);
441 clk_unprepare(info->rtc_clk);
443 return 0;
446 static int s3c_rtc_probe(struct platform_device *pdev)
448 struct s3c_rtc *info = NULL;
449 struct rtc_time rtc_tm;
450 struct resource *res;
451 int ret;
453 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
454 if (!info)
455 return -ENOMEM;
457 /* find the IRQs */
458 info->irq_tick = platform_get_irq(pdev, 1);
459 if (info->irq_tick < 0) {
460 dev_err(&pdev->dev, "no irq for rtc tick\n");
461 return info->irq_tick;
464 info->dev = &pdev->dev;
465 info->data = of_device_get_match_data(&pdev->dev);
466 if (!info->data) {
467 dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
468 return -EINVAL;
470 spin_lock_init(&info->pie_lock);
471 spin_lock_init(&info->alarm_lock);
473 platform_set_drvdata(pdev, info);
475 info->irq_alarm = platform_get_irq(pdev, 0);
476 if (info->irq_alarm < 0) {
477 dev_err(&pdev->dev, "no irq for alarm\n");
478 return info->irq_alarm;
481 dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
482 info->irq_tick, info->irq_alarm);
484 /* get the memory region */
485 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
486 info->base = devm_ioremap_resource(&pdev->dev, res);
487 if (IS_ERR(info->base))
488 return PTR_ERR(info->base);
490 info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
491 if (IS_ERR(info->rtc_clk)) {
492 ret = PTR_ERR(info->rtc_clk);
493 if (ret != -EPROBE_DEFER)
494 dev_err(&pdev->dev, "failed to find rtc clock\n");
495 else
496 dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
497 return ret;
499 ret = clk_prepare_enable(info->rtc_clk);
500 if (ret)
501 return ret;
503 if (info->data->needs_src_clk) {
504 info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
505 if (IS_ERR(info->rtc_src_clk)) {
506 ret = PTR_ERR(info->rtc_src_clk);
507 if (ret != -EPROBE_DEFER)
508 dev_err(&pdev->dev,
509 "failed to find rtc source clock\n");
510 else
511 dev_dbg(&pdev->dev,
512 "probe deferred due to missing rtc src clk\n");
513 goto err_src_clk;
515 ret = clk_prepare_enable(info->rtc_src_clk);
516 if (ret)
517 goto err_src_clk;
520 /* check to see if everything is setup correctly */
521 if (info->data->enable)
522 info->data->enable(info);
524 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
525 readw(info->base + S3C2410_RTCCON));
527 device_init_wakeup(&pdev->dev, 1);
529 /* Check RTC Time */
530 if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) {
531 rtc_tm.tm_year = 100;
532 rtc_tm.tm_mon = 0;
533 rtc_tm.tm_mday = 1;
534 rtc_tm.tm_hour = 0;
535 rtc_tm.tm_min = 0;
536 rtc_tm.tm_sec = 0;
538 s3c_rtc_settime(&pdev->dev, &rtc_tm);
540 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
543 /* register RTC and exit */
544 info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
545 THIS_MODULE);
546 if (IS_ERR(info->rtc)) {
547 dev_err(&pdev->dev, "cannot attach rtc\n");
548 ret = PTR_ERR(info->rtc);
549 goto err_nortc;
552 ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
553 0, "s3c2410-rtc alarm", info);
554 if (ret) {
555 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
556 goto err_nortc;
559 ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
560 0, "s3c2410-rtc tick", info);
561 if (ret) {
562 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
563 goto err_nortc;
566 if (info->data->select_tick_clk)
567 info->data->select_tick_clk(info);
569 s3c_rtc_setfreq(info, 1);
571 s3c_rtc_disable_clk(info);
573 return 0;
575 err_nortc:
576 if (info->data->disable)
577 info->data->disable(info);
579 if (info->data->needs_src_clk)
580 clk_disable_unprepare(info->rtc_src_clk);
581 err_src_clk:
582 clk_disable_unprepare(info->rtc_clk);
584 return ret;
587 #ifdef CONFIG_PM_SLEEP
589 static int s3c_rtc_suspend(struct device *dev)
591 struct s3c_rtc *info = dev_get_drvdata(dev);
592 int ret;
594 ret = s3c_rtc_enable_clk(info);
595 if (ret)
596 return ret;
598 /* save TICNT for anyone using periodic interrupts */
599 if (info->data->save_tick_cnt)
600 info->data->save_tick_cnt(info);
602 if (info->data->disable)
603 info->data->disable(info);
605 if (device_may_wakeup(dev) && !info->wake_en) {
606 if (enable_irq_wake(info->irq_alarm) == 0)
607 info->wake_en = true;
608 else
609 dev_err(dev, "enable_irq_wake failed\n");
612 return 0;
615 static int s3c_rtc_resume(struct device *dev)
617 struct s3c_rtc *info = dev_get_drvdata(dev);
619 if (info->data->enable)
620 info->data->enable(info);
622 if (info->data->restore_tick_cnt)
623 info->data->restore_tick_cnt(info);
625 s3c_rtc_disable_clk(info);
627 if (device_may_wakeup(dev) && info->wake_en) {
628 disable_irq_wake(info->irq_alarm);
629 info->wake_en = false;
632 return 0;
634 #endif
635 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
637 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
639 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
642 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
644 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
645 writeb(mask, info->base + S3C2410_INTP);
648 static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
650 unsigned int tmp = 0;
651 int val;
653 tmp = readb(info->base + S3C2410_TICNT);
654 tmp &= S3C2410_TICNT_ENABLE;
656 val = (info->rtc->max_user_freq / freq) - 1;
657 tmp |= val;
659 writel(tmp, info->base + S3C2410_TICNT);
662 static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
664 unsigned int tmp = 0;
665 int val;
667 tmp = readb(info->base + S3C2410_TICNT);
668 tmp &= S3C2410_TICNT_ENABLE;
670 val = (info->rtc->max_user_freq / freq) - 1;
672 tmp |= S3C2443_TICNT_PART(val);
673 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
675 writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
677 writel(tmp, info->base + S3C2410_TICNT);
680 static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
682 unsigned int tmp = 0;
683 int val;
685 tmp = readb(info->base + S3C2410_TICNT);
686 tmp &= S3C2410_TICNT_ENABLE;
688 val = (info->rtc->max_user_freq / freq) - 1;
690 tmp |= S3C2443_TICNT_PART(val);
691 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
693 writel(tmp, info->base + S3C2410_TICNT);
696 static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
698 int val;
700 val = (info->rtc->max_user_freq / freq) - 1;
701 writel(val, info->base + S3C2410_TICNT);
704 static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
706 unsigned int ticnt;
708 ticnt = readb(info->base + S3C2410_TICNT);
709 ticnt &= S3C2410_TICNT_ENABLE;
711 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
714 static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
716 unsigned int con;
718 con = readw(info->base + S3C2410_RTCCON);
719 con |= S3C2443_RTCCON_TICSEL;
720 writew(con, info->base + S3C2410_RTCCON);
723 static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
725 unsigned int ticnt;
727 ticnt = readw(info->base + S3C2410_RTCCON);
728 ticnt &= S3C64XX_RTCCON_TICEN;
730 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
733 static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
735 info->ticnt_save = readb(info->base + S3C2410_TICNT);
738 static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
740 writeb(info->ticnt_save, info->base + S3C2410_TICNT);
743 static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
745 info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
746 info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
747 info->ticnt_save = readl(info->base + S3C2410_TICNT);
750 static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
752 unsigned int con;
754 writel(info->ticnt_save, info->base + S3C2410_TICNT);
755 if (info->ticnt_en_save) {
756 con = readw(info->base + S3C2410_RTCCON);
757 writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON);
761 static struct s3c_rtc_data const s3c2410_rtc_data = {
762 .max_user_freq = 128,
763 .irq_handler = s3c24xx_rtc_irq,
764 .set_freq = s3c2410_rtc_setfreq,
765 .enable_tick = s3c24xx_rtc_enable_tick,
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,
772 static struct s3c_rtc_data const s3c2416_rtc_data = {
773 .max_user_freq = 32768,
774 .irq_handler = s3c24xx_rtc_irq,
775 .set_freq = s3c2416_rtc_setfreq,
776 .enable_tick = s3c24xx_rtc_enable_tick,
777 .select_tick_clk = s3c2416_rtc_select_tick_clk,
778 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
779 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
780 .enable = s3c24xx_rtc_enable,
781 .disable = s3c24xx_rtc_disable,
784 static struct s3c_rtc_data const s3c2443_rtc_data = {
785 .max_user_freq = 32768,
786 .irq_handler = s3c24xx_rtc_irq,
787 .set_freq = s3c2443_rtc_setfreq,
788 .enable_tick = s3c24xx_rtc_enable_tick,
789 .select_tick_clk = s3c2416_rtc_select_tick_clk,
790 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
791 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
792 .enable = s3c24xx_rtc_enable,
793 .disable = s3c24xx_rtc_disable,
796 static struct s3c_rtc_data const s3c6410_rtc_data = {
797 .max_user_freq = 32768,
798 .needs_src_clk = true,
799 .irq_handler = s3c6410_rtc_irq,
800 .set_freq = s3c6410_rtc_setfreq,
801 .enable_tick = s3c6410_rtc_enable_tick,
802 .save_tick_cnt = s3c6410_rtc_save_tick_cnt,
803 .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
804 .enable = s3c24xx_rtc_enable,
805 .disable = s3c6410_rtc_disable,
808 static const struct of_device_id s3c_rtc_dt_match[] = {
810 .compatible = "samsung,s3c2410-rtc",
811 .data = &s3c2410_rtc_data,
812 }, {
813 .compatible = "samsung,s3c2416-rtc",
814 .data = &s3c2416_rtc_data,
815 }, {
816 .compatible = "samsung,s3c2443-rtc",
817 .data = &s3c2443_rtc_data,
818 }, {
819 .compatible = "samsung,s3c6410-rtc",
820 .data = &s3c6410_rtc_data,
821 }, {
822 .compatible = "samsung,exynos3250-rtc",
823 .data = &s3c6410_rtc_data,
825 { /* sentinel */ },
827 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
829 static struct platform_driver s3c_rtc_driver = {
830 .probe = s3c_rtc_probe,
831 .remove = s3c_rtc_remove,
832 .driver = {
833 .name = "s3c-rtc",
834 .pm = &s3c_rtc_pm_ops,
835 .of_match_table = of_match_ptr(s3c_rtc_dt_match),
838 module_platform_driver(s3c_rtc_driver);
840 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
841 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
842 MODULE_LICENSE("GPL");
843 MODULE_ALIAS("platform:s3c2410-rtc");