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