linux/drivers/rtc/rtc-lpc32xx.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 NXP Semiconductors
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 *  You should have received a copy of the GNU General Public License along
  10 *  with this program; if not, write to the Free Software Foundation, Inc.,
  11 *  675 Mass Ave, Cambridge, MA 02139, USA.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/platform_device.h>
  18#include <linux/spinlock.h>
  19#include <linux/rtc.h>
  20#include <linux/slab.h>
  21#include <linux/io.h>
  22#include <linux/of.h>
  23
  24/*
  25 * Clock and Power control register offsets
  26 */
  27#define LPC32XX_RTC_UCOUNT              0x00
  28#define LPC32XX_RTC_DCOUNT              0x04
  29#define LPC32XX_RTC_MATCH0              0x08
  30#define LPC32XX_RTC_MATCH1              0x0C
  31#define LPC32XX_RTC_CTRL                0x10
  32#define LPC32XX_RTC_INTSTAT             0x14
  33#define LPC32XX_RTC_KEY                 0x18
  34#define LPC32XX_RTC_SRAM                0x80
  35
  36#define LPC32XX_RTC_CTRL_MATCH0         (1 << 0)
  37#define LPC32XX_RTC_CTRL_MATCH1         (1 << 1)
  38#define LPC32XX_RTC_CTRL_ONSW_MATCH0    (1 << 2)
  39#define LPC32XX_RTC_CTRL_ONSW_MATCH1    (1 << 3)
  40#define LPC32XX_RTC_CTRL_SW_RESET       (1 << 4)
  41#define LPC32XX_RTC_CTRL_CNTR_DIS       (1 << 6)
  42#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI  (1 << 7)
  43
  44#define LPC32XX_RTC_INTSTAT_MATCH0      (1 << 0)
  45#define LPC32XX_RTC_INTSTAT_MATCH1      (1 << 1)
  46#define LPC32XX_RTC_INTSTAT_ONSW        (1 << 2)
  47
  48#define LPC32XX_RTC_KEY_ONSW_LOADVAL    0xB5C13F27
  49
  50#define RTC_NAME "rtc-lpc32xx"
  51
  52#define rtc_readl(dev, reg) \
  53        __raw_readl((dev)->rtc_base + (reg))
  54#define rtc_writel(dev, reg, val) \
  55        __raw_writel((val), (dev)->rtc_base + (reg))
  56
  57struct lpc32xx_rtc {
  58        void __iomem *rtc_base;
  59        int irq;
  60        unsigned char alarm_enabled;
  61        struct rtc_device *rtc;
  62        spinlock_t lock;
  63};
  64
  65static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)
  66{
  67        unsigned long elapsed_sec;
  68        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  69
  70        elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);
  71        rtc_time_to_tm(elapsed_sec, time);
  72
  73        return rtc_valid_tm(time);
  74}
  75
  76static int lpc32xx_rtc_set_mmss(struct device *dev, unsigned long secs)
  77{
  78        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  79        u32 tmp;
  80
  81        spin_lock_irq(&rtc->lock);
  82
  83        /* RTC must be disabled during count update */
  84        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
  85        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);
  86        rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);
  87        rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);
  88        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);
  89
  90        spin_unlock_irq(&rtc->lock);
  91
  92        return 0;
  93}
  94
  95static int lpc32xx_rtc_read_alarm(struct device *dev,
  96        struct rtc_wkalrm *wkalrm)
  97{
  98        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  99
 100        rtc_time_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);
 101        wkalrm->enabled = rtc->alarm_enabled;
 102        wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &
 103                LPC32XX_RTC_INTSTAT_MATCH0);
 104
 105        return rtc_valid_tm(&wkalrm->time);
 106}
 107
 108static int lpc32xx_rtc_set_alarm(struct device *dev,
 109        struct rtc_wkalrm *wkalrm)
 110{
 111        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 112        unsigned long alarmsecs;
 113        u32 tmp;
 114        int ret;
 115
 116        ret = rtc_tm_to_time(&wkalrm->time, &alarmsecs);
 117        if (ret < 0) {
 118                dev_warn(dev, "Failed to convert time: %d\n", ret);
 119                return ret;
 120        }
 121
 122        spin_lock_irq(&rtc->lock);
 123
 124        /* Disable alarm during update */
 125        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 126        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);
 127
 128        rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);
 129
 130        rtc->alarm_enabled = wkalrm->enabled;
 131        if (wkalrm->enabled) {
 132                rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
 133                           LPC32XX_RTC_INTSTAT_MATCH0);
 134                rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |
 135                           LPC32XX_RTC_CTRL_MATCH0);
 136        }
 137
 138        spin_unlock_irq(&rtc->lock);
 139
 140        return 0;
 141}
 142
 143static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,
 144        unsigned int enabled)
 145{
 146        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 147        u32 tmp;
 148
 149        spin_lock_irq(&rtc->lock);
 150        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 151
 152        if (enabled) {
 153                rtc->alarm_enabled = 1;
 154                tmp |= LPC32XX_RTC_CTRL_MATCH0;
 155        } else {
 156                rtc->alarm_enabled = 0;
 157                tmp &= ~LPC32XX_RTC_CTRL_MATCH0;
 158        }
 159
 160        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
 161        spin_unlock_irq(&rtc->lock);
 162
 163        return 0;
 164}
 165
 166static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)
 167{
 168        struct lpc32xx_rtc *rtc = dev;
 169
 170        spin_lock(&rtc->lock);
 171
 172        /* Disable alarm interrupt */
 173        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 174                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 175                          ~LPC32XX_RTC_CTRL_MATCH0);
 176        rtc->alarm_enabled = 0;
 177
 178        /*
 179         * Write a large value to the match value so the RTC won't
 180         * keep firing the match status
 181         */
 182        rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
 183        rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);
 184
 185        spin_unlock(&rtc->lock);
 186
 187        rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
 188
 189        return IRQ_HANDLED;
 190}
 191
 192static const struct rtc_class_ops lpc32xx_rtc_ops = {
 193        .read_time              = lpc32xx_rtc_read_time,
 194        .set_mmss               = lpc32xx_rtc_set_mmss,
 195        .read_alarm             = lpc32xx_rtc_read_alarm,
 196        .set_alarm              = lpc32xx_rtc_set_alarm,
 197        .alarm_irq_enable       = lpc32xx_rtc_alarm_irq_enable,
 198};
 199
 200static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev)
 201{
 202        struct resource *res;
 203        struct lpc32xx_rtc *rtc;
 204        resource_size_t size;
 205        int rtcirq;
 206        u32 tmp;
 207
 208        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 209        if (!res) {
 210                dev_err(&pdev->dev, "Can't get memory resource\n");
 211                return -ENOENT;
 212        }
 213
 214        rtcirq = platform_get_irq(pdev, 0);
 215        if (rtcirq < 0 || rtcirq >= NR_IRQS) {
 216                dev_warn(&pdev->dev, "Can't get interrupt resource\n");
 217                rtcirq = -1;
 218        }
 219
 220        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 221        if (unlikely(!rtc)) {
 222                dev_err(&pdev->dev, "Can't allocate memory\n");
 223                return -ENOMEM;
 224        }
 225        rtc->irq = rtcirq;
 226
 227        size = resource_size(res);
 228
 229        if (!devm_request_mem_region(&pdev->dev, res->start, size,
 230                                     pdev->name)) {
 231                dev_err(&pdev->dev, "RTC registers are not free\n");
 232                return -EBUSY;
 233        }
 234
 235        rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size);
 236        if (!rtc->rtc_base) {
 237                dev_err(&pdev->dev, "Can't map memory\n");
 238                return -ENOMEM;
 239        }
 240
 241        spin_lock_init(&rtc->lock);
 242
 243        /*
 244         * The RTC is on a separate power domain and can keep it's state
 245         * across a chip power cycle. If the RTC has never been previously
 246         * setup, then set it up now for the first time.
 247         */
 248        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 249        if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
 250                tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
 251                        LPC32XX_RTC_CTRL_CNTR_DIS |
 252                        LPC32XX_RTC_CTRL_MATCH0 |
 253                        LPC32XX_RTC_CTRL_MATCH1 |
 254                        LPC32XX_RTC_CTRL_ONSW_MATCH0 |
 255                        LPC32XX_RTC_CTRL_ONSW_MATCH1 |
 256                        LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
 257                rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
 258
 259                /* Clear latched interrupt states */
 260                rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
 261                rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
 262                           LPC32XX_RTC_INTSTAT_MATCH0 |
 263                           LPC32XX_RTC_INTSTAT_MATCH1 |
 264                           LPC32XX_RTC_INTSTAT_ONSW);
 265
 266                /* Write key value to RTC so it won't reload on reset */
 267                rtc_writel(rtc, LPC32XX_RTC_KEY,
 268                           LPC32XX_RTC_KEY_ONSW_LOADVAL);
 269        } else {
 270                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 271                           tmp & ~LPC32XX_RTC_CTRL_MATCH0);
 272        }
 273
 274        platform_set_drvdata(pdev, rtc);
 275
 276        rtc->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &lpc32xx_rtc_ops,
 277                THIS_MODULE);
 278        if (IS_ERR(rtc->rtc)) {
 279                dev_err(&pdev->dev, "Can't get RTC\n");
 280                platform_set_drvdata(pdev, NULL);
 281                return PTR_ERR(rtc->rtc);
 282        }
 283
 284        /*
 285         * IRQ is enabled after device registration in case alarm IRQ
 286         * is pending upon suspend exit.
 287         */
 288        if (rtc->irq >= 0) {
 289                if (devm_request_irq(&pdev->dev, rtc->irq,
 290                                     lpc32xx_rtc_alarm_interrupt,
 291                                     0, pdev->name, rtc) < 0) {
 292                        dev_warn(&pdev->dev, "Can't request interrupt.\n");
 293                        rtc->irq = -1;
 294                } else {
 295                        device_init_wakeup(&pdev->dev, 1);
 296                }
 297        }
 298
 299        return 0;
 300}
 301
 302static int __devexit lpc32xx_rtc_remove(struct platform_device *pdev)
 303{
 304        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 305
 306        if (rtc->irq >= 0)
 307                device_init_wakeup(&pdev->dev, 0);
 308
 309        platform_set_drvdata(pdev, NULL);
 310        rtc_device_unregister(rtc->rtc);
 311
 312        return 0;
 313}
 314
 315#ifdef CONFIG_PM
 316static int lpc32xx_rtc_suspend(struct device *dev)
 317{
 318        struct platform_device *pdev = to_platform_device(dev);
 319        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 320
 321        if (rtc->irq >= 0) {
 322                if (device_may_wakeup(&pdev->dev))
 323                        enable_irq_wake(rtc->irq);
 324                else
 325                        disable_irq_wake(rtc->irq);
 326        }
 327
 328        return 0;
 329}
 330
 331static int lpc32xx_rtc_resume(struct device *dev)
 332{
 333        struct platform_device *pdev = to_platform_device(dev);
 334        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 335
 336        if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
 337                disable_irq_wake(rtc->irq);
 338
 339        return 0;
 340}
 341
 342/* Unconditionally disable the alarm */
 343static int lpc32xx_rtc_freeze(struct device *dev)
 344{
 345        struct platform_device *pdev = to_platform_device(dev);
 346        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 347
 348        spin_lock_irq(&rtc->lock);
 349
 350        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 351                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 352                          ~LPC32XX_RTC_CTRL_MATCH0);
 353
 354        spin_unlock_irq(&rtc->lock);
 355
 356        return 0;
 357}
 358
 359static int lpc32xx_rtc_thaw(struct device *dev)
 360{
 361        struct platform_device *pdev = to_platform_device(dev);
 362        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 363
 364        if (rtc->alarm_enabled) {
 365                spin_lock_irq(&rtc->lock);
 366
 367                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 368                           rtc_readl(rtc, LPC32XX_RTC_CTRL) |
 369                           LPC32XX_RTC_CTRL_MATCH0);
 370
 371                spin_unlock_irq(&rtc->lock);
 372        }
 373
 374        return 0;
 375}
 376
 377static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
 378        .suspend = lpc32xx_rtc_suspend,
 379        .resume = lpc32xx_rtc_resume,
 380        .freeze = lpc32xx_rtc_freeze,
 381        .thaw = lpc32xx_rtc_thaw,
 382        .restore = lpc32xx_rtc_resume
 383};
 384
 385#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
 386#else
 387#define LPC32XX_RTC_PM_OPS NULL
 388#endif
 389
 390#ifdef CONFIG_OF
 391static const struct of_device_id lpc32xx_rtc_match[] = {
 392        { .compatible = "nxp,lpc3220-rtc" },
 393        { }
 394};
 395MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 396#endif
 397
 398static struct platform_driver lpc32xx_rtc_driver = {
 399        .probe          = lpc32xx_rtc_probe,
 400        .remove         = __devexit_p(lpc32xx_rtc_remove),
 401        .driver = {
 402                .name   = RTC_NAME,
 403                .owner  = THIS_MODULE,
 404                .pm     = LPC32XX_RTC_PM_OPS,
 405                .of_match_table = of_match_ptr(lpc32xx_rtc_match),
 406        },
 407};
 408
 409module_platform_driver(lpc32xx_rtc_driver);
 410
 411MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
 412MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
 413MODULE_LICENSE("GPL");
 414MODULE_ALIAS("platform:rtc-lpc32xx");
 415
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.