linux/drivers/rtc/rtc-pl031.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * drivers/rtc/rtc-pl031.c
   4 *
   5 * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
   6 *
   7 * Author: Deepak Saxena <dsaxena@plexity.net>
   8 *
   9 * Copyright 2006 (c) MontaVista Software, Inc.
  10 *
  11 * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
  12 * Copyright 2010 (c) ST-Ericsson AB
  13 */
  14#include <linux/module.h>
  15#include <linux/rtc.h>
  16#include <linux/init.h>
  17#include <linux/interrupt.h>
  18#include <linux/amba/bus.h>
  19#include <linux/io.h>
  20#include <linux/bcd.h>
  21#include <linux/delay.h>
  22#include <linux/pm_wakeirq.h>
  23#include <linux/slab.h>
  24
  25/*
  26 * Register definitions
  27 */
  28#define RTC_DR          0x00    /* Data read register */
  29#define RTC_MR          0x04    /* Match register */
  30#define RTC_LR          0x08    /* Data load register */
  31#define RTC_CR          0x0c    /* Control register */
  32#define RTC_IMSC        0x10    /* Interrupt mask and set register */
  33#define RTC_RIS         0x14    /* Raw interrupt status register */
  34#define RTC_MIS         0x18    /* Masked interrupt status register */
  35#define RTC_ICR         0x1c    /* Interrupt clear register */
  36/* ST variants have additional timer functionality */
  37#define RTC_TDR         0x20    /* Timer data read register */
  38#define RTC_TLR         0x24    /* Timer data load register */
  39#define RTC_TCR         0x28    /* Timer control register */
  40#define RTC_YDR         0x30    /* Year data read register */
  41#define RTC_YMR         0x34    /* Year match register */
  42#define RTC_YLR         0x38    /* Year data load register */
  43
  44#define RTC_CR_EN       (1 << 0)        /* counter enable bit */
  45#define RTC_CR_CWEN     (1 << 26)       /* Clockwatch enable bit */
  46
  47#define RTC_TCR_EN      (1 << 1) /* Periodic timer enable bit */
  48
  49/* Common bit definitions for Interrupt status and control registers */
  50#define RTC_BIT_AI      (1 << 0) /* Alarm interrupt bit */
  51#define RTC_BIT_PI      (1 << 1) /* Periodic interrupt bit. ST variants only. */
  52
  53/* Common bit definations for ST v2 for reading/writing time */
  54#define RTC_SEC_SHIFT 0
  55#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
  56#define RTC_MIN_SHIFT 6
  57#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
  58#define RTC_HOUR_SHIFT 12
  59#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
  60#define RTC_WDAY_SHIFT 17
  61#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
  62#define RTC_MDAY_SHIFT 20
  63#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
  64#define RTC_MON_SHIFT 25
  65#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
  66
  67#define RTC_TIMER_FREQ 32768
  68
  69/**
  70 * struct pl031_vendor_data - per-vendor variations
  71 * @ops: the vendor-specific operations used on this silicon version
  72 * @clockwatch: if this is an ST Microelectronics silicon version with a
  73 *      clockwatch function
  74 * @st_weekday: if this is an ST Microelectronics silicon version that need
  75 *      the weekday fix
  76 * @irqflags: special IRQ flags per variant
  77 */
  78struct pl031_vendor_data {
  79        struct rtc_class_ops ops;
  80        bool clockwatch;
  81        bool st_weekday;
  82        unsigned long irqflags;
  83};
  84
  85struct pl031_local {
  86        struct pl031_vendor_data *vendor;
  87        struct rtc_device *rtc;
  88        void __iomem *base;
  89};
  90
  91static int pl031_alarm_irq_enable(struct device *dev,
  92        unsigned int enabled)
  93{
  94        struct pl031_local *ldata = dev_get_drvdata(dev);
  95        unsigned long imsc;
  96
  97        /* Clear any pending alarm interrupts. */
  98        writel(RTC_BIT_AI, ldata->base + RTC_ICR);
  99
 100        imsc = readl(ldata->base + RTC_IMSC);
 101
 102        if (enabled == 1)
 103                writel(imsc | RTC_BIT_AI, ldata->base + RTC_IMSC);
 104        else
 105                writel(imsc & ~RTC_BIT_AI, ldata->base + RTC_IMSC);
 106
 107        return 0;
 108}
 109
 110/*
 111 * Convert Gregorian date to ST v2 RTC format.
 112 */
 113static int pl031_stv2_tm_to_time(struct device *dev,
 114                                 struct rtc_time *tm, unsigned long *st_time,
 115        unsigned long *bcd_year)
 116{
 117        int year = tm->tm_year + 1900;
 118        int wday = tm->tm_wday;
 119
 120        /* wday masking is not working in hardware so wday must be valid */
 121        if (wday < -1 || wday > 6) {
 122                dev_err(dev, "invalid wday value %d\n", tm->tm_wday);
 123                return -EINVAL;
 124        } else if (wday == -1) {
 125                /* wday is not provided, calculate it here */
 126                unsigned long time;
 127                struct rtc_time calc_tm;
 128
 129                rtc_tm_to_time(tm, &time);
 130                rtc_time_to_tm(time, &calc_tm);
 131                wday = calc_tm.tm_wday;
 132        }
 133
 134        *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
 135
 136        *st_time = ((tm->tm_mon + 1) << RTC_MON_SHIFT)
 137                        |       (tm->tm_mday << RTC_MDAY_SHIFT)
 138                        |       ((wday + 1) << RTC_WDAY_SHIFT)
 139                        |       (tm->tm_hour << RTC_HOUR_SHIFT)
 140                        |       (tm->tm_min << RTC_MIN_SHIFT)
 141                        |       (tm->tm_sec << RTC_SEC_SHIFT);
 142
 143        return 0;
 144}
 145
 146/*
 147 * Convert ST v2 RTC format to Gregorian date.
 148 */
 149static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
 150        struct rtc_time *tm)
 151{
 152        tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
 153        tm->tm_mon  = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT) - 1;
 154        tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
 155        tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
 156        tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
 157        tm->tm_min  = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
 158        tm->tm_sec  = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
 159
 160        tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
 161        tm->tm_year -= 1900;
 162
 163        return 0;
 164}
 165
 166static int pl031_stv2_read_time(struct device *dev, struct rtc_time *tm)
 167{
 168        struct pl031_local *ldata = dev_get_drvdata(dev);
 169
 170        pl031_stv2_time_to_tm(readl(ldata->base + RTC_DR),
 171                        readl(ldata->base + RTC_YDR), tm);
 172
 173        return 0;
 174}
 175
 176static int pl031_stv2_set_time(struct device *dev, struct rtc_time *tm)
 177{
 178        unsigned long time;
 179        unsigned long bcd_year;
 180        struct pl031_local *ldata = dev_get_drvdata(dev);
 181        int ret;
 182
 183        ret = pl031_stv2_tm_to_time(dev, tm, &time, &bcd_year);
 184        if (ret == 0) {
 185                writel(bcd_year, ldata->base + RTC_YLR);
 186                writel(time, ldata->base + RTC_LR);
 187        }
 188
 189        return ret;
 190}
 191
 192static int pl031_stv2_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 193{
 194        struct pl031_local *ldata = dev_get_drvdata(dev);
 195        int ret;
 196
 197        ret = pl031_stv2_time_to_tm(readl(ldata->base + RTC_MR),
 198                        readl(ldata->base + RTC_YMR), &alarm->time);
 199
 200        alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
 201        alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
 202
 203        return ret;
 204}
 205
 206static int pl031_stv2_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 207{
 208        struct pl031_local *ldata = dev_get_drvdata(dev);
 209        unsigned long time;
 210        unsigned long bcd_year;
 211        int ret;
 212
 213        /* At the moment, we can only deal with non-wildcarded alarm times. */
 214        ret = rtc_valid_tm(&alarm->time);
 215        if (ret == 0) {
 216                ret = pl031_stv2_tm_to_time(dev, &alarm->time,
 217                                            &time, &bcd_year);
 218                if (ret == 0) {
 219                        writel(bcd_year, ldata->base + RTC_YMR);
 220                        writel(time, ldata->base + RTC_MR);
 221
 222                        pl031_alarm_irq_enable(dev, alarm->enabled);
 223                }
 224        }
 225
 226        return ret;
 227}
 228
 229static irqreturn_t pl031_interrupt(int irq, void *dev_id)
 230{
 231        struct pl031_local *ldata = dev_id;
 232        unsigned long rtcmis;
 233        unsigned long events = 0;
 234
 235        rtcmis = readl(ldata->base + RTC_MIS);
 236        if (rtcmis & RTC_BIT_AI) {
 237                writel(RTC_BIT_AI, ldata->base + RTC_ICR);
 238                events |= (RTC_AF | RTC_IRQF);
 239                rtc_update_irq(ldata->rtc, 1, events);
 240
 241                return IRQ_HANDLED;
 242        }
 243
 244        return IRQ_NONE;
 245}
 246
 247static int pl031_read_time(struct device *dev, struct rtc_time *tm)
 248{
 249        struct pl031_local *ldata = dev_get_drvdata(dev);
 250
 251        rtc_time_to_tm(readl(ldata->base + RTC_DR), tm);
 252
 253        return 0;
 254}
 255
 256static int pl031_set_time(struct device *dev, struct rtc_time *tm)
 257{
 258        unsigned long time;
 259        struct pl031_local *ldata = dev_get_drvdata(dev);
 260        int ret;
 261
 262        ret = rtc_tm_to_time(tm, &time);
 263
 264        if (ret == 0)
 265                writel(time, ldata->base + RTC_LR);
 266
 267        return ret;
 268}
 269
 270static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 271{
 272        struct pl031_local *ldata = dev_get_drvdata(dev);
 273
 274        rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time);
 275
 276        alarm->pending = readl(ldata->base + RTC_RIS) & RTC_BIT_AI;
 277        alarm->enabled = readl(ldata->base + RTC_IMSC) & RTC_BIT_AI;
 278
 279        return 0;
 280}
 281
 282static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
 283{
 284        struct pl031_local *ldata = dev_get_drvdata(dev);
 285        unsigned long time;
 286        int ret;
 287
 288        /* At the moment, we can only deal with non-wildcarded alarm times. */
 289        ret = rtc_valid_tm(&alarm->time);
 290        if (ret == 0) {
 291                ret = rtc_tm_to_time(&alarm->time, &time);
 292                if (ret == 0) {
 293                        writel(time, ldata->base + RTC_MR);
 294                        pl031_alarm_irq_enable(dev, alarm->enabled);
 295                }
 296        }
 297
 298        return ret;
 299}
 300
 301static int pl031_remove(struct amba_device *adev)
 302{
 303        struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
 304
 305        dev_pm_clear_wake_irq(&adev->dev);
 306        device_init_wakeup(&adev->dev, false);
 307        if (adev->irq[0])
 308                free_irq(adev->irq[0], ldata);
 309        amba_release_regions(adev);
 310
 311        return 0;
 312}
 313
 314static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 315{
 316        int ret;
 317        struct pl031_local *ldata;
 318        struct pl031_vendor_data *vendor = id->data;
 319        struct rtc_class_ops *ops;
 320        unsigned long time, data;
 321
 322        ret = amba_request_regions(adev, NULL);
 323        if (ret)
 324                goto err_req;
 325
 326        ldata = devm_kzalloc(&adev->dev, sizeof(struct pl031_local),
 327                             GFP_KERNEL);
 328        ops = devm_kmemdup(&adev->dev, &vendor->ops, sizeof(vendor->ops),
 329                           GFP_KERNEL);
 330        if (!ldata || !ops) {
 331                ret = -ENOMEM;
 332                goto out;
 333        }
 334
 335        ldata->vendor = vendor;
 336        ldata->base = devm_ioremap(&adev->dev, adev->res.start,
 337                                   resource_size(&adev->res));
 338        if (!ldata->base) {
 339                ret = -ENOMEM;
 340                goto out;
 341        }
 342
 343        amba_set_drvdata(adev, ldata);
 344
 345        dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev));
 346        dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));
 347
 348        data = readl(ldata->base + RTC_CR);
 349        /* Enable the clockwatch on ST Variants */
 350        if (vendor->clockwatch)
 351                data |= RTC_CR_CWEN;
 352        else
 353                data |= RTC_CR_EN;
 354        writel(data, ldata->base + RTC_CR);
 355
 356        /*
 357         * On ST PL031 variants, the RTC reset value does not provide correct
 358         * weekday for 2000-01-01. Correct the erroneous sunday to saturday.
 359         */
 360        if (vendor->st_weekday) {
 361                if (readl(ldata->base + RTC_YDR) == 0x2000) {
 362                        time = readl(ldata->base + RTC_DR);
 363                        if ((time &
 364                             (RTC_MON_MASK | RTC_MDAY_MASK | RTC_WDAY_MASK))
 365                            == 0x02120000) {
 366                                time = time | (0x7 << RTC_WDAY_SHIFT);
 367                                writel(0x2000, ldata->base + RTC_YLR);
 368                                writel(time, ldata->base + RTC_LR);
 369                        }
 370                }
 371        }
 372
 373        if (!adev->irq[0]) {
 374                /* When there's no interrupt, no point in exposing the alarm */
 375                ops->read_alarm = NULL;
 376                ops->set_alarm = NULL;
 377                ops->alarm_irq_enable = NULL;
 378        }
 379
 380        device_init_wakeup(&adev->dev, true);
 381        ldata->rtc = devm_rtc_allocate_device(&adev->dev);
 382        if (IS_ERR(ldata->rtc))
 383                return PTR_ERR(ldata->rtc);
 384
 385        ldata->rtc->ops = ops;
 386
 387        ret = rtc_register_device(ldata->rtc);
 388        if (ret)
 389                goto out;
 390
 391        if (adev->irq[0]) {
 392                ret = request_irq(adev->irq[0], pl031_interrupt,
 393                                  vendor->irqflags, "rtc-pl031", ldata);
 394                if (ret)
 395                        goto out;
 396                dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
 397        }
 398        return 0;
 399
 400out:
 401        amba_release_regions(adev);
 402err_req:
 403
 404        return ret;
 405}
 406
 407/* Operations for the original ARM version */
 408static struct pl031_vendor_data arm_pl031 = {
 409        .ops = {
 410                .read_time = pl031_read_time,
 411                .set_time = pl031_set_time,
 412                .read_alarm = pl031_read_alarm,
 413                .set_alarm = pl031_set_alarm,
 414                .alarm_irq_enable = pl031_alarm_irq_enable,
 415        },
 416};
 417
 418/* The First ST derivative */
 419static struct pl031_vendor_data stv1_pl031 = {
 420        .ops = {
 421                .read_time = pl031_read_time,
 422                .set_time = pl031_set_time,
 423                .read_alarm = pl031_read_alarm,
 424                .set_alarm = pl031_set_alarm,
 425                .alarm_irq_enable = pl031_alarm_irq_enable,
 426        },
 427        .clockwatch = true,
 428        .st_weekday = true,
 429};
 430
 431/* And the second ST derivative */
 432static struct pl031_vendor_data stv2_pl031 = {
 433        .ops = {
 434                .read_time = pl031_stv2_read_time,
 435                .set_time = pl031_stv2_set_time,
 436                .read_alarm = pl031_stv2_read_alarm,
 437                .set_alarm = pl031_stv2_set_alarm,
 438                .alarm_irq_enable = pl031_alarm_irq_enable,
 439        },
 440        .clockwatch = true,
 441        .st_weekday = true,
 442        /*
 443         * This variant shares the IRQ with another block and must not
 444         * suspend that IRQ line.
 445         * TODO check if it shares with IRQF_NO_SUSPEND user, else we can
 446         * remove IRQF_COND_SUSPEND
 447         */
 448        .irqflags = IRQF_SHARED | IRQF_COND_SUSPEND,
 449};
 450
 451static const struct amba_id pl031_ids[] = {
 452        {
 453                .id = 0x00041031,
 454                .mask = 0x000fffff,
 455                .data = &arm_pl031,
 456        },
 457        /* ST Micro variants */
 458        {
 459                .id = 0x00180031,
 460                .mask = 0x00ffffff,
 461                .data = &stv1_pl031,
 462        },
 463        {
 464                .id = 0x00280031,
 465                .mask = 0x00ffffff,
 466                .data = &stv2_pl031,
 467        },
 468        {0, 0},
 469};
 470
 471MODULE_DEVICE_TABLE(amba, pl031_ids);
 472
 473static struct amba_driver pl031_driver = {
 474        .drv = {
 475                .name = "rtc-pl031",
 476        },
 477        .id_table = pl031_ids,
 478        .probe = pl031_probe,
 479        .remove = pl031_remove,
 480};
 481
 482module_amba_driver(pl031_driver);
 483
 484MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
 485MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
 486MODULE_LICENSE("GPL");
 487