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