1 /* drivers/rtc/rtc-s3c.c 2 * 3 * Copyright (c) 2010 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com/ 5 * 6 * Copyright (c) 2004,2006 Simtec Electronics 7 * Ben Dooks, <ben@simtec.co.uk> 8 * http://armlinux.simtec.co.uk/ 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * S3C2410/S3C2440/S3C24XX Internal RTC Driver 15 */ 16 17 #include <linux/module.h> 18 #include <linux/fs.h> 19 #include <linux/string.h> 20 #include <linux/init.h> 21 #include <linux/platform_device.h> 22 #include <linux/interrupt.h> 23 #include <linux/rtc.h> 24 #include <linux/bcd.h> 25 #include <linux/clk.h> 26 #include <linux/log2.h> 27 #include <linux/slab.h> 28 #include <linux/of.h> 29 #include <linux/of_device.h> 30 #include <linux/uaccess.h> 31 #include <linux/io.h> 32 33 #include <asm/irq.h> 34 #include "rtc-s3c.h" 35 36 struct s3c_rtc { 37 struct device *dev; 38 struct rtc_device *rtc; 39 40 void __iomem *base; 41 struct clk *rtc_clk; 42 struct clk *rtc_src_clk; 43 bool alarm_enabled; 44 45 const struct s3c_rtc_data *data; 46 47 int irq_alarm; 48 int irq_tick; 49 50 spinlock_t pie_lock; 51 spinlock_t alarm_lock; 52 53 int ticnt_save; 54 int ticnt_en_save; 55 bool wake_en; 56 }; 57 58 struct s3c_rtc_data { 59 int max_user_freq; 60 bool needs_src_clk; 61 62 void (*irq_handler) (struct s3c_rtc *info, int mask); 63 void (*set_freq) (struct s3c_rtc *info, int freq); 64 void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq); 65 void (*select_tick_clk) (struct s3c_rtc *info); 66 void (*save_tick_cnt) (struct s3c_rtc *info); 67 void (*restore_tick_cnt) (struct s3c_rtc *info); 68 void (*enable) (struct s3c_rtc *info); 69 void (*disable) (struct s3c_rtc *info); 70 }; 71 72 static int s3c_rtc_enable_clk(struct s3c_rtc *info) 73 { 74 int ret; 75 76 ret = clk_enable(info->rtc_clk); 77 if (ret) 78 return ret; 79 80 if (info->data->needs_src_clk) { 81 ret = clk_enable(info->rtc_src_clk); 82 if (ret) { 83 clk_disable(info->rtc_clk); 84 return ret; 85 } 86 } 87 return 0; 88 } 89 90 static void s3c_rtc_disable_clk(struct s3c_rtc *info) 91 { 92 if (info->data->needs_src_clk) 93 clk_disable(info->rtc_src_clk); 94 clk_disable(info->rtc_clk); 95 } 96 97 /* IRQ Handlers */ 98 static irqreturn_t s3c_rtc_tickirq(int irq, void *id) 99 { 100 struct s3c_rtc *info = (struct s3c_rtc *)id; 101 102 if (info->data->irq_handler) 103 info->data->irq_handler(info, S3C2410_INTP_TIC); 104 105 return IRQ_HANDLED; 106 } 107 108 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) 109 { 110 struct s3c_rtc *info = (struct s3c_rtc *)id; 111 112 if (info->data->irq_handler) 113 info->data->irq_handler(info, S3C2410_INTP_ALM); 114 115 return IRQ_HANDLED; 116 } 117 118 /* Update control registers */ 119 static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) 120 { 121 struct s3c_rtc *info = dev_get_drvdata(dev); 122 unsigned long flags; 123 unsigned int tmp; 124 int ret; 125 126 dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); 127 128 ret = s3c_rtc_enable_clk(info); 129 if (ret) 130 return ret; 131 132 tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; 133 134 if (enabled) 135 tmp |= S3C2410_RTCALM_ALMEN; 136 137 writeb(tmp, info->base + S3C2410_RTCALM); 138 139 spin_lock_irqsave(&info->alarm_lock, flags); 140 141 if (info->alarm_enabled && !enabled) 142 s3c_rtc_disable_clk(info); 143 else if (!info->alarm_enabled && enabled) 144 ret = s3c_rtc_enable_clk(info); 145 146 info->alarm_enabled = enabled; 147 spin_unlock_irqrestore(&info->alarm_lock, flags); 148 149 s3c_rtc_disable_clk(info); 150 151 return ret; 152 } 153 154 /* Set RTC frequency */ 155 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq) 156 { 157 int ret; 158 159 if (!is_power_of_2(freq)) 160 return -EINVAL; 161 162 ret = s3c_rtc_enable_clk(info); 163 if (ret) 164 return ret; 165 spin_lock_irq(&info->pie_lock); 166 167 if (info->data->set_freq) 168 info->data->set_freq(info, freq); 169 170 spin_unlock_irq(&info->pie_lock); 171 s3c_rtc_disable_clk(info); 172 173 return 0; 174 } 175 176 /* Time read/write */ 177 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) 178 { 179 struct s3c_rtc *info = dev_get_drvdata(dev); 180 unsigned int have_retried = 0; 181 int ret; 182 183 ret = s3c_rtc_enable_clk(info); 184 if (ret) 185 return ret; 186 187 retry_get_time: 188 rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); 189 rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); 190 rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE); 191 rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON); 192 rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR); 193 rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC); 194 195 /* the only way to work out whether the system was mid-update 196 * when we read it is to check the second counter, and if it 197 * is zero, then we re-try the entire read 198 */ 199 200 if (rtc_tm->tm_sec == 0 && !have_retried) { 201 have_retried = 1; 202 goto retry_get_time; 203 } 204 205 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); 206 rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); 207 rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); 208 rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); 209 rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); 210 rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); 211 212 s3c_rtc_disable_clk(info); 213 214 rtc_tm->tm_year += 100; 215 rtc_tm->tm_mon -= 1; 216 217 dev_dbg(dev, "read time %ptR\n", rtc_tm); 218 return 0; 219 } 220 221 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) 222 { 223 struct s3c_rtc *info = dev_get_drvdata(dev); 224 int year = tm->tm_year - 100; 225 int ret; 226 227 dev_dbg(dev, "set time %ptR\n", tm); 228 229 /* we get around y2k by simply not supporting it */ 230 231 if (year < 0 || year >= 100) { 232 dev_err(dev, "rtc only supports 100 years\n"); 233 return -EINVAL; 234 } 235 236 ret = s3c_rtc_enable_clk(info); 237 if (ret) 238 return ret; 239 240 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); 241 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); 242 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR); 243 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE); 244 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON); 245 writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); 246 247 s3c_rtc_disable_clk(info); 248 249 return 0; 250 } 251 252 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) 253 { 254 struct s3c_rtc *info = dev_get_drvdata(dev); 255 struct rtc_time *alm_tm = &alrm->time; 256 unsigned int alm_en; 257 int ret; 258 259 ret = s3c_rtc_enable_clk(info); 260 if (ret) 261 return ret; 262 263 alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); 264 alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); 265 alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR); 266 alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON); 267 alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE); 268 alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR); 269 270 alm_en = readb(info->base + S3C2410_RTCALM); 271 272 s3c_rtc_disable_clk(info); 273 274 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; 275 276 dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm); 277 278 /* decode the alarm enable field */ 279 if (alm_en & S3C2410_RTCALM_SECEN) 280 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); 281 282 if (alm_en & S3C2410_RTCALM_MINEN) 283 alm_tm->tm_min = bcd2bin(alm_tm->tm_min); 284 285 if (alm_en & S3C2410_RTCALM_HOUREN) 286 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); 287 288 if (alm_en & S3C2410_RTCALM_DAYEN) 289 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); 290 291 if (alm_en & S3C2410_RTCALM_MONEN) { 292 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); 293 alm_tm->tm_mon -= 1; 294 } 295 296 if (alm_en & S3C2410_RTCALM_YEAREN) 297 alm_tm->tm_year = bcd2bin(alm_tm->tm_year); 298 299 return 0; 300 } 301 302 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) 303 { 304 struct s3c_rtc *info = dev_get_drvdata(dev); 305 struct rtc_time *tm = &alrm->time; 306 unsigned int alrm_en; 307 int ret; 308 309 dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm); 310 311 ret = s3c_rtc_enable_clk(info); 312 if (ret) 313 return ret; 314 315 alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; 316 writeb(0x00, info->base + S3C2410_RTCALM); 317 318 if (tm->tm_sec < 60 && tm->tm_sec >= 0) { 319 alrm_en |= S3C2410_RTCALM_SECEN; 320 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC); 321 } 322 323 if (tm->tm_min < 60 && tm->tm_min >= 0) { 324 alrm_en |= S3C2410_RTCALM_MINEN; 325 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN); 326 } 327 328 if (tm->tm_hour < 24 && tm->tm_hour >= 0) { 329 alrm_en |= S3C2410_RTCALM_HOUREN; 330 writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); 331 } 332 333 if (tm->tm_mon < 12 && tm->tm_mon >= 0) { 334 alrm_en |= S3C2410_RTCALM_MONEN; 335 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); 336 } 337 338 if (tm->tm_mday <= 31 && tm->tm_mday >= 1) { 339 alrm_en |= S3C2410_RTCALM_DAYEN; 340 writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE); 341 } 342 343 dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); 344 345 writeb(alrm_en, info->base + S3C2410_RTCALM); 346 347 s3c_rtc_setaie(dev, alrm->enabled); 348 349 s3c_rtc_disable_clk(info); 350 351 return 0; 352 } 353 354 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 355 { 356 struct s3c_rtc *info = dev_get_drvdata(dev); 357 int ret; 358 359 ret = s3c_rtc_enable_clk(info); 360 if (ret) 361 return ret; 362 363 if (info->data->enable_tick) 364 info->data->enable_tick(info, seq); 365 366 s3c_rtc_disable_clk(info); 367 368 return 0; 369 } 370 371 static const struct rtc_class_ops s3c_rtcops = { 372 .read_time = s3c_rtc_gettime, 373 .set_time = s3c_rtc_settime, 374 .read_alarm = s3c_rtc_getalarm, 375 .set_alarm = s3c_rtc_setalarm, 376 .proc = s3c_rtc_proc, 377 .alarm_irq_enable = s3c_rtc_setaie, 378 }; 379 380 static void s3c24xx_rtc_enable(struct s3c_rtc *info) 381 { 382 unsigned int con, tmp; 383 384 con = readw(info->base + S3C2410_RTCCON); 385 /* re-enable the device, and check it is ok */ 386 if ((con & S3C2410_RTCCON_RTCEN) == 0) { 387 dev_info(info->dev, "rtc disabled, re-enabling\n"); 388 389 tmp = readw(info->base + S3C2410_RTCCON); 390 writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON); 391 } 392 393 if (con & S3C2410_RTCCON_CNTSEL) { 394 dev_info(info->dev, "removing RTCCON_CNTSEL\n"); 395 396 tmp = readw(info->base + S3C2410_RTCCON); 397 writew(tmp & ~S3C2410_RTCCON_CNTSEL, 398 info->base + S3C2410_RTCCON); 399 } 400 401 if (con & S3C2410_RTCCON_CLKRST) { 402 dev_info(info->dev, "removing RTCCON_CLKRST\n"); 403 404 tmp = readw(info->base + S3C2410_RTCCON); 405 writew(tmp & ~S3C2410_RTCCON_CLKRST, 406 info->base + S3C2410_RTCCON); 407 } 408 } 409 410 static void s3c24xx_rtc_disable(struct s3c_rtc *info) 411 { 412 unsigned int con; 413 414 con = readw(info->base + S3C2410_RTCCON); 415 con &= ~S3C2410_RTCCON_RTCEN; 416 writew(con, info->base + S3C2410_RTCCON); 417 418 con = readb(info->base + S3C2410_TICNT); 419 con &= ~S3C2410_TICNT_ENABLE; 420 writeb(con, info->base + S3C2410_TICNT); 421 } 422 423 static void s3c6410_rtc_disable(struct s3c_rtc *info) 424 { 425 unsigned int con; 426 427 con = readw(info->base + S3C2410_RTCCON); 428 con &= ~S3C64XX_RTCCON_TICEN; 429 con &= ~S3C2410_RTCCON_RTCEN; 430 writew(con, info->base + S3C2410_RTCCON); 431 } 432 433 static int s3c_rtc_remove(struct platform_device *pdev) 434 { 435 struct s3c_rtc *info = platform_get_drvdata(pdev); 436 437 s3c_rtc_setaie(info->dev, 0); 438 439 if (info->data->needs_src_clk) 440 clk_unprepare(info->rtc_src_clk); 441 clk_unprepare(info->rtc_clk); 442 443 return 0; 444 } 445 446 static int s3c_rtc_probe(struct platform_device *pdev) 447 { 448 struct s3c_rtc *info = NULL; 449 struct rtc_time rtc_tm; 450 struct resource *res; 451 int ret; 452 453 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 454 if (!info) 455 return -ENOMEM; 456 457 /* find the IRQs */ 458 info->irq_tick = platform_get_irq(pdev, 1); 459 if (info->irq_tick < 0) { 460 dev_err(&pdev->dev, "no irq for rtc tick\n"); 461 return info->irq_tick; 462 } 463 464 info->dev = &pdev->dev; 465 info->data = of_device_get_match_data(&pdev->dev); 466 if (!info->data) { 467 dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); 468 return -EINVAL; 469 } 470 spin_lock_init(&info->pie_lock); 471 spin_lock_init(&info->alarm_lock); 472 473 platform_set_drvdata(pdev, info); 474 475 info->irq_alarm = platform_get_irq(pdev, 0); 476 if (info->irq_alarm < 0) { 477 dev_err(&pdev->dev, "no irq for alarm\n"); 478 return info->irq_alarm; 479 } 480 481 dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", 482 info->irq_tick, info->irq_alarm); 483 484 /* get the memory region */ 485 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 486 info->base = devm_ioremap_resource(&pdev->dev, res); 487 if (IS_ERR(info->base)) 488 return PTR_ERR(info->base); 489 490 info->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); 491 if (IS_ERR(info->rtc_clk)) { 492 ret = PTR_ERR(info->rtc_clk); 493 if (ret != -EPROBE_DEFER) 494 dev_err(&pdev->dev, "failed to find rtc clock\n"); 495 else 496 dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n"); 497 return ret; 498 } 499 ret = clk_prepare_enable(info->rtc_clk); 500 if (ret) 501 return ret; 502 503 if (info->data->needs_src_clk) { 504 info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); 505 if (IS_ERR(info->rtc_src_clk)) { 506 ret = PTR_ERR(info->rtc_src_clk); 507 if (ret != -EPROBE_DEFER) 508 dev_err(&pdev->dev, 509 "failed to find rtc source clock\n"); 510 else 511 dev_dbg(&pdev->dev, 512 "probe deferred due to missing rtc src clk\n"); 513 goto err_src_clk; 514 } 515 ret = clk_prepare_enable(info->rtc_src_clk); 516 if (ret) 517 goto err_src_clk; 518 } 519 520 /* check to see if everything is setup correctly */ 521 if (info->data->enable) 522 info->data->enable(info); 523 524 dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n", 525 readw(info->base + S3C2410_RTCCON)); 526 527 device_init_wakeup(&pdev->dev, 1); 528 529 /* Check RTC Time */ 530 if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) { 531 rtc_tm.tm_year = 100; 532 rtc_tm.tm_mon = 0; 533 rtc_tm.tm_mday = 1; 534 rtc_tm.tm_hour = 0; 535 rtc_tm.tm_min = 0; 536 rtc_tm.tm_sec = 0; 537 538 s3c_rtc_settime(&pdev->dev, &rtc_tm); 539 540 dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n"); 541 } 542 543 /* register RTC and exit */ 544 info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, 545 THIS_MODULE); 546 if (IS_ERR(info->rtc)) { 547 dev_err(&pdev->dev, "cannot attach rtc\n"); 548 ret = PTR_ERR(info->rtc); 549 goto err_nortc; 550 } 551 552 ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq, 553 0, "s3c2410-rtc alarm", info); 554 if (ret) { 555 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret); 556 goto err_nortc; 557 } 558 559 ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq, 560 0, "s3c2410-rtc tick", info); 561 if (ret) { 562 dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret); 563 goto err_nortc; 564 } 565 566 if (info->data->select_tick_clk) 567 info->data->select_tick_clk(info); 568 569 s3c_rtc_setfreq(info, 1); 570 571 s3c_rtc_disable_clk(info); 572 573 return 0; 574 575 err_nortc: 576 if (info->data->disable) 577 info->data->disable(info); 578 579 if (info->data->needs_src_clk) 580 clk_disable_unprepare(info->rtc_src_clk); 581 err_src_clk: 582 clk_disable_unprepare(info->rtc_clk); 583 584 return ret; 585 } 586 587 #ifdef CONFIG_PM_SLEEP 588 589 static int s3c_rtc_suspend(struct device *dev) 590 { 591 struct s3c_rtc *info = dev_get_drvdata(dev); 592 int ret; 593 594 ret = s3c_rtc_enable_clk(info); 595 if (ret) 596 return ret; 597 598 /* save TICNT for anyone using periodic interrupts */ 599 if (info->data->save_tick_cnt) 600 info->data->save_tick_cnt(info); 601 602 if (info->data->disable) 603 info->data->disable(info); 604 605 if (device_may_wakeup(dev) && !info->wake_en) { 606 if (enable_irq_wake(info->irq_alarm) == 0) 607 info->wake_en = true; 608 else 609 dev_err(dev, "enable_irq_wake failed\n"); 610 } 611 612 return 0; 613 } 614 615 static int s3c_rtc_resume(struct device *dev) 616 { 617 struct s3c_rtc *info = dev_get_drvdata(dev); 618 619 if (info->data->enable) 620 info->data->enable(info); 621 622 if (info->data->restore_tick_cnt) 623 info->data->restore_tick_cnt(info); 624 625 s3c_rtc_disable_clk(info); 626 627 if (device_may_wakeup(dev) && info->wake_en) { 628 disable_irq_wake(info->irq_alarm); 629 info->wake_en = false; 630 } 631 632 return 0; 633 } 634 #endif 635 static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); 636 637 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) 638 { 639 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 640 } 641 642 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) 643 { 644 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 645 writeb(mask, info->base + S3C2410_INTP); 646 } 647 648 static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq) 649 { 650 unsigned int tmp = 0; 651 int val; 652 653 tmp = readb(info->base + S3C2410_TICNT); 654 tmp &= S3C2410_TICNT_ENABLE; 655 656 val = (info->rtc->max_user_freq / freq) - 1; 657 tmp |= val; 658 659 writel(tmp, info->base + S3C2410_TICNT); 660 } 661 662 static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq) 663 { 664 unsigned int tmp = 0; 665 int val; 666 667 tmp = readb(info->base + S3C2410_TICNT); 668 tmp &= S3C2410_TICNT_ENABLE; 669 670 val = (info->rtc->max_user_freq / freq) - 1; 671 672 tmp |= S3C2443_TICNT_PART(val); 673 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); 674 675 writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2); 676 677 writel(tmp, info->base + S3C2410_TICNT); 678 } 679 680 static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq) 681 { 682 unsigned int tmp = 0; 683 int val; 684 685 tmp = readb(info->base + S3C2410_TICNT); 686 tmp &= S3C2410_TICNT_ENABLE; 687 688 val = (info->rtc->max_user_freq / freq) - 1; 689 690 tmp |= S3C2443_TICNT_PART(val); 691 writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); 692 693 writel(tmp, info->base + S3C2410_TICNT); 694 } 695 696 static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq) 697 { 698 int val; 699 700 val = (info->rtc->max_user_freq / freq) - 1; 701 writel(val, info->base + S3C2410_TICNT); 702 } 703 704 static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) 705 { 706 unsigned int ticnt; 707 708 ticnt = readb(info->base + S3C2410_TICNT); 709 ticnt &= S3C2410_TICNT_ENABLE; 710 711 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); 712 } 713 714 static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info) 715 { 716 unsigned int con; 717 718 con = readw(info->base + S3C2410_RTCCON); 719 con |= S3C2443_RTCCON_TICSEL; 720 writew(con, info->base + S3C2410_RTCCON); 721 } 722 723 static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq) 724 { 725 unsigned int ticnt; 726 727 ticnt = readw(info->base + S3C2410_RTCCON); 728 ticnt &= S3C64XX_RTCCON_TICEN; 729 730 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); 731 } 732 733 static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info) 734 { 735 info->ticnt_save = readb(info->base + S3C2410_TICNT); 736 } 737 738 static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info) 739 { 740 writeb(info->ticnt_save, info->base + S3C2410_TICNT); 741 } 742 743 static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info) 744 { 745 info->ticnt_en_save = readw(info->base + S3C2410_RTCCON); 746 info->ticnt_en_save &= S3C64XX_RTCCON_TICEN; 747 info->ticnt_save = readl(info->base + S3C2410_TICNT); 748 } 749 750 static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info) 751 { 752 unsigned int con; 753 754 writel(info->ticnt_save, info->base + S3C2410_TICNT); 755 if (info->ticnt_en_save) { 756 con = readw(info->base + S3C2410_RTCCON); 757 writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON); 758 } 759 } 760 761 static struct s3c_rtc_data const s3c2410_rtc_data = { 762 .max_user_freq = 128, 763 .irq_handler = s3c24xx_rtc_irq, 764 .set_freq = s3c2410_rtc_setfreq, 765 .enable_tick = s3c24xx_rtc_enable_tick, 766 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt, 767 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt, 768 .enable = s3c24xx_rtc_enable, 769 .disable = s3c24xx_rtc_disable, 770 }; 771 772 static struct s3c_rtc_data const s3c2416_rtc_data = { 773 .max_user_freq = 32768, 774 .irq_handler = s3c24xx_rtc_irq, 775 .set_freq = s3c2416_rtc_setfreq, 776 .enable_tick = s3c24xx_rtc_enable_tick, 777 .select_tick_clk = s3c2416_rtc_select_tick_clk, 778 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt, 779 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt, 780 .enable = s3c24xx_rtc_enable, 781 .disable = s3c24xx_rtc_disable, 782 }; 783 784 static struct s3c_rtc_data const s3c2443_rtc_data = { 785 .max_user_freq = 32768, 786 .irq_handler = s3c24xx_rtc_irq, 787 .set_freq = s3c2443_rtc_setfreq, 788 .enable_tick = s3c24xx_rtc_enable_tick, 789 .select_tick_clk = s3c2416_rtc_select_tick_clk, 790 .save_tick_cnt = s3c24xx_rtc_save_tick_cnt, 791 .restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt, 792 .enable = s3c24xx_rtc_enable, 793 .disable = s3c24xx_rtc_disable, 794 }; 795 796 static struct s3c_rtc_data const s3c6410_rtc_data = { 797 .max_user_freq = 32768, 798 .needs_src_clk = true, 799 .irq_handler = s3c6410_rtc_irq, 800 .set_freq = s3c6410_rtc_setfreq, 801 .enable_tick = s3c6410_rtc_enable_tick, 802 .save_tick_cnt = s3c6410_rtc_save_tick_cnt, 803 .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt, 804 .enable = s3c24xx_rtc_enable, 805 .disable = s3c6410_rtc_disable, 806 }; 807 808 static const struct of_device_id s3c_rtc_dt_match[] = { 809 { 810 .compatible = "samsung,s3c2410-rtc", 811 .data = &s3c2410_rtc_data, 812 }, { 813 .compatible = "samsung,s3c2416-rtc", 814 .data = &s3c2416_rtc_data, 815 }, { 816 .compatible = "samsung,s3c2443-rtc", 817 .data = &s3c2443_rtc_data, 818 }, { 819 .compatible = "samsung,s3c6410-rtc", 820 .data = &s3c6410_rtc_data, 821 }, { 822 .compatible = "samsung,exynos3250-rtc", 823 .data = &s3c6410_rtc_data, 824 }, 825 { /* sentinel */ }, 826 }; 827 MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); 828 829 static struct platform_driver s3c_rtc_driver = { 830 .probe = s3c_rtc_probe, 831 .remove = s3c_rtc_remove, 832 .driver = { 833 .name = "s3c-rtc", 834 .pm = &s3c_rtc_pm_ops, 835 .of_match_table = of_match_ptr(s3c_rtc_dt_match), 836 }, 837 }; 838 module_platform_driver(s3c_rtc_driver); 839 840 MODULE_DESCRIPTION("Samsung S3C RTC Driver"); 841 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 842 MODULE_LICENSE("GPL"); 843 MODULE_ALIAS("platform:s3c2410-rtc"); 844