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