1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * "RTT as Real Time Clock" driver for AT91SAM9 SoC family |
4 | * |
5 | * (C) 2007 Michel Benoit |
6 | * |
7 | * Based on rtc-at91rm9200.c by Rick Bronson |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/interrupt.h> |
12 | #include <linux/ioctl.h> |
13 | #include <linux/io.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/mfd/syscon.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/rtc.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/suspend.h> |
23 | #include <linux/time.h> |
24 | |
25 | /* |
26 | * This driver uses two configurable hardware resources that live in the |
27 | * AT91SAM9 backup power domain (intended to be powered at all times) |
28 | * to implement the Real Time Clock interfaces |
29 | * |
30 | * - A "Real-time Timer" (RTT) counts up in seconds from a base time. |
31 | * We can't assign the counter value (CRTV) ... but we can reset it. |
32 | * |
33 | * - One of the "General Purpose Backup Registers" (GPBRs) holds the |
34 | * base time, normally an offset from the beginning of the POSIX |
35 | * epoch (1970-Jan-1 00:00:00 UTC). Some systems also include the |
36 | * local timezone's offset. |
37 | * |
38 | * The RTC's value is the RTT counter plus that offset. The RTC's alarm |
39 | * is likewise a base (ALMV) plus that offset. |
40 | * |
41 | * Not all RTTs will be used as RTCs; some systems have multiple RTTs to |
42 | * choose from, or a "real" RTC module. All systems have multiple GPBR |
43 | * registers available, likewise usable for more than "RTC" support. |
44 | */ |
45 | |
46 | #define AT91_RTT_MR 0x00 /* Real-time Mode Register */ |
47 | #define AT91_RTT_RTPRES (0xffff << 0) /* Timer Prescaler Value */ |
48 | #define AT91_RTT_ALMIEN BIT(16) /* Alarm Interrupt Enable */ |
49 | #define AT91_RTT_RTTINCIEN BIT(17) /* Increment Interrupt Enable */ |
50 | #define AT91_RTT_RTTRST BIT(18) /* Timer Restart */ |
51 | |
52 | #define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ |
53 | #define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ |
54 | |
55 | #define AT91_RTT_VR 0x08 /* Real-time Value Register */ |
56 | #define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ |
57 | |
58 | #define AT91_RTT_SR 0x0c /* Real-time Status Register */ |
59 | #define AT91_RTT_ALMS BIT(0) /* Alarm Status */ |
60 | #define AT91_RTT_RTTINC BIT(1) /* Timer Increment */ |
61 | |
62 | /* |
63 | * We store ALARM_DISABLED in ALMV to record that no alarm is set. |
64 | * It's also the reset value for that field. |
65 | */ |
66 | #define ALARM_DISABLED ((u32)~0) |
67 | |
68 | struct sam9_rtc { |
69 | void __iomem *rtt; |
70 | struct rtc_device *rtcdev; |
71 | u32 imr; |
72 | struct regmap *gpbr; |
73 | unsigned int gpbr_offset; |
74 | int irq; |
75 | struct clk *sclk; |
76 | bool suspended; |
77 | unsigned long events; |
78 | spinlock_t lock; |
79 | }; |
80 | |
81 | #define rtt_readl(rtc, field) \ |
82 | readl((rtc)->rtt + AT91_RTT_ ## field) |
83 | #define rtt_writel(rtc, field, val) \ |
84 | writel((val), (rtc)->rtt + AT91_RTT_ ## field) |
85 | |
86 | static inline unsigned int gpbr_readl(struct sam9_rtc *rtc) |
87 | { |
88 | unsigned int val; |
89 | |
90 | regmap_read(map: rtc->gpbr, reg: rtc->gpbr_offset, val: &val); |
91 | |
92 | return val; |
93 | } |
94 | |
95 | static inline void gpbr_writel(struct sam9_rtc *rtc, unsigned int val) |
96 | { |
97 | regmap_write(map: rtc->gpbr, reg: rtc->gpbr_offset, val); |
98 | } |
99 | |
100 | /* |
101 | * Read current time and date in RTC |
102 | */ |
103 | static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) |
104 | { |
105 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
106 | u32 secs, secs2; |
107 | u32 offset; |
108 | |
109 | /* read current time offset */ |
110 | offset = gpbr_readl(rtc); |
111 | if (offset == 0) |
112 | return -EILSEQ; |
113 | |
114 | /* reread the counter to help sync the two clock domains */ |
115 | secs = rtt_readl(rtc, VR); |
116 | secs2 = rtt_readl(rtc, VR); |
117 | if (secs != secs2) |
118 | secs = rtt_readl(rtc, VR); |
119 | |
120 | rtc_time64_to_tm(time: offset + secs, tm); |
121 | |
122 | dev_dbg(dev, "%s: %ptR\n" , __func__, tm); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | /* |
128 | * Set current time and date in RTC |
129 | */ |
130 | static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) |
131 | { |
132 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
133 | u32 offset, alarm, mr; |
134 | unsigned long secs; |
135 | |
136 | dev_dbg(dev, "%s: %ptR\n" , __func__, tm); |
137 | |
138 | secs = rtc_tm_to_time64(tm); |
139 | |
140 | mr = rtt_readl(rtc, MR); |
141 | |
142 | /* disable interrupts */ |
143 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); |
144 | |
145 | /* read current time offset */ |
146 | offset = gpbr_readl(rtc); |
147 | |
148 | /* store the new base time in a battery backup register */ |
149 | secs += 1; |
150 | gpbr_writel(rtc, val: secs); |
151 | |
152 | /* adjust the alarm time for the new base */ |
153 | alarm = rtt_readl(rtc, AR); |
154 | if (alarm != ALARM_DISABLED) { |
155 | if (offset > secs) { |
156 | /* time jumped backwards, increase time until alarm */ |
157 | alarm += (offset - secs); |
158 | } else if ((alarm + offset) > secs) { |
159 | /* time jumped forwards, decrease time until alarm */ |
160 | alarm -= (secs - offset); |
161 | } else { |
162 | /* time jumped past the alarm, disable alarm */ |
163 | alarm = ALARM_DISABLED; |
164 | mr &= ~AT91_RTT_ALMIEN; |
165 | } |
166 | rtt_writel(rtc, AR, alarm); |
167 | } |
168 | |
169 | /* reset the timer, and re-enable interrupts */ |
170 | rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST); |
171 | |
172 | return 0; |
173 | } |
174 | |
175 | static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) |
176 | { |
177 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
178 | struct rtc_time *tm = &alrm->time; |
179 | u32 alarm = rtt_readl(rtc, AR); |
180 | u32 offset; |
181 | |
182 | offset = gpbr_readl(rtc); |
183 | if (offset == 0) |
184 | return -EILSEQ; |
185 | |
186 | memset(alrm, 0, sizeof(*alrm)); |
187 | if (alarm != ALARM_DISABLED) { |
188 | rtc_time64_to_tm(time: offset + alarm, tm); |
189 | |
190 | dev_dbg(dev, "%s: %ptR\n" , __func__, tm); |
191 | |
192 | if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN) |
193 | alrm->enabled = 1; |
194 | } |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) |
200 | { |
201 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
202 | struct rtc_time *tm = &alrm->time; |
203 | unsigned long secs; |
204 | u32 offset; |
205 | u32 mr; |
206 | |
207 | secs = rtc_tm_to_time64(tm); |
208 | |
209 | offset = gpbr_readl(rtc); |
210 | if (offset == 0) { |
211 | /* time is not set */ |
212 | return -EILSEQ; |
213 | } |
214 | mr = rtt_readl(rtc, MR); |
215 | rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); |
216 | |
217 | /* alarm in the past? finish and leave disabled */ |
218 | if (secs <= offset) { |
219 | rtt_writel(rtc, AR, ALARM_DISABLED); |
220 | return 0; |
221 | } |
222 | |
223 | /* else set alarm and maybe enable it */ |
224 | rtt_writel(rtc, AR, secs - offset); |
225 | if (alrm->enabled) |
226 | rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); |
227 | |
228 | dev_dbg(dev, "%s: %ptR\n" , __func__, tm); |
229 | |
230 | return 0; |
231 | } |
232 | |
233 | static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
234 | { |
235 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
236 | u32 mr = rtt_readl(rtc, MR); |
237 | |
238 | dev_dbg(dev, "alarm_irq_enable: enabled=%08x, mr %08x\n" , enabled, mr); |
239 | if (enabled) |
240 | rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); |
241 | else |
242 | rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); |
243 | return 0; |
244 | } |
245 | |
246 | /* |
247 | * Provide additional RTC information in /proc/driver/rtc |
248 | */ |
249 | static int at91_rtc_proc(struct device *dev, struct seq_file *seq) |
250 | { |
251 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
252 | u32 mr = rtt_readl(rtc, MR); |
253 | |
254 | seq_printf(m: seq, fmt: "update_IRQ\t: %s\n" , |
255 | (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no" ); |
256 | return 0; |
257 | } |
258 | |
259 | static irqreturn_t at91_rtc_cache_events(struct sam9_rtc *rtc) |
260 | { |
261 | u32 sr, mr; |
262 | |
263 | /* Shared interrupt may be for another device. Note: reading |
264 | * SR clears it, so we must only read it in this irq handler! |
265 | */ |
266 | mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
267 | sr = rtt_readl(rtc, SR) & (mr >> 16); |
268 | if (!sr) |
269 | return IRQ_NONE; |
270 | |
271 | /* alarm status */ |
272 | if (sr & AT91_RTT_ALMS) |
273 | rtc->events |= (RTC_AF | RTC_IRQF); |
274 | |
275 | /* timer update/increment */ |
276 | if (sr & AT91_RTT_RTTINC) |
277 | rtc->events |= (RTC_UF | RTC_IRQF); |
278 | |
279 | return IRQ_HANDLED; |
280 | } |
281 | |
282 | static void at91_rtc_flush_events(struct sam9_rtc *rtc) |
283 | { |
284 | if (!rtc->events) |
285 | return; |
286 | |
287 | rtc_update_irq(rtc: rtc->rtcdev, num: 1, events: rtc->events); |
288 | rtc->events = 0; |
289 | |
290 | pr_debug("%s: num=%ld, events=0x%02lx\n" , __func__, |
291 | rtc->events >> 8, rtc->events & 0x000000FF); |
292 | } |
293 | |
294 | /* |
295 | * IRQ handler for the RTC |
296 | */ |
297 | static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) |
298 | { |
299 | struct sam9_rtc *rtc = _rtc; |
300 | int ret; |
301 | |
302 | spin_lock(lock: &rtc->lock); |
303 | |
304 | ret = at91_rtc_cache_events(rtc); |
305 | |
306 | /* We're called in suspended state */ |
307 | if (rtc->suspended) { |
308 | /* Mask irqs coming from this peripheral */ |
309 | rtt_writel(rtc, MR, |
310 | rtt_readl(rtc, MR) & |
311 | ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); |
312 | /* Trigger a system wakeup */ |
313 | pm_system_wakeup(); |
314 | } else { |
315 | at91_rtc_flush_events(rtc); |
316 | } |
317 | |
318 | spin_unlock(lock: &rtc->lock); |
319 | |
320 | return ret; |
321 | } |
322 | |
323 | static const struct rtc_class_ops at91_rtc_ops = { |
324 | .read_time = at91_rtc_readtime, |
325 | .set_time = at91_rtc_settime, |
326 | .read_alarm = at91_rtc_readalarm, |
327 | .set_alarm = at91_rtc_setalarm, |
328 | .proc = at91_rtc_proc, |
329 | .alarm_irq_enable = at91_rtc_alarm_irq_enable, |
330 | }; |
331 | |
332 | /* |
333 | * Initialize and install RTC driver |
334 | */ |
335 | static int at91_rtc_probe(struct platform_device *pdev) |
336 | { |
337 | struct sam9_rtc *rtc; |
338 | int ret, irq; |
339 | u32 mr; |
340 | unsigned int sclk_rate; |
341 | struct of_phandle_args args; |
342 | |
343 | irq = platform_get_irq(pdev, 0); |
344 | if (irq < 0) |
345 | return irq; |
346 | |
347 | rtc = devm_kzalloc(dev: &pdev->dev, size: sizeof(*rtc), GFP_KERNEL); |
348 | if (!rtc) |
349 | return -ENOMEM; |
350 | |
351 | spin_lock_init(&rtc->lock); |
352 | rtc->irq = irq; |
353 | |
354 | /* platform setup code should have handled this; sigh */ |
355 | if (!device_can_wakeup(dev: &pdev->dev)) |
356 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
357 | |
358 | platform_set_drvdata(pdev, data: rtc); |
359 | |
360 | rtc->rtt = devm_platform_ioremap_resource(pdev, index: 0); |
361 | if (IS_ERR(ptr: rtc->rtt)) |
362 | return PTR_ERR(ptr: rtc->rtt); |
363 | |
364 | ret = of_parse_phandle_with_fixed_args(np: pdev->dev.of_node, |
365 | list_name: "atmel,rtt-rtc-time-reg" , cell_count: 1, index: 0, |
366 | out_args: &args); |
367 | if (ret) |
368 | return ret; |
369 | |
370 | rtc->gpbr = syscon_node_to_regmap(np: args.np); |
371 | rtc->gpbr_offset = args.args[0]; |
372 | if (IS_ERR(ptr: rtc->gpbr)) { |
373 | dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n" ); |
374 | return -ENOMEM; |
375 | } |
376 | |
377 | rtc->sclk = devm_clk_get(dev: &pdev->dev, NULL); |
378 | if (IS_ERR(ptr: rtc->sclk)) |
379 | return PTR_ERR(ptr: rtc->sclk); |
380 | |
381 | ret = clk_prepare_enable(clk: rtc->sclk); |
382 | if (ret) { |
383 | dev_err(&pdev->dev, "Could not enable slow clock\n" ); |
384 | return ret; |
385 | } |
386 | |
387 | sclk_rate = clk_get_rate(clk: rtc->sclk); |
388 | if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { |
389 | dev_err(&pdev->dev, "Invalid slow clock rate\n" ); |
390 | ret = -EINVAL; |
391 | goto err_clk; |
392 | } |
393 | |
394 | mr = rtt_readl(rtc, MR); |
395 | |
396 | /* unless RTT is counting at 1 Hz, re-initialize it */ |
397 | if ((mr & AT91_RTT_RTPRES) != sclk_rate) { |
398 | mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES); |
399 | gpbr_writel(rtc, val: 0); |
400 | } |
401 | |
402 | /* disable all interrupts (same as on shutdown path) */ |
403 | mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
404 | rtt_writel(rtc, MR, mr); |
405 | |
406 | rtc->rtcdev = devm_rtc_allocate_device(dev: &pdev->dev); |
407 | if (IS_ERR(ptr: rtc->rtcdev)) { |
408 | ret = PTR_ERR(ptr: rtc->rtcdev); |
409 | goto err_clk; |
410 | } |
411 | |
412 | rtc->rtcdev->ops = &at91_rtc_ops; |
413 | rtc->rtcdev->range_max = U32_MAX; |
414 | |
415 | /* register irq handler after we know what name we'll use */ |
416 | ret = devm_request_irq(dev: &pdev->dev, irq: rtc->irq, handler: at91_rtc_interrupt, |
417 | IRQF_SHARED | IRQF_COND_SUSPEND, |
418 | devname: dev_name(dev: &rtc->rtcdev->dev), dev_id: rtc); |
419 | if (ret) { |
420 | dev_dbg(&pdev->dev, "can't share IRQ %d?\n" , rtc->irq); |
421 | goto err_clk; |
422 | } |
423 | |
424 | /* NOTE: sam9260 rev A silicon has a ROM bug which resets the |
425 | * RTT on at least some reboots. If you have that chip, you must |
426 | * initialize the time from some external source like a GPS, wall |
427 | * clock, discrete RTC, etc |
428 | */ |
429 | |
430 | if (gpbr_readl(rtc) == 0) |
431 | dev_warn(&pdev->dev, "%s: SET TIME!\n" , |
432 | dev_name(&rtc->rtcdev->dev)); |
433 | |
434 | return devm_rtc_register_device(rtc->rtcdev); |
435 | |
436 | err_clk: |
437 | clk_disable_unprepare(clk: rtc->sclk); |
438 | |
439 | return ret; |
440 | } |
441 | |
442 | /* |
443 | * Disable and remove the RTC driver |
444 | */ |
445 | static void at91_rtc_remove(struct platform_device *pdev) |
446 | { |
447 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); |
448 | u32 mr = rtt_readl(rtc, MR); |
449 | |
450 | /* disable all interrupts */ |
451 | rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); |
452 | |
453 | clk_disable_unprepare(clk: rtc->sclk); |
454 | } |
455 | |
456 | static void at91_rtc_shutdown(struct platform_device *pdev) |
457 | { |
458 | struct sam9_rtc *rtc = platform_get_drvdata(pdev); |
459 | u32 mr = rtt_readl(rtc, MR); |
460 | |
461 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
462 | rtt_writel(rtc, MR, mr & ~rtc->imr); |
463 | } |
464 | |
465 | #ifdef CONFIG_PM_SLEEP |
466 | |
467 | /* AT91SAM9 RTC Power management control */ |
468 | |
469 | static int at91_rtc_suspend(struct device *dev) |
470 | { |
471 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
472 | u32 mr = rtt_readl(rtc, MR); |
473 | |
474 | /* |
475 | * This IRQ is shared with DBGU and other hardware which isn't |
476 | * necessarily a wakeup event source. |
477 | */ |
478 | rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
479 | if (rtc->imr) { |
480 | if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) { |
481 | unsigned long flags; |
482 | |
483 | enable_irq_wake(irq: rtc->irq); |
484 | spin_lock_irqsave(&rtc->lock, flags); |
485 | rtc->suspended = true; |
486 | spin_unlock_irqrestore(lock: &rtc->lock, flags); |
487 | /* don't let RTTINC cause wakeups */ |
488 | if (mr & AT91_RTT_RTTINCIEN) |
489 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); |
490 | } else { |
491 | rtt_writel(rtc, MR, mr & ~rtc->imr); |
492 | } |
493 | } |
494 | |
495 | return 0; |
496 | } |
497 | |
498 | static int at91_rtc_resume(struct device *dev) |
499 | { |
500 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
501 | u32 mr; |
502 | |
503 | if (rtc->imr) { |
504 | unsigned long flags; |
505 | |
506 | if (device_may_wakeup(dev)) |
507 | disable_irq_wake(irq: rtc->irq); |
508 | mr = rtt_readl(rtc, MR); |
509 | rtt_writel(rtc, MR, mr | rtc->imr); |
510 | |
511 | spin_lock_irqsave(&rtc->lock, flags); |
512 | rtc->suspended = false; |
513 | at91_rtc_cache_events(rtc); |
514 | at91_rtc_flush_events(rtc); |
515 | spin_unlock_irqrestore(lock: &rtc->lock, flags); |
516 | } |
517 | |
518 | return 0; |
519 | } |
520 | #endif |
521 | |
522 | static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); |
523 | |
524 | static const struct of_device_id at91_rtc_dt_ids[] = { |
525 | { .compatible = "atmel,at91sam9260-rtt" }, |
526 | { /* sentinel */ } |
527 | }; |
528 | MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); |
529 | |
530 | static struct platform_driver at91_rtc_driver = { |
531 | .probe = at91_rtc_probe, |
532 | .remove_new = at91_rtc_remove, |
533 | .shutdown = at91_rtc_shutdown, |
534 | .driver = { |
535 | .name = "rtc-at91sam9" , |
536 | .pm = &at91_rtc_pm_ops, |
537 | .of_match_table = at91_rtc_dt_ids, |
538 | }, |
539 | }; |
540 | |
541 | module_platform_driver(at91_rtc_driver); |
542 | |
543 | MODULE_AUTHOR("Michel Benoit" ); |
544 | MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x" ); |
545 | MODULE_LICENSE("GPL" ); |
546 | |