linux/drivers/rtc/rtc-lpc24xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC)
   4 *
   5 * Copyright (C) 2011 NXP Semiconductors
   6 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
   7 */
   8
   9#include <linux/clk.h>
  10#include <linux/io.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/of.h>
  14#include <linux/of_device.h>
  15#include <linux/platform_device.h>
  16#include <linux/rtc.h>
  17
  18/* LPC24xx RTC register offsets and bits */
  19#define LPC24XX_ILR             0x00
  20#define  LPC24XX_RTCCIF         BIT(0)
  21#define  LPC24XX_RTCALF         BIT(1)
  22#define LPC24XX_CTC             0x04
  23#define LPC24XX_CCR             0x08
  24#define  LPC24XX_CLKEN          BIT(0)
  25#define  LPC178X_CCALEN         BIT(4)
  26#define LPC24XX_CIIR            0x0c
  27#define LPC24XX_AMR             0x10
  28#define  LPC24XX_ALARM_DISABLE  0xff
  29#define LPC24XX_CTIME0          0x14
  30#define LPC24XX_CTIME1          0x18
  31#define LPC24XX_CTIME2          0x1c
  32#define LPC24XX_SEC             0x20
  33#define LPC24XX_MIN             0x24
  34#define LPC24XX_HOUR            0x28
  35#define LPC24XX_DOM             0x2c
  36#define LPC24XX_DOW             0x30
  37#define LPC24XX_DOY             0x34
  38#define LPC24XX_MONTH           0x38
  39#define LPC24XX_YEAR            0x3c
  40#define LPC24XX_ALSEC           0x60
  41#define LPC24XX_ALMIN           0x64
  42#define LPC24XX_ALHOUR          0x68
  43#define LPC24XX_ALDOM           0x6c
  44#define LPC24XX_ALDOW           0x70
  45#define LPC24XX_ALDOY           0x74
  46#define LPC24XX_ALMON           0x78
  47#define LPC24XX_ALYEAR          0x7c
  48
  49/* Macros to read fields in consolidated time (CT) registers */
  50#define CT0_SECS(x)             (((x) >> 0)  & 0x3f)
  51#define CT0_MINS(x)             (((x) >> 8)  & 0x3f)
  52#define CT0_HOURS(x)            (((x) >> 16) & 0x1f)
  53#define CT0_DOW(x)              (((x) >> 24) & 0x07)
  54#define CT1_DOM(x)              (((x) >> 0)  & 0x1f)
  55#define CT1_MONTH(x)            (((x) >> 8)  & 0x0f)
  56#define CT1_YEAR(x)             (((x) >> 16) & 0xfff)
  57#define CT2_DOY(x)              (((x) >> 0)  & 0xfff)
  58
  59#define rtc_readl(dev, reg)             readl((dev)->rtc_base + (reg))
  60#define rtc_writel(dev, reg, val)       writel((val), (dev)->rtc_base + (reg))
  61
  62struct lpc24xx_rtc {
  63        void __iomem *rtc_base;
  64        struct rtc_device *rtc;
  65        struct clk *clk_rtc;
  66        struct clk *clk_reg;
  67};
  68
  69static int lpc24xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
  70{
  71        struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
  72
  73        /* Disable RTC during update */
  74        rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN);
  75
  76        rtc_writel(rtc, LPC24XX_SEC,    tm->tm_sec);
  77        rtc_writel(rtc, LPC24XX_MIN,    tm->tm_min);
  78        rtc_writel(rtc, LPC24XX_HOUR,   tm->tm_hour);
  79        rtc_writel(rtc, LPC24XX_DOW,    tm->tm_wday);
  80        rtc_writel(rtc, LPC24XX_DOM,    tm->tm_mday);
  81        rtc_writel(rtc, LPC24XX_DOY,    tm->tm_yday);
  82        rtc_writel(rtc, LPC24XX_MONTH,  tm->tm_mon);
  83        rtc_writel(rtc, LPC24XX_YEAR,   tm->tm_year);
  84
  85        rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN);
  86
  87        return 0;
  88}
  89
  90static int lpc24xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
  91{
  92        struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
  93        u32 ct0, ct1, ct2;
  94
  95        ct0 = rtc_readl(rtc, LPC24XX_CTIME0);
  96        ct1 = rtc_readl(rtc, LPC24XX_CTIME1);
  97        ct2 = rtc_readl(rtc, LPC24XX_CTIME2);
  98
  99        tm->tm_sec  = CT0_SECS(ct0);
 100        tm->tm_min  = CT0_MINS(ct0);
 101        tm->tm_hour = CT0_HOURS(ct0);
 102        tm->tm_wday = CT0_DOW(ct0);
 103        tm->tm_mon  = CT1_MONTH(ct1);
 104        tm->tm_mday = CT1_DOM(ct1);
 105        tm->tm_year = CT1_YEAR(ct1);
 106        tm->tm_yday = CT2_DOY(ct2);
 107
 108        return 0;
 109}
 110
 111static int lpc24xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 112{
 113        struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
 114        struct rtc_time *tm = &wkalrm->time;
 115
 116        tm->tm_sec  = rtc_readl(rtc, LPC24XX_ALSEC);
 117        tm->tm_min  = rtc_readl(rtc, LPC24XX_ALMIN);
 118        tm->tm_hour = rtc_readl(rtc, LPC24XX_ALHOUR);
 119        tm->tm_mday = rtc_readl(rtc, LPC24XX_ALDOM);
 120        tm->tm_wday = rtc_readl(rtc, LPC24XX_ALDOW);
 121        tm->tm_yday = rtc_readl(rtc, LPC24XX_ALDOY);
 122        tm->tm_mon  = rtc_readl(rtc, LPC24XX_ALMON);
 123        tm->tm_year = rtc_readl(rtc, LPC24XX_ALYEAR);
 124
 125        wkalrm->enabled = rtc_readl(rtc, LPC24XX_AMR) == 0;
 126        wkalrm->pending = !!(rtc_readl(rtc, LPC24XX_ILR) & LPC24XX_RTCCIF);
 127
 128        return rtc_valid_tm(&wkalrm->time);
 129}
 130
 131static int lpc24xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 132{
 133        struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
 134        struct rtc_time *tm = &wkalrm->time;
 135
 136        /* Disable alarm irq during update */
 137        rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
 138
 139        rtc_writel(rtc, LPC24XX_ALSEC,  tm->tm_sec);
 140        rtc_writel(rtc, LPC24XX_ALMIN,  tm->tm_min);
 141        rtc_writel(rtc, LPC24XX_ALHOUR, tm->tm_hour);
 142        rtc_writel(rtc, LPC24XX_ALDOM,  tm->tm_mday);
 143        rtc_writel(rtc, LPC24XX_ALDOW,  tm->tm_wday);
 144        rtc_writel(rtc, LPC24XX_ALDOY,  tm->tm_yday);
 145        rtc_writel(rtc, LPC24XX_ALMON,  tm->tm_mon);
 146        rtc_writel(rtc, LPC24XX_ALYEAR, tm->tm_year);
 147
 148        if (wkalrm->enabled)
 149                rtc_writel(rtc, LPC24XX_AMR, 0);
 150
 151        return 0;
 152}
 153
 154static int lpc24xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
 155{
 156        struct lpc24xx_rtc *rtc = dev_get_drvdata(dev);
 157
 158        if (enable)
 159                rtc_writel(rtc, LPC24XX_AMR, 0);
 160        else
 161                rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
 162
 163        return 0;
 164}
 165
 166static irqreturn_t lpc24xx_rtc_interrupt(int irq, void *data)
 167{
 168        unsigned long events = RTC_IRQF;
 169        struct lpc24xx_rtc *rtc = data;
 170        u32 rtc_iir;
 171
 172        /* Check interrupt cause */
 173        rtc_iir = rtc_readl(rtc, LPC24XX_ILR);
 174        if (rtc_iir & LPC24XX_RTCALF) {
 175                events |= RTC_AF;
 176                rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
 177        }
 178
 179        /* Clear interrupt status and report event */
 180        rtc_writel(rtc, LPC24XX_ILR, rtc_iir);
 181        rtc_update_irq(rtc->rtc, 1, events);
 182
 183        return IRQ_HANDLED;
 184}
 185
 186static const struct rtc_class_ops lpc24xx_rtc_ops = {
 187        .read_time              = lpc24xx_rtc_read_time,
 188        .set_time               = lpc24xx_rtc_set_time,
 189        .read_alarm             = lpc24xx_rtc_read_alarm,
 190        .set_alarm              = lpc24xx_rtc_set_alarm,
 191        .alarm_irq_enable       = lpc24xx_rtc_alarm_irq_enable,
 192};
 193
 194static int lpc24xx_rtc_probe(struct platform_device *pdev)
 195{
 196        struct lpc24xx_rtc *rtc;
 197        int irq, ret;
 198
 199        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
 200        if (!rtc)
 201                return -ENOMEM;
 202
 203        rtc->rtc_base = devm_platform_ioremap_resource(pdev, 0);
 204        if (IS_ERR(rtc->rtc_base))
 205                return PTR_ERR(rtc->rtc_base);
 206
 207        irq = platform_get_irq(pdev, 0);
 208        if (irq < 0)
 209                return irq;
 210
 211        rtc->clk_rtc = devm_clk_get(&pdev->dev, "rtc");
 212        if (IS_ERR(rtc->clk_rtc)) {
 213                dev_err(&pdev->dev, "error getting rtc clock\n");
 214                return PTR_ERR(rtc->clk_rtc);
 215        }
 216
 217        rtc->clk_reg = devm_clk_get(&pdev->dev, "reg");
 218        if (IS_ERR(rtc->clk_reg)) {
 219                dev_err(&pdev->dev, "error getting reg clock\n");
 220                return PTR_ERR(rtc->clk_reg);
 221        }
 222
 223        ret = clk_prepare_enable(rtc->clk_rtc);
 224        if (ret) {
 225                dev_err(&pdev->dev, "unable to enable rtc clock\n");
 226                return ret;
 227        }
 228
 229        ret = clk_prepare_enable(rtc->clk_reg);
 230        if (ret) {
 231                dev_err(&pdev->dev, "unable to enable reg clock\n");
 232                goto disable_rtc_clk;
 233        }
 234
 235        platform_set_drvdata(pdev, rtc);
 236
 237        /* Clear any pending interrupts */
 238        rtc_writel(rtc, LPC24XX_ILR, LPC24XX_RTCCIF | LPC24XX_RTCALF);
 239
 240        /* Enable RTC count */
 241        rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN);
 242
 243        ret = devm_request_irq(&pdev->dev, irq, lpc24xx_rtc_interrupt, 0,
 244                               pdev->name, rtc);
 245        if (ret < 0) {
 246                dev_warn(&pdev->dev, "can't request interrupt\n");
 247                goto disable_clks;
 248        }
 249
 250        rtc->rtc = devm_rtc_device_register(&pdev->dev, "lpc24xx-rtc",
 251                                            &lpc24xx_rtc_ops, THIS_MODULE);
 252        if (IS_ERR(rtc->rtc)) {
 253                dev_err(&pdev->dev, "can't register rtc device\n");
 254                ret = PTR_ERR(rtc->rtc);
 255                goto disable_clks;
 256        }
 257
 258        return 0;
 259
 260disable_clks:
 261        clk_disable_unprepare(rtc->clk_reg);
 262disable_rtc_clk:
 263        clk_disable_unprepare(rtc->clk_rtc);
 264        return ret;
 265}
 266
 267static int lpc24xx_rtc_remove(struct platform_device *pdev)
 268{
 269        struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev);
 270
 271        /* Ensure all interrupt sources are masked */
 272        rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE);
 273        rtc_writel(rtc, LPC24XX_CIIR, 0);
 274
 275        rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN);
 276
 277        clk_disable_unprepare(rtc->clk_rtc);
 278        clk_disable_unprepare(rtc->clk_reg);
 279
 280        return 0;
 281}
 282
 283static const struct of_device_id lpc24xx_rtc_match[] = {
 284        { .compatible = "nxp,lpc1788-rtc" },
 285        { }
 286};
 287MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match);
 288
 289static struct platform_driver lpc24xx_rtc_driver = {
 290        .probe  = lpc24xx_rtc_probe,
 291        .remove = lpc24xx_rtc_remove,
 292        .driver = {
 293                .name = "lpc24xx-rtc",
 294                .of_match_table = lpc24xx_rtc_match,
 295        },
 296};
 297module_platform_driver(lpc24xx_rtc_driver);
 298
 299MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com>");
 300MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs");
 301MODULE_LICENSE("GPL");
 302