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