| .. | .. |
|---|
| 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, |
|---|