xref: /openbmc/linux/drivers/rtc/rtc-s3c.c (revision d0bd7f2a)
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/uaccess.h>
30 #include <linux/io.h>
31 
32 #include <asm/irq.h>
33 #include "rtc-s3c.h"
34 
35 struct s3c_rtc {
36 	struct device *dev;
37 	struct rtc_device *rtc;
38 
39 	void __iomem *base;
40 	struct clk *rtc_clk;
41 	struct clk *rtc_src_clk;
42 
43 	struct s3c_rtc_data *data;
44 
45 	int irq_alarm;
46 	int irq_tick;
47 
48 	spinlock_t pie_lock;
49 	spinlock_t alarm_clk_lock;
50 
51 	int ticnt_save, ticnt_en_save;
52 	bool wake_en;
53 };
54 
55 struct s3c_rtc_data {
56 	int max_user_freq;
57 	bool needs_src_clk;
58 
59 	void (*irq_handler) (struct s3c_rtc *info, int mask);
60 	void (*set_freq) (struct s3c_rtc *info, int freq);
61 	void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
62 	void (*select_tick_clk) (struct s3c_rtc *info);
63 	void (*save_tick_cnt) (struct s3c_rtc *info);
64 	void (*restore_tick_cnt) (struct s3c_rtc *info);
65 	void (*enable) (struct s3c_rtc *info);
66 	void (*disable) (struct s3c_rtc *info);
67 };
68 
69 static void s3c_rtc_enable_clk(struct s3c_rtc *info)
70 {
71 	unsigned long irq_flags;
72 
73 	spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
74 	clk_enable(info->rtc_clk);
75 	if (info->data->needs_src_clk)
76 		clk_enable(info->rtc_src_clk);
77 	spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
78 }
79 
80 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
81 {
82 	unsigned long irq_flags;
83 
84 	spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
85 	if (info->data->needs_src_clk)
86 		clk_disable(info->rtc_src_clk);
87 	clk_disable(info->rtc_clk);
88 	spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
89 }
90 
91 /* IRQ Handlers */
92 static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
93 {
94 	struct s3c_rtc *info = (struct s3c_rtc *)id;
95 
96 	if (info->data->irq_handler)
97 		info->data->irq_handler(info, S3C2410_INTP_TIC);
98 
99 	return IRQ_HANDLED;
100 }
101 
102 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
103 {
104 	struct s3c_rtc *info = (struct s3c_rtc *)id;
105 
106 	if (info->data->irq_handler)
107 		info->data->irq_handler(info, S3C2410_INTP_ALM);
108 
109 	return IRQ_HANDLED;
110 }
111 
112 /* Update control registers */
113 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
114 {
115 	struct s3c_rtc *info = dev_get_drvdata(dev);
116 	unsigned int tmp;
117 
118 	dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
119 
120 	s3c_rtc_enable_clk(info);
121 
122 	tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
123 
124 	if (enabled)
125 		tmp |= S3C2410_RTCALM_ALMEN;
126 
127 	writeb(tmp, info->base + S3C2410_RTCALM);
128 
129 	s3c_rtc_disable_clk(info);
130 
131 	return 0;
132 }
133 
134 /* Set RTC frequency */
135 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
136 {
137 	if (!is_power_of_2(freq))
138 		return -EINVAL;
139 
140 	spin_lock_irq(&info->pie_lock);
141 
142 	if (info->data->set_freq)
143 		info->data->set_freq(info, freq);
144 
145 	spin_unlock_irq(&info->pie_lock);
146 
147 	return 0;
148 }
149 
150 /* Time read/write */
151 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
152 {
153 	struct s3c_rtc *info = dev_get_drvdata(dev);
154 	unsigned int have_retried = 0;
155 
156 	s3c_rtc_enable_clk(info);
157 
158  retry_get_time:
159 	rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
160 	rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
161 	rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
162 	rtc_tm->tm_mon  = readb(info->base + S3C2410_RTCMON);
163 	rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
164 	rtc_tm->tm_sec  = readb(info->base + S3C2410_RTCSEC);
165 
166 	/* the only way to work out whether the system was mid-update
167 	 * when we read it is to check the second counter, and if it
168 	 * is zero, then we re-try the entire read
169 	 */
170 
171 	if (rtc_tm->tm_sec == 0 && !have_retried) {
172 		have_retried = 1;
173 		goto retry_get_time;
174 	}
175 
176 	rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
177 	rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
178 	rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
179 	rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
180 	rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
181 	rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
182 
183 	s3c_rtc_disable_clk(info);
184 
185 	rtc_tm->tm_year += 100;
186 
187 	dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
188 		 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
189 		 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
190 
191 	rtc_tm->tm_mon -= 1;
192 
193 	return rtc_valid_tm(rtc_tm);
194 }
195 
196 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
197 {
198 	struct s3c_rtc *info = dev_get_drvdata(dev);
199 	int year = tm->tm_year - 100;
200 
201 	dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
202 		 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
203 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
204 
205 	/* we get around y2k by simply not supporting it */
206 
207 	if (year < 0 || year >= 100) {
208 		dev_err(dev, "rtc only supports 100 years\n");
209 		return -EINVAL;
210 	}
211 
212 	s3c_rtc_enable_clk(info);
213 
214 	writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
215 	writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
216 	writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
217 	writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
218 	writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
219 	writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
220 
221 	s3c_rtc_disable_clk(info);
222 
223 	return 0;
224 }
225 
226 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
227 {
228 	struct s3c_rtc *info = dev_get_drvdata(dev);
229 	struct rtc_time *alm_tm = &alrm->time;
230 	unsigned int alm_en;
231 
232 	s3c_rtc_enable_clk(info);
233 
234 	alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
235 	alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
236 	alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
237 	alm_tm->tm_mon  = readb(info->base + S3C2410_ALMMON);
238 	alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
239 	alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
240 
241 	alm_en = readb(info->base + S3C2410_RTCALM);
242 
243 	s3c_rtc_disable_clk(info);
244 
245 	alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
246 
247 	dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
248 		 alm_en,
249 		 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
250 		 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
251 
252 	/* decode the alarm enable field */
253 	if (alm_en & S3C2410_RTCALM_SECEN)
254 		alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
255 	else
256 		alm_tm->tm_sec = -1;
257 
258 	if (alm_en & S3C2410_RTCALM_MINEN)
259 		alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
260 	else
261 		alm_tm->tm_min = -1;
262 
263 	if (alm_en & S3C2410_RTCALM_HOUREN)
264 		alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
265 	else
266 		alm_tm->tm_hour = -1;
267 
268 	if (alm_en & S3C2410_RTCALM_DAYEN)
269 		alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
270 	else
271 		alm_tm->tm_mday = -1;
272 
273 	if (alm_en & S3C2410_RTCALM_MONEN) {
274 		alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
275 		alm_tm->tm_mon -= 1;
276 	} else {
277 		alm_tm->tm_mon = -1;
278 	}
279 
280 	if (alm_en & S3C2410_RTCALM_YEAREN)
281 		alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
282 	else
283 		alm_tm->tm_year = -1;
284 
285 	return 0;
286 }
287 
288 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
289 {
290 	struct s3c_rtc *info = dev_get_drvdata(dev);
291 	struct rtc_time *tm = &alrm->time;
292 	unsigned int alrm_en;
293 
294 	dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
295 		 alrm->enabled,
296 		 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
297 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
298 
299 	s3c_rtc_enable_clk(info);
300 
301 	alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
302 	writeb(0x00, info->base + S3C2410_RTCALM);
303 
304 	if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
305 		alrm_en |= S3C2410_RTCALM_SECEN;
306 		writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
307 	}
308 
309 	if (tm->tm_min < 60 && tm->tm_min >= 0) {
310 		alrm_en |= S3C2410_RTCALM_MINEN;
311 		writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
312 	}
313 
314 	if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
315 		alrm_en |= S3C2410_RTCALM_HOUREN;
316 		writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
317 	}
318 
319 	dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
320 
321 	writeb(alrm_en, info->base + S3C2410_RTCALM);
322 
323 	s3c_rtc_disable_clk(info);
324 
325 	s3c_rtc_setaie(dev, alrm->enabled);
326 
327 	return 0;
328 }
329 
330 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
331 {
332 	struct s3c_rtc *info = dev_get_drvdata(dev);
333 
334 	s3c_rtc_enable_clk(info);
335 
336 	if (info->data->enable_tick)
337 		info->data->enable_tick(info, seq);
338 
339 	s3c_rtc_disable_clk(info);
340 
341 	return 0;
342 }
343 
344 static const struct rtc_class_ops s3c_rtcops = {
345 	.read_time	= s3c_rtc_gettime,
346 	.set_time	= s3c_rtc_settime,
347 	.read_alarm	= s3c_rtc_getalarm,
348 	.set_alarm	= s3c_rtc_setalarm,
349 	.proc		= s3c_rtc_proc,
350 	.alarm_irq_enable = s3c_rtc_setaie,
351 };
352 
353 static void s3c24xx_rtc_enable(struct s3c_rtc *info)
354 {
355 	unsigned int con, tmp;
356 
357 	con = readw(info->base + S3C2410_RTCCON);
358 	/* re-enable the device, and check it is ok */
359 	if ((con & S3C2410_RTCCON_RTCEN) == 0) {
360 		dev_info(info->dev, "rtc disabled, re-enabling\n");
361 
362 		tmp = readw(info->base + S3C2410_RTCCON);
363 		writew(tmp | S3C2410_RTCCON_RTCEN,
364 			info->base + S3C2410_RTCCON);
365 	}
366 
367 	if (con & S3C2410_RTCCON_CNTSEL) {
368 		dev_info(info->dev, "removing RTCCON_CNTSEL\n");
369 
370 		tmp = readw(info->base + S3C2410_RTCCON);
371 		writew(tmp & ~S3C2410_RTCCON_CNTSEL,
372 			info->base + S3C2410_RTCCON);
373 	}
374 
375 	if (con & S3C2410_RTCCON_CLKRST) {
376 		dev_info(info->dev, "removing RTCCON_CLKRST\n");
377 
378 		tmp = readw(info->base + S3C2410_RTCCON);
379 		writew(tmp & ~S3C2410_RTCCON_CLKRST,
380 			info->base + S3C2410_RTCCON);
381 	}
382 }
383 
384 static void s3c24xx_rtc_disable(struct s3c_rtc *info)
385 {
386 	unsigned int con;
387 
388 	con = readw(info->base + S3C2410_RTCCON);
389 	con &= ~S3C2410_RTCCON_RTCEN;
390 	writew(con, info->base + S3C2410_RTCCON);
391 
392 	con = readb(info->base + S3C2410_TICNT);
393 	con &= ~S3C2410_TICNT_ENABLE;
394 	writeb(con, info->base + S3C2410_TICNT);
395 }
396 
397 static void s3c6410_rtc_disable(struct s3c_rtc *info)
398 {
399 	unsigned int con;
400 
401 	con = readw(info->base + S3C2410_RTCCON);
402 	con &= ~S3C64XX_RTCCON_TICEN;
403 	con &= ~S3C2410_RTCCON_RTCEN;
404 	writew(con, info->base + S3C2410_RTCCON);
405 }
406 
407 static int s3c_rtc_remove(struct platform_device *pdev)
408 {
409 	struct s3c_rtc *info = platform_get_drvdata(pdev);
410 
411 	s3c_rtc_setaie(info->dev, 0);
412 
413 	clk_unprepare(info->rtc_clk);
414 	info->rtc_clk = NULL;
415 
416 	return 0;
417 }
418 
419 static const struct of_device_id s3c_rtc_dt_match[];
420 
421 static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
422 {
423 	const struct of_device_id *match;
424 
425 	match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
426 	return (struct s3c_rtc_data *)match->data;
427 }
428 
429 static int s3c_rtc_probe(struct platform_device *pdev)
430 {
431 	struct s3c_rtc *info = NULL;
432 	struct rtc_time rtc_tm;
433 	struct resource *res;
434 	int ret;
435 
436 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
437 	if (!info)
438 		return -ENOMEM;
439 
440 	/* find the IRQs */
441 	info->irq_tick = platform_get_irq(pdev, 1);
442 	if (info->irq_tick < 0) {
443 		dev_err(&pdev->dev, "no irq for rtc tick\n");
444 		return info->irq_tick;
445 	}
446 
447 	info->dev = &pdev->dev;
448 	info->data = s3c_rtc_get_data(pdev);
449 	if (!info->data) {
450 		dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
451 		return -EINVAL;
452 	}
453 	spin_lock_init(&info->pie_lock);
454 	spin_lock_init(&info->alarm_clk_lock);
455 
456 	platform_set_drvdata(pdev, info);
457 
458 	info->irq_alarm = platform_get_irq(pdev, 0);
459 	if (info->irq_alarm < 0) {
460 		dev_err(&pdev->dev, "no irq for alarm\n");
461 		return info->irq_alarm;
462 	}
463 
464 	dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
465 		 info->irq_tick, info->irq_alarm);
466 
467 	/* get the memory region */
468 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
469 	info->base = devm_ioremap_resource(&pdev->dev, res);
470 	if (IS_ERR(info->base))
471 		return PTR_ERR(info->base);
472 
473 	info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
474 	if (IS_ERR(info->rtc_clk)) {
475 		dev_err(&pdev->dev, "failed to find rtc clock\n");
476 		return PTR_ERR(info->rtc_clk);
477 	}
478 	clk_prepare_enable(info->rtc_clk);
479 
480 	if (info->data->needs_src_clk) {
481 		info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
482 		if (IS_ERR(info->rtc_src_clk)) {
483 			dev_err(&pdev->dev,
484 				"failed to find rtc source clock\n");
485 			return PTR_ERR(info->rtc_src_clk);
486 		}
487 		clk_prepare_enable(info->rtc_src_clk);
488 	}
489 
490 	/* check to see if everything is setup correctly */
491 	if (info->data->enable)
492 		info->data->enable(info);
493 
494 	dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
495 		 readw(info->base + S3C2410_RTCCON));
496 
497 	device_init_wakeup(&pdev->dev, 1);
498 
499 	/* Check RTC Time */
500 	if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) {
501 		rtc_tm.tm_year	= 100;
502 		rtc_tm.tm_mon	= 0;
503 		rtc_tm.tm_mday	= 1;
504 		rtc_tm.tm_hour	= 0;
505 		rtc_tm.tm_min	= 0;
506 		rtc_tm.tm_sec	= 0;
507 
508 		s3c_rtc_settime(&pdev->dev, &rtc_tm);
509 
510 		dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
511 	}
512 
513 	/* register RTC and exit */
514 	info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
515 				  THIS_MODULE);
516 	if (IS_ERR(info->rtc)) {
517 		dev_err(&pdev->dev, "cannot attach rtc\n");
518 		ret = PTR_ERR(info->rtc);
519 		goto err_nortc;
520 	}
521 
522 	ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
523 			  0,  "s3c2410-rtc alarm", info);
524 	if (ret) {
525 		dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
526 		goto err_nortc;
527 	}
528 
529 	ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
530 			  0,  "s3c2410-rtc tick", info);
531 	if (ret) {
532 		dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
533 		goto err_nortc;
534 	}
535 
536 	if (info->data->select_tick_clk)
537 		info->data->select_tick_clk(info);
538 
539 	s3c_rtc_setfreq(info, 1);
540 
541 	s3c_rtc_disable_clk(info);
542 
543 	return 0;
544 
545  err_nortc:
546 	if (info->data->disable)
547 		info->data->disable(info);
548 
549 	if (info->data->needs_src_clk)
550 		clk_disable_unprepare(info->rtc_src_clk);
551 	clk_disable_unprepare(info->rtc_clk);
552 
553 	return ret;
554 }
555 
556 #ifdef CONFIG_PM_SLEEP
557 
558 static int s3c_rtc_suspend(struct device *dev)
559 {
560 	struct s3c_rtc *info = dev_get_drvdata(dev);
561 
562 	s3c_rtc_enable_clk(info);
563 
564 	/* save TICNT for anyone using periodic interrupts */
565 	if (info->data->save_tick_cnt)
566 		info->data->save_tick_cnt(info);
567 
568 	if (info->data->disable)
569 		info->data->disable(info);
570 
571 	if (device_may_wakeup(dev) && !info->wake_en) {
572 		if (enable_irq_wake(info->irq_alarm) == 0)
573 			info->wake_en = true;
574 		else
575 			dev_err(dev, "enable_irq_wake failed\n");
576 	}
577 
578 	return 0;
579 }
580 
581 static int s3c_rtc_resume(struct device *dev)
582 {
583 	struct s3c_rtc *info = dev_get_drvdata(dev);
584 
585 	if (info->data->enable)
586 		info->data->enable(info);
587 
588 	if (info->data->restore_tick_cnt)
589 		info->data->restore_tick_cnt(info);
590 
591 	s3c_rtc_disable_clk(info);
592 
593 	if (device_may_wakeup(dev) && info->wake_en) {
594 		disable_irq_wake(info->irq_alarm);
595 		info->wake_en = false;
596 	}
597 
598 	return 0;
599 }
600 #endif
601 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
602 
603 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
604 {
605 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
606 }
607 
608 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
609 {
610 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
611 	writeb(mask, info->base + S3C2410_INTP);
612 }
613 
614 static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
615 {
616 	unsigned int tmp = 0;
617 	int val;
618 
619 	tmp = readb(info->base + S3C2410_TICNT);
620 	tmp &= S3C2410_TICNT_ENABLE;
621 
622 	val = (info->rtc->max_user_freq / freq) - 1;
623 	tmp |= val;
624 
625 	writel(tmp, info->base + S3C2410_TICNT);
626 }
627 
628 static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
629 {
630 	unsigned int tmp = 0;
631 	int val;
632 
633 	tmp = readb(info->base + S3C2410_TICNT);
634 	tmp &= S3C2410_TICNT_ENABLE;
635 
636 	val = (info->rtc->max_user_freq / freq) - 1;
637 
638 	tmp |= S3C2443_TICNT_PART(val);
639 	writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
640 
641 	writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2);
642 
643 	writel(tmp, info->base + S3C2410_TICNT);
644 }
645 
646 static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
647 {
648 	unsigned int tmp = 0;
649 	int val;
650 
651 	tmp = readb(info->base + S3C2410_TICNT);
652 	tmp &= S3C2410_TICNT_ENABLE;
653 
654 	val = (info->rtc->max_user_freq / freq) - 1;
655 
656 	tmp |= S3C2443_TICNT_PART(val);
657 	writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1);
658 
659 	writel(tmp, info->base + S3C2410_TICNT);
660 }
661 
662 static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
663 {
664 	int val;
665 
666 	val = (info->rtc->max_user_freq / freq) - 1;
667 	writel(val, info->base + S3C2410_TICNT);
668 }
669 
670 static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
671 {
672 	unsigned int ticnt;
673 
674 	ticnt = readb(info->base + S3C2410_TICNT);
675 	ticnt &= S3C2410_TICNT_ENABLE;
676 
677 	seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
678 }
679 
680 static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
681 {
682 	unsigned int con;
683 
684 	con = readw(info->base + S3C2410_RTCCON);
685 	con |= S3C2443_RTCCON_TICSEL;
686 	writew(con, info->base + S3C2410_RTCCON);
687 }
688 
689 static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
690 {
691 	unsigned int ticnt;
692 
693 	ticnt = readw(info->base + S3C2410_RTCCON);
694 	ticnt &= S3C64XX_RTCCON_TICEN;
695 
696 	seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt  ? "yes" : "no");
697 }
698 
699 static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
700 {
701 	info->ticnt_save = readb(info->base + S3C2410_TICNT);
702 }
703 
704 static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
705 {
706 	writeb(info->ticnt_save, info->base + S3C2410_TICNT);
707 }
708 
709 static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
710 {
711 	info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
712 	info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
713 	info->ticnt_save = readl(info->base + S3C2410_TICNT);
714 }
715 
716 static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
717 {
718 	unsigned int con;
719 
720 	writel(info->ticnt_save, info->base + S3C2410_TICNT);
721 	if (info->ticnt_en_save) {
722 		con = readw(info->base + S3C2410_RTCCON);
723 		writew(con | info->ticnt_en_save,
724 				info->base + S3C2410_RTCCON);
725 	}
726 }
727 
728 static struct s3c_rtc_data const s3c2410_rtc_data = {
729 	.max_user_freq		= 128,
730 	.irq_handler		= s3c24xx_rtc_irq,
731 	.set_freq		= s3c2410_rtc_setfreq,
732 	.enable_tick		= s3c24xx_rtc_enable_tick,
733 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt,
734 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt,
735 	.enable			= s3c24xx_rtc_enable,
736 	.disable		= s3c24xx_rtc_disable,
737 };
738 
739 static struct s3c_rtc_data const s3c2416_rtc_data = {
740 	.max_user_freq		= 32768,
741 	.irq_handler		= s3c24xx_rtc_irq,
742 	.set_freq		= s3c2416_rtc_setfreq,
743 	.enable_tick		= s3c24xx_rtc_enable_tick,
744 	.select_tick_clk	= s3c2416_rtc_select_tick_clk,
745 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt,
746 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt,
747 	.enable			= s3c24xx_rtc_enable,
748 	.disable		= s3c24xx_rtc_disable,
749 };
750 
751 static struct s3c_rtc_data const s3c2443_rtc_data = {
752 	.max_user_freq		= 32768,
753 	.irq_handler		= s3c24xx_rtc_irq,
754 	.set_freq		= s3c2443_rtc_setfreq,
755 	.enable_tick		= s3c24xx_rtc_enable_tick,
756 	.select_tick_clk	= s3c2416_rtc_select_tick_clk,
757 	.save_tick_cnt		= s3c24xx_rtc_save_tick_cnt,
758 	.restore_tick_cnt	= s3c24xx_rtc_restore_tick_cnt,
759 	.enable			= s3c24xx_rtc_enable,
760 	.disable		= s3c24xx_rtc_disable,
761 };
762 
763 static struct s3c_rtc_data const s3c6410_rtc_data = {
764 	.max_user_freq		= 32768,
765 	.needs_src_clk		= true,
766 	.irq_handler		= s3c6410_rtc_irq,
767 	.set_freq		= s3c6410_rtc_setfreq,
768 	.enable_tick		= s3c6410_rtc_enable_tick,
769 	.save_tick_cnt		= s3c6410_rtc_save_tick_cnt,
770 	.restore_tick_cnt	= s3c6410_rtc_restore_tick_cnt,
771 	.enable			= s3c24xx_rtc_enable,
772 	.disable		= s3c6410_rtc_disable,
773 };
774 
775 static struct s3c_rtc_data const exynos3250_rtc_data = {
776 	.max_user_freq		= 32768,
777 	.needs_src_clk		= true,
778 	.irq_handler		= s3c6410_rtc_irq,
779 	.set_freq		= s3c6410_rtc_setfreq,
780 	.enable_tick		= s3c6410_rtc_enable_tick,
781 	.save_tick_cnt		= s3c6410_rtc_save_tick_cnt,
782 	.restore_tick_cnt	= s3c6410_rtc_restore_tick_cnt,
783 	.enable			= s3c24xx_rtc_enable,
784 	.disable		= s3c6410_rtc_disable,
785 };
786 
787 static const struct of_device_id s3c_rtc_dt_match[] = {
788 	{
789 		.compatible = "samsung,s3c2410-rtc",
790 		.data = (void *)&s3c2410_rtc_data,
791 	}, {
792 		.compatible = "samsung,s3c2416-rtc",
793 		.data = (void *)&s3c2416_rtc_data,
794 	}, {
795 		.compatible = "samsung,s3c2443-rtc",
796 		.data = (void *)&s3c2443_rtc_data,
797 	}, {
798 		.compatible = "samsung,s3c6410-rtc",
799 		.data = (void *)&s3c6410_rtc_data,
800 	}, {
801 		.compatible = "samsung,exynos3250-rtc",
802 		.data = (void *)&exynos3250_rtc_data,
803 	},
804 	{ /* sentinel */ },
805 };
806 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
807 
808 static struct platform_driver s3c_rtc_driver = {
809 	.probe		= s3c_rtc_probe,
810 	.remove		= s3c_rtc_remove,
811 	.driver		= {
812 		.name	= "s3c-rtc",
813 		.pm	= &s3c_rtc_pm_ops,
814 		.of_match_table	= of_match_ptr(s3c_rtc_dt_match),
815 	},
816 };
817 module_platform_driver(s3c_rtc_driver);
818 
819 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
820 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
821 MODULE_LICENSE("GPL");
822 MODULE_ALIAS("platform:s3c2410-rtc");
823