.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * "RTT as Real Time Clock" driver for AT91SAM9 SoC family |
---|
3 | 4 | * |
---|
4 | 5 | * (C) 2007 Michel Benoit |
---|
5 | 6 | * |
---|
6 | 7 | * Based on rtc-at91rm9200.c by Rick Bronson |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License |
---|
10 | | - * as published by the Free Software Foundation; either version |
---|
11 | | - * 2 of the License, or (at your option) any later version. |
---|
12 | 8 | */ |
---|
13 | 9 | |
---|
14 | 10 | #include <linux/clk.h> |
---|
.. | .. |
---|
47 | 43 | * registers available, likewise usable for more than "RTC" support. |
---|
48 | 44 | */ |
---|
49 | 45 | |
---|
50 | | -#define AT91_RTT_MR 0x00 /* Real-time Mode Register */ |
---|
51 | | -#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */ |
---|
52 | | -#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */ |
---|
53 | | -#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */ |
---|
54 | | -#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */ |
---|
| 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 */ |
---|
55 | 51 | |
---|
56 | | -#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ |
---|
57 | | -#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ |
---|
| 52 | +#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */ |
---|
| 53 | +#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */ |
---|
58 | 54 | |
---|
59 | | -#define AT91_RTT_VR 0x08 /* Real-time Value Register */ |
---|
60 | | -#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ |
---|
| 55 | +#define AT91_RTT_VR 0x08 /* Real-time Value Register */ |
---|
| 56 | +#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */ |
---|
61 | 57 | |
---|
62 | | -#define AT91_RTT_SR 0x0c /* Real-time Status Register */ |
---|
63 | | -#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */ |
---|
64 | | -#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */ |
---|
| 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 */ |
---|
65 | 61 | |
---|
66 | 62 | /* |
---|
67 | 63 | * We store ALARM_DISABLED in ALMV to record that no alarm is set. |
---|
.. | .. |
---|
69 | 65 | */ |
---|
70 | 66 | #define ALARM_DISABLED ((u32)~0) |
---|
71 | 67 | |
---|
72 | | - |
---|
73 | 68 | struct sam9_rtc { |
---|
74 | 69 | void __iomem *rtt; |
---|
75 | 70 | struct rtc_device *rtcdev; |
---|
76 | 71 | u32 imr; |
---|
77 | 72 | struct regmap *gpbr; |
---|
78 | 73 | unsigned int gpbr_offset; |
---|
79 | | - int irq; |
---|
| 74 | + int irq; |
---|
80 | 75 | struct clk *sclk; |
---|
81 | 76 | bool suspended; |
---|
82 | 77 | unsigned long events; |
---|
.. | .. |
---|
122 | 117 | if (secs != secs2) |
---|
123 | 118 | secs = rtt_readl(rtc, VR); |
---|
124 | 119 | |
---|
125 | | - rtc_time_to_tm(offset + secs, tm); |
---|
| 120 | + rtc_time64_to_tm(offset + secs, tm); |
---|
126 | 121 | |
---|
127 | | - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime", |
---|
128 | | - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
---|
129 | | - tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
| 122 | + dev_dbg(dev, "%s: %ptR\n", __func__, tm); |
---|
130 | 123 | |
---|
131 | 124 | return 0; |
---|
132 | 125 | } |
---|
.. | .. |
---|
137 | 130 | static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) |
---|
138 | 131 | { |
---|
139 | 132 | struct sam9_rtc *rtc = dev_get_drvdata(dev); |
---|
140 | | - int err; |
---|
141 | 133 | u32 offset, alarm, mr; |
---|
142 | 134 | unsigned long secs; |
---|
143 | 135 | |
---|
144 | | - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime", |
---|
145 | | - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
---|
146 | | - tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
| 136 | + dev_dbg(dev, "%s: %ptR\n", __func__, tm); |
---|
147 | 137 | |
---|
148 | | - err = rtc_tm_to_time(tm, &secs); |
---|
149 | | - if (err != 0) |
---|
150 | | - return err; |
---|
| 138 | + secs = rtc_tm_to_time64(tm); |
---|
151 | 139 | |
---|
152 | 140 | mr = rtt_readl(rtc, MR); |
---|
153 | 141 | |
---|
.. | .. |
---|
197 | 185 | |
---|
198 | 186 | memset(alrm, 0, sizeof(*alrm)); |
---|
199 | 187 | if (alarm != ALARM_DISABLED && offset != 0) { |
---|
200 | | - rtc_time_to_tm(offset + alarm, tm); |
---|
| 188 | + rtc_time64_to_tm(offset + alarm, tm); |
---|
201 | 189 | |
---|
202 | | - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm", |
---|
203 | | - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
---|
204 | | - tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
| 190 | + dev_dbg(dev, "%s: %ptR\n", __func__, tm); |
---|
205 | 191 | |
---|
206 | 192 | if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN) |
---|
207 | 193 | alrm->enabled = 1; |
---|
.. | .. |
---|
217 | 203 | unsigned long secs; |
---|
218 | 204 | u32 offset; |
---|
219 | 205 | u32 mr; |
---|
220 | | - int err; |
---|
221 | 206 | |
---|
222 | | - err = rtc_tm_to_time(tm, &secs); |
---|
223 | | - if (err != 0) |
---|
224 | | - return err; |
---|
| 207 | + secs = rtc_tm_to_time64(tm); |
---|
225 | 208 | |
---|
226 | 209 | offset = gpbr_readl(rtc); |
---|
227 | 210 | if (offset == 0) { |
---|
.. | .. |
---|
242 | 225 | if (alrm->enabled) |
---|
243 | 226 | rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); |
---|
244 | 227 | |
---|
245 | | - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm", |
---|
246 | | - tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, |
---|
247 | | - tm->tm_min, tm->tm_sec); |
---|
| 228 | + dev_dbg(dev, "%s: %ptR\n", __func__, tm); |
---|
248 | 229 | |
---|
249 | 230 | return 0; |
---|
250 | 231 | } |
---|
.. | .. |
---|
271 | 252 | u32 mr = rtt_readl(rtc, MR); |
---|
272 | 253 | |
---|
273 | 254 | seq_printf(seq, "update_IRQ\t: %s\n", |
---|
274 | | - (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no"); |
---|
| 255 | + (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no"); |
---|
275 | 256 | return 0; |
---|
276 | 257 | } |
---|
277 | 258 | |
---|
.. | .. |
---|
307 | 288 | rtc->events = 0; |
---|
308 | 289 | |
---|
309 | 290 | pr_debug("%s: num=%ld, events=0x%02lx\n", __func__, |
---|
310 | | - rtc->events >> 8, rtc->events & 0x000000FF); |
---|
| 291 | + rtc->events >> 8, rtc->events & 0x000000FF); |
---|
311 | 292 | } |
---|
312 | 293 | |
---|
313 | 294 | /* |
---|
.. | .. |
---|
348 | 329 | .alarm_irq_enable = at91_rtc_alarm_irq_enable, |
---|
349 | 330 | }; |
---|
350 | 331 | |
---|
351 | | -static const struct regmap_config gpbr_regmap_config = { |
---|
352 | | - .name = "gpbr", |
---|
353 | | - .reg_bits = 32, |
---|
354 | | - .val_bits = 32, |
---|
355 | | - .reg_stride = 4, |
---|
356 | | -}; |
---|
357 | | - |
---|
358 | 332 | /* |
---|
359 | 333 | * Initialize and install RTC driver |
---|
360 | 334 | */ |
---|
361 | 335 | static int at91_rtc_probe(struct platform_device *pdev) |
---|
362 | 336 | { |
---|
363 | | - struct resource *r; |
---|
364 | 337 | struct sam9_rtc *rtc; |
---|
365 | 338 | int ret, irq; |
---|
366 | 339 | u32 mr; |
---|
367 | 340 | unsigned int sclk_rate; |
---|
| 341 | + struct of_phandle_args args; |
---|
368 | 342 | |
---|
369 | 343 | irq = platform_get_irq(pdev, 0); |
---|
370 | | - if (irq < 0) { |
---|
371 | | - dev_err(&pdev->dev, "failed to get interrupt resource\n"); |
---|
| 344 | + if (irq < 0) |
---|
372 | 345 | return irq; |
---|
373 | | - } |
---|
374 | 346 | |
---|
375 | 347 | rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); |
---|
376 | 348 | if (!rtc) |
---|
.. | .. |
---|
385 | 357 | |
---|
386 | 358 | platform_set_drvdata(pdev, rtc); |
---|
387 | 359 | |
---|
388 | | - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
389 | | - rtc->rtt = devm_ioremap_resource(&pdev->dev, r); |
---|
| 360 | + rtc->rtt = devm_platform_ioremap_resource(pdev, 0); |
---|
390 | 361 | if (IS_ERR(rtc->rtt)) |
---|
391 | 362 | return PTR_ERR(rtc->rtt); |
---|
392 | 363 | |
---|
393 | | - if (!pdev->dev.of_node) { |
---|
394 | | - /* |
---|
395 | | - * TODO: Remove this code chunk when removing non DT board |
---|
396 | | - * support. Remember to remove the gpbr_regmap_config |
---|
397 | | - * variable too. |
---|
398 | | - */ |
---|
399 | | - void __iomem *gpbr; |
---|
| 364 | + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, |
---|
| 365 | + "atmel,rtt-rtc-time-reg", 1, 0, |
---|
| 366 | + &args); |
---|
| 367 | + if (ret) |
---|
| 368 | + return ret; |
---|
400 | 369 | |
---|
401 | | - r = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
---|
402 | | - gpbr = devm_ioremap_resource(&pdev->dev, r); |
---|
403 | | - if (IS_ERR(gpbr)) |
---|
404 | | - return PTR_ERR(gpbr); |
---|
405 | | - |
---|
406 | | - rtc->gpbr = regmap_init_mmio(NULL, gpbr, |
---|
407 | | - &gpbr_regmap_config); |
---|
408 | | - } else { |
---|
409 | | - struct of_phandle_args args; |
---|
410 | | - |
---|
411 | | - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, |
---|
412 | | - "atmel,rtt-rtc-time-reg", 1, 0, |
---|
413 | | - &args); |
---|
414 | | - if (ret) |
---|
415 | | - return ret; |
---|
416 | | - |
---|
417 | | - rtc->gpbr = syscon_node_to_regmap(args.np); |
---|
418 | | - rtc->gpbr_offset = args.args[0]; |
---|
419 | | - } |
---|
420 | | - |
---|
| 370 | + rtc->gpbr = syscon_node_to_regmap(args.np); |
---|
| 371 | + rtc->gpbr_offset = args.args[0]; |
---|
421 | 372 | if (IS_ERR(rtc->gpbr)) { |
---|
422 | 373 | dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n"); |
---|
423 | 374 | return -ENOMEM; |
---|
.. | .. |
---|
452 | 403 | mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); |
---|
453 | 404 | rtt_writel(rtc, MR, mr); |
---|
454 | 405 | |
---|
455 | | - rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, |
---|
456 | | - &at91_rtc_ops, THIS_MODULE); |
---|
| 406 | + rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev); |
---|
457 | 407 | if (IS_ERR(rtc->rtcdev)) { |
---|
458 | 408 | ret = PTR_ERR(rtc->rtcdev); |
---|
459 | 409 | goto err_clk; |
---|
460 | 410 | } |
---|
| 411 | + |
---|
| 412 | + rtc->rtcdev->ops = &at91_rtc_ops; |
---|
| 413 | + rtc->rtcdev->range_max = U32_MAX; |
---|
461 | 414 | |
---|
462 | 415 | /* register irq handler after we know what name we'll use */ |
---|
463 | 416 | ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, |
---|
.. | .. |
---|
476 | 429 | |
---|
477 | 430 | if (gpbr_readl(rtc) == 0) |
---|
478 | 431 | dev_warn(&pdev->dev, "%s: SET TIME!\n", |
---|
479 | | - dev_name(&rtc->rtcdev->dev)); |
---|
| 432 | + dev_name(&rtc->rtcdev->dev)); |
---|
480 | 433 | |
---|
481 | | - return 0; |
---|
| 434 | + return rtc_register_device(rtc->rtcdev); |
---|
482 | 435 | |
---|
483 | 436 | err_clk: |
---|
484 | 437 | clk_disable_unprepare(rtc->sclk); |
---|
.. | .. |
---|
536 | 489 | /* don't let RTTINC cause wakeups */ |
---|
537 | 490 | if (mr & AT91_RTT_RTTINCIEN) |
---|
538 | 491 | rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); |
---|
539 | | - } else |
---|
| 492 | + } else { |
---|
540 | 493 | rtt_writel(rtc, MR, mr & ~rtc->imr); |
---|
| 494 | + } |
---|
541 | 495 | } |
---|
542 | 496 | |
---|
543 | 497 | return 0; |
---|
.. | .. |
---|
569 | 523 | |
---|
570 | 524 | static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume); |
---|
571 | 525 | |
---|
572 | | -#ifdef CONFIG_OF |
---|
573 | 526 | static const struct of_device_id at91_rtc_dt_ids[] = { |
---|
574 | 527 | { .compatible = "atmel,at91sam9260-rtt" }, |
---|
575 | 528 | { /* sentinel */ } |
---|
576 | 529 | }; |
---|
577 | 530 | MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids); |
---|
578 | | -#endif |
---|
579 | 531 | |
---|
580 | 532 | static struct platform_driver at91_rtc_driver = { |
---|
581 | 533 | .probe = at91_rtc_probe, |
---|