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