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 /* Read time from RTC and convert it from BCD */ 131 static int s3c_rtc_read_time(struct s3c_rtc *info, struct rtc_time *tm) 132 { 133 unsigned int have_retried = 0; 134 int ret; 135 136 ret = s3c_rtc_enable_clk(info); 137 if (ret) 138 return ret; 139 140 retry_get_time: 141 tm->tm_min = readb(info->base + S3C2410_RTCMIN); 142 tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); 143 tm->tm_mday = readb(info->base + S3C2410_RTCDATE); 144 tm->tm_mon = readb(info->base + S3C2410_RTCMON); 145 tm->tm_year = readb(info->base + S3C2410_RTCYEAR); 146 tm->tm_sec = readb(info->base + S3C2410_RTCSEC); 147 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 if (tm->tm_sec == 0 && !have_retried) { 154 have_retried = 1; 155 goto retry_get_time; 156 } 157 158 s3c_rtc_disable_clk(info); 159 160 tm->tm_sec = bcd2bin(tm->tm_sec); 161 tm->tm_min = bcd2bin(tm->tm_min); 162 tm->tm_hour = bcd2bin(tm->tm_hour); 163 tm->tm_mday = bcd2bin(tm->tm_mday); 164 tm->tm_mon = bcd2bin(tm->tm_mon); 165 tm->tm_year = bcd2bin(tm->tm_year); 166 167 return 0; 168 } 169 170 /* Convert time to BCD and write it to RTC */ 171 static int s3c_rtc_write_time(struct s3c_rtc *info, const struct rtc_time *tm) 172 { 173 int ret; 174 175 ret = s3c_rtc_enable_clk(info); 176 if (ret) 177 return ret; 178 179 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); 180 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); 181 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR); 182 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE); 183 writeb(bin2bcd(tm->tm_mon), info->base + S3C2410_RTCMON); 184 writeb(bin2bcd(tm->tm_year), info->base + S3C2410_RTCYEAR); 185 186 s3c_rtc_disable_clk(info); 187 188 return 0; 189 } 190 191 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *tm) 192 { 193 struct s3c_rtc *info = dev_get_drvdata(dev); 194 int ret; 195 196 ret = s3c_rtc_read_time(info, tm); 197 if (ret) 198 return ret; 199 200 /* Convert internal representation to actual date/time */ 201 tm->tm_year += 100; 202 tm->tm_mon -= 1; 203 204 dev_dbg(dev, "read time %ptR\n", tm); 205 return 0; 206 } 207 208 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) 209 { 210 struct s3c_rtc *info = dev_get_drvdata(dev); 211 struct rtc_time rtc_tm = *tm; 212 213 dev_dbg(dev, "set time %ptR\n", tm); 214 215 /* 216 * Convert actual date/time to internal representation. 217 * We get around Y2K by simply not supporting it. 218 */ 219 rtc_tm.tm_year -= 100; 220 rtc_tm.tm_mon += 1; 221 222 return s3c_rtc_write_time(info, &rtc_tm); 223 } 224 225 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) 226 { 227 struct s3c_rtc *info = dev_get_drvdata(dev); 228 struct rtc_time *alm_tm = &alrm->time; 229 unsigned int alm_en; 230 int ret; 231 232 ret = s3c_rtc_enable_clk(info); 233 if (ret) 234 return ret; 235 236 alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); 237 alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); 238 alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR); 239 alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON); 240 alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE); 241 alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR); 242 243 alm_en = readb(info->base + S3C2410_RTCALM); 244 245 s3c_rtc_disable_clk(info); 246 247 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; 248 249 dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm); 250 251 /* decode the alarm enable field */ 252 if (alm_en & S3C2410_RTCALM_SECEN) 253 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); 254 255 if (alm_en & S3C2410_RTCALM_MINEN) 256 alm_tm->tm_min = bcd2bin(alm_tm->tm_min); 257 258 if (alm_en & S3C2410_RTCALM_HOUREN) 259 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); 260 261 if (alm_en & S3C2410_RTCALM_DAYEN) 262 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); 263 264 if (alm_en & S3C2410_RTCALM_MONEN) { 265 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); 266 alm_tm->tm_mon -= 1; 267 } 268 269 if (alm_en & S3C2410_RTCALM_YEAREN) 270 alm_tm->tm_year = bcd2bin(alm_tm->tm_year); 271 272 return 0; 273 } 274 275 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) 276 { 277 struct s3c_rtc *info = dev_get_drvdata(dev); 278 struct rtc_time *tm = &alrm->time; 279 unsigned int alrm_en; 280 int ret; 281 282 dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm); 283 284 ret = s3c_rtc_enable_clk(info); 285 if (ret) 286 return ret; 287 288 alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; 289 writeb(0x00, info->base + S3C2410_RTCALM); 290 291 if (tm->tm_sec < 60 && tm->tm_sec >= 0) { 292 alrm_en |= S3C2410_RTCALM_SECEN; 293 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC); 294 } 295 296 if (tm->tm_min < 60 && tm->tm_min >= 0) { 297 alrm_en |= S3C2410_RTCALM_MINEN; 298 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN); 299 } 300 301 if (tm->tm_hour < 24 && tm->tm_hour >= 0) { 302 alrm_en |= S3C2410_RTCALM_HOUREN; 303 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); 304 } 305 306 if (tm->tm_mon < 12 && tm->tm_mon >= 0) { 307 alrm_en |= S3C2410_RTCALM_MONEN; 308 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); 309 } 310 311 if (tm->tm_mday <= 31 && tm->tm_mday >= 1) { 312 alrm_en |= S3C2410_RTCALM_DAYEN; 313 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE); 314 } 315 316 dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); 317 318 writeb(alrm_en, info->base + S3C2410_RTCALM); 319 320 s3c_rtc_setaie(dev, alrm->enabled); 321 322 s3c_rtc_disable_clk(info); 323 324 return 0; 325 } 326 327 static const struct rtc_class_ops s3c_rtcops = { 328 .read_time = s3c_rtc_gettime, 329 .set_time = s3c_rtc_settime, 330 .read_alarm = s3c_rtc_getalarm, 331 .set_alarm = s3c_rtc_setalarm, 332 .alarm_irq_enable = s3c_rtc_setaie, 333 }; 334 335 static void s3c24xx_rtc_enable(struct s3c_rtc *info) 336 { 337 unsigned int con, tmp; 338 339 con = readw(info->base + S3C2410_RTCCON); 340 /* re-enable the device, and check it is ok */ 341 if ((con & S3C2410_RTCCON_RTCEN) == 0) { 342 dev_info(info->dev, "rtc disabled, re-enabling\n"); 343 344 tmp = readw(info->base + S3C2410_RTCCON); 345 writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON); 346 } 347 348 if (con & S3C2410_RTCCON_CNTSEL) { 349 dev_info(info->dev, "removing RTCCON_CNTSEL\n"); 350 351 tmp = readw(info->base + S3C2410_RTCCON); 352 writew(tmp & ~S3C2410_RTCCON_CNTSEL, 353 info->base + S3C2410_RTCCON); 354 } 355 356 if (con & S3C2410_RTCCON_CLKRST) { 357 dev_info(info->dev, "removing RTCCON_CLKRST\n"); 358 359 tmp = readw(info->base + S3C2410_RTCCON); 360 writew(tmp & ~S3C2410_RTCCON_CLKRST, 361 info->base + S3C2410_RTCCON); 362 } 363 } 364 365 static void s3c24xx_rtc_disable(struct s3c_rtc *info) 366 { 367 unsigned int con; 368 369 con = readw(info->base + S3C2410_RTCCON); 370 con &= ~S3C2410_RTCCON_RTCEN; 371 writew(con, info->base + S3C2410_RTCCON); 372 373 con = readb(info->base + S3C2410_TICNT); 374 con &= ~S3C2410_TICNT_ENABLE; 375 writeb(con, info->base + S3C2410_TICNT); 376 } 377 378 static void s3c6410_rtc_disable(struct s3c_rtc *info) 379 { 380 unsigned int con; 381 382 con = readw(info->base + S3C2410_RTCCON); 383 con &= ~S3C64XX_RTCCON_TICEN; 384 con &= ~S3C2410_RTCCON_RTCEN; 385 writew(con, info->base + S3C2410_RTCCON); 386 } 387 388 static void s3c_rtc_remove(struct platform_device *pdev) 389 { 390 struct s3c_rtc *info = platform_get_drvdata(pdev); 391 392 s3c_rtc_setaie(info->dev, 0); 393 394 if (info->data->needs_src_clk) 395 clk_unprepare(info->rtc_src_clk); 396 clk_unprepare(info->rtc_clk); 397 } 398 399 static int s3c_rtc_probe(struct platform_device *pdev) 400 { 401 struct s3c_rtc *info = NULL; 402 int ret; 403 404 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 405 if (!info) 406 return -ENOMEM; 407 408 info->dev = &pdev->dev; 409 info->data = of_device_get_match_data(&pdev->dev); 410 if (!info->data) { 411 dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); 412 return -EINVAL; 413 } 414 spin_lock_init(&info->alarm_lock); 415 416 platform_set_drvdata(pdev, info); 417 418 info->irq_alarm = platform_get_irq(pdev, 0); 419 if (info->irq_alarm < 0) 420 return info->irq_alarm; 421 422 dev_dbg(&pdev->dev, "s3c2410_rtc: alarm irq %d\n", info->irq_alarm); 423 424 /* get the memory region */ 425 info->base = devm_platform_ioremap_resource(pdev, 0); 426 if (IS_ERR(info->base)) 427 return PTR_ERR(info->base); 428 429 info->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); 430 if (IS_ERR(info->rtc_clk)) 431 return dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_clk), 432 "failed to find rtc clock\n"); 433 ret = clk_prepare_enable(info->rtc_clk); 434 if (ret) 435 return ret; 436 437 if (info->data->needs_src_clk) { 438 info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); 439 if (IS_ERR(info->rtc_src_clk)) { 440 ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk), 441 "failed to find rtc source clock\n"); 442 goto err_src_clk; 443 } 444 ret = clk_prepare_enable(info->rtc_src_clk); 445 if (ret) 446 goto err_src_clk; 447 } 448 449 /* disable RTC enable bits potentially set by the bootloader */ 450 if (info->data->disable) 451 info->data->disable(info); 452 453 /* check to see if everything is setup correctly */ 454 if (info->data->enable) 455 info->data->enable(info); 456 457 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", 458 readw(info->base + S3C2410_RTCCON)); 459 460 device_init_wakeup(&pdev->dev, 1); 461 462 info->rtc = devm_rtc_allocate_device(&pdev->dev); 463 if (IS_ERR(info->rtc)) { 464 ret = PTR_ERR(info->rtc); 465 goto err_nortc; 466 } 467 468 info->rtc->ops = &s3c_rtcops; 469 info->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 470 info->rtc->range_max = RTC_TIMESTAMP_END_2099; 471 472 ret = devm_rtc_register_device(info->rtc); 473 if (ret) 474 goto err_nortc; 475 476 ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq, 477 0, "s3c2410-rtc alarm", info); 478 if (ret) { 479 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret); 480 goto err_nortc; 481 } 482 483 s3c_rtc_disable_clk(info); 484 485 return 0; 486 487 err_nortc: 488 if (info->data->disable) 489 info->data->disable(info); 490 491 if (info->data->needs_src_clk) 492 clk_disable_unprepare(info->rtc_src_clk); 493 err_src_clk: 494 clk_disable_unprepare(info->rtc_clk); 495 496 return ret; 497 } 498 499 #ifdef CONFIG_PM_SLEEP 500 501 static int s3c_rtc_suspend(struct device *dev) 502 { 503 struct s3c_rtc *info = dev_get_drvdata(dev); 504 int ret; 505 506 ret = s3c_rtc_enable_clk(info); 507 if (ret) 508 return ret; 509 510 if (info->data->disable) 511 info->data->disable(info); 512 513 if (device_may_wakeup(dev) && !info->wake_en) { 514 if (enable_irq_wake(info->irq_alarm) == 0) 515 info->wake_en = true; 516 else 517 dev_err(dev, "enable_irq_wake failed\n"); 518 } 519 520 return 0; 521 } 522 523 static int s3c_rtc_resume(struct device *dev) 524 { 525 struct s3c_rtc *info = dev_get_drvdata(dev); 526 527 if (info->data->enable) 528 info->data->enable(info); 529 530 s3c_rtc_disable_clk(info); 531 532 if (device_may_wakeup(dev) && info->wake_en) { 533 disable_irq_wake(info->irq_alarm); 534 info->wake_en = false; 535 } 536 537 return 0; 538 } 539 #endif 540 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); 541 542 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) 543 { 544 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 545 } 546 547 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) 548 { 549 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 550 writeb(mask, info->base + S3C2410_INTP); 551 } 552 553 static struct s3c_rtc_data const s3c2410_rtc_data = { 554 .irq_handler = s3c24xx_rtc_irq, 555 .enable = s3c24xx_rtc_enable, 556 .disable = s3c24xx_rtc_disable, 557 }; 558 559 static struct s3c_rtc_data const s3c2416_rtc_data = { 560 .irq_handler = s3c24xx_rtc_irq, 561 .enable = s3c24xx_rtc_enable, 562 .disable = s3c24xx_rtc_disable, 563 }; 564 565 static struct s3c_rtc_data const s3c2443_rtc_data = { 566 .irq_handler = s3c24xx_rtc_irq, 567 .enable = s3c24xx_rtc_enable, 568 .disable = s3c24xx_rtc_disable, 569 }; 570 571 static struct s3c_rtc_data const s3c6410_rtc_data = { 572 .needs_src_clk = true, 573 .irq_handler = s3c6410_rtc_irq, 574 .enable = s3c24xx_rtc_enable, 575 .disable = s3c6410_rtc_disable, 576 }; 577 578 static const __maybe_unused struct of_device_id s3c_rtc_dt_match[] = { 579 { 580 .compatible = "samsung,s3c2410-rtc", 581 .data = &s3c2410_rtc_data, 582 }, { 583 .compatible = "samsung,s3c2416-rtc", 584 .data = &s3c2416_rtc_data, 585 }, { 586 .compatible = "samsung,s3c2443-rtc", 587 .data = &s3c2443_rtc_data, 588 }, { 589 .compatible = "samsung,s3c6410-rtc", 590 .data = &s3c6410_rtc_data, 591 }, { 592 .compatible = "samsung,exynos3250-rtc", 593 .data = &s3c6410_rtc_data, 594 }, 595 { /* sentinel */ }, 596 }; 597 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); 598 599 static struct platform_driver s3c_rtc_driver = { 600 .probe = s3c_rtc_probe, 601 .remove_new = s3c_rtc_remove, 602 .driver = { 603 .name = "s3c-rtc", 604 .pm = &s3c_rtc_pm_ops, 605 .of_match_table = of_match_ptr(s3c_rtc_dt_match), 606 }, 607 }; 608 module_platform_driver(s3c_rtc_driver); 609 610 MODULE_DESCRIPTION("Samsung S3C RTC Driver"); 611 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 612 MODULE_LICENSE("GPL"); 613 MODULE_ALIAS("platform:s3c2410-rtc"); 614