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