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 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 = devm_rtc_device_register(&pdev->dev, RTC_NAME,
 277                                        &lpc32xx_rtc_ops, 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 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
 311        return 0;
 312}
 313
 314#ifdef CONFIG_PM
 315static int lpc32xx_rtc_suspend(struct device *dev)
 316{
 317        struct platform_device *pdev = to_platform_device(dev);
 318        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 319
 320        if (rtc->irq >= 0) {
 321                if (device_may_wakeup(&pdev->dev))
 322                        enable_irq_wake(rtc->irq);
 323                else
 324                        disable_irq_wake(rtc->irq);
 325        }
 326
 327        return 0;
 328}
 329
 330static int lpc32xx_rtc_resume(struct device *dev)
 331{
 332        struct platform_device *pdev = to_platform_device(dev);
 333        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 334
 335        if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
 336                disable_irq_wake(rtc->irq);
 337
 338        return 0;
 339}
 340
 341/* Unconditionally disable the alarm */
 342static int lpc32xx_rtc_freeze(struct device *dev)
 343{
 344        struct platform_device *pdev = to_platform_device(dev);
 345        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 346
 347        spin_lock_irq(&rtc->lock);
 348
 349        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 350                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 351                          ~LPC32XX_RTC_CTRL_MATCH0);
 352
 353        spin_unlock_irq(&rtc->lock);
 354
 355        return 0;
 356}
 357
 358static int lpc32xx_rtc_thaw(struct device *dev)
 359{
 360        struct platform_device *pdev = to_platform_device(dev);
 361        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 362
 363        if (rtc->alarm_enabled) {
 364                spin_lock_irq(&rtc->lock);
 365
 366                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 367                           rtc_readl(rtc, LPC32XX_RTC_CTRL) |
 368                           LPC32XX_RTC_CTRL_MATCH0);
 369
 370                spin_unlock_irq(&rtc->lock);
 371        }
 372
 373        return 0;
 374}
 375
 376static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
 377        .suspend = lpc32xx_rtc_suspend,
 378        .resume = lpc32xx_rtc_resume,
 379        .freeze = lpc32xx_rtc_freeze,
 380        .thaw = lpc32xx_rtc_thaw,
 381        .restore = lpc32xx_rtc_resume
 382};
 383
 384#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
 385#else
 386#define LPC32XX_RTC_PM_OPS NULL
 387#endif
 388
 389#ifdef CONFIG_OF
 390static const struct of_device_id lpc32xx_rtc_match[] = {
 391        { .compatible = "nxp,lpc3220-rtc" },
 392        { }
 393};
 394MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 395#endif
 396
 397static struct platform_driver lpc32xx_rtc_driver = {
 398        .probe          = lpc32xx_rtc_probe,
 399        .remove         = lpc32xx_rtc_remove,
 400        .driver = {
 401                .name   = RTC_NAME,
 402                .owner  = THIS_MODULE,
 403                .pm     = LPC32XX_RTC_PM_OPS,
 404                .of_match_table = of_match_ptr(lpc32xx_rtc_match),
 405        },
 406};
 407
 408module_platform_driver(lpc32xx_rtc_driver);
 409
 410MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
 411MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
 412MODULE_LICENSE("GPL");
 413MODULE_ALIAS("platform:rtc-lpc32xx");
 414
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.