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 35enum 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 43static struct resource *s3c_rtc_mem; 44 45static struct clk *rtc_clk; 46static void __iomem *s3c_rtc_base; 47static int s3c_rtc_alarmno = NO_IRQ; 48static int s3c_rtc_tickno = NO_IRQ; 49static enum s3c_cpu_type s3c_rtc_cpu_type; 50 51static DEFINE_SPINLOCK(s3c_rtc_pie_lock); 52 53/* IRQ Handlers */ 54 55static 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 67static 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 */ 80static 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 94static 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 125static 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 151static 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 191static 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 217static 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 277static 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 return 0; 314} 315 316static int s3c_rtc_proc(struct device *dev, struct seq_file *seq) 317{ 318 unsigned int ticnt; 319 320 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 321 ticnt = readb(s3c_rtc_base + S3C2410_RTCCON); 322 ticnt &= S3C64XX_RTCCON_TICEN; 323 } else { 324 ticnt = readb(s3c_rtc_base + S3C2410_TICNT); 325 ticnt &= S3C2410_TICNT_ENABLE; 326 } 327 328 seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no"); 329 return 0; 330} 331 332static int s3c_rtc_open(struct device *dev) 333{ 334 struct platform_device *pdev = to_platform_device(dev); 335 struct rtc_device *rtc_dev = platform_get_drvdata(pdev); 336 int ret; 337 338 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, 339 IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev); 340 341 if (ret) { 342 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret); 343 return ret; 344 } 345 346 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, 347 IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev); 348 349 if (ret) { 350 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); 351 goto tick_err; 352 } 353 354 return ret; 355 356 tick_err: 357 free_irq(s3c_rtc_alarmno, rtc_dev); 358 return ret; 359} 360 361static void s3c_rtc_release(struct device *dev) 362{ 363 struct platform_device *pdev = to_platform_device(dev); 364 struct rtc_device *rtc_dev = platform_get_drvdata(pdev); 365 366 /* do not clear AIE here, it may be needed for wake */ 367 368 s3c_rtc_setpie(dev, 0); 369 free_irq(s3c_rtc_alarmno, rtc_dev); 370 free_irq(s3c_rtc_tickno, rtc_dev); 371} 372 373static const struct rtc_class_ops s3c_rtcops = { 374 .open = s3c_rtc_open, 375 .release = s3c_rtc_release, 376 .read_time = s3c_rtc_gettime, 377 .set_time = s3c_rtc_settime, 378 .read_alarm = s3c_rtc_getalarm, 379 .set_alarm = s3c_rtc_setalarm, 380 .irq_set_freq = s3c_rtc_setfreq, 381 .irq_set_state = s3c_rtc_setpie, 382 .proc = s3c_rtc_proc, 383}; 384 385static void s3c_rtc_enable(struct platform_device *pdev, int en) 386{ 387 void __iomem *base = s3c_rtc_base; 388 unsigned int tmp; 389 390 if (s3c_rtc_base == NULL) 391 return; 392 393 if (!en) { 394 tmp = readb(base + S3C2410_RTCCON); 395 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 396 tmp &= ~S3C64XX_RTCCON_TICEN; 397 tmp &= ~S3C2410_RTCCON_RTCEN; 398 writeb(tmp, base + S3C2410_RTCCON); 399 400 if (s3c_rtc_cpu_type == TYPE_S3C2410) { 401 tmp = readb(base + S3C2410_TICNT); 402 tmp &= ~S3C2410_TICNT_ENABLE; 403 writeb(tmp, base + S3C2410_TICNT); 404 } 405 } else { 406 /* re-enable the device, and check it is ok */ 407 408 if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){ 409 dev_info(&pdev->dev, "rtc disabled, re-enabling\n"); 410 411 tmp = readb(base + S3C2410_RTCCON); 412 writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON); 413 } 414 415 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){ 416 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n"); 417 418 tmp = readb(base + S3C2410_RTCCON); 419 writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON); 420 } 421 422 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){ 423 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n"); 424 425 tmp = readb(base + S3C2410_RTCCON); 426 writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON); 427 } 428 } 429} 430 431static int __devexit s3c_rtc_remove(struct platform_device *dev) 432{ 433 struct rtc_device *rtc = platform_get_drvdata(dev); 434 435 platform_set_drvdata(dev, NULL); 436 rtc_device_unregister(rtc); 437 438 s3c_rtc_setpie(&dev->dev, 0); 439 s3c_rtc_setaie(0); 440 441 clk_disable(rtc_clk); 442 clk_put(rtc_clk); 443 rtc_clk = NULL; 444 445 iounmap(s3c_rtc_base); 446 release_resource(s3c_rtc_mem); 447 kfree(s3c_rtc_mem); 448 449 return 0; 450} 451 452static int __devinit s3c_rtc_probe(struct platform_device *pdev) 453{ 454 struct rtc_device *rtc; 455 struct resource *res; 456 unsigned int tmp, i; 457 int ret; 458 459 pr_debug("%s: probe=%p\n", __func__, pdev); 460 461 /* find the IRQs */ 462 463 s3c_rtc_tickno = platform_get_irq(pdev, 1); 464 if (s3c_rtc_tickno < 0) { 465 dev_err(&pdev->dev, "no irq for rtc tick\n"); 466 return -ENOENT; 467 } 468 469 s3c_rtc_alarmno = platform_get_irq(pdev, 0); 470 if (s3c_rtc_alarmno < 0) { 471 dev_err(&pdev->dev, "no irq for alarm\n"); 472 return -ENOENT; 473 } 474 475 pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", 476 s3c_rtc_tickno, s3c_rtc_alarmno); 477 478 /* get the memory region */ 479 480 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 481 if (res == NULL) { 482 dev_err(&pdev->dev, "failed to get memory region resource\n"); 483 return -ENOENT; 484 } 485 486 s3c_rtc_mem = request_mem_region(res->start, 487 res->end-res->start+1, 488 pdev->name); 489 490 if (s3c_rtc_mem == NULL) { 491 dev_err(&pdev->dev, "failed to reserve memory region\n"); 492 ret = -ENOENT; 493 goto err_nores; 494 } 495 496 s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); 497 if (s3c_rtc_base == NULL) { 498 dev_err(&pdev->dev, "failed ioremap()\n"); 499 ret = -EINVAL; 500 goto err_nomap; 501 } 502 503 rtc_clk = clk_get(&pdev->dev, "rtc"); 504 if (IS_ERR(rtc_clk)) { 505 dev_err(&pdev->dev, "failed to find rtc clock source\n"); 506 ret = PTR_ERR(rtc_clk); 507 rtc_clk = NULL; 508 goto err_clk; 509 } 510 511 clk_enable(rtc_clk); 512 513 /* check to see if everything is setup correctly */ 514 515 s3c_rtc_enable(pdev, 1); 516 517 pr_debug("s3c2410_rtc: RTCCON=%02x\n", 518 readb(s3c_rtc_base + S3C2410_RTCCON)); 519 520 device_init_wakeup(&pdev->dev, 1); 521 522 /* register RTC and exit */ 523 524 rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, 525 THIS_MODULE); 526 527 if (IS_ERR(rtc)) { 528 dev_err(&pdev->dev, "cannot attach rtc\n"); 529 ret = PTR_ERR(rtc); 530 goto err_nortc; 531 } 532 533 s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; 534 535 /* Check RTC Time */ 536 537 for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) { 538 tmp = readb(s3c_rtc_base + i); 539 540 if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9) 541 writeb(0, s3c_rtc_base + i); 542 } 543 544 if (s3c_rtc_cpu_type == TYPE_S3C64XX) 545 rtc->max_user_freq = 32768; 546 else 547 rtc->max_user_freq = 128; 548 549 platform_set_drvdata(pdev, rtc); 550 551 s3c_rtc_setfreq(&pdev->dev, 1); 552 553 return 0; 554 555 err_nortc: 556 s3c_rtc_enable(pdev, 0); 557 clk_disable(rtc_clk); 558 clk_put(rtc_clk); 559 560 err_clk: 561 iounmap(s3c_rtc_base); 562 563 err_nomap: 564 release_resource(s3c_rtc_mem); 565 566 err_nores: 567 return ret; 568} 569 570#ifdef CONFIG_PM 571 572/* RTC Power management control */ 573 574static int ticnt_save, ticnt_en_save; 575 576static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) 577{ 578 /* save TICNT for anyone using periodic interrupts */ 579 ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); 580 if (s3c_rtc_cpu_type == TYPE_S3C64XX) { 581 ticnt_en_save = readb(s3c_rtc_base + S3C2410_RTCCON); 582 ticnt_en_save &= S3C64XX_RTCCON_TICEN; 583 } 584 s3c_rtc_enable(pdev, 0); 585 586 if (device_may_wakeup(&pdev->dev)) 587 enable_irq_wake(s3c_rtc_alarmno); 588 589 return 0; 590} 591 592static int s3c_rtc_resume(struct platform_device *pdev) 593{ 594 unsigned int tmp; 595 596 s3c_rtc_enable(pdev, 1); 597 writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); 598 if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { 599 tmp = readb(s3c_rtc_base + S3C2410_RTCCON); 600 writeb(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); 601 } 602 603 if (device_may_wakeup(&pdev->dev)) 604 disable_irq_wake(s3c_rtc_alarmno); 605 606 return 0; 607} 608#else 609#define s3c_rtc_suspend NULL 610#define s3c_rtc_resume NULL 611#endif 612 613static struct platform_device_id s3c_rtc_driver_ids[] = { 614 { 615 .name = "s3c2410-rtc", 616 .driver_data = TYPE_S3C2410, 617 }, { 618 .name = "s3c64xx-rtc", 619 .driver_data = TYPE_S3C64XX, 620 }, 621 { } 622}; 623 624MODULE_DEVICE_TABLE(platform, s3c_rtc_driver_ids); 625 626static struct platform_driver s3c_rtc_driver = { 627 .probe = s3c_rtc_probe, 628 .remove = __devexit_p(s3c_rtc_remove), 629 .suspend = s3c_rtc_suspend, 630 .resume = s3c_rtc_resume, 631 .id_table = s3c_rtc_driver_ids, 632 .driver = { 633 .name = "s3c-rtc", 634 .owner = THIS_MODULE, 635 }, 636}; 637 638static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n"; 639 640static int __init s3c_rtc_init(void) 641{ 642 printk(banner); 643 return platform_driver_register(&s3c_rtc_driver); 644} 645 646static void __exit s3c_rtc_exit(void) 647{ 648 platform_driver_unregister(&s3c_rtc_driver); 649} 650 651module_init(s3c_rtc_init); 652module_exit(s3c_rtc_exit); 653 654MODULE_DESCRIPTION("Samsung S3C RTC Driver"); 655MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 656MODULE_LICENSE("GPL"); 657MODULE_ALIAS("platform:s3c2410-rtc"); 658