linux/drivers/rtc/rtc-lpc32xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2010 NXP Semiconductors
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/module.h>
   8#include <linux/init.h>
   9#include <linux/platform_device.h>
  10#include <linux/spinlock.h>
  11#include <linux/rtc.h>
  12#include <linux/slab.h>
  13#include <linux/io.h>
  14#include <linux/of.h>
  15
  16/*
  17 * Clock and Power control register offsets
  18 */
  19#define LPC32XX_RTC_UCOUNT              0x00
  20#define LPC32XX_RTC_DCOUNT              0x04
  21#define LPC32XX_RTC_MATCH0              0x08
  22#define LPC32XX_RTC_MATCH1              0x0C
  23#define LPC32XX_RTC_CTRL                0x10
  24#define LPC32XX_RTC_INTSTAT             0x14
  25#define LPC32XX_RTC_KEY                 0x18
  26#define LPC32XX_RTC_SRAM                0x80
  27
  28#define LPC32XX_RTC_CTRL_MATCH0         (1 << 0)
  29#define LPC32XX_RTC_CTRL_MATCH1         (1 << 1)
  30#define LPC32XX_RTC_CTRL_ONSW_MATCH0    (1 << 2)
  31#define LPC32XX_RTC_CTRL_ONSW_MATCH1    (1 << 3)
  32#define LPC32XX_RTC_CTRL_SW_RESET       (1 << 4)
  33#define LPC32XX_RTC_CTRL_CNTR_DIS       (1 << 6)
  34#define LPC32XX_RTC_CTRL_ONSW_FORCE_HI  (1 << 7)
  35
  36#define LPC32XX_RTC_INTSTAT_MATCH0      (1 << 0)
  37#define LPC32XX_RTC_INTSTAT_MATCH1      (1 << 1)
  38#define LPC32XX_RTC_INTSTAT_ONSW        (1 << 2)
  39
  40#define LPC32XX_RTC_KEY_ONSW_LOADVAL    0xB5C13F27
  41
  42#define rtc_readl(dev, reg) \
  43        __raw_readl((dev)->rtc_base + (reg))
  44#define rtc_writel(dev, reg, val) \
  45        __raw_writel((val), (dev)->rtc_base + (reg))
  46
  47struct lpc32xx_rtc {
  48        void __iomem *rtc_base;
  49        int irq;
  50        unsigned char alarm_enabled;
  51        struct rtc_device *rtc;
  52        spinlock_t lock;
  53};
  54
  55static int lpc32xx_rtc_read_time(struct device *dev, struct rtc_time *time)
  56{
  57        unsigned long elapsed_sec;
  58        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  59
  60        elapsed_sec = rtc_readl(rtc, LPC32XX_RTC_UCOUNT);
  61        rtc_time64_to_tm(elapsed_sec, time);
  62
  63        return 0;
  64}
  65
  66static int lpc32xx_rtc_set_time(struct device *dev, struct rtc_time *time)
  67{
  68        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  69        u32 secs = rtc_tm_to_time64(time);
  70        u32 tmp;
  71
  72        spin_lock_irq(&rtc->lock);
  73
  74        /* RTC must be disabled during count update */
  75        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
  76        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp | LPC32XX_RTC_CTRL_CNTR_DIS);
  77        rtc_writel(rtc, LPC32XX_RTC_UCOUNT, secs);
  78        rtc_writel(rtc, LPC32XX_RTC_DCOUNT, 0xFFFFFFFF - secs);
  79        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp &= ~LPC32XX_RTC_CTRL_CNTR_DIS);
  80
  81        spin_unlock_irq(&rtc->lock);
  82
  83        return 0;
  84}
  85
  86static int lpc32xx_rtc_read_alarm(struct device *dev,
  87        struct rtc_wkalrm *wkalrm)
  88{
  89        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
  90
  91        rtc_time64_to_tm(rtc_readl(rtc, LPC32XX_RTC_MATCH0), &wkalrm->time);
  92        wkalrm->enabled = rtc->alarm_enabled;
  93        wkalrm->pending = !!(rtc_readl(rtc, LPC32XX_RTC_INTSTAT) &
  94                LPC32XX_RTC_INTSTAT_MATCH0);
  95
  96        return rtc_valid_tm(&wkalrm->time);
  97}
  98
  99static int lpc32xx_rtc_set_alarm(struct device *dev,
 100        struct rtc_wkalrm *wkalrm)
 101{
 102        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 103        unsigned long alarmsecs;
 104        u32 tmp;
 105
 106        alarmsecs = rtc_tm_to_time64(&wkalrm->time);
 107
 108        spin_lock_irq(&rtc->lock);
 109
 110        /* Disable alarm during update */
 111        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 112        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp & ~LPC32XX_RTC_CTRL_MATCH0);
 113
 114        rtc_writel(rtc, LPC32XX_RTC_MATCH0, alarmsecs);
 115
 116        rtc->alarm_enabled = wkalrm->enabled;
 117        if (wkalrm->enabled) {
 118                rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
 119                           LPC32XX_RTC_INTSTAT_MATCH0);
 120                rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp |
 121                           LPC32XX_RTC_CTRL_MATCH0);
 122        }
 123
 124        spin_unlock_irq(&rtc->lock);
 125
 126        return 0;
 127}
 128
 129static int lpc32xx_rtc_alarm_irq_enable(struct device *dev,
 130        unsigned int enabled)
 131{
 132        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 133        u32 tmp;
 134
 135        spin_lock_irq(&rtc->lock);
 136        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 137
 138        if (enabled) {
 139                rtc->alarm_enabled = 1;
 140                tmp |= LPC32XX_RTC_CTRL_MATCH0;
 141        } else {
 142                rtc->alarm_enabled = 0;
 143                tmp &= ~LPC32XX_RTC_CTRL_MATCH0;
 144        }
 145
 146        rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
 147        spin_unlock_irq(&rtc->lock);
 148
 149        return 0;
 150}
 151
 152static irqreturn_t lpc32xx_rtc_alarm_interrupt(int irq, void *dev)
 153{
 154        struct lpc32xx_rtc *rtc = dev;
 155
 156        spin_lock(&rtc->lock);
 157
 158        /* Disable alarm interrupt */
 159        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 160                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 161                          ~LPC32XX_RTC_CTRL_MATCH0);
 162        rtc->alarm_enabled = 0;
 163
 164        /*
 165         * Write a large value to the match value so the RTC won't
 166         * keep firing the match status
 167         */
 168        rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
 169        rtc_writel(rtc, LPC32XX_RTC_INTSTAT, LPC32XX_RTC_INTSTAT_MATCH0);
 170
 171        spin_unlock(&rtc->lock);
 172
 173        rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
 174
 175        return IRQ_HANDLED;
 176}
 177
 178static const struct rtc_class_ops lpc32xx_rtc_ops = {
 179        .read_time              = lpc32xx_rtc_read_time,
 180        .set_time               = lpc32xx_rtc_set_time,
 181        .read_alarm             = lpc32xx_rtc_read_alarm,
 182        .set_alarm              = lpc32xx_rtc_set_alarm,
 183        .alarm_irq_enable       = lpc32xx_rtc_alarm_irq_enable,
 184};
 185
 186static int lpc32xx_rtc_probe(struct platform_device *pdev)
 187{
 188        struct lpc32xx_rtc *rtc;
 189        int err;
 190        u32 tmp;
 191
 192        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 193        if (unlikely(!rtc))
 194                return -ENOMEM;
 195
 196        rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);
 197        if (IS_ERR(rtc->rtc_base))
 198                return PTR_ERR(rtc->rtc_base);
 199
 200        spin_lock_init(&rtc->lock);
 201
 202        /*
 203         * The RTC is on a separate power domain and can keep it's state
 204         * across a chip power cycle. If the RTC has never been previously
 205         * setup, then set it up now for the first time.
 206         */
 207        tmp = rtc_readl(rtc, LPC32XX_RTC_CTRL);
 208        if (rtc_readl(rtc, LPC32XX_RTC_KEY) != LPC32XX_RTC_KEY_ONSW_LOADVAL) {
 209                tmp &= ~(LPC32XX_RTC_CTRL_SW_RESET |
 210                        LPC32XX_RTC_CTRL_CNTR_DIS |
 211                        LPC32XX_RTC_CTRL_MATCH0 |
 212                        LPC32XX_RTC_CTRL_MATCH1 |
 213                        LPC32XX_RTC_CTRL_ONSW_MATCH0 |
 214                        LPC32XX_RTC_CTRL_ONSW_MATCH1 |
 215                        LPC32XX_RTC_CTRL_ONSW_FORCE_HI);
 216                rtc_writel(rtc, LPC32XX_RTC_CTRL, tmp);
 217
 218                /* Clear latched interrupt states */
 219                rtc_writel(rtc, LPC32XX_RTC_MATCH0, 0xFFFFFFFF);
 220                rtc_writel(rtc, LPC32XX_RTC_INTSTAT,
 221                           LPC32XX_RTC_INTSTAT_MATCH0 |
 222                           LPC32XX_RTC_INTSTAT_MATCH1 |
 223                           LPC32XX_RTC_INTSTAT_ONSW);
 224
 225                /* Write key value to RTC so it won't reload on reset */
 226                rtc_writel(rtc, LPC32XX_RTC_KEY,
 227                           LPC32XX_RTC_KEY_ONSW_LOADVAL);
 228        } else {
 229                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 230                           tmp & ~LPC32XX_RTC_CTRL_MATCH0);
 231        }
 232
 233        platform_set_drvdata(pdev, rtc);
 234
 235        rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
 236        if (IS_ERR(rtc->rtc))
 237                return PTR_ERR(rtc->rtc);
 238
 239        rtc->rtc->ops = &lpc32xx_rtc_ops;
 240        rtc->rtc->range_max = U32_MAX;
 241
 242        err = rtc_register_device(rtc->rtc);
 243        if (err)
 244                return err;
 245
 246        /*
 247         * IRQ is enabled after device registration in case alarm IRQ
 248         * is pending upon suspend exit.
 249         */
 250        rtc->irq = platform_get_irq(pdev, 0);
 251        if (rtc->irq < 0) {
 252                dev_warn(&pdev->dev, "Can't get interrupt resource\n");
 253        } else {
 254                if (devm_request_irq(&pdev->dev, rtc->irq,
 255                                     lpc32xx_rtc_alarm_interrupt,
 256                                     0, pdev->name, rtc) < 0) {
 257                        dev_warn(&pdev->dev, "Can't request interrupt.\n");
 258                        rtc->irq = -1;
 259                } else {
 260                        device_init_wakeup(&pdev->dev, 1);
 261                }
 262        }
 263
 264        return 0;
 265}
 266
 267#ifdef CONFIG_PM
 268static int lpc32xx_rtc_suspend(struct device *dev)
 269{
 270        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 271
 272        if (rtc->irq >= 0) {
 273                if (device_may_wakeup(dev))
 274                        enable_irq_wake(rtc->irq);
 275                else
 276                        disable_irq_wake(rtc->irq);
 277        }
 278
 279        return 0;
 280}
 281
 282static int lpc32xx_rtc_resume(struct device *dev)
 283{
 284        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 285
 286        if (rtc->irq >= 0 && device_may_wakeup(dev))
 287                disable_irq_wake(rtc->irq);
 288
 289        return 0;
 290}
 291
 292/* Unconditionally disable the alarm */
 293static int lpc32xx_rtc_freeze(struct device *dev)
 294{
 295        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 296
 297        spin_lock_irq(&rtc->lock);
 298
 299        rtc_writel(rtc, LPC32XX_RTC_CTRL,
 300                rtc_readl(rtc, LPC32XX_RTC_CTRL) &
 301                          ~LPC32XX_RTC_CTRL_MATCH0);
 302
 303        spin_unlock_irq(&rtc->lock);
 304
 305        return 0;
 306}
 307
 308static int lpc32xx_rtc_thaw(struct device *dev)
 309{
 310        struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
 311
 312        if (rtc->alarm_enabled) {
 313                spin_lock_irq(&rtc->lock);
 314
 315                rtc_writel(rtc, LPC32XX_RTC_CTRL,
 316                           rtc_readl(rtc, LPC32XX_RTC_CTRL) |
 317                           LPC32XX_RTC_CTRL_MATCH0);
 318
 319                spin_unlock_irq(&rtc->lock);
 320        }
 321
 322        return 0;
 323}
 324
 325static const struct dev_pm_ops lpc32xx_rtc_pm_ops = {
 326        .suspend = lpc32xx_rtc_suspend,
 327        .resume = lpc32xx_rtc_resume,
 328        .freeze = lpc32xx_rtc_freeze,
 329        .thaw = lpc32xx_rtc_thaw,
 330        .restore = lpc32xx_rtc_resume
 331};
 332
 333#define LPC32XX_RTC_PM_OPS (&lpc32xx_rtc_pm_ops)
 334#else
 335#define LPC32XX_RTC_PM_OPS NULL
 336#endif
 337
 338#ifdef CONFIG_OF
 339static const struct of_device_id lpc32xx_rtc_match[] = {
 340        { .compatible = "nxp,lpc3220-rtc" },
 341        { }
 342};
 343MODULE_DEVICE_TABLE(of, lpc32xx_rtc_match);
 344#endif
 345
 346static struct platform_driver lpc32xx_rtc_driver = {
 347        .probe          = lpc32xx_rtc_probe,
 348        .driver = {
 349                .name   = "rtc-lpc32xx",
 350                .pm     = LPC32XX_RTC_PM_OPS,
 351                .of_match_table = of_match_ptr(lpc32xx_rtc_match),
 352        },
 353};
 354
 355module_platform_driver(lpc32xx_rtc_driver);
 356
 357MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com");
 358MODULE_DESCRIPTION("RTC driver for the LPC32xx SoC");
 359MODULE_LICENSE("GPL");
 360MODULE_ALIAS("platform:rtc-lpc32xx");
 361