linux/drivers/rtc/rtc-tx4939.c
<<
>>
Prefs
   1/*
   2 * TX4939 internal RTC driver
   3 * Based on RBTX49xx patch from CELF patch archive.
   4 *
   5 * This file is subject to the terms and conditions of the GNU General Public
   6 * License.  See the file "COPYING" in the main directory of this archive
   7 * for more details.
   8 *
   9 * (C) Copyright TOSHIBA CORPORATION 2005-2007
  10 */
  11#include <linux/rtc.h>
  12#include <linux/platform_device.h>
  13#include <linux/interrupt.h>
  14#include <linux/io.h>
  15#include <asm/txx9/tx4939.h>
  16
  17struct tx4939rtc_plat_data {
  18        struct rtc_device *rtc;
  19        struct tx4939_rtc_reg __iomem *rtcreg;
  20};
  21
  22static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev)
  23{
  24        return platform_get_drvdata(to_platform_device(dev));
  25}
  26
  27static int tx4939_rtc_cmd(struct tx4939_rtc_reg __iomem *rtcreg, int cmd)
  28{
  29        int i = 0;
  30
  31        __raw_writel(cmd, &rtcreg->ctl);
  32        /* This might take 30us (next 32.768KHz clock) */
  33        while (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_BUSY) {
  34                /* timeout on approx. 100us (@ GBUS200MHz) */
  35                if (i++ > 200 * 100)
  36                        return -EBUSY;
  37                cpu_relax();
  38        }
  39        return 0;
  40}
  41
  42static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs)
  43{
  44        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
  45        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
  46        int i, ret;
  47        unsigned char buf[6];
  48
  49        buf[0] = 0;
  50        buf[1] = 0;
  51        buf[2] = secs;
  52        buf[3] = secs >> 8;
  53        buf[4] = secs >> 16;
  54        buf[5] = secs >> 24;
  55        spin_lock_irq(&pdata->rtc->irq_lock);
  56        __raw_writel(0, &rtcreg->adr);
  57        for (i = 0; i < 6; i++)
  58                __raw_writel(buf[i], &rtcreg->dat);
  59        ret = tx4939_rtc_cmd(rtcreg,
  60                             TX4939_RTCCTL_COMMAND_SETTIME |
  61                             (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
  62        spin_unlock_irq(&pdata->rtc->irq_lock);
  63        return ret;
  64}
  65
  66static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm)
  67{
  68        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
  69        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
  70        int i, ret;
  71        unsigned long sec;
  72        unsigned char buf[6];
  73
  74        spin_lock_irq(&pdata->rtc->irq_lock);
  75        ret = tx4939_rtc_cmd(rtcreg,
  76                             TX4939_RTCCTL_COMMAND_GETTIME |
  77                             (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
  78        if (ret) {
  79                spin_unlock_irq(&pdata->rtc->irq_lock);
  80                return ret;
  81        }
  82        __raw_writel(2, &rtcreg->adr);
  83        for (i = 2; i < 6; i++)
  84                buf[i] = __raw_readl(&rtcreg->dat);
  85        spin_unlock_irq(&pdata->rtc->irq_lock);
  86        sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
  87        rtc_time_to_tm(sec, tm);
  88        return rtc_valid_tm(tm);
  89}
  90
  91static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  92{
  93        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
  94        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
  95        int i, ret;
  96        unsigned long sec;
  97        unsigned char buf[6];
  98
  99        if (alrm->time.tm_sec < 0 ||
 100            alrm->time.tm_min < 0 ||
 101            alrm->time.tm_hour < 0 ||
 102            alrm->time.tm_mday < 0 ||
 103            alrm->time.tm_mon < 0 ||
 104            alrm->time.tm_year < 0)
 105                return -EINVAL;
 106        rtc_tm_to_time(&alrm->time, &sec);
 107        buf[0] = 0;
 108        buf[1] = 0;
 109        buf[2] = sec;
 110        buf[3] = sec >> 8;
 111        buf[4] = sec >> 16;
 112        buf[5] = sec >> 24;
 113        spin_lock_irq(&pdata->rtc->irq_lock);
 114        __raw_writel(0, &rtcreg->adr);
 115        for (i = 0; i < 6; i++)
 116                __raw_writel(buf[i], &rtcreg->dat);
 117        ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM |
 118                             (alrm->enabled ? TX4939_RTCCTL_ALME : 0));
 119        spin_unlock_irq(&pdata->rtc->irq_lock);
 120        return ret;
 121}
 122
 123static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 124{
 125        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
 126        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
 127        int i, ret;
 128        unsigned long sec;
 129        unsigned char buf[6];
 130        u32 ctl;
 131
 132        spin_lock_irq(&pdata->rtc->irq_lock);
 133        ret = tx4939_rtc_cmd(rtcreg,
 134                             TX4939_RTCCTL_COMMAND_GETALARM |
 135                             (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));
 136        if (ret) {
 137                spin_unlock_irq(&pdata->rtc->irq_lock);
 138                return ret;
 139        }
 140        __raw_writel(2, &rtcreg->adr);
 141        for (i = 2; i < 6; i++)
 142                buf[i] = __raw_readl(&rtcreg->dat);
 143        ctl = __raw_readl(&rtcreg->ctl);
 144        alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0;
 145        alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0;
 146        spin_unlock_irq(&pdata->rtc->irq_lock);
 147        sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];
 148        rtc_time_to_tm(sec, &alrm->time);
 149        return rtc_valid_tm(&alrm->time);
 150}
 151
 152static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 153{
 154        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
 155
 156        spin_lock_irq(&pdata->rtc->irq_lock);
 157        tx4939_rtc_cmd(pdata->rtcreg,
 158                       TX4939_RTCCTL_COMMAND_NOP |
 159                       (enabled ? TX4939_RTCCTL_ALME : 0));
 160        spin_unlock_irq(&pdata->rtc->irq_lock);
 161        return 0;
 162}
 163
 164static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)
 165{
 166        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev_id);
 167        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
 168        unsigned long events = RTC_IRQF;
 169
 170        spin_lock(&pdata->rtc->irq_lock);
 171        if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) {
 172                events |= RTC_AF;
 173                tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);
 174        }
 175        spin_unlock(&pdata->rtc->irq_lock);
 176        rtc_update_irq(pdata->rtc, 1, events);
 177        return IRQ_HANDLED;
 178}
 179
 180static const struct rtc_class_ops tx4939_rtc_ops = {
 181        .read_time              = tx4939_rtc_read_time,
 182        .read_alarm             = tx4939_rtc_read_alarm,
 183        .set_alarm              = tx4939_rtc_set_alarm,
 184        .set_mmss               = tx4939_rtc_set_mmss,
 185        .alarm_irq_enable       = tx4939_rtc_alarm_irq_enable,
 186};
 187
 188static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,
 189                                     struct bin_attribute *bin_attr,
 190                                     char *buf, loff_t pos, size_t size)
 191{
 192        struct device *dev = container_of(kobj, struct device, kobj);
 193        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
 194        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
 195        ssize_t count;
 196
 197        spin_lock_irq(&pdata->rtc->irq_lock);
 198        for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
 199             count++, size--) {
 200                __raw_writel(pos++, &rtcreg->adr);
 201                *buf++ = __raw_readl(&rtcreg->dat);
 202        }
 203        spin_unlock_irq(&pdata->rtc->irq_lock);
 204        return count;
 205}
 206
 207static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj,
 208                                      struct bin_attribute *bin_attr,
 209                                      char *buf, loff_t pos, size_t size)
 210{
 211        struct device *dev = container_of(kobj, struct device, kobj);
 212        struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev);
 213        struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;
 214        ssize_t count;
 215
 216        spin_lock_irq(&pdata->rtc->irq_lock);
 217        for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;
 218             count++, size--) {
 219                __raw_writel(pos++, &rtcreg->adr);
 220                __raw_writel(*buf++, &rtcreg->dat);
 221        }
 222        spin_unlock_irq(&pdata->rtc->irq_lock);
 223        return count;
 224}
 225
 226static struct bin_attribute tx4939_rtc_nvram_attr = {
 227        .attr = {
 228                .name = "nvram",
 229                .mode = S_IRUGO | S_IWUSR,
 230        },
 231        .size = TX4939_RTC_REG_RAMSIZE,
 232        .read = tx4939_rtc_nvram_read,
 233        .write = tx4939_rtc_nvram_write,
 234};
 235
 236static int __init tx4939_rtc_probe(struct platform_device *pdev)
 237{
 238        struct rtc_device *rtc;
 239        struct tx4939rtc_plat_data *pdata;
 240        struct resource *res;
 241        int irq, ret;
 242
 243        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 244        if (!res)
 245                return -ENODEV;
 246        irq = platform_get_irq(pdev, 0);
 247        if (irq < 0)
 248                return -ENODEV;
 249        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 250        if (!pdata)
 251                return -ENOMEM;
 252        platform_set_drvdata(pdev, pdata);
 253
 254        if (!devm_request_mem_region(&pdev->dev, res->start,
 255                                     resource_size(res), pdev->name))
 256                return -EBUSY;
 257        pdata->rtcreg = devm_ioremap(&pdev->dev, res->start,
 258                                     resource_size(res));
 259        if (!pdata->rtcreg)
 260                return -EBUSY;
 261
 262        tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
 263        if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,
 264                             IRQF_DISABLED | IRQF_SHARED,
 265                             pdev->name, &pdev->dev) < 0) {
 266                return -EBUSY;
 267        }
 268        rtc = rtc_device_register(pdev->name, &pdev->dev,
 269                                  &tx4939_rtc_ops, THIS_MODULE);
 270        if (IS_ERR(rtc))
 271                return PTR_ERR(rtc);
 272        pdata->rtc = rtc;
 273        ret = sysfs_create_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
 274        if (ret)
 275                rtc_device_unregister(rtc);
 276        return ret;
 277}
 278
 279static int __exit tx4939_rtc_remove(struct platform_device *pdev)
 280{
 281        struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev);
 282        struct rtc_device *rtc = pdata->rtc;
 283
 284        spin_lock_irq(&rtc->irq_lock);
 285        tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
 286        spin_unlock_irq(&rtc->irq_lock);
 287        sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr);
 288        rtc_device_unregister(rtc);
 289        platform_set_drvdata(pdev, NULL);
 290        return 0;
 291}
 292
 293static struct platform_driver tx4939_rtc_driver = {
 294        .remove         = __exit_p(tx4939_rtc_remove),
 295        .driver         = {
 296                .name   = "tx4939rtc",
 297                .owner  = THIS_MODULE,
 298        },
 299};
 300
 301static int __init tx4939rtc_init(void)
 302{
 303        return platform_driver_probe(&tx4939_rtc_driver, tx4939_rtc_probe);
 304}
 305
 306static void __exit tx4939rtc_exit(void)
 307{
 308        platform_driver_unregister(&tx4939_rtc_driver);
 309}
 310
 311module_init(tx4939rtc_init);
 312module_exit(tx4939rtc_exit);
 313
 314MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 315MODULE_DESCRIPTION("TX4939 internal RTC driver");
 316MODULE_LICENSE("GPL");
 317MODULE_ALIAS("platform:tx4939rtc");
 318