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 29 #include <mach/hardware.h> 30 #include <asm/uaccess.h> 31 #include <asm/io.h> 32 #include <asm/irq.h> 33 #include <plat/regs-rtc.h> 34 35 enum s3c_cpu_type { 36 TYPE_S3C2410, 37 TYPE_S3C64XX, 38 }; 39 40 /* I have yet to find an S3C implementation with more than one 41 * of these rtc blocks in */ 42 43 static struct resource *s3c_rtc_mem; 44 45 static struct clk *rtc_clk; 46 static void __iomem *s3c_rtc_base; 47 static int s3c_rtc_alarmno = NO_IRQ; 48 static int s3c_rtc_tickno = NO_IRQ; 49 static enum s3c_cpu_type s3c_rtc_cpu_type; 50 51 static DEFINE_SPINLOCK(s3c_rtc_pie_lock); 52 53 /* IRQ Handlers */ 54 55 static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) 56 { 57 struct rtc_device *rdev = id; 58 59 rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); 60 61 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 62 writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); 63 64 return IRQ_HANDLED; 65 } 66 67 static irqreturn_t s3c_rtc_tickirq(int irq, void *id) 68 { 69 struct rtc_device *rdev = id; 70 71 rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); 72 73 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 74 writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); 75 76 return IRQ_HANDLED; 77 } 78 79 /* Update control registers */ 80 static void s3c_rtc_setaie(int to) 81 { 82 unsigned int tmp; 83 84 pr_debug("%s: aie=%d\n", __func__, to); 85 86 tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; 87 88 if (to) 89 tmp |= S3C2410_RTCALM_ALMEN; 90 91 writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); 92 } 93 94 static int s3c_rtc_setpie(struct device *dev, int enabled) 95 { 96 unsigned int tmp; 97 98 pr_debug("%s: pie=%d\n", __func__, enabled); 99 100 spin_lock_irq(&s3c_rtc_pie_lock); 101 102 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 103 tmp = readb(s3c_rtc_base + S3C2410_RTCCON); 104 tmp &= ~S3C64XX_RTCCON_TICEN; 105 106 if (enabled) 107 tmp |= S3C64XX_RTCCON_TICEN; 108 109 writew(tmp, s3c_rtc_base + S3C2410_RTCCON); 110 } else { 111 tmp = readb(s3c_rtc_base + S3C2410_TICNT); 112 tmp &= ~S3C2410_TICNT_ENABLE; 113 114 if (enabled) 115 tmp |= S3C2410_TICNT_ENABLE; 116 117 writeb(tmp, s3c_rtc_base + S3C2410_TICNT); 118 } 119 120 spin_unlock_irq(&s3c_rtc_pie_lock); 121 122 return 0; 123 } 124 125 static int s3c_rtc_setfreq(struct device *dev, int freq) 126 { 127 struct platform_device *pdev = to_platform_device(dev); 128 struct rtc_device *rtc_dev = platform_get_drvdata(pdev); 129 unsigned int tmp = 0; 130 131 if (!is_power_of_2(freq)) 132 return -EINVAL; 133 134 spin_lock_irq(&s3c_rtc_pie_lock); 135 136 if (s3c_rtc_cpu_type == TYPE_S3C2410) { 137 tmp = readb(s3c_rtc_base + S3C2410_TICNT); 138 tmp &= S3C2410_TICNT_ENABLE; 139 } 140 141 tmp |= (rtc_dev->max_user_freq / freq)-1; 142 143 writel(tmp, s3c_rtc_base + S3C2410_TICNT); 144 spin_unlock_irq(&s3c_rtc_pie_lock); 145 146 return 0; 147 } 148 149 /* Time read/write */ 150 151 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) 152 { 153 unsigned int have_retried = 0; 154 void __iomem *base = s3c_rtc_base; 155 156 retry_get_time: 157 rtc_tm->tm_min = readb(base + S3C2410_RTCMIN); 158 rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR); 159 rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE); 160 rtc_tm->tm_mon = readb(base + S3C2410_RTCMON); 161 rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR); 162 rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC); 163 164 /* the only way to work out wether the system was mid-update 165 * when we read it is to check the second counter, and if it 166 * is zero, then we re-try the entire read 167 */ 168 169 if (rtc_tm->tm_sec == 0 && !have_retried) { 170 have_retried = 1; 171 goto retry_get_time; 172 } 173 174 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", 175 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, 176 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); 177 178 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); 179 rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); 180 rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); 181 rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); 182 rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); 183 rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); 184 185 rtc_tm->tm_year += 100; 186 rtc_tm->tm_mon -= 1; 187 188 return 0; 189 } 190 191 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) 192 { 193 void __iomem *base = s3c_rtc_base; 194 int year = tm->tm_year - 100; 195 196 pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", 197 tm->tm_year, tm->tm_mon, tm->tm_mday, 198 tm->tm_hour, tm->tm_min, tm->tm_sec); 199 200 /* we get around y2k by simply not supporting it */ 201 202 if (year < 0 || year >= 100) { 203 dev_err(dev, "rtc only supports 100 years\n"); 204 return -EINVAL; 205 } 206 207 writeb(bin2bcd(tm->tm_sec), base + S3C2410_RTCSEC); 208 writeb(bin2bcd(tm->tm_min), base + S3C2410_RTCMIN); 209 writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR); 210 writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE); 211 writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON); 212 writeb(bin2bcd(year), base + S3C2410_RTCYEAR); 213 214 return 0; 215 } 216 217 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) 218 { 219 struct rtc_time *alm_tm = &alrm->time; 220 void __iomem *base = s3c_rtc_base; 221 unsigned int alm_en; 222 223 alm_tm->tm_sec = readb(base + S3C2410_ALMSEC); 224 alm_tm->tm_min = readb(base + S3C2410_ALMMIN); 225 alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR); 226 alm_tm->tm_mon = readb(base + S3C2410_ALMMON); 227 alm_tm->tm_mday = readb(base + S3C2410_ALMDATE); 228 alm_tm->tm_year = readb(base + S3C2410_ALMYEAR); 229 230 alm_en = readb(base + S3C2410_RTCALM); 231 232 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; 233 234 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", 235 alm_en, 236 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, 237 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); 238 239 240 /* decode the alarm enable field */ 241 242 if (alm_en & S3C2410_RTCALM_SECEN) 243 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); 244 else 245 alm_tm->tm_sec = 0xff; 246 247 if (alm_en & S3C2410_RTCALM_MINEN) 248 alm_tm->tm_min = bcd2bin(alm_tm->tm_min); 249 else 250 alm_tm->tm_min = 0xff; 251 252 if (alm_en & S3C2410_RTCALM_HOUREN) 253 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); 254 else 255 alm_tm->tm_hour = 0xff; 256 257 if (alm_en & S3C2410_RTCALM_DAYEN) 258 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday); 259 else 260 alm_tm->tm_mday = 0xff; 261 262 if (alm_en & S3C2410_RTCALM_MONEN) { 263 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon); 264 alm_tm->tm_mon -= 1; 265 } else { 266 alm_tm->tm_mon = 0xff; 267 } 268 269 if (alm_en & S3C2410_RTCALM_YEAREN) 270 alm_tm->tm_year = bcd2bin(alm_tm->tm_year); 271 else 272 alm_tm->tm_year = 0xffff; 273 274 return 0; 275 } 276 277 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) 278 { 279 struct rtc_time *tm = &alrm->time; 280 void __iomem *base = s3c_rtc_base; 281 unsigned int alrm_en; 282 283 pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", 284 alrm->enabled, 285 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, 286 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); 287 288 289 alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN; 290 writeb(0x00, base + S3C2410_RTCALM); 291 292 if (tm->tm_sec < 60 && tm->tm_sec >= 0) { 293 alrm_en |= S3C2410_RTCALM_SECEN; 294 writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC); 295 } 296 297 if (tm->tm_min < 60 && tm->tm_min >= 0) { 298 alrm_en |= S3C2410_RTCALM_MINEN; 299 writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN); 300 } 301 302 if (tm->tm_hour < 24 && tm->tm_hour >= 0) { 303 alrm_en |= S3C2410_RTCALM_HOUREN; 304 writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR); 305 } 306 307 pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en); 308 309 writeb(alrm_en, base + S3C2410_RTCALM); 310 311 s3c_rtc_setaie(alrm->enabled); 312 313 if (alrm->enabled) 314 enable_irq_wake(s3c_rtc_alarmno); 315 else 316 disable_irq_wake(s3c_rtc_alarmno); 317 318 return 0; 319 } 320 321 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 322 { 323 unsigned int ticnt; 324 325 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 326 ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); 327 ticnt &= S3C64XX_RTCCON_TICEN; 328 } else { 329 ticnt = readb(s3c_rtc_base + S3C2410_TICNT); 330 ticnt &= S3C2410_TICNT_ENABLE; 331 } 332 333 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); 334 return 0; 335 } 336 337 static int s3c_rtc_open(struct device *dev) 338 { 339 struct platform_device *pdev = to_platform_device(dev); 340 struct rtc_device *rtc_dev = platform_get_drvdata(pdev); 341 int ret; 342 343 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, 344 IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev); 345 346 if (ret) { 347 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); 348 return ret; 349 } 350 351 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, 352 IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev); 353 354 if (ret) { 355 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); 356 goto tick_err; 357 } 358 359 return ret; 360 361 tick_err: 362 free_irq(s3c_rtc_alarmno, rtc_dev); 363 return ret; 364 } 365 366 static void s3c_rtc_release(struct device *dev) 367 { 368 struct platform_device *pdev = to_platform_device(dev); 369 struct rtc_device *rtc_dev = platform_get_drvdata(pdev); 370 371 /* do not clear AIE here, it may be needed for wake */ 372 373 s3c_rtc_setpie(dev, 0); 374 free_irq(s3c_rtc_alarmno, rtc_dev); 375 free_irq(s3c_rtc_tickno, rtc_dev); 376 } 377 378 static const struct rtc_class_ops s3c_rtcops = { 379 .open = s3c_rtc_open, 380 .release = s3c_rtc_release, 381 .read_time = s3c_rtc_gettime, 382 .set_time = s3c_rtc_settime, 383 .read_alarm = s3c_rtc_getalarm, 384 .set_alarm = s3c_rtc_setalarm, 385 .irq_set_freq = s3c_rtc_setfreq, 386 .irq_set_state = s3c_rtc_setpie, 387 .proc = s3c_rtc_proc, 388 }; 389 390 static void s3c_rtc_enable(struct platform_device *pdev, int en) 391 { 392 void __iomem *base = s3c_rtc_base; 393 unsigned int tmp; 394 395 if (s3c_rtc_base == NULL) 396 return; 397 398 if (!en) { 399 tmp = readb(base + S3C2410_RTCCON); 400 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 401 tmp &= ~S3C64XX_RTCCON_TICEN; 402 tmp &= ~S3C2410_RTCCON_RTCEN; 403 writeb(tmp, base + S3C2410_RTCCON); 404 405 if (s3c_rtc_cpu_type == TYPE_S3C2410) { 406 tmp = readb(base + S3C2410_TICNT); 407 tmp &= ~S3C2410_TICNT_ENABLE; 408 writeb(tmp, base + S3C2410_TICNT); 409 } 410 } else { 411 /* re-enable the device, and check it is ok */ 412 413 if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ 414 dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); 415 416 tmp = readb(base + S3C2410_RTCCON); 417 writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); 418 } 419 420 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ 421 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); 422 423 tmp = readb(base + S3C2410_RTCCON); 424 writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); 425 } 426 427 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ 428 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); 429 430 tmp = readb(base + S3C2410_RTCCON); 431 writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); 432 } 433 } 434 } 435 436 static int __devexit s3c_rtc_remove(struct platform_device *dev) 437 { 438 struct rtc_device *rtc = platform_get_drvdata(dev); 439 440 platform_set_drvdata(dev, NULL); 441 rtc_device_unregister(rtc); 442 443 s3c_rtc_setpie(&dev->dev, 0); 444 s3c_rtc_setaie(0); 445 446 clk_disable(rtc_clk); 447 clk_put(rtc_clk); 448 rtc_clk = NULL; 449 450 iounmap(s3c_rtc_base); 451 release_resource(s3c_rtc_mem); 452 kfree(s3c_rtc_mem); 453 454 return 0; 455 } 456 457 static int __devinit s3c_rtc_probe(struct platform_device *pdev) 458 { 459 struct rtc_device *rtc; 460 struct resource *res; 461 unsigned int tmp, i; 462 int ret; 463 464 pr_debug("%s: probe=%p\n", __func__, pdev); 465 466 /* find the IRQs */ 467 468 s3c_rtc_tickno = platform_get_irq(pdev, 1); 469 if (s3c_rtc_tickno < 0) { 470 dev_err(&pdev->dev, "no irq for rtc tick\n"); 471 return -ENOENT; 472 } 473 474 s3c_rtc_alarmno = platform_get_irq(pdev, 0); 475 if (s3c_rtc_alarmno < 0) { 476 dev_err(&pdev->dev, "no irq for alarm\n"); 477 return -ENOENT; 478 } 479 480 pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", 481 s3c_rtc_tickno, s3c_rtc_alarmno); 482 483 /* get the memory region */ 484 485 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 486 if (res == NULL) { 487 dev_err(&pdev->dev, "failed to get memory region resource\n"); 488 return -ENOENT; 489 } 490 491 s3c_rtc_mem = request_mem_region(res->start, 492 res->end-res->start+1, 493 pdev->name); 494 495 if (s3c_rtc_mem == NULL) { 496 dev_err(&pdev->dev, "failed to reserve memory region\n"); 497 ret = -ENOENT; 498 goto err_nores; 499 } 500 501 s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); 502 if (s3c_rtc_base == NULL) { 503 dev_err(&pdev->dev, "failed ioremap()\n"); 504 ret = -EINVAL; 505 goto err_nomap; 506 } 507 508 rtc_clk = clk_get(&pdev->dev, "rtc"); 509 if (IS_ERR(rtc_clk)) { 510 dev_err(&pdev->dev, "failed to find rtc clock source\n"); 511 ret = PTR_ERR(rtc_clk); 512 rtc_clk = NULL; 513 goto err_clk; 514 } 515 516 clk_enable(rtc_clk); 517 518 /* check to see if everything is setup correctly */ 519 520 s3c_rtc_enable(pdev, 1); 521 522 pr_debug("s3c2410_rtc: RTCCON=%02x\n", 523 readb(s3c_rtc_base + S3C2410_RTCCON)); 524 525 device_init_wakeup(&pdev->dev, 1); 526 527 /* register RTC and exit */ 528 529 rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, 530 THIS_MODULE); 531 532 if (IS_ERR(rtc)) { 533 dev_err(&pdev->dev, "cannot attach rtc\n"); 534 ret = PTR_ERR(rtc); 535 goto err_nortc; 536 } 537 538 s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; 539 540 /* Check RTC Time */ 541 542 for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) { 543 tmp = readb(s3c_rtc_base + i); 544 545 if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9) 546 writeb(0, s3c_rtc_base + i); 547 } 548 549 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 550 rtc->max_user_freq = 32768; 551 else 552 rtc->max_user_freq = 128; 553 554 platform_set_drvdata(pdev, rtc); 555 556 s3c_rtc_setfreq(&pdev->dev, 1); 557 558 return 0; 559 560 err_nortc: 561 s3c_rtc_enable(pdev, 0); 562 clk_disable(rtc_clk); 563 clk_put(rtc_clk); 564 565 err_clk: 566 iounmap(s3c_rtc_base); 567 568 err_nomap: 569 release_resource(s3c_rtc_mem); 570 571 err_nores: 572 return ret; 573 } 574 575 #ifdef CONFIG_PM 576 577 /* RTC Power management control */ 578 579 static int ticnt_save, ticnt_en_save; 580 581 static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) 582 { 583 /* save TICNT for anyone using periodic interrupts */ 584 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); 585 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 586 ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); 587 ticnt_en_save &= S3C64XX_RTCCON_TICEN; 588 } 589 s3c_rtc_enable(pdev, 0); 590 return 0; 591 } 592 593 static int s3c_rtc_resume(struct platform_device *pdev) 594 { 595 unsigned int tmp; 596 597 s3c_rtc_enable(pdev, 1); 598 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); 599 if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { 600 tmp = readb(s3c_rtc_base + S3C2410_RTCCON); 601 writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); 602 } 603 return 0; 604 } 605 #else 606 #define s3c_rtc_suspend NULL 607 #define s3c_rtc_resume NULL 608 #endif 609 610 static struct platform_device_id s3c_rtc_driver_ids[] = { 611 { 612 .name = "s3c2410-rtc", 613 .driver_data = TYPE_S3C2410, 614 }, { 615 .name = "s3c64xx-rtc", 616 .driver_data = TYPE_S3C64XX, 617 }, 618 { } 619 }; 620 621 MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); 622 623 static struct platform_driver s3c_rtc_driver = { 624 .probe = s3c_rtc_probe, 625 .remove = __devexit_p(s3c_rtc_remove), 626 .suspend = s3c_rtc_suspend, 627 .resume = s3c_rtc_resume, 628 .id_table = s3c_rtc_driver_ids, 629 .driver = { 630 .name = "s3c-rtc", 631 .owner = THIS_MODULE, 632 }, 633 }; 634 635 static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n"; 636 637 static int __init s3c_rtc_init(void) 638 { 639 printk(banner); 640 return platform_driver_register(&s3c_rtc_driver); 641 } 642 643 static void __exit s3c_rtc_exit(void) 644 { 645 platform_driver_unregister(&s3c_rtc_driver); 646 } 647 648 module_init(s3c_rtc_init); 649 module_exit(s3c_rtc_exit); 650 651 MODULE_DESCRIPTION("Samsung S3C RTC Driver"); 652 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 653 MODULE_LICENSE("GPL"); 654 MODULE_ALIAS("platform:s3c2410-rtc"); 655