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