linux/drivers/rtc/rtc-at91sam9.c
<<
>>
Prefs
   1/*
   2 * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
   3 *
   4 * (C) 2007 Michel Benoit
   5 *
   6 * Based on rtc-at91rm9200.c by Rick Bronson
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version
  11 * 2 of the License, or (at your option) any later version.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/kernel.h>
  16#include <linux/platform_device.h>
  17#include <linux/time.h>
  18#include <linux/rtc.h>
  19#include <linux/interrupt.h>
  20#include <linux/ioctl.h>
  21
  22#include <mach/board.h>
  23#include <mach/at91_rtt.h>
  24#include <mach/cpu.h>
  25
  26
  27/*
  28 * This driver uses two configurable hardware resources that live in the
  29 * AT91SAM9 backup power domain (intended to be powered at all times)
  30 * to implement the Real Time Clock interfaces
  31 *
  32 *  - A "Real-time Timer" (RTT) counts up in seconds from a base time.
  33 *    We can't assign the counter value (CRTV) ... but we can reset it.
  34 *
  35 *  - One of the "General Purpose Backup Registers" (GPBRs) holds the
  36 *    base time, normally an offset from the beginning of the POSIX
  37 *    epoch (1970-Jan-1 00:00:00 UTC).  Some systems also include the
  38 *    local timezone's offset.
  39 *
  40 * The RTC's value is the RTT counter plus that offset.  The RTC's alarm
  41 * is likewise a base (ALMV) plus that offset.
  42 *
  43 * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
  44 * choose from, or a "real" RTC module.  All systems have multiple GPBR
  45 * registers available, likewise usable for more than "RTC" support.
  46 */
  47
  48/*
  49 * We store ALARM_DISABLED in ALMV to record that no alarm is set.
  50 * It's also the reset value for that field.
  51 */
  52#define ALARM_DISABLED  ((u32)~0)
  53
  54
  55struct sam9_rtc {
  56        void __iomem            *rtt;
  57        struct rtc_device       *rtcdev;
  58        u32                     imr;
  59};
  60
  61#define rtt_readl(rtc, field) \
  62        __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
  63#define rtt_writel(rtc, field, val) \
  64        __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
  65
  66#define gpbr_readl(rtc) \
  67        at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
  68#define gpbr_writel(rtc, val) \
  69        at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
  70
  71/*
  72 * Read current time and date in RTC
  73 */
  74static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
  75{
  76        struct sam9_rtc *rtc = dev_get_drvdata(dev);
  77        u32 secs, secs2;
  78        u32 offset;
  79
  80        /* read current time offset */
  81        offset = gpbr_readl(rtc);
  82        if (offset == 0)
  83                return -EILSEQ;
  84
  85        /* reread the counter to help sync the two clock domains */
  86        secs = rtt_readl(rtc, VR);
  87        secs2 = rtt_readl(rtc, VR);
  88        if (secs != secs2)
  89                secs = rtt_readl(rtc, VR);
  90
  91        rtc_time_to_tm(offset + secs, tm);
  92
  93        dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
  94                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
  95                tm->tm_hour, tm->tm_min, tm->tm_sec);
  96
  97        return 0;
  98}
  99
 100/*
 101 * Set current time and date in RTC
 102 */
 103static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
 104{
 105        struct sam9_rtc *rtc = dev_get_drvdata(dev);
 106        int err;
 107        u32 offset, alarm, mr;
 108        unsigned long secs;
 109
 110        dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
 111                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 112                tm->tm_hour, tm->tm_min, tm->tm_sec);
 113
 114        err = rtc_tm_to_time(tm, &secs);
 115        if (err != 0)
 116                return err;
 117
 118        mr = rtt_readl(rtc, MR);
 119
 120        /* disable interrupts */
 121        rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
 122
 123        /* read current time offset */
 124        offset = gpbr_readl(rtc);
 125
 126        /* store the new base time in a battery backup register */
 127        secs += 1;
 128        gpbr_writel(rtc, secs);
 129
 130        /* adjust the alarm time for the new base */
 131        alarm = rtt_readl(rtc, AR);
 132        if (alarm != ALARM_DISABLED) {
 133                if (offset > secs) {
 134                        /* time jumped backwards, increase time until alarm */
 135                        alarm += (offset - secs);
 136                } else if ((alarm + offset) > secs) {
 137                        /* time jumped forwards, decrease time until alarm */
 138                        alarm -= (secs - offset);
 139                } else {
 140                        /* time jumped past the alarm, disable alarm */
 141                        alarm = ALARM_DISABLED;
 142                        mr &= ~AT91_RTT_ALMIEN;
 143                }
 144                rtt_writel(rtc, AR, alarm);
 145        }
 146
 147        /* reset the timer, and re-enable interrupts */
 148        rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
 149
 150        return 0;
 151}
 152
 153static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
 154{
 155        struct sam9_rtc *rtc = dev_get_drvdata(dev);
 156        struct rtc_time *tm = &alrm->time;
 157        u32 alarm = rtt_readl(rtc, AR);
 158        u32 offset;
 159
 160        offset = gpbr_readl(rtc);
 161        if (offset == 0)
 162                return -EILSEQ;
 163
 164        memset(alrm, 0, sizeof(alrm));
 165        if (alarm != ALARM_DISABLED && offset != 0) {
 166                rtc_time_to_tm(offset + alarm, tm);
 167
 168                dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
 169                        1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 170                        tm->tm_hour, tm->tm_min, tm->tm_sec);
 171
 172                if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
 173                        alrm->enabled = 1;
 174        }
 175
 176        return 0;
 177}
 178
 179static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 180{
 181        struct sam9_rtc *rtc = dev_get_drvdata(dev);
 182        struct rtc_time *tm = &alrm->time;
 183        unsigned long secs;
 184        u32 offset;
 185        u32 mr;
 186        int err;
 187
 188        err = rtc_tm_to_time(tm, &secs);
 189        if (err != 0)
 190                return err;
 191
 192        offset = gpbr_readl(rtc);
 193        if (offset == 0) {
 194                /* time is not set */
 195                return -EILSEQ;
 196        }
 197        mr = rtt_readl(rtc, MR);
 198        rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
 199
 200        /* alarm in the past? finish and leave disabled */
 201        if (secs <= offset) {
 202                rtt_writel(rtc, AR, ALARM_DISABLED);
 203                return 0;
 204        }
 205
 206        /* else set alarm and maybe enable it */
 207        rtt_writel(rtc, AR, secs - offset);
 208        if (alrm->enabled)
 209                rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
 210
 211        dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
 212                tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
 213                tm->tm_min, tm->tm_sec);
 214
 215        return 0;
 216}
 217
 218/*
 219 * Handle commands from user-space
 220 */
 221static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
 222                        unsigned long arg)
 223{
 224        struct sam9_rtc *rtc = dev_get_drvdata(dev);
 225        int ret = 0;
 226        u32 mr = rtt_readl(rtc, MR);
 227
 228        dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
 229
 230        switch (cmd) {
 231        case RTC_AIE_OFF:               /* alarm off */
 232                rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
 233                break;
 234        case RTC_AIE_ON:                /* alarm on */
 235                rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
 236                break;
 237        case RTC_UIE_OFF:               /* update off */
 238                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
 239                break;
 240        case RTC_UIE_ON:                /* update on */
 241                rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
 242                break;
 243        default:
 244                ret = -ENOIOCTLCMD;
 245                break;
 246        }
 247
 248        return ret;
 249}
 250
 251/*
 252 * Provide additional RTC information in /proc/driver/rtc
 253 */
 254static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
 255{
 256        struct sam9_rtc *rtc = dev_get_drvdata(dev);
 257        u32 mr = mr = rtt_readl(rtc, MR);
 258
 259        seq_printf(seq, "update_IRQ\t: %s\n",
 260                        (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
 261        return 0;
 262}
 263
 264/*
 265 * IRQ handler for the RTC
 266 */
 267static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
 268{
 269        struct sam9_rtc *rtc = _rtc;
 270        u32 sr, mr;
 271        unsigned long events = 0;
 272
 273        /* Shared interrupt may be for another device.  Note: reading
 274         * SR clears it, so we must only read it in this irq handler!
 275         */
 276        mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
 277        sr = rtt_readl(rtc, SR) & (mr >> 16);
 278        if (!sr)
 279                return IRQ_NONE;
 280
 281        /* alarm status */
 282        if (sr & AT91_RTT_ALMS)
 283                events |= (RTC_AF | RTC_IRQF);
 284
 285        /* timer update/increment */
 286        if (sr & AT91_RTT_RTTINC)
 287                events |= (RTC_UF | RTC_IRQF);
 288
 289        rtc_update_irq(rtc->rtcdev, 1, events);
 290
 291        pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
 292                events >> 8, events & 0x000000FF);
 293
 294        return IRQ_HANDLED;
 295}
 296
 297static const struct rtc_class_ops at91_rtc_ops = {
 298        .ioctl          = at91_rtc_ioctl,
 299        .read_time      = at91_rtc_readtime,
 300        .set_time       = at91_rtc_settime,
 301        .read_alarm     = at91_rtc_readalarm,
 302        .set_alarm      = at91_rtc_setalarm,
 303        .proc           = at91_rtc_proc,
 304};
 305
 306/*
 307 * Initialize and install RTC driver
 308 */
 309static int __init at91_rtc_probe(struct platform_device *pdev)
 310{
 311        struct resource *r;
 312        struct sam9_rtc *rtc;
 313        int             ret;
 314        u32             mr;
 315
 316        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 317        if (!r)
 318                return -ENODEV;
 319
 320        rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
 321        if (!rtc)
 322                return -ENOMEM;
 323
 324        /* platform setup code should have handled this; sigh */
 325        if (!device_can_wakeup(&pdev->dev))
 326                device_init_wakeup(&pdev->dev, 1);
 327
 328        platform_set_drvdata(pdev, rtc);
 329        rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
 330        rtc->rtt += r->start;
 331
 332        mr = rtt_readl(rtc, MR);
 333
 334        /* unless RTT is counting at 1 Hz, re-initialize it */
 335        if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
 336                mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
 337                gpbr_writel(rtc, 0);
 338        }
 339
 340        /* disable all interrupts (same as on shutdown path) */
 341        mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
 342        rtt_writel(rtc, MR, mr);
 343
 344        rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
 345                                &at91_rtc_ops, THIS_MODULE);
 346        if (IS_ERR(rtc->rtcdev)) {
 347                ret = PTR_ERR(rtc->rtcdev);
 348                goto fail;
 349        }
 350
 351        /* register irq handler after we know what name we'll use */
 352        ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
 353                                IRQF_DISABLED | IRQF_SHARED,
 354                                dev_name(&rtc->rtcdev->dev), rtc);
 355        if (ret) {
 356                dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
 357                rtc_device_unregister(rtc->rtcdev);
 358                goto fail;
 359        }
 360
 361        /* NOTE:  sam9260 rev A silicon has a ROM bug which resets the
 362         * RTT on at least some reboots.  If you have that chip, you must
 363         * initialize the time from some external source like a GPS, wall
 364         * clock, discrete RTC, etc
 365         */
 366
 367        if (gpbr_readl(rtc) == 0)
 368                dev_warn(&pdev->dev, "%s: SET TIME!\n",
 369                                dev_name(&rtc->rtcdev->dev));
 370
 371        return 0;
 372
 373fail:
 374        platform_set_drvdata(pdev, NULL);
 375        kfree(rtc);
 376        return ret;
 377}
 378
 379/*
 380 * Disable and remove the RTC driver
 381 */
 382static int __exit at91_rtc_remove(struct platform_device *pdev)
 383{
 384        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
 385        u32             mr = rtt_readl(rtc, MR);
 386
 387        /* disable all interrupts */
 388        rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
 389        free_irq(AT91_ID_SYS, rtc);
 390
 391        rtc_device_unregister(rtc->rtcdev);
 392
 393        platform_set_drvdata(pdev, NULL);
 394        kfree(rtc);
 395        return 0;
 396}
 397
 398static void at91_rtc_shutdown(struct platform_device *pdev)
 399{
 400        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
 401        u32             mr = rtt_readl(rtc, MR);
 402
 403        rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
 404        rtt_writel(rtc, MR, mr & ~rtc->imr);
 405}
 406
 407#ifdef CONFIG_PM
 408
 409/* AT91SAM9 RTC Power management control */
 410
 411static int at91_rtc_suspend(struct platform_device *pdev,
 412                                        pm_message_t state)
 413{
 414        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
 415        u32             mr = rtt_readl(rtc, MR);
 416
 417        /*
 418         * This IRQ is shared with DBGU and other hardware which isn't
 419         * necessarily a wakeup event source.
 420         */
 421        rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
 422        if (rtc->imr) {
 423                if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
 424                        enable_irq_wake(AT91_ID_SYS);
 425                        /* don't let RTTINC cause wakeups */
 426                        if (mr & AT91_RTT_RTTINCIEN)
 427                                rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
 428                } else
 429                        rtt_writel(rtc, MR, mr & ~rtc->imr);
 430        }
 431
 432        return 0;
 433}
 434
 435static int at91_rtc_resume(struct platform_device *pdev)
 436{
 437        struct sam9_rtc *rtc = platform_get_drvdata(pdev);
 438        u32             mr;
 439
 440        if (rtc->imr) {
 441                if (device_may_wakeup(&pdev->dev))
 442                        disable_irq_wake(AT91_ID_SYS);
 443                mr = rtt_readl(rtc, MR);
 444                rtt_writel(rtc, MR, mr | rtc->imr);
 445        }
 446
 447        return 0;
 448}
 449#else
 450#define at91_rtc_suspend        NULL
 451#define at91_rtc_resume         NULL
 452#endif
 453
 454static struct platform_driver at91_rtc_driver = {
 455        .driver.name    = "rtc-at91sam9",
 456        .driver.owner   = THIS_MODULE,
 457        .remove         = __exit_p(at91_rtc_remove),
 458        .shutdown       = at91_rtc_shutdown,
 459        .suspend        = at91_rtc_suspend,
 460        .resume         = at91_rtc_resume,
 461};
 462
 463/* Chips can have more than one RTT module, and they can be used for more
 464 * than just RTCs.  So we can't just register as "the" RTT driver.
 465 *
 466 * A normal approach in such cases is to create a library to allocate and
 467 * free the modules.  Here we just use bus_find_device() as like such a
 468 * library, binding directly ... no runtime "library" footprint is needed.
 469 */
 470static int __init at91_rtc_match(struct device *dev, void *v)
 471{
 472        struct platform_device *pdev = to_platform_device(dev);
 473        int ret;
 474
 475        /* continue searching if this isn't the RTT we need */
 476        if (strcmp("at91_rtt", pdev->name) != 0
 477                        || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
 478                goto fail;
 479
 480        /* else we found it ... but fail unless we can bind to the RTC driver */
 481        if (dev->driver) {
 482                dev_dbg(dev, "busy, can't use as RTC!\n");
 483                goto fail;
 484        }
 485        dev->driver = &at91_rtc_driver.driver;
 486        if (device_attach(dev) == 0) {
 487                dev_dbg(dev, "can't attach RTC!\n");
 488                goto fail;
 489        }
 490        ret = at91_rtc_probe(pdev);
 491        if (ret == 0)
 492                return true;
 493
 494        dev_dbg(dev, "RTC probe err %d!\n", ret);
 495fail:
 496        return false;
 497}
 498
 499static int __init at91_rtc_init(void)
 500{
 501        int status;
 502        struct device *rtc;
 503
 504        status = platform_driver_register(&at91_rtc_driver);
 505        if (status)
 506                return status;
 507        rtc = bus_find_device(&platform_bus_type, NULL,
 508                        NULL, at91_rtc_match);
 509        if (!rtc)
 510                platform_driver_unregister(&at91_rtc_driver);
 511        return rtc ? 0 : -ENODEV;
 512}
 513module_init(at91_rtc_init);
 514
 515static void __exit at91_rtc_exit(void)
 516{
 517        platform_driver_unregister(&at91_rtc_driver);
 518}
 519module_exit(at91_rtc_exit);
 520
 521
 522MODULE_AUTHOR("Michel Benoit");
 523MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
 524MODULE_LICENSE("GPL");
 525