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