xref: /openbmc/linux/drivers/rtc/rtc-s3c.c (revision f5cc14e4)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* drivers/rtc/rtc-s3c.c
3  *
4  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
5  *		http://www.samsung.com/
6  *
7  * Copyright (c) 2004,2006 Simtec Electronics
8  *	Ben Dooks, <ben@simtec.co.uk>
9  *	http://armlinux.simtec.co.uk/
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 #include <linux/log2.h>
24 #include <linux/slab.h>
25 #include <linux/of.h>
26 #include <linux/of_device.h>
27 #include <linux/uaccess.h>
28 #include <linux/io.h>
29 
30 #include <asm/irq.h>
31 #include "rtc-s3c.h"
32 
33 struct s3c_rtc {
34 	struct device *dev;
35 	struct rtc_device *rtc;
36 
37 	void __iomem *base;
38 	struct clk *rtc_clk;
39 	struct clk *rtc_src_clk;
40 	bool alarm_enabled;
41 
42 	const struct s3c_rtc_data *data;
43 
44 	int irq_alarm;
45 	spinlock_t alarm_lock;
46 
47 	bool wake_en;
48 };
49 
50 struct s3c_rtc_data {
51 	bool needs_src_clk;
52 
53 	void (*irq_handler) (struct s3c_rtc *info, int mask);
54 	void (*enable) (struct s3c_rtc *info);
55 	void (*disable) (struct s3c_rtc *info);
56 };
57 
58 static int s3c_rtc_enable_clk(struct s3c_rtc *info)
59 {
60 	int ret;
61 
62 	ret = clk_enable(info->rtc_clk);
63 	if (ret)
64 		return ret;
65 
66 	if (info->data->needs_src_clk) {
67 		ret = clk_enable(info->rtc_src_clk);
68 		if (ret) {
69 			clk_disable(info->rtc_clk);
70 			return ret;
71 		}
72 	}
73 	return 0;
74 }
75 
76 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
77 {
78 	if (info->data->needs_src_clk)
79 		clk_disable(info->rtc_src_clk);
80 	clk_disable(info->rtc_clk);
81 }
82 
83 /* IRQ Handler */
84 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
85 {
86 	struct s3c_rtc *info = (struct s3c_rtc *)id;
87 
88 	if (info->data->irq_handler)
89 		info->data->irq_handler(info, S3C2410_INTP_ALM);
90 
91 	return IRQ_HANDLED;
92 }
93 
94 /* Update control registers */
95 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
96 {
97 	struct s3c_rtc *info = dev_get_drvdata(dev);
98 	unsigned long flags;
99 	unsigned int tmp;
100 	int ret;
101 
102 	dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
103 
104 	ret = s3c_rtc_enable_clk(info);
105 	if (ret)
106 		return ret;
107 
108 	tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
109 
110 	if (enabled)
111 		tmp |= S3C2410_RTCALM_ALMEN;
112 
113 	writeb(tmp, info->base + S3C2410_RTCALM);
114 
115 	spin_lock_irqsave(&info->alarm_lock, flags);
116 
117 	if (info->alarm_enabled && !enabled)
118 		s3c_rtc_disable_clk(info);
119 	else if (!info->alarm_enabled && enabled)
120 		ret = s3c_rtc_enable_clk(info);
121 
122 	info->alarm_enabled = enabled;
123 	spin_unlock_irqrestore(&info->alarm_lock, flags);
124 
125 	s3c_rtc_disable_clk(info);
126 
127 	return ret;
128 }
129 
130 /* Time read/write */
131 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
132 {
133 	struct s3c_rtc *info = dev_get_drvdata(dev);
134 	unsigned int have_retried = 0;
135 	int ret;
136 
137 	ret = s3c_rtc_enable_clk(info);
138 	if (ret)
139 		return ret;
140 
141 retry_get_time:
142 	rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
143 	rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
144 	rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
145 	rtc_tm->tm_mon  = readb(info->base + S3C2410_RTCMON);
146 	rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
147 	rtc_tm->tm_sec  = readb(info->base + S3C2410_RTCSEC);
148 
149 	/* the only way to work out whether the system was mid-update
150 	 * when we read it is to check the second counter, and if it
151 	 * is zero, then we re-try the entire read
152 	 */
153 
154 	if (rtc_tm->tm_sec == 0 && !have_retried) {
155 		have_retried = 1;
156 		goto retry_get_time;
157 	}
158 
159 	rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
160 	rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
161 	rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
162 	rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
163 	rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
164 	rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
165 
166 	s3c_rtc_disable_clk(info);
167 
168 	rtc_tm->tm_year += 100;
169 	rtc_tm->tm_mon -= 1;
170 
171 	dev_dbg(dev, "read time %ptR\n", rtc_tm);
172 	return 0;
173 }
174 
175 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
176 {
177 	struct s3c_rtc *info = dev_get_drvdata(dev);
178 	int year = tm->tm_year - 100;
179 	int ret;
180 
181 	dev_dbg(dev, "set time %ptR\n", tm);
182 
183 	/* we get around y2k by simply not supporting it */
184 
185 	if (year < 0 || year >= 100) {
186 		dev_err(dev, "rtc only supports 100 years\n");
187 		return -EINVAL;
188 	}
189 
190 	ret = s3c_rtc_enable_clk(info);
191 	if (ret)
192 		return ret;
193 
194 	writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
195 	writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
196 	writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
197 	writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
198 	writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON);
199 	writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR);
200 
201 	s3c_rtc_disable_clk(info);
202 
203 	return 0;
204 }
205 
206 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
207 {
208 	struct s3c_rtc *info = dev_get_drvdata(dev);
209 	struct rtc_time *alm_tm = &alrm->time;
210 	unsigned int alm_en;
211 	int ret;
212 
213 	ret = s3c_rtc_enable_clk(info);
214 	if (ret)
215 		return ret;
216 
217 	alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
218 	alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
219 	alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
220 	alm_tm->tm_mon  = readb(info->base + S3C2410_ALMMON);
221 	alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
222 	alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR);
223 
224 	alm_en = readb(info->base + S3C2410_RTCALM);
225 
226 	s3c_rtc_disable_clk(info);
227 
228 	alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
229 
230 	dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm);
231 
232 	/* decode the alarm enable field */
233 	if (alm_en & S3C2410_RTCALM_SECEN)
234 		alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
235 
236 	if (alm_en & S3C2410_RTCALM_MINEN)
237 		alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
238 
239 	if (alm_en & S3C2410_RTCALM_HOUREN)
240 		alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
241 
242 	if (alm_en & S3C2410_RTCALM_DAYEN)
243 		alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
244 
245 	if (alm_en & S3C2410_RTCALM_MONEN) {
246 		alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
247 		alm_tm->tm_mon -= 1;
248 	}
249 
250 	if (alm_en & S3C2410_RTCALM_YEAREN)
251 		alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
252 
253 	return 0;
254 }
255 
256 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
257 {
258 	struct s3c_rtc *info = dev_get_drvdata(dev);
259 	struct rtc_time *tm = &alrm->time;
260 	unsigned int alrm_en;
261 	int ret;
262 
263 	dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm);
264 
265 	ret = s3c_rtc_enable_clk(info);
266 	if (ret)
267 		return ret;
268 
269 	alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
270 	writeb(0x00, info->base + S3C2410_RTCALM);
271 
272 	if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
273 		alrm_en |= S3C2410_RTCALM_SECEN;
274 		writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
275 	}
276 
277 	if (tm->tm_min < 60 && tm->tm_min >= 0) {
278 		alrm_en |= S3C2410_RTCALM_MINEN;
279 		writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
280 	}
281 
282 	if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
283 		alrm_en |= S3C2410_RTCALM_HOUREN;
284 		writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
285 	}
286 
287 	if (tm->tm_mon < 12 && tm->tm_mon >= 0) {
288 		alrm_en |= S3C2410_RTCALM_MONEN;
289 		writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON);
290 	}
291 
292 	if (tm->tm_mday <= 31 && tm->tm_mday >= 1) {
293 		alrm_en |= S3C2410_RTCALM_DAYEN;
294 		writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE);
295 	}
296 
297 	dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
298 
299 	writeb(alrm_en, info->base + S3C2410_RTCALM);
300 
301 	s3c_rtc_setaie(dev, alrm->enabled);
302 
303 	s3c_rtc_disable_clk(info);
304 
305 	return 0;
306 }
307 
308 static const struct rtc_class_ops s3c_rtcops = {
309 	.read_time	= s3c_rtc_gettime,
310 	.set_time	= s3c_rtc_settime,
311 	.read_alarm	= s3c_rtc_getalarm,
312 	.set_alarm	= s3c_rtc_setalarm,
313 	.alarm_irq_enable = s3c_rtc_setaie,
314 };
315 
316 static void s3c24xx_rtc_enable(struct s3c_rtc *info)
317 {
318 	unsigned int con, tmp;
319 
320 	con = readw(info->base + S3C2410_RTCCON);
321 	/* re-enable the device, and check it is ok */
322 	if ((con & S3C2410_RTCCON_RTCEN) == 0) {
323 		dev_info(info->dev, "rtc disabled, re-enabling\n");
324 
325 		tmp = readw(info->base + S3C2410_RTCCON);
326 		writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
327 	}
328 
329 	if (con & S3C2410_RTCCON_CNTSEL) {
330 		dev_info(info->dev, "removing RTCCON_CNTSEL\n");
331 
332 		tmp = readw(info->base + S3C2410_RTCCON);
333 		writew(tmp & ~S3C2410_RTCCON_CNTSEL,
334 		       info->base + S3C2410_RTCCON);
335 	}
336 
337 	if (con & S3C2410_RTCCON_CLKRST) {
338 		dev_info(info->dev, "removing RTCCON_CLKRST\n");
339 
340 		tmp = readw(info->base + S3C2410_RTCCON);
341 		writew(tmp & ~S3C2410_RTCCON_CLKRST,
342 		       info->base + S3C2410_RTCCON);
343 	}
344 }
345 
346 static void s3c24xx_rtc_disable(struct s3c_rtc *info)
347 {
348 	unsigned int con;
349 
350 	con = readw(info->base + S3C2410_RTCCON);
351 	con &= ~S3C2410_RTCCON_RTCEN;
352 	writew(con, info->base + S3C2410_RTCCON);
353 
354 	con = readb(info->base + S3C2410_TICNT);
355 	con &= ~S3C2410_TICNT_ENABLE;
356 	writeb(con, info->base + S3C2410_TICNT);
357 }
358 
359 static void s3c6410_rtc_disable(struct s3c_rtc *info)
360 {
361 	unsigned int con;
362 
363 	con = readw(info->base + S3C2410_RTCCON);
364 	con &= ~S3C64XX_RTCCON_TICEN;
365 	con &= ~S3C2410_RTCCON_RTCEN;
366 	writew(con, info->base + S3C2410_RTCCON);
367 }
368 
369 static int s3c_rtc_remove(struct platform_device *pdev)
370 {
371 	struct s3c_rtc *info = platform_get_drvdata(pdev);
372 
373 	s3c_rtc_setaie(info->dev, 0);
374 
375 	if (info->data->needs_src_clk)
376 		clk_unprepare(info->rtc_src_clk);
377 	clk_unprepare(info->rtc_clk);
378 
379 	return 0;
380 }
381 
382 static int s3c_rtc_probe(struct platform_device *pdev)
383 {
384 	struct s3c_rtc *info = NULL;
385 	struct rtc_time rtc_tm;
386 	int ret;
387 
388 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
389 	if (!info)
390 		return -ENOMEM;
391 
392 	info->dev = &pdev->dev;
393 	info->data = of_device_get_match_data(&pdev->dev);
394 	if (!info->data) {
395 		dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
396 		return -EINVAL;
397 	}
398 	spin_lock_init(&info->alarm_lock);
399 
400 	platform_set_drvdata(pdev, info);
401 
402 	info->irq_alarm = platform_get_irq(pdev, 0);
403 	if (info->irq_alarm < 0)
404 		return info->irq_alarm;
405 
406 	dev_dbg(&pdev->dev, "s3c2410_rtc: alarm irq %d\n", info->irq_alarm);
407 
408 	/* get the memory region */
409 	info->base = devm_platform_ioremap_resource(pdev, 0);
410 	if (IS_ERR(info->base))
411 		return PTR_ERR(info->base);
412 
413 	info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
414 	if (IS_ERR(info->rtc_clk)) {
415 		ret = PTR_ERR(info->rtc_clk);
416 		if (ret != -EPROBE_DEFER)
417 			dev_err(&pdev->dev, "failed to find rtc clock\n");
418 		else
419 			dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
420 		return ret;
421 	}
422 	ret = clk_prepare_enable(info->rtc_clk);
423 	if (ret)
424 		return ret;
425 
426 	if (info->data->needs_src_clk) {
427 		info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
428 		if (IS_ERR(info->rtc_src_clk)) {
429 			ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk),
430 					    "failed to find rtc source clock\n");
431 			goto err_src_clk;
432 		}
433 		ret = clk_prepare_enable(info->rtc_src_clk);
434 		if (ret)
435 			goto err_src_clk;
436 	}
437 
438 	/* disable RTC enable bits potentially set by the bootloader */
439 	if (info->data->disable)
440 		info->data->disable(info);
441 
442 	/* check to see if everything is setup correctly */
443 	if (info->data->enable)
444 		info->data->enable(info);
445 
446 	dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
447 		readw(info->base + S3C2410_RTCCON));
448 
449 	device_init_wakeup(&pdev->dev, 1);
450 
451 	/* Check RTC Time */
452 	if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) {
453 		rtc_tm.tm_year	= 100;
454 		rtc_tm.tm_mon	= 0;
455 		rtc_tm.tm_mday	= 1;
456 		rtc_tm.tm_hour	= 0;
457 		rtc_tm.tm_min	= 0;
458 		rtc_tm.tm_sec	= 0;
459 
460 		s3c_rtc_settime(&pdev->dev, &rtc_tm);
461 
462 		dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
463 	}
464 
465 	/* register RTC and exit */
466 	info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
467 					     THIS_MODULE);
468 	if (IS_ERR(info->rtc)) {
469 		dev_err(&pdev->dev, "cannot attach rtc\n");
470 		ret = PTR_ERR(info->rtc);
471 		goto err_nortc;
472 	}
473 
474 	ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
475 			       0, "s3c2410-rtc alarm", info);
476 	if (ret) {
477 		dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
478 		goto err_nortc;
479 	}
480 
481 	s3c_rtc_disable_clk(info);
482 
483 	return 0;
484 
485 err_nortc:
486 	if (info->data->disable)
487 		info->data->disable(info);
488 
489 	if (info->data->needs_src_clk)
490 		clk_disable_unprepare(info->rtc_src_clk);
491 err_src_clk:
492 	clk_disable_unprepare(info->rtc_clk);
493 
494 	return ret;
495 }
496 
497 #ifdef CONFIG_PM_SLEEP
498 
499 static int s3c_rtc_suspend(struct device *dev)
500 {
501 	struct s3c_rtc *info = dev_get_drvdata(dev);
502 	int ret;
503 
504 	ret = s3c_rtc_enable_clk(info);
505 	if (ret)
506 		return ret;
507 
508 	if (info->data->disable)
509 		info->data->disable(info);
510 
511 	if (device_may_wakeup(dev) && !info->wake_en) {
512 		if (enable_irq_wake(info->irq_alarm) == 0)
513 			info->wake_en = true;
514 		else
515 			dev_err(dev, "enable_irq_wake failed\n");
516 	}
517 
518 	return 0;
519 }
520 
521 static int s3c_rtc_resume(struct device *dev)
522 {
523 	struct s3c_rtc *info = dev_get_drvdata(dev);
524 
525 	if (info->data->enable)
526 		info->data->enable(info);
527 
528 	s3c_rtc_disable_clk(info);
529 
530 	if (device_may_wakeup(dev) && info->wake_en) {
531 		disable_irq_wake(info->irq_alarm);
532 		info->wake_en = false;
533 	}
534 
535 	return 0;
536 }
537 #endif
538 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume);
539 
540 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
541 {
542 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
543 }
544 
545 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
546 {
547 	rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF);
548 	writeb(mask, info->base + S3C2410_INTP);
549 }
550 
551 static struct s3c_rtc_data const s3c2410_rtc_data = {
552 	.irq_handler		= s3c24xx_rtc_irq,
553 	.enable			= s3c24xx_rtc_enable,
554 	.disable		= s3c24xx_rtc_disable,
555 };
556 
557 static struct s3c_rtc_data const s3c2416_rtc_data = {
558 	.irq_handler		= s3c24xx_rtc_irq,
559 	.enable			= s3c24xx_rtc_enable,
560 	.disable		= s3c24xx_rtc_disable,
561 };
562 
563 static struct s3c_rtc_data const s3c2443_rtc_data = {
564 	.irq_handler		= s3c24xx_rtc_irq,
565 	.enable			= s3c24xx_rtc_enable,
566 	.disable		= s3c24xx_rtc_disable,
567 };
568 
569 static struct s3c_rtc_data const s3c6410_rtc_data = {
570 	.needs_src_clk		= true,
571 	.irq_handler		= s3c6410_rtc_irq,
572 	.enable			= s3c24xx_rtc_enable,
573 	.disable		= s3c6410_rtc_disable,
574 };
575 
576 static const struct of_device_id s3c_rtc_dt_match[] = {
577 	{
578 		.compatible = "samsung,s3c2410-rtc",
579 		.data = &s3c2410_rtc_data,
580 	}, {
581 		.compatible = "samsung,s3c2416-rtc",
582 		.data = &s3c2416_rtc_data,
583 	}, {
584 		.compatible = "samsung,s3c2443-rtc",
585 		.data = &s3c2443_rtc_data,
586 	}, {
587 		.compatible = "samsung,s3c6410-rtc",
588 		.data = &s3c6410_rtc_data,
589 	}, {
590 		.compatible = "samsung,exynos3250-rtc",
591 		.data = &s3c6410_rtc_data,
592 	},
593 	{ /* sentinel */ },
594 };
595 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match);
596 
597 static struct platform_driver s3c_rtc_driver = {
598 	.probe		= s3c_rtc_probe,
599 	.remove		= s3c_rtc_remove,
600 	.driver		= {
601 		.name	= "s3c-rtc",
602 		.pm	= &s3c_rtc_pm_ops,
603 		.of_match_table	= of_match_ptr(s3c_rtc_dt_match),
604 	},
605 };
606 module_platform_driver(s3c_rtc_driver);
607 
608 MODULE_DESCRIPTION("Samsung S3C RTC Driver");
609 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
610 MODULE_LICENSE("GPL");
611 MODULE_ALIAS("platform:s3c2410-rtc");
612