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