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        int rtcirq;
 205        u32 tmp;
 206
 207        rtcirq = platform_get_irq(pdev, 0);
 208        if (rtcirq < 0 || rtcirq >= NR_IRQS) {
 209                dev_warn(&pdev->dev, "Can't get interrupt resource\n");
 210                rtcirq = -1;
 211        }
 212
 213        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 214        if (unlikely(!rtc)) {
 215                dev_err(&pdev->dev, "Can't allocate memory\n");
 216                return -ENOMEM;
 217        }
 218        rtc->irq = rtcirq;
 219
 220        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 221        rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res);
 222        if (IS_ERR(rtc->rtc_base))
 223                return PTR_ERR(rtc->rtc_base);
 224
 225        spin_lock_init(&rtc->lock);
 226
 227        /*
 228         * The RTC is on a separate power domain and can keep it's state
 229         * across a chip power cycle. If the RTC has never been previously
 230         * setup, then set it up now for the first time.
 231         */
 232        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 233        if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
 234                tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
 235                        LPC32XX_RTC_CTRL_CNTR_DIS |
 236                        LPC32XX_RTC_CTRL_MATCH0 |
 237                        LPC32XX_RTC_CTRL_MATCH1 |
 238                        LPC32XX_RTC_CTRL_ONSW_MATCH0 |
 239                        LPC32XX_RTC_CTRL_ONSW_MATCH1 |
 240                        LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
 241                rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
 242
 243                /* Clear latched interrupt states */
 244                rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
 245                rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
 246                           LPC32XX_RTC_INTSTAT_MATCH0 |
 247                           LPC32XX_RTC_INTSTAT_MATCH1 |
 248                           LPC32XX_RTC_INTSTAT_ONSW);
 249
 250                /* Write key value to RTC so it won't reload on reset */
 251                rtc_writel(rtc, LPC32XX_RTC_KEY,
 252                           LPC32XX_RTC_KEY_ONSW_LOADVAL);
 253        } else {
 254                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 255                           tmp & ~LPC32XX_RTC_CTRL_MATCH0);
 256        }
 257
 258        platform_set_drvdata(pdev, rtc);
 259
 260        rtc->rtc = devm_rtc_device_register(&pdev->dev, RTC_NAME,
 261                                        &lpc32xx_rtc_ops, THIS_MODULE);
 262        if (IS_ERR(rtc->rtc)) {
 263                dev_err(&pdev->dev, "Can't get RTC\n");
 264                return PTR_ERR(rtc->rtc);
 265        }
 266
 267        /*
 268         * IRQ is enabled after device registration in case alarm IRQ
 269         * is pending upon suspend exit.
 270         */
 271        if (rtc->irq >= 0) {
 272                if (devm_request_irq(&pdev->dev, rtc->irq,
 273                                     lpc32xx_rtc_alarm_interrupt,
 274                                     0, pdev->name, rtc) < 0) {
 275                        dev_warn(&pdev->dev, "Can't request interrupt.\n");
 276                        rtc->irq = -1;
 277                } else {
 278                        device_init_wakeup(&pdev->dev, 1);
 279                }
 280        }
 281
 282        return 0;
 283}
 284
 285static int lpc32xx_rtc_remove(struct platform_device *pdev)
 286{
 287        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 288
 289        if (rtc->irq >= 0)
 290                device_init_wakeup(&pdev->dev, 0);
 291
 292        return 0;
 293}
 294
 295#ifdef CONFIG_PM
 296static int lpc32xx_rtc_suspend(struct device *dev)
 297{
 298        struct platform_device *pdev = to_platform_device(dev);
 299        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 300
 301        if (rtc->irq >= 0) {
 302                if (device_may_wakeup(&pdev->dev))
 303                        enable_irq_wake(rtc->irq);
 304                else
 305                        disable_irq_wake(rtc->irq);
 306        }
 307
 308        return 0;
 309}
 310
 311static int lpc32xx_rtc_resume(struct device *dev)
 312{
 313        struct platform_device *pdev = to_platform_device(dev);
 314        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 315
 316        if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
 317                disable_irq_wake(rtc->irq);
 318
 319        return 0;
 320}
 321
 322/* Unconditionally disable the alarm */
 323static int lpc32xx_rtc_freeze(struct device *dev)
 324{
 325        struct platform_device *pdev = to_platform_device(dev);
 326        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 327
 328        spin_lock_irq(&rtc->lock);
 329
 330        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 331                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 332                          ~LPC32XX_RTC_CTRL_MATCH0);
 333
 334        spin_unlock_irq(&rtc->lock);
 335
 336        return 0;
 337}
 338
 339static int lpc32xx_rtc_thaw(struct device *dev)
 340{
 341        struct platform_device *pdev = to_platform_device(dev);
 342        struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
 343
 344        if (rtc->alarm_enabled) {
 345                spin_lock_irq(&rtc->lock);
 346
 347                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 348                           rtc_readl(rtc, LPC32XX_RTC_CTRL) |
 349                           LPC32XX_RTC_CTRL_MATCH0);
 350
 351                spin_unlock_irq(&rtc->lock);
 352        }
 353
 354        return 0;
 355}
 356
 357static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
 358        .suspend = lpc32xx_rtc_suspend,
 359        .resume = lpc32xx_rtc_resume,
 360        .freeze = lpc32xx_rtc_freeze,
 361        .thaw = lpc32xx_rtc_thaw,
 362        .restore = lpc32xx_rtc_resume
 363};
 364
 365#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
 366#else
 367#define LPC32XX_RTC_PM_OPS NULL
 368#endif
 369
 370#ifdef CONFIG_OF
 371static const struct of_device_id lpc32xx_rtc_match[] = {
 372        { .compatible = "nxp,lpc3220-rtc" },
 373        { }
 374};
 375MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 376#endif
 377
 378static struct platform_driver lpc32xx_rtc_driver = {
 379        .probe          = lpc32xx_rtc_probe,
 380        .remove         = lpc32xx_rtc_remove,
 381        .driver = {
 382                .name   = RTC_NAME,
 383                .owner  = THIS_MODULE,
 384                .pm     = LPC32XX_RTC_PM_OPS,
 385                .of_match_table = of_match_ptr(lpc32xx_rtc_match),
 386        },
 387};
 388
 389module_platform_driver(lpc32xx_rtc_driver);
 390
 391MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
 392MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
 393MODULE_LICENSE("GPL");
 394MODULE_ALIAS("platform:rtc-lpc32xx");
 395
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.