xref: /linux/drivers/rtc/rtc-s3c.c (revision 173d6681380aa1d60dfc35ed7178bd7811ba2784)
1 /* drivers/rtc/rtc-s3c.c
2  *
3  * Copyright (c) 2004,2006 Simtec Electronics
4  *	Ben Dooks, <ben@simtec.co.uk>
5  *	http://armlinux.simtec.co.uk/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * S3C2410/S3C2440/S3C24XX Internal RTC Driver
12 */
13 
14 #include <linux/module.h>
15 #include <linux/fs.h>
16 #include <linux/string.h>
17 #include <linux/init.h>
18 #include <linux/platform_device.h>
19 #include <linux/interrupt.h>
20 #include <linux/rtc.h>
21 #include <linux/bcd.h>
22 #include <linux/clk.h>
23 
24 #include <asm/hardware.h>
25 #include <asm/uaccess.h>
26 #include <asm/io.h>
27 #include <asm/irq.h>
28 #include <asm/rtc.h>
29 
30 #include <asm/mach/time.h>
31 
32 #include <asm/arch/regs-rtc.h>
33 
34 /* I have yet to find an S3C implementation with more than one
35  * of these rtc blocks in */
36 
37 static struct resource *s3c_rtc_mem;
38 
39 static void __iomem *s3c_rtc_base;
40 static int s3c_rtc_alarmno = NO_IRQ;
41 static int s3c_rtc_tickno  = NO_IRQ;
42 static int s3c_rtc_freq    = 1;
43 
44 static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
45 static unsigned int tick_count;
46 
47 /* IRQ Handlers */
48 
49 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
50 {
51 	struct rtc_device *rdev = id;
52 
53 	rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF);
54 	return IRQ_HANDLED;
55 }
56 
57 static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
58 {
59 	struct rtc_device *rdev = id;
60 
61 	rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
62 	return IRQ_HANDLED;
63 }
64 
65 /* Update control registers */
66 static void s3c_rtc_setaie(int to)
67 {
68 	unsigned int tmp;
69 
70 	pr_debug("%s: aie=%d\n", __FUNCTION__, to);
71 
72 	tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
73 
74 	if (to)
75 		tmp |= S3C2410_RTCALM_ALMEN;
76 
77 	writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
78 }
79 
80 static void s3c_rtc_setpie(int to)
81 {
82 	unsigned int tmp;
83 
84 	pr_debug("%s: pie=%d\n", __FUNCTION__, to);
85 
86 	spin_lock_irq(&s3c_rtc_pie_lock);
87 	tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
88 
89 	if (to)
90 		tmp |= S3C2410_TICNT_ENABLE;
91 
92 	writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
93 	spin_unlock_irq(&s3c_rtc_pie_lock);
94 }
95 
96 static void s3c_rtc_setfreq(int freq)
97 {
98 	unsigned int tmp;
99 
100 	spin_lock_irq(&s3c_rtc_pie_lock);
101 	tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
102 
103 	s3c_rtc_freq = freq;
104 
105 	tmp |= (128 / freq)-1;
106 
107 	writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
108 	spin_unlock_irq(&s3c_rtc_pie_lock);
109 }
110 
111 /* Time read/write */
112 
113 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
114 {
115 	unsigned int have_retried = 0;
116 	void __iomem *base = s3c_rtc_base;
117 
118  retry_get_time:
119 	rtc_tm->tm_min  = readb(base + S3C2410_RTCMIN);
120 	rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
121 	rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
122 	rtc_tm->tm_mon  = readb(base + S3C2410_RTCMON);
123 	rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
124 	rtc_tm->tm_sec  = readb(base + S3C2410_RTCSEC);
125 
126 	/* the only way to work out wether the system was mid-update
127 	 * when we read it is to check the second counter, and if it
128 	 * is zero, then we re-try the entire read
129 	 */
130 
131 	if (rtc_tm->tm_sec == 0 && !have_retried) {
132 		have_retried = 1;
133 		goto retry_get_time;
134 	}
135 
136 	pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
137 		 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
138 		 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
139 
140 	BCD_TO_BIN(rtc_tm->tm_sec);
141 	BCD_TO_BIN(rtc_tm->tm_min);
142 	BCD_TO_BIN(rtc_tm->tm_hour);
143 	BCD_TO_BIN(rtc_tm->tm_mday);
144 	BCD_TO_BIN(rtc_tm->tm_mon);
145 	BCD_TO_BIN(rtc_tm->tm_year);
146 
147 	rtc_tm->tm_year += 100;
148 	rtc_tm->tm_mon -= 1;
149 
150 	return 0;
151 }
152 
153 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
154 {
155 	void __iomem *base = s3c_rtc_base;
156 	int year = tm->tm_year - 100;
157 
158 	pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
159 		 tm->tm_year, tm->tm_mon, tm->tm_mday,
160 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
161 
162 	/* we get around y2k by simply not supporting it */
163 
164 	if (year < 0 || year >= 100) {
165 		dev_err(dev, "rtc only supports 100 years\n");
166 		return -EINVAL;
167 	}
168 
169 	writeb(BIN2BCD(tm->tm_sec),  base + S3C2410_RTCSEC);
170 	writeb(BIN2BCD(tm->tm_min),  base + S3C2410_RTCMIN);
171 	writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR);
172 	writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE);
173 	writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON);
174 	writeb(BIN2BCD(year), base + S3C2410_RTCYEAR);
175 
176 	return 0;
177 }
178 
179 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
180 {
181 	struct rtc_time *alm_tm = &alrm->time;
182 	void __iomem *base = s3c_rtc_base;
183 	unsigned int alm_en;
184 
185 	alm_tm->tm_sec  = readb(base + S3C2410_ALMSEC);
186 	alm_tm->tm_min  = readb(base + S3C2410_ALMMIN);
187 	alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
188 	alm_tm->tm_mon  = readb(base + S3C2410_ALMMON);
189 	alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);
190 	alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);
191 
192 	alm_en = readb(base + S3C2410_RTCALM);
193 
194 	pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
195 		 alm_en,
196 		 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
197 		 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
198 
199 
200 	/* decode the alarm enable field */
201 
202 	if (alm_en & S3C2410_RTCALM_SECEN)
203 		BCD_TO_BIN(alm_tm->tm_sec);
204 	else
205 		alm_tm->tm_sec = 0xff;
206 
207 	if (alm_en & S3C2410_RTCALM_MINEN)
208 		BCD_TO_BIN(alm_tm->tm_min);
209 	else
210 		alm_tm->tm_min = 0xff;
211 
212 	if (alm_en & S3C2410_RTCALM_HOUREN)
213 		BCD_TO_BIN(alm_tm->tm_hour);
214 	else
215 		alm_tm->tm_hour = 0xff;
216 
217 	if (alm_en & S3C2410_RTCALM_DAYEN)
218 		BCD_TO_BIN(alm_tm->tm_mday);
219 	else
220 		alm_tm->tm_mday = 0xff;
221 
222 	if (alm_en & S3C2410_RTCALM_MONEN) {
223 		BCD_TO_BIN(alm_tm->tm_mon);
224 		alm_tm->tm_mon -= 1;
225 	} else {
226 		alm_tm->tm_mon = 0xff;
227 	}
228 
229 	if (alm_en & S3C2410_RTCALM_YEAREN)
230 		BCD_TO_BIN(alm_tm->tm_year);
231 	else
232 		alm_tm->tm_year = 0xffff;
233 
234 	return 0;
235 }
236 
237 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
238 {
239 	struct rtc_time *tm = &alrm->time;
240 	void __iomem *base = s3c_rtc_base;
241 	unsigned int alrm_en;
242 
243 	pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
244 		 alrm->enabled,
245 		 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
246 		 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
247 
248 
249 	alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
250 	writeb(0x00, base + S3C2410_RTCALM);
251 
252 	if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
253 		alrm_en |= S3C2410_RTCALM_SECEN;
254 		writeb(BIN2BCD(tm->tm_sec), base + S3C2410_ALMSEC);
255 	}
256 
257 	if (tm->tm_min < 60 && tm->tm_min >= 0) {
258 		alrm_en |= S3C2410_RTCALM_MINEN;
259 		writeb(BIN2BCD(tm->tm_min), base + S3C2410_ALMMIN);
260 	}
261 
262 	if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
263 		alrm_en |= S3C2410_RTCALM_HOUREN;
264 		writeb(BIN2BCD(tm->tm_hour), base + S3C2410_ALMHOUR);
265 	}
266 
267 	pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
268 
269 	writeb(alrm_en, base + S3C2410_RTCALM);
270 
271 	if (0) {
272 		alrm_en = readb(base + S3C2410_RTCALM);
273 		alrm_en &= ~S3C2410_RTCALM_ALMEN;
274 		writeb(alrm_en, base + S3C2410_RTCALM);
275 		disable_irq_wake(s3c_rtc_alarmno);
276 	}
277 
278 	if (alrm->enabled)
279 		enable_irq_wake(s3c_rtc_alarmno);
280 	else
281 		disable_irq_wake(s3c_rtc_alarmno);
282 
283 	return 0;
284 }
285 
286 static int s3c_rtc_ioctl(struct device *dev,
287 			 unsigned int cmd, unsigned long arg)
288 {
289 	unsigned int ret = -ENOIOCTLCMD;
290 
291 	switch (cmd) {
292 	case RTC_AIE_OFF:
293 	case RTC_AIE_ON:
294 		s3c_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
295 		ret = 0;
296 		break;
297 
298 	case RTC_PIE_OFF:
299 	case RTC_PIE_ON:
300 		tick_count = 0;
301 		s3c_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
302 		ret = 0;
303 		break;
304 
305 	case RTC_IRQP_READ:
306 		ret = put_user(s3c_rtc_freq, (unsigned long __user *)arg);
307 		break;
308 
309 	case RTC_IRQP_SET:
310 		/* check for power of 2 */
311 
312 		if ((arg & (arg-1)) != 0 || arg < 1) {
313 			ret = -EINVAL;
314 			goto exit;
315 		}
316 
317 		pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
318 
319 		s3c_rtc_setfreq(arg);
320 		ret = 0;
321 		break;
322 
323 	case RTC_UIE_ON:
324 	case RTC_UIE_OFF:
325 		ret = -EINVAL;
326 	}
327 
328  exit:
329 	return ret;
330 }
331 
332 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
333 {
334 	unsigned int rtcalm = readb(s3c_rtc_base + S3C2410_RTCALM);
335 	unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
336 
337 	seq_printf(seq, "alarm_IRQ\t: %s\n",
338 		   (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
339 
340 	seq_printf(seq, "periodic_IRQ\t: %s\n",
341 		     (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
342 
343 	seq_printf(seq, "periodic_freq\t: %d\n", s3c_rtc_freq);
344 
345 	return 0;
346 }
347 
348 static int s3c_rtc_open(struct device *dev)
349 {
350 	struct platform_device *pdev = to_platform_device(dev);
351 	struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
352 	int ret;
353 
354 	ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
355 			  SA_INTERRUPT,  "s3c2410-rtc alarm", rtc_dev);
356 
357 	if (ret) {
358 		dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
359 		return ret;
360 	}
361 
362 	ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
363 			  SA_INTERRUPT,  "s3c2410-rtc tick", rtc_dev);
364 
365 	if (ret) {
366 		dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
367 		goto tick_err;
368 	}
369 
370 	return ret;
371 
372  tick_err:
373 	free_irq(s3c_rtc_alarmno, rtc_dev);
374 	return ret;
375 }
376 
377 static void s3c_rtc_release(struct device *dev)
378 {
379 	struct platform_device *pdev = to_platform_device(dev);
380 	struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
381 
382 	/* do not clear AIE here, it may be needed for wake */
383 
384 	s3c_rtc_setpie(0);
385 	free_irq(s3c_rtc_alarmno, rtc_dev);
386 	free_irq(s3c_rtc_tickno, rtc_dev);
387 }
388 
389 static const struct rtc_class_ops s3c_rtcops = {
390 	.open		= s3c_rtc_open,
391 	.release	= s3c_rtc_release,
392 	.ioctl		= s3c_rtc_ioctl,
393 	.read_time	= s3c_rtc_gettime,
394 	.set_time	= s3c_rtc_settime,
395 	.read_alarm	= s3c_rtc_getalarm,
396 	.set_alarm	= s3c_rtc_setalarm,
397 	.proc	        = s3c_rtc_proc,
398 };
399 
400 static void s3c_rtc_enable(struct platform_device *pdev, int en)
401 {
402 	void __iomem *base = s3c_rtc_base;
403 	unsigned int tmp;
404 
405 	if (s3c_rtc_base == NULL)
406 		return;
407 
408 	if (!en) {
409 		tmp = readb(base + S3C2410_RTCCON);
410 		writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
411 
412 		tmp = readb(base + S3C2410_TICNT);
413 		writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
414 	} else {
415 		/* re-enable the device, and check it is ok */
416 
417 		if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
418 			dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
419 
420 			tmp = readb(base + S3C2410_RTCCON);
421 			writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);
422 		}
423 
424 		if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
425 			dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
426 
427 			tmp = readb(base + S3C2410_RTCCON);
428 			writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);
429 		}
430 
431 		if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
432 			dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
433 
434 			tmp = readb(base + S3C2410_RTCCON);
435 			writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);
436 		}
437 	}
438 }
439 
440 static int s3c_rtc_remove(struct platform_device *dev)
441 {
442 	struct rtc_device *rtc = platform_get_drvdata(dev);
443 
444 	platform_set_drvdata(dev, NULL);
445 	rtc_device_unregister(rtc);
446 
447 	s3c_rtc_setpie(0);
448 	s3c_rtc_setaie(0);
449 
450 	iounmap(s3c_rtc_base);
451 	release_resource(s3c_rtc_mem);
452 	kfree(s3c_rtc_mem);
453 
454 	return 0;
455 }
456 
457 static int s3c_rtc_probe(struct platform_device *pdev)
458 {
459 	struct rtc_device *rtc;
460 	struct resource *res;
461 	int ret;
462 
463 	pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
464 
465 	/* find the IRQs */
466 
467 	s3c_rtc_tickno = platform_get_irq(pdev, 1);
468 	if (s3c_rtc_tickno < 0) {
469 		dev_err(&pdev->dev, "no irq for rtc tick\n");
470 		return -ENOENT;
471 	}
472 
473 	s3c_rtc_alarmno = platform_get_irq(pdev, 0);
474 	if (s3c_rtc_alarmno < 0) {
475 		dev_err(&pdev->dev, "no irq for alarm\n");
476 		return -ENOENT;
477 	}
478 
479 	pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
480 		 s3c_rtc_tickno, s3c_rtc_alarmno);
481 
482 	/* get the memory region */
483 
484 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
485 	if (res == NULL) {
486 		dev_err(&pdev->dev, "failed to get memory region resource\n");
487 		return -ENOENT;
488 	}
489 
490 	s3c_rtc_mem = request_mem_region(res->start,
491 					 res->end-res->start+1,
492 					 pdev->name);
493 
494 	if (s3c_rtc_mem == NULL) {
495 		dev_err(&pdev->dev, "failed to reserve memory region\n");
496 		ret = -ENOENT;
497 		goto err_nores;
498 	}
499 
500 	s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
501 	if (s3c_rtc_base == NULL) {
502 		dev_err(&pdev->dev, "failed ioremap()\n");
503 		ret = -EINVAL;
504 		goto err_nomap;
505 	}
506 
507 	/* check to see if everything is setup correctly */
508 
509 	s3c_rtc_enable(pdev, 1);
510 
511  	pr_debug("s3c2410_rtc: RTCCON=%02x\n",
512 		 readb(s3c_rtc_base + S3C2410_RTCCON));
513 
514 	s3c_rtc_setfreq(s3c_rtc_freq);
515 
516 	/* register RTC and exit */
517 
518 	rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
519 				  THIS_MODULE);
520 
521 	if (IS_ERR(rtc)) {
522 		dev_err(&pdev->dev, "cannot attach rtc\n");
523 		ret = PTR_ERR(rtc);
524 		goto err_nortc;
525 	}
526 
527 	rtc->max_user_freq = 128;
528 
529 	platform_set_drvdata(pdev, rtc);
530 	return 0;
531 
532  err_nortc:
533 	s3c_rtc_enable(pdev, 0);
534 	iounmap(s3c_rtc_base);
535 
536  err_nomap:
537 	release_resource(s3c_rtc_mem);
538 
539  err_nores:
540 	return ret;
541 }
542 
543 #ifdef CONFIG_PM
544 
545 /* RTC Power management control */
546 
547 static struct timespec s3c_rtc_delta;
548 
549 static int ticnt_save;
550 
551 static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
552 {
553 	struct rtc_time tm;
554 	struct timespec time;
555 
556 	time.tv_nsec = 0;
557 
558 	/* save TICNT for anyone using periodic interrupts */
559 
560 	ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
561 
562 	/* calculate time delta for suspend */
563 
564 	s3c_rtc_gettime(&pdev->dev, &tm);
565 	rtc_tm_to_time(&tm, &time.tv_sec);
566 	save_time_delta(&s3c_rtc_delta, &time);
567 	s3c_rtc_enable(pdev, 0);
568 
569 	return 0;
570 }
571 
572 static int s3c_rtc_resume(struct platform_device *pdev)
573 {
574 	struct rtc_time tm;
575 	struct timespec time;
576 
577 	time.tv_nsec = 0;
578 
579 	s3c_rtc_enable(pdev, 1);
580 	s3c_rtc_gettime(&pdev->dev, &tm);
581 	rtc_tm_to_time(&tm, &time.tv_sec);
582 	restore_time_delta(&s3c_rtc_delta, &time);
583 
584 	writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
585 	return 0;
586 }
587 #else
588 #define s3c_rtc_suspend NULL
589 #define s3c_rtc_resume  NULL
590 #endif
591 
592 static struct platform_driver s3c2410_rtcdrv = {
593 	.probe		= s3c_rtc_probe,
594 	.remove		= s3c_rtc_remove,
595 	.suspend	= s3c_rtc_suspend,
596 	.resume		= s3c_rtc_resume,
597 	.driver		= {
598 		.name	= "s3c2410-rtc",
599 		.owner	= THIS_MODULE,
600 	},
601 };
602 
603 static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
604 
605 static int __init s3c_rtc_init(void)
606 {
607 	printk(banner);
608 	return platform_driver_register(&s3c2410_rtcdrv);
609 }
610 
611 static void __exit s3c_rtc_exit(void)
612 {
613 	platform_driver_unregister(&s3c2410_rtcdrv);
614 }
615 
616 module_init(s3c_rtc_init);
617 module_exit(s3c_rtc_exit);
618 
619 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
620 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
621 MODULE_LICENSE("GPL");
622