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