]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/rtc/rtc-s3c.c
Merge tag 'mips_fixes_5.1_1' into mips-next
[thirdparty/kernel/stable.git] / drivers / rtc / rtc-s3c.c
1 /* drivers/rtc/rtc-s3c.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * Copyright (c) 2004,2006 Simtec Electronics
7 * Ben Dooks, <ben@simtec.co.uk>
8 * http://armlinux.simtec.co.uk/
9 *
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.
13 *
14 * S3C2410/S3C2440/S3C24XX Internal RTC Driver
15 */
16
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>
32
33 #include <asm/irq.h>
34 #include "rtc-s3c.h"
35
36 struct s3c_rtc {
37 struct device *dev;
38 struct rtc_device *rtc;
39
40 void __iomem *base;
41 struct clk *rtc_clk;
42 struct clk *rtc_src_clk;
43 bool alarm_enabled;
44
45 const struct s3c_rtc_data *data;
46
47 int irq_alarm;
48 int irq_tick;
49
50 spinlock_t pie_lock;
51 spinlock_t alarm_lock;
52
53 int ticnt_save;
54 int ticnt_en_save;
55 bool wake_en;
56 };
57
58 struct s3c_rtc_data {
59 int max_user_freq;
60 bool needs_src_clk;
61
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);
70 };
71
72 static int s3c_rtc_enable_clk(struct s3c_rtc *info)
73 {
74 int ret;
75
76 ret = clk_enable(info->rtc_clk);
77 if (ret)
78 return ret;
79
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;
85 }
86 }
87 return 0;
88 }
89
90 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
91 {
92 if (info->data->needs_src_clk)
93 clk_disable(info->rtc_src_clk);
94 clk_disable(info->rtc_clk);
95 }
96
97 /* IRQ Handlers */
98 static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
99 {
100 struct s3c_rtc *info = (struct s3c_rtc *)id;
101
102 if (info->data->irq_handler)
103 info->data->irq_handler(info, S3C2410_INTP_TIC);
104
105 return IRQ_HANDLED;
106 }
107
108 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
109 {
110 struct s3c_rtc *info = (struct s3c_rtc *)id;
111
112 if (info->data->irq_handler)
113 info->data->irq_handler(info, S3C2410_INTP_ALM);
114
115 return IRQ_HANDLED;
116 }
117
118 /* Update control registers */
119 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
120 {
121 struct s3c_rtc *info = dev_get_drvdata(dev);
122 unsigned long flags;
123 unsigned int tmp;
124 int ret;
125
126 dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
127
128 ret = s3c_rtc_enable_clk(info);
129 if (ret)
130 return ret;
131
132 tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
133
134 if (enabled)
135 tmp |= S3C2410_RTCALM_ALMEN;
136
137 writeb(tmp, info->base + S3C2410_RTCALM);
138
139 spin_lock_irqsave(&info->alarm_lock, flags);
140
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);
145
146 info->alarm_enabled = enabled;
147 spin_unlock_irqrestore(&info->alarm_lock, flags);
148
149 s3c_rtc_disable_clk(info);
150
151 return ret;
152 }
153
154 /* Set RTC frequency */
155 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
156 {
157 int ret;
158
159 if (!is_power_of_2(freq))
160 return -EINVAL;
161
162 ret = s3c_rtc_enable_clk(info);
163 if (ret)
164 return ret;
165 spin_lock_irq(&info->pie_lock);
166
167 if (info->data->set_freq)
168 info->data->set_freq(info, freq);
169
170 spin_unlock_irq(&info->pie_lock);
171 s3c_rtc_disable_clk(info);
172
173 return 0;
174 }
175
176 /* Time read/write */
177 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
178 {
179 struct s3c_rtc *info = dev_get_drvdata(dev);
180 unsigned int have_retried = 0;
181 int ret;
182
183 ret = s3c_rtc_enable_clk(info);
184 if (ret)
185 return ret;
186
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);
194
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
198 */
199
200 if (rtc_tm->tm_sec == 0 && !have_retried) {
201 have_retried = 1;
202 goto retry_get_time;
203 }
204
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);
211
212 s3c_rtc_disable_clk(info);
213
214 rtc_tm->tm_year += 100;
215 rtc_tm->tm_mon -= 1;
216
217 dev_dbg(dev, "read time %ptR\n", rtc_tm);
218 return 0;
219 }
220
221 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
222 {
223 struct s3c_rtc *info = dev_get_drvdata(dev);
224 int year = tm->tm_year - 100;
225 int ret;
226
227 dev_dbg(dev, "set time %ptR\n", tm);
228
229 /* we get around y2k by simply not supporting it */
230
231 if (year < 0 || year >= 100) {
232 dev_err(dev, "rtc only supports 100 years\n");
233 return -EINVAL;
234 }
235
236 ret = s3c_rtc_enable_clk(info);
237 if (ret)
238 return ret;
239
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);
246
247 s3c_rtc_disable_clk(info);
248
249 return 0;
250 }
251
252 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
253 {
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;
258
259 ret = s3c_rtc_enable_clk(info);
260 if (ret)
261 return ret;
262
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);
269
270 alm_en = readb(info->base + S3C2410_RTCALM);
271
272 s3c_rtc_disable_clk(info);
273
274 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
275
276 dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
277
278 /* decode the alarm enable field */
279 if (alm_en & S3C2410_RTCALM_SECEN)
280 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
281
282 if (alm_en & S3C2410_RTCALM_MINEN)
283 alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
284
285 if (alm_en & S3C2410_RTCALM_HOUREN)
286 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
287
288 if (alm_en & S3C2410_RTCALM_DAYEN)
289 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
290
291 if (alm_en & S3C2410_RTCALM_MONEN) {
292 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
293 alm_tm->tm_mon -= 1;
294 }
295
296 if (alm_en & S3C2410_RTCALM_YEAREN)
297 alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
298
299 return 0;
300 }
301
302 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
303 {
304 struct s3c_rtc *info = dev_get_drvdata(dev);
305 struct rtc_time *tm = &alrm->time;
306 unsigned int alrm_en;
307 int ret;
308
309 dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
310
311 ret = s3c_rtc_enable_clk(info);
312 if (ret)
313 return ret;
314
315 alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
316 writeb(0x00, info->base + S3C2410_RTCALM);
317
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);
321 }
322
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);
326 }
327
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);
331 }
332
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);
336 }
337
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);
341 }
342
343 dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
344
345 writeb(alrm_en, info->base + S3C2410_RTCALM);
346
347 s3c_rtc_setaie(dev, alrm->enabled);
348
349 s3c_rtc_disable_clk(info);
350
351 return 0;
352 }
353
354 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
355 {
356 struct s3c_rtc *info = dev_get_drvdata(dev);
357 int ret;
358
359 ret = s3c_rtc_enable_clk(info);
360 if (ret)
361 return ret;
362
363 if (info->data->enable_tick)
364 info->data->enable_tick(info, seq);
365
366 s3c_rtc_disable_clk(info);
367
368 return 0;
369 }
370
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,
378 };
379
380 static void s3c24xx_rtc_enable(struct s3c_rtc *info)
381 {
382 unsigned int con, tmp;
383
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");
388
389 tmp = readw(info->base + S3C2410_RTCCON);
390 writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
391 }
392
393 if (con & S3C2410_RTCCON_CNTSEL) {
394 dev_info(info->dev, "removing RTCCON_CNTSEL\n");
395
396 tmp = readw(info->base + S3C2410_RTCCON);
397 writew(tmp & ~S3C2410_RTCCON_CNTSEL,
398 info->base + S3C2410_RTCCON);
399 }
400
401 if (con & S3C2410_RTCCON_CLKRST) {
402 dev_info(info->dev, "removing RTCCON_CLKRST\n");
403
404 tmp = readw(info->base + S3C2410_RTCCON);
405 writew(tmp & ~S3C2410_RTCCON_CLKRST,
406 info->base + S3C2410_RTCCON);
407 }
408 }
409
410 static void s3c24xx_rtc_disable(struct s3c_rtc *info)
411 {
412 unsigned int con;
413
414 con = readw(info->base + S3C2410_RTCCON);
415 con &= ~S3C2410_RTCCON_RTCEN;
416 writew(con, info->base + S3C2410_RTCCON);
417
418 con = readb(info->base + S3C2410_TICNT);
419 con &= ~S3C2410_TICNT_ENABLE;
420 writeb(con, info->base + S3C2410_TICNT);
421 }
422
423 static void s3c6410_rtc_disable(struct s3c_rtc *info)
424 {
425 unsigned int con;
426
427 con = readw(info->base + S3C2410_RTCCON);
428 con &= ~S3C64XX_RTCCON_TICEN;
429 con &= ~S3C2410_RTCCON_RTCEN;
430 writew(con, info->base + S3C2410_RTCCON);
431 }
432
433 static int s3c_rtc_remove(struct platform_device *pdev)
434 {
435 struct s3c_rtc *info = platform_get_drvdata(pdev);
436
437 s3c_rtc_setaie(info->dev, 0);
438
439 if (info->data->needs_src_clk)
440 clk_unprepare(info->rtc_src_clk);
441 clk_unprepare(info->rtc_clk);
442
443 return 0;
444 }
445
446 static int s3c_rtc_probe(struct platform_device *pdev)
447 {
448 struct s3c_rtc *info = NULL;
449 struct rtc_time rtc_tm;
450 struct resource *res;
451 int ret;
452
453 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
454 if (!info)
455 return -ENOMEM;
456
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;
462 }
463
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;
469 }
470 spin_lock_init(&info->pie_lock);
471 spin_lock_init(&info->alarm_lock);
472
473 platform_set_drvdata(pdev, info);
474
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;
479 }
480
481 dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
482 info->irq_tick, info->irq_alarm);
483
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);
489
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;
498 }
499 ret = clk_prepare_enable(info->rtc_clk);
500 if (ret)
501 return ret;
502
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;
514 }
515 ret = clk_prepare_enable(info->rtc_src_clk);
516 if (ret)
517 goto err_src_clk;
518 }
519
520 /* check to see if everything is setup correctly */
521 if (info->data->enable)
522 info->data->enable(info);
523
524 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
525 readw(info->base + S3C2410_RTCCON));
526
527 device_init_wakeup(&pdev->dev, 1);
528
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;
537
538 s3c_rtc_settime(&pdev->dev, &rtc_tm);
539
540 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
541 }
542
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;
550 }
551
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;
557 }
558
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;
564 }
565
566 if (info->data->select_tick_clk)
567 info->data->select_tick_clk(info);
568
569 s3c_rtc_setfreq(info, 1);
570
571 s3c_rtc_disable_clk(info);
572
573 return 0;
574
575 err_nortc:
576 if (info->data->disable)
577 info->data->disable(info);
578
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);
583
584 return ret;
585 }
586
587 #ifdef CONFIG_PM_SLEEP
588
589 static int s3c_rtc_suspend(struct device *dev)
590 {
591 struct s3c_rtc *info = dev_get_drvdata(dev);
592 int ret;
593
594 ret = s3c_rtc_enable_clk(info);
595 if (ret)
596 return ret;
597
598 /* save TICNT for anyone using periodic interrupts */
599 if (info->data->save_tick_cnt)
600 info->data->save_tick_cnt(info);
601
602 if (info->data->disable)
603 info->data->disable(info);
604
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");
610 }
611
612 return 0;
613 }
614
615 static int s3c_rtc_resume(struct device *dev)
616 {
617 struct s3c_rtc *info = dev_get_drvdata(dev);
618
619 if (info->data->enable)
620 info->data->enable(info);
621
622 if (info->data->restore_tick_cnt)
623 info->data->restore_tick_cnt(info);
624
625 s3c_rtc_disable_clk(info);
626
627 if (device_may_wakeup(dev) && info->wake_en) {
628 disable_irq_wake(info->irq_alarm);
629 info->wake_en = false;
630 }
631
632 return 0;
633 }
634 #endif
635 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
636
637 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
638 {
639 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
640 }
641
642 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
643 {
644 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
645 writeb(mask, info->base + S3C2410_INTP);
646 }
647
648 static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
649 {
650 unsigned int tmp = 0;
651 int val;
652
653 tmp = readb(info->base + S3C2410_TICNT);
654 tmp &= S3C2410_TICNT_ENABLE;
655
656 val = (info->rtc->max_user_freq / freq) - 1;
657 tmp |= val;
658
659 writel(tmp, info->base + S3C2410_TICNT);
660 }
661
662 static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
663 {
664 unsigned int tmp = 0;
665 int val;
666
667 tmp = readb(info->base + S3C2410_TICNT);
668 tmp &= S3C2410_TICNT_ENABLE;
669
670 val = (info->rtc->max_user_freq / freq) - 1;
671
672 tmp |= S3C2443_TICNT_PART(val);
673 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
674
675 writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
676
677 writel(tmp, info->base + S3C2410_TICNT);
678 }
679
680 static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
681 {
682 unsigned int tmp = 0;
683 int val;
684
685 tmp = readb(info->base + S3C2410_TICNT);
686 tmp &= S3C2410_TICNT_ENABLE;
687
688 val = (info->rtc->max_user_freq / freq) - 1;
689
690 tmp |= S3C2443_TICNT_PART(val);
691 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
692
693 writel(tmp, info->base + S3C2410_TICNT);
694 }
695
696 static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
697 {
698 int val;
699
700 val = (info->rtc->max_user_freq / freq) - 1;
701 writel(val, info->base + S3C2410_TICNT);
702 }
703
704 static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
705 {
706 unsigned int ticnt;
707
708 ticnt = readb(info->base + S3C2410_TICNT);
709 ticnt &= S3C2410_TICNT_ENABLE;
710
711 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
712 }
713
714 static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
715 {
716 unsigned int con;
717
718 con = readw(info->base + S3C2410_RTCCON);
719 con |= S3C2443_RTCCON_TICSEL;
720 writew(con, info->base + S3C2410_RTCCON);
721 }
722
723 static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
724 {
725 unsigned int ticnt;
726
727 ticnt = readw(info->base + S3C2410_RTCCON);
728 ticnt &= S3C64XX_RTCCON_TICEN;
729
730 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
731 }
732
733 static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
734 {
735 info->ticnt_save = readb(info->base + S3C2410_TICNT);
736 }
737
738 static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
739 {
740 writeb(info->ticnt_save, info->base + S3C2410_TICNT);
741 }
742
743 static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
744 {
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);
748 }
749
750 static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
751 {
752 unsigned int con;
753
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);
758 }
759 }
760
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,
770 };
771
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,
782 };
783
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,
794 };
795
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,
806 };
807
808 static const struct of_device_id s3c_rtc_dt_match[] = {
809 {
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,
824 },
825 { /* sentinel */ },
826 };
827 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
828
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),
836 },
837 };
838 module_platform_driver(s3c_rtc_driver);
839
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");