linux/drivers/rtc/rtc-cadence.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Copyright 2019 Cadence
   5 *
   6 * Authors:
   7 *  Jan Kotas <jank@cadence.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/platform_device.h>
  12#include <linux/of.h>
  13#include <linux/io.h>
  14#include <linux/rtc.h>
  15#include <linux/clk.h>
  16#include <linux/bcd.h>
  17#include <linux/bitfield.h>
  18#include <linux/interrupt.h>
  19#include <linux/pm_wakeirq.h>
  20
  21/* Registers */
  22#define CDNS_RTC_CTLR           0x00
  23#define CDNS_RTC_HMR            0x04
  24#define CDNS_RTC_TIMR           0x08
  25#define CDNS_RTC_CALR           0x0C
  26#define CDNS_RTC_TIMAR          0x10
  27#define CDNS_RTC_CALAR          0x14
  28#define CDNS_RTC_AENR           0x18
  29#define CDNS_RTC_EFLR           0x1C
  30#define CDNS_RTC_IENR           0x20
  31#define CDNS_RTC_IDISR          0x24
  32#define CDNS_RTC_IMSKR          0x28
  33#define CDNS_RTC_STSR           0x2C
  34#define CDNS_RTC_KRTCR          0x30
  35
  36/* Control */
  37#define CDNS_RTC_CTLR_TIME      BIT(0)
  38#define CDNS_RTC_CTLR_CAL       BIT(1)
  39#define CDNS_RTC_CTLR_TIME_CAL  (CDNS_RTC_CTLR_TIME | CDNS_RTC_CTLR_CAL)
  40
  41/* Status */
  42#define CDNS_RTC_STSR_VT        BIT(0)
  43#define CDNS_RTC_STSR_VC        BIT(1)
  44#define CDNS_RTC_STSR_VTA       BIT(2)
  45#define CDNS_RTC_STSR_VCA       BIT(3)
  46#define CDNS_RTC_STSR_VT_VC     (CDNS_RTC_STSR_VT | CDNS_RTC_STSR_VC)
  47#define CDNS_RTC_STSR_VTA_VCA   (CDNS_RTC_STSR_VTA | CDNS_RTC_STSR_VCA)
  48
  49/* Keep RTC */
  50#define CDNS_RTC_KRTCR_KRTC     BIT(0)
  51
  52/* Alarm, Event, Interrupt */
  53#define CDNS_RTC_AEI_HOS        BIT(0)
  54#define CDNS_RTC_AEI_SEC        BIT(1)
  55#define CDNS_RTC_AEI_MIN        BIT(2)
  56#define CDNS_RTC_AEI_HOUR       BIT(3)
  57#define CDNS_RTC_AEI_DATE       BIT(4)
  58#define CDNS_RTC_AEI_MNTH       BIT(5)
  59#define CDNS_RTC_AEI_ALRM       BIT(6)
  60
  61/* Time */
  62#define CDNS_RTC_TIME_H         GENMASK(7, 0)
  63#define CDNS_RTC_TIME_S         GENMASK(14, 8)
  64#define CDNS_RTC_TIME_M         GENMASK(22, 16)
  65#define CDNS_RTC_TIME_HR        GENMASK(29, 24)
  66#define CDNS_RTC_TIME_PM        BIT(30)
  67#define CDNS_RTC_TIME_CH        BIT(31)
  68
  69/* Calendar */
  70#define CDNS_RTC_CAL_DAY        GENMASK(2, 0)
  71#define CDNS_RTC_CAL_M          GENMASK(7, 3)
  72#define CDNS_RTC_CAL_D          GENMASK(13, 8)
  73#define CDNS_RTC_CAL_Y          GENMASK(23, 16)
  74#define CDNS_RTC_CAL_C          GENMASK(29, 24)
  75#define CDNS_RTC_CAL_CH         BIT(31)
  76
  77#define CDNS_RTC_MAX_REGS_TRIES 3
  78
  79struct cdns_rtc {
  80        struct rtc_device *rtc_dev;
  81        struct clk *pclk;
  82        struct clk *ref_clk;
  83        void __iomem *regs;
  84        int irq;
  85};
  86
  87static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)
  88{
  89        u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;
  90
  91        writel(reg, crtc->regs + CDNS_RTC_CTLR);
  92}
  93
  94static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)
  95{
  96        return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);
  97}
  98
  99static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)
 100{
 101        struct device *dev = id;
 102        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 103
 104        /* Reading the register clears it */
 105        if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))
 106                return IRQ_NONE;
 107
 108        rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
 109        return IRQ_HANDLED;
 110}
 111
 112static u32 cdns_rtc_time2reg(struct rtc_time *tm)
 113{
 114        return FIELD_PREP(CDNS_RTC_TIME_S,  bin2bcd(tm->tm_sec))
 115             | FIELD_PREP(CDNS_RTC_TIME_M,  bin2bcd(tm->tm_min))
 116             | FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));
 117}
 118
 119static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)
 120{
 121        tm->tm_sec  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));
 122        tm->tm_min  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));
 123        tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));
 124}
 125
 126static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)
 127{
 128        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 129        u32 reg;
 130
 131        /* If the RTC is disabled, assume the values are invalid */
 132        if (!cdns_rtc_get_enabled(crtc))
 133                return -EINVAL;
 134
 135        cdns_rtc_set_enabled(crtc, false);
 136
 137        reg = readl(crtc->regs + CDNS_RTC_TIMR);
 138        cdns_rtc_reg2time(reg, tm);
 139
 140        reg = readl(crtc->regs + CDNS_RTC_CALR);
 141        tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
 142        tm->tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
 143        tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))
 144                    + bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;
 145        tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;
 146
 147        cdns_rtc_set_enabled(crtc, true);
 148        return 0;
 149}
 150
 151static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)
 152{
 153        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 154        u32 timr, calr, stsr;
 155        int ret = -EIO;
 156        int year = tm->tm_year + 1900;
 157        int tries;
 158
 159        cdns_rtc_set_enabled(crtc, false);
 160
 161        timr = cdns_rtc_time2reg(tm);
 162
 163        calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))
 164             | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))
 165             | FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))
 166             | FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))
 167             | FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);
 168
 169        /* Update registers, check valid flags */
 170        for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
 171                writel(timr, crtc->regs + CDNS_RTC_TIMR);
 172                writel(calr, crtc->regs + CDNS_RTC_CALR);
 173                stsr = readl(crtc->regs + CDNS_RTC_STSR);
 174
 175                if ((stsr & CDNS_RTC_STSR_VT_VC) == CDNS_RTC_STSR_VT_VC) {
 176                        ret = 0;
 177                        break;
 178                }
 179        }
 180
 181        cdns_rtc_set_enabled(crtc, true);
 182        return ret;
 183}
 184
 185static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 186{
 187        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 188
 189        if (enabled) {
 190                writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR
 191                        | CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_MNTH),
 192                       crtc->regs + CDNS_RTC_AENR);
 193                writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);
 194        } else {
 195                writel(0, crtc->regs + CDNS_RTC_AENR);
 196                writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);
 197        }
 198
 199        return 0;
 200}
 201
 202static int cdns_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 203{
 204        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 205        u32 reg;
 206
 207        reg = readl(crtc->regs + CDNS_RTC_TIMAR);
 208        cdns_rtc_reg2time(reg, &alarm->time);
 209
 210        reg = readl(crtc->regs + CDNS_RTC_CALAR);
 211        alarm->time.tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
 212        alarm->time.tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
 213
 214        return 0;
 215}
 216
 217static int cdns_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 218{
 219        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 220        int ret = -EIO;
 221        int tries;
 222        u32 timar, calar, stsr;
 223
 224        cdns_rtc_alarm_irq_enable(dev, 0);
 225
 226        timar = cdns_rtc_time2reg(&alarm->time);
 227        calar = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(alarm->time.tm_mday))
 228              | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(alarm->time.tm_mon + 1));
 229
 230        /* Update registers, check valid alarm flags */
 231        for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
 232                writel(timar, crtc->regs + CDNS_RTC_TIMAR);
 233                writel(calar, crtc->regs + CDNS_RTC_CALAR);
 234                stsr = readl(crtc->regs + CDNS_RTC_STSR);
 235
 236                if ((stsr & CDNS_RTC_STSR_VTA_VCA) == CDNS_RTC_STSR_VTA_VCA) {
 237                        ret = 0;
 238                        break;
 239                }
 240        }
 241
 242        if (!ret)
 243                cdns_rtc_alarm_irq_enable(dev, alarm->enabled);
 244        return ret;
 245}
 246
 247static const struct rtc_class_ops cdns_rtc_ops = {
 248        .read_time      = cdns_rtc_read_time,
 249        .set_time       = cdns_rtc_set_time,
 250        .read_alarm     = cdns_rtc_read_alarm,
 251        .set_alarm      = cdns_rtc_set_alarm,
 252        .alarm_irq_enable = cdns_rtc_alarm_irq_enable,
 253};
 254
 255static int cdns_rtc_probe(struct platform_device *pdev)
 256{
 257        struct cdns_rtc *crtc;
 258        int ret;
 259        unsigned long ref_clk_freq;
 260
 261        crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);
 262        if (!crtc)
 263                return -ENOMEM;
 264
 265        crtc->regs = devm_platform_ioremap_resource(pdev, 0);
 266        if (IS_ERR(crtc->regs))
 267                return PTR_ERR(crtc->regs);
 268
 269        crtc->irq = platform_get_irq(pdev, 0);
 270        if (crtc->irq < 0)
 271                return -EINVAL;
 272
 273        crtc->pclk = devm_clk_get(&pdev->dev, "pclk");
 274        if (IS_ERR(crtc->pclk)) {
 275                ret = PTR_ERR(crtc->pclk);
 276                dev_err(&pdev->dev,
 277                        "Failed to retrieve the peripheral clock, %d\n", ret);
 278                return ret;
 279        }
 280
 281        crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
 282        if (IS_ERR(crtc->ref_clk)) {
 283                ret = PTR_ERR(crtc->ref_clk);
 284                dev_err(&pdev->dev,
 285                        "Failed to retrieve the reference clock, %d\n", ret);
 286                return ret;
 287        }
 288
 289        crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
 290        if (IS_ERR(crtc->rtc_dev))
 291                return PTR_ERR(crtc->rtc_dev);
 292
 293        platform_set_drvdata(pdev, crtc);
 294
 295        ret = clk_prepare_enable(crtc->pclk);
 296        if (ret) {
 297                dev_err(&pdev->dev,
 298                        "Failed to enable the peripheral clock, %d\n", ret);
 299                return ret;
 300        }
 301
 302        ret = clk_prepare_enable(crtc->ref_clk);
 303        if (ret) {
 304                dev_err(&pdev->dev,
 305                        "Failed to enable the reference clock, %d\n", ret);
 306                goto err_disable_pclk;
 307        }
 308
 309        ref_clk_freq = clk_get_rate(crtc->ref_clk);
 310        if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {
 311                dev_err(&pdev->dev,
 312                        "Invalid reference clock frequency %lu Hz.\n",
 313                        ref_clk_freq);
 314                ret = -EINVAL;
 315                goto err_disable_ref_clk;
 316        }
 317
 318        ret = devm_request_irq(&pdev->dev, crtc->irq,
 319                               cdns_rtc_irq_handler, 0,
 320                               dev_name(&pdev->dev), &pdev->dev);
 321        if (ret) {
 322                dev_err(&pdev->dev,
 323                        "Failed to request interrupt for the device, %d\n",
 324                        ret);
 325                goto err_disable_ref_clk;
 326        }
 327
 328        /* The RTC supports 01.01.1900 - 31.12.2999 */
 329        crtc->rtc_dev->range_min = mktime64(1900,  1,  1,  0,  0,  0);
 330        crtc->rtc_dev->range_max = mktime64(2999, 12, 31, 23, 59, 59);
 331
 332        crtc->rtc_dev->ops = &cdns_rtc_ops;
 333        device_init_wakeup(&pdev->dev, true);
 334
 335        /* Always use 24-hour mode and keep the RTC values */
 336        writel(0, crtc->regs + CDNS_RTC_HMR);
 337        writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);
 338
 339        ret = rtc_register_device(crtc->rtc_dev);
 340        if (ret)
 341                goto err_disable_wakeup;
 342
 343        return 0;
 344
 345err_disable_wakeup:
 346        device_init_wakeup(&pdev->dev, false);
 347
 348err_disable_ref_clk:
 349        clk_disable_unprepare(crtc->ref_clk);
 350
 351err_disable_pclk:
 352        clk_disable_unprepare(crtc->pclk);
 353
 354        return ret;
 355}
 356
 357static int cdns_rtc_remove(struct platform_device *pdev)
 358{
 359        struct cdns_rtc *crtc = platform_get_drvdata(pdev);
 360
 361        cdns_rtc_alarm_irq_enable(&pdev->dev, 0);
 362        device_init_wakeup(&pdev->dev, 0);
 363
 364        clk_disable_unprepare(crtc->pclk);
 365        clk_disable_unprepare(crtc->ref_clk);
 366
 367        return 0;
 368}
 369
 370#ifdef CONFIG_PM_SLEEP
 371static int cdns_rtc_suspend(struct device *dev)
 372{
 373        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 374
 375        if (device_may_wakeup(dev))
 376                enable_irq_wake(crtc->irq);
 377
 378        return 0;
 379}
 380
 381static int cdns_rtc_resume(struct device *dev)
 382{
 383        struct cdns_rtc *crtc = dev_get_drvdata(dev);
 384
 385        if (device_may_wakeup(dev))
 386                disable_irq_wake(crtc->irq);
 387
 388        return 0;
 389}
 390#endif
 391
 392static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);
 393
 394static const struct of_device_id cdns_rtc_of_match[] = {
 395        { .compatible = "cdns,rtc-r109v3" },
 396        { },
 397};
 398MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);
 399
 400static struct platform_driver cdns_rtc_driver = {
 401        .driver = {
 402                .name = "cdns-rtc",
 403                .of_match_table = cdns_rtc_of_match,
 404                .pm = &cdns_rtc_pm_ops,
 405        },
 406        .probe = cdns_rtc_probe,
 407        .remove = cdns_rtc_remove,
 408};
 409module_platform_driver(cdns_rtc_driver);
 410
 411MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
 412MODULE_DESCRIPTION("Cadence RTC driver");
 413MODULE_LICENSE("GPL v2");
 414MODULE_ALIAS("platform:cdns-rtc");
 415