linux/drivers/rtc/rtc-vt8500.c
<<
>>
Prefs
   1/*
   2 * drivers/rtc/rtc-vt8500.c
   3 *
   4 *  Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
   5 *
   6 * Based on rtc-pxa.c
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/rtc.h>
  20#include <linux/init.h>
  21#include <linux/interrupt.h>
  22#include <linux/io.h>
  23#include <linux/bcd.h>
  24#include <linux/platform_device.h>
  25#include <linux/slab.h>
  26
  27/*
  28 * Register definitions
  29 */
  30#define VT8500_RTC_TS           0x00    /* Time set */
  31#define VT8500_RTC_DS           0x04    /* Date set */
  32#define VT8500_RTC_AS           0x08    /* Alarm set */
  33#define VT8500_RTC_CR           0x0c    /* Control */
  34#define VT8500_RTC_TR           0x10    /* Time read */
  35#define VT8500_RTC_DR           0x14    /* Date read */
  36#define VT8500_RTC_WS           0x18    /* Write status */
  37#define VT8500_RTC_CL           0x20    /* Calibration */
  38#define VT8500_RTC_IS           0x24    /* Interrupt status */
  39#define VT8500_RTC_ST           0x28    /* Status */
  40
  41#define INVALID_TIME_BIT        (1 << 31)
  42
  43#define DATE_CENTURY_S          19
  44#define DATE_YEAR_S             11
  45#define DATE_YEAR_MASK          (0xff << DATE_YEAR_S)
  46#define DATE_MONTH_S            6
  47#define DATE_MONTH_MASK         (0x1f << DATE_MONTH_S)
  48#define DATE_DAY_MASK           0x3f
  49
  50#define TIME_DOW_S              20
  51#define TIME_DOW_MASK           (0x07 << TIME_DOW_S)
  52#define TIME_HOUR_S             14
  53#define TIME_HOUR_MASK          (0x3f << TIME_HOUR_S)
  54#define TIME_MIN_S              7
  55#define TIME_MIN_MASK           (0x7f << TIME_MIN_S)
  56#define TIME_SEC_MASK           0x7f
  57
  58#define ALARM_DAY_S             20
  59#define ALARM_DAY_MASK          (0x3f << ALARM_DAY_S)
  60
  61#define ALARM_DAY_BIT           (1 << 29)
  62#define ALARM_HOUR_BIT          (1 << 28)
  63#define ALARM_MIN_BIT           (1 << 27)
  64#define ALARM_SEC_BIT           (1 << 26)
  65
  66#define ALARM_ENABLE_MASK       (ALARM_DAY_BIT \
  67                                | ALARM_HOUR_BIT \
  68                                | ALARM_MIN_BIT \
  69                                | ALARM_SEC_BIT)
  70
  71#define VT8500_RTC_CR_ENABLE    (1 << 0)        /* Enable RTC */
  72#define VT8500_RTC_CR_24H       (1 << 1)        /* 24h time format */
  73#define VT8500_RTC_CR_SM_ENABLE (1 << 2)        /* Enable periodic irqs */
  74#define VT8500_RTC_CR_SM_SEC    (1 << 3)        /* 0: 1Hz/60, 1: 1Hz */
  75#define VT8500_RTC_CR_CALIB     (1 << 4)        /* Enable calibration */
  76
  77#define VT8500_RTC_IS_ALARM     (1 << 0)        /* Alarm interrupt status */
  78
  79struct vt8500_rtc {
  80        void __iomem            *regbase;
  81        struct resource         *res;
  82        int                     irq_alarm;
  83        struct rtc_device       *rtc;
  84        spinlock_t              lock;           /* Protects this structure */
  85};
  86
  87static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id)
  88{
  89        struct vt8500_rtc *vt8500_rtc = dev_id;
  90        u32 isr;
  91        unsigned long events = 0;
  92
  93        spin_lock(&vt8500_rtc->lock);
  94
  95        /* clear interrupt sources */
  96        isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
  97        writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS);
  98
  99        spin_unlock(&vt8500_rtc->lock);
 100
 101        if (isr & VT8500_RTC_IS_ALARM)
 102                events |= RTC_AF | RTC_IRQF;
 103
 104        rtc_update_irq(vt8500_rtc->rtc, 1, events);
 105
 106        return IRQ_HANDLED;
 107}
 108
 109static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
 110{
 111        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 112        u32 date, time;
 113
 114        date = readl(vt8500_rtc->regbase + VT8500_RTC_DR);
 115        time = readl(vt8500_rtc->regbase + VT8500_RTC_TR);
 116
 117        tm->tm_sec = bcd2bin(time & TIME_SEC_MASK);
 118        tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S);
 119        tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S);
 120        tm->tm_mday = bcd2bin(date & DATE_DAY_MASK);
 121        tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S);
 122        tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S)
 123                        + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100);
 124        tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S;
 125
 126        return 0;
 127}
 128
 129static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
 130{
 131        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 132
 133        if (tm->tm_year < 100) {
 134                dev_warn(dev, "Only years 2000-2199 are supported by the "
 135                              "hardware!\n");
 136                return -EINVAL;
 137        }
 138
 139        writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
 140                | (bin2bcd(tm->tm_mon) << DATE_MONTH_S)
 141                | (bin2bcd(tm->tm_mday)),
 142                vt8500_rtc->regbase + VT8500_RTC_DS);
 143        writel((bin2bcd(tm->tm_wday) << TIME_DOW_S)
 144                | (bin2bcd(tm->tm_hour) << TIME_HOUR_S)
 145                | (bin2bcd(tm->tm_min) << TIME_MIN_S)
 146                | (bin2bcd(tm->tm_sec)),
 147                vt8500_rtc->regbase + VT8500_RTC_TS);
 148
 149        return 0;
 150}
 151
 152static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 153{
 154        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 155        u32 isr, alarm;
 156
 157        alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
 158        isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
 159
 160        alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S);
 161        alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S);
 162        alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S);
 163        alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK));
 164
 165        alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0;
 166        alrm->pending = (isr & VT8500_RTC_IS_ALARM) ? 1 : 0;
 167
 168        return rtc_valid_tm(&alrm->time);
 169}
 170
 171static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 172{
 173        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 174
 175        writel((alrm->enabled ? ALARM_ENABLE_MASK : 0)
 176                | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S)
 177                | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S)
 178                | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S)
 179                | (bin2bcd(alrm->time.tm_sec)),
 180                vt8500_rtc->regbase + VT8500_RTC_AS);
 181
 182        return 0;
 183}
 184
 185static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled)
 186{
 187        struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
 188        unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
 189
 190        if (enabled)
 191                tmp |= ALARM_ENABLE_MASK;
 192        else
 193                tmp &= ~ALARM_ENABLE_MASK;
 194
 195        writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS);
 196        return 0;
 197}
 198
 199static const struct rtc_class_ops vt8500_rtc_ops = {
 200        .read_time = vt8500_rtc_read_time,
 201        .set_time = vt8500_rtc_set_time,
 202        .read_alarm = vt8500_rtc_read_alarm,
 203        .set_alarm = vt8500_rtc_set_alarm,
 204        .alarm_irq_enable = vt8500_alarm_irq_enable,
 205};
 206
 207static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
 208{
 209        struct vt8500_rtc *vt8500_rtc;
 210        int ret;
 211
 212        vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL);
 213        if (!vt8500_rtc)
 214                return -ENOMEM;
 215
 216        spin_lock_init(&vt8500_rtc->lock);
 217        platform_set_drvdata(pdev, vt8500_rtc);
 218
 219        vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 220        if (!vt8500_rtc->res) {
 221                dev_err(&pdev->dev, "No I/O memory resource defined\n");
 222                ret = -ENXIO;
 223                goto err_free;
 224        }
 225
 226        vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
 227        if (vt8500_rtc->irq_alarm < 0) {
 228                dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
 229                ret = -ENXIO;
 230                goto err_free;
 231        }
 232
 233        vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
 234                                             resource_size(vt8500_rtc->res),
 235                                             "vt8500-rtc");
 236        if (vt8500_rtc->res == NULL) {
 237                dev_err(&pdev->dev, "failed to request I/O memory\n");
 238                ret = -EBUSY;
 239                goto err_free;
 240        }
 241
 242        vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
 243                                      resource_size(vt8500_rtc->res));
 244        if (!vt8500_rtc->regbase) {
 245                dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
 246                ret = -EBUSY;
 247                goto err_release;
 248        }
 249
 250        /* Enable RTC and set it to 24-hour mode */
 251        writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H,
 252               vt8500_rtc->regbase + VT8500_RTC_CR);
 253
 254        vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
 255                                              &vt8500_rtc_ops, THIS_MODULE);
 256        if (IS_ERR(vt8500_rtc->rtc)) {
 257                ret = PTR_ERR(vt8500_rtc->rtc);
 258                dev_err(&pdev->dev,
 259                        "Failed to register RTC device -> %d\n", ret);
 260                goto err_unmap;
 261        }
 262
 263        ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
 264                          "rtc alarm", vt8500_rtc);
 265        if (ret < 0) {
 266                dev_err(&pdev->dev, "can't get irq %i, err %d\n",
 267                        vt8500_rtc->irq_alarm, ret);
 268                goto err_unreg;
 269        }
 270
 271        return 0;
 272
 273err_unreg:
 274        rtc_device_unregister(vt8500_rtc->rtc);
 275err_unmap:
 276        iounmap(vt8500_rtc->regbase);
 277err_release:
 278        release_mem_region(vt8500_rtc->res->start,
 279                           resource_size(vt8500_rtc->res));
 280err_free:
 281        kfree(vt8500_rtc);
 282        return ret;
 283}
 284
 285static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
 286{
 287        struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
 288
 289        free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
 290
 291        rtc_device_unregister(vt8500_rtc->rtc);
 292
 293        /* Disable alarm matching */
 294        writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
 295        iounmap(vt8500_rtc->regbase);
 296        release_mem_region(vt8500_rtc->res->start,
 297                           resource_size(vt8500_rtc->res));
 298
 299        kfree(vt8500_rtc);
 300        platform_set_drvdata(pdev, NULL);
 301
 302        return 0;
 303}
 304
 305static struct platform_driver vt8500_rtc_driver = {
 306        .probe          = vt8500_rtc_probe,
 307        .remove         = __devexit_p(vt8500_rtc_remove),
 308        .driver         = {
 309                .name   = "vt8500-rtc",
 310                .owner  = THIS_MODULE,
 311        },
 312};
 313
 314module_platform_driver(vt8500_rtc_driver);
 315
 316MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
 317MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)");
 318MODULE_LICENSE("GPL");
 319MODULE_ALIAS("platform:vt8500-rtc");
 320
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.