Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: s3c: add support for RTC of Exynos3250 SoC

Add support for RTC of Exynos3250 SoC. The Exynos3250 needs source
clock(32.768KHz) for RTC block. If source clock of RTC is registerd on
clock list of common clk framework, Exynos RTC drvier have to control
this clock.

Clock list for s3c-rtc device:
- rtc : CLK_RTC of CLK_GATE_IP_PERIR is gate clock for RTC.
- rtc_src : XrtcXTI is 32.768.kHz source clock for RTC.
(XRTCXTI: Specifies a clock from 32.768 kHz crystal pad with XRTCXTI and
XRTCXTO pins. RTC uses this clock as the source of a real-time clock.)

Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Chanwoo Choi and committed by
Linus Torvalds
df9e26d0 ae05c950

+93 -1
+1
Documentation/devicetree/bindings/rtc/s3c-rtc.txt
··· 6 6 * "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc. 7 7 * "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc. 8 8 * "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc. 9 + * "samsung,exynos3250-rtc" - for controllers compatible with exynos3250 rtc. 9 10 - reg: physical base address of the controller and length of memory mapped 10 11 region. 11 12 - interrupts: Two interrupt numbers to the cpu should be specified. First
+92 -1
drivers/rtc/rtc-s3c.c
··· 38 38 39 39 void __iomem *base; 40 40 struct clk *rtc_clk; 41 + struct clk *rtc_src_clk; 41 42 bool enabled; 42 43 43 44 struct s3c_rtc_data *data; ··· 55 54 56 55 struct s3c_rtc_data { 57 56 int max_user_freq; 57 + bool needs_src_clk; 58 58 59 59 void (*irq_handler) (struct s3c_rtc *info, int mask); 60 60 void (*set_freq) (struct s3c_rtc *info, int freq); ··· 75 73 if (enable) { 76 74 if (!info->enabled) { 77 75 clk_enable(info->rtc_clk); 76 + if (info->data->needs_src_clk) 77 + clk_enable(info->rtc_src_clk); 78 78 info->enabled = true; 79 79 } 80 80 } else { 81 81 if (info->enabled) { 82 + if (info->data->needs_src_clk) 83 + clk_disable(info->rtc_src_clk); 82 84 clk_disable(info->rtc_clk); 83 85 info->enabled = false; 84 86 } ··· 120 114 dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); 121 115 122 116 clk_enable(info->rtc_clk); 117 + if (info->data->needs_src_clk) 118 + clk_enable(info->rtc_src_clk); 123 119 tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; 124 120 125 121 if (enabled) 126 122 tmp |= S3C2410_RTCALM_ALMEN; 127 123 128 124 writeb(tmp, info->base + S3C2410_RTCALM); 125 + if (info->data->needs_src_clk) 126 + clk_disable(info->rtc_src_clk); 129 127 clk_disable(info->rtc_clk); 130 128 131 129 s3c_rtc_alarm_clk_enable(info, enabled); ··· 144 134 return -EINVAL; 145 135 146 136 clk_enable(info->rtc_clk); 137 + if (info->data->needs_src_clk) 138 + clk_enable(info->rtc_src_clk); 147 139 spin_lock_irq(&info->pie_lock); 148 140 149 141 if (info->data->set_freq) 150 142 info->data->set_freq(info, freq); 151 143 152 144 spin_unlock_irq(&info->pie_lock); 145 + if (info->data->needs_src_clk) 146 + clk_disable(info->rtc_src_clk); 153 147 clk_disable(info->rtc_clk); 154 148 155 149 return 0; ··· 166 152 unsigned int have_retried = 0; 167 153 168 154 clk_enable(info->rtc_clk); 155 + if (info->data->needs_src_clk) 156 + clk_enable(info->rtc_src_clk); 157 + 169 158 retry_get_time: 170 159 rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN); 171 160 rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR); ··· 202 185 203 186 rtc_tm->tm_mon -= 1; 204 187 188 + if (info->data->needs_src_clk) 189 + clk_disable(info->rtc_src_clk); 205 190 clk_disable(info->rtc_clk); 206 191 207 192 return rtc_valid_tm(rtc_tm); ··· 226 207 } 227 208 228 209 clk_enable(info->rtc_clk); 210 + if (info->data->needs_src_clk) 211 + clk_enable(info->rtc_src_clk); 229 212 230 213 writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC); 231 214 writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN); ··· 236 215 writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_RTCMON); 237 216 writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); 238 217 218 + if (info->data->needs_src_clk) 219 + clk_disable(info->rtc_src_clk); 239 220 clk_disable(info->rtc_clk); 240 221 241 222 return 0; ··· 250 227 unsigned int alm_en; 251 228 252 229 clk_enable(info->rtc_clk); 230 + if (info->data->needs_src_clk) 231 + clk_enable(info->rtc_src_clk); 232 + 253 233 alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC); 254 234 alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN); 255 235 alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR); ··· 304 278 else 305 279 alm_tm->tm_year = -1; 306 280 281 + if (info->data->needs_src_clk) 282 + clk_disable(info->rtc_src_clk); 307 283 clk_disable(info->rtc_clk); 284 + 308 285 return 0; 309 286 } 310 287 ··· 318 289 unsigned int alrm_en; 319 290 320 291 clk_enable(info->rtc_clk); 292 + if (info->data->needs_src_clk) 293 + clk_enable(info->rtc_src_clk); 294 + 321 295 dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", 322 296 alrm->enabled, 323 297 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, ··· 350 318 351 319 s3c_rtc_setaie(dev, alrm->enabled); 352 320 321 + if (info->data->needs_src_clk) 322 + clk_disable(info->rtc_src_clk); 353 323 clk_disable(info->rtc_clk); 354 324 355 325 return 0; ··· 362 328 struct s3c_rtc *info = dev_get_drvdata(dev); 363 329 364 330 clk_enable(info->rtc_clk); 331 + if (info->data->needs_src_clk) 332 + clk_enable(info->rtc_src_clk); 365 333 366 334 if (info->data->enable_tick) 367 335 info->data->enable_tick(info, seq); 368 336 337 + if (info->data->needs_src_clk) 338 + clk_disable(info->rtc_src_clk); 369 339 clk_disable(info->rtc_clk); 370 340 371 341 return 0; ··· 389 351 unsigned int con, tmp; 390 352 391 353 clk_enable(info->rtc_clk); 354 + if (info->data->needs_src_clk) 355 + clk_enable(info->rtc_src_clk); 392 356 393 357 con = readw(info->base + S3C2410_RTCCON); 394 358 /* re-enable the device, and check it is ok */ ··· 418 378 info->base + S3C2410_RTCCON); 419 379 } 420 380 381 + if (info->data->needs_src_clk) 382 + clk_disable(info->rtc_src_clk); 421 383 clk_disable(info->rtc_clk); 422 384 } 423 385 ··· 428 386 unsigned int con; 429 387 430 388 clk_enable(info->rtc_clk); 389 + if (info->data->needs_src_clk) 390 + clk_enable(info->rtc_src_clk); 431 391 432 392 con = readw(info->base + S3C2410_RTCCON); 433 393 con &= ~S3C2410_RTCCON_RTCEN; ··· 439 395 con &= ~S3C2410_TICNT_ENABLE; 440 396 writeb(con, info->base + S3C2410_TICNT); 441 397 398 + if (info->data->needs_src_clk) 399 + clk_disable(info->rtc_src_clk); 442 400 clk_disable(info->rtc_clk); 443 401 } 444 402 ··· 449 403 unsigned int con; 450 404 451 405 clk_enable(info->rtc_clk); 406 + if (info->data->needs_src_clk) 407 + clk_enable(info->rtc_src_clk); 452 408 453 409 con = readw(info->base + S3C2410_RTCCON); 454 410 con &= ~S3C64XX_RTCCON_TICEN; 455 411 con &= ~S3C2410_RTCCON_RTCEN; 456 412 writew(con, info->base + S3C2410_RTCCON); 457 413 414 + if (info->data->needs_src_clk) 415 + clk_disable(info->rtc_src_clk); 458 416 clk_disable(info->rtc_clk); 459 417 } 460 418 ··· 530 480 531 481 info->rtc_clk = devm_clk_get(&pdev->dev, "rtc"); 532 482 if (IS_ERR(info->rtc_clk)) { 533 - dev_err(&pdev->dev, "failed to find rtc clock source\n"); 483 + dev_err(&pdev->dev, "failed to find rtc clock\n"); 534 484 return PTR_ERR(info->rtc_clk); 535 485 } 536 486 clk_prepare_enable(info->rtc_clk); 487 + 488 + info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); 489 + if (IS_ERR(info->rtc_src_clk)) { 490 + dev_err(&pdev->dev, "failed to find rtc source clock\n"); 491 + return PTR_ERR(info->rtc_src_clk); 492 + } 493 + clk_prepare_enable(info->rtc_src_clk); 494 + 537 495 538 496 /* check to see if everything is setup correctly */ 539 497 if (info->data->enable) ··· 596 538 597 539 s3c_rtc_setfreq(info, 1); 598 540 541 + if (info->data->needs_src_clk) 542 + clk_disable(info->rtc_src_clk); 599 543 clk_disable(info->rtc_clk); 600 544 601 545 return 0; ··· 617 557 struct s3c_rtc *info = dev_get_drvdata(dev); 618 558 619 559 clk_enable(info->rtc_clk); 560 + if (info->data->needs_src_clk) 561 + clk_enable(info->rtc_src_clk); 620 562 621 563 /* save TICNT for anyone using periodic interrupts */ 622 564 if (info->data->save_tick_cnt) ··· 634 572 dev_err(dev, "enable_irq_wake failed\n"); 635 573 } 636 574 575 + if (info->data->needs_src_clk) 576 + clk_disable(info->rtc_src_clk); 637 577 clk_disable(info->rtc_clk); 638 578 639 579 return 0; ··· 646 582 struct s3c_rtc *info = dev_get_drvdata(dev); 647 583 648 584 clk_enable(info->rtc_clk); 585 + if (info->data->needs_src_clk) 586 + clk_enable(info->rtc_src_clk); 649 587 650 588 if (info->data->enable) 651 589 info->data->enable(info); ··· 660 594 info->wake_en = false; 661 595 } 662 596 597 + if (info->data->needs_src_clk) 598 + clk_disable(info->rtc_src_clk); 663 599 clk_disable(info->rtc_clk); 664 600 665 601 return 0; ··· 672 604 static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask) 673 605 { 674 606 clk_enable(info->rtc_clk); 607 + if (info->data->needs_src_clk) 608 + clk_enable(info->rtc_src_clk); 675 609 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 610 + if (info->data->needs_src_clk) 611 + clk_disable(info->rtc_src_clk); 676 612 clk_disable(info->rtc_clk); 677 613 678 614 s3c_rtc_alarm_clk_enable(info, false); ··· 685 613 static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask) 686 614 { 687 615 clk_enable(info->rtc_clk); 616 + if (info->data->needs_src_clk) 617 + clk_enable(info->rtc_src_clk); 688 618 rtc_update_irq(info->rtc, 1, RTC_AF | RTC_IRQF); 689 619 writeb(mask, info->base + S3C2410_INTP); 620 + if (info->data->needs_src_clk) 621 + clk_disable(info->rtc_src_clk); 690 622 clk_disable(info->rtc_clk); 691 623 692 624 s3c_rtc_alarm_clk_enable(info, false); ··· 856 780 .disable = s3c6410_rtc_disable, 857 781 }; 858 782 783 + static struct s3c_rtc_data const exynos3250_rtc_data = { 784 + .max_user_freq = 32768, 785 + .needs_src_clk = true, 786 + .irq_handler = s3c6410_rtc_irq, 787 + .set_freq = s3c6410_rtc_setfreq, 788 + .enable_tick = s3c6410_rtc_enable_tick, 789 + .save_tick_cnt = s3c6410_rtc_save_tick_cnt, 790 + .restore_tick_cnt = s3c6410_rtc_restore_tick_cnt, 791 + .enable = s3c24xx_rtc_enable, 792 + .disable = s3c6410_rtc_disable, 793 + }; 794 + 859 795 static const struct of_device_id s3c_rtc_dt_match[] = { 860 796 { 861 797 .compatible = "samsung,s3c2410-rtc", ··· 881 793 }, { 882 794 .compatible = "samsung,s3c6410-rtc", 883 795 .data = (void *)&s3c6410_rtc_data, 796 + }, { 797 + .compatible = "samsung,exynos3250-rtc", 798 + .data = (void *)&exynos3250_rtc_data, 884 799 }, 885 800 { /* sentinel */ }, 886 801 };