Commit 0e1492330cd2c95df2553335d7a77351021a938f

Authored by Atsushi Nemoto
Committed by Linus Torvalds
1 parent bbccf83f6c

rtc: add rtc-tx4939 driver

Add support for RTC in TX4939 SoC.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Acked-by: Alessandro Zummo <a.zummo@towertech.it>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 325 additions and 0 deletions Side-by-side Diff

... ... @@ -705,5 +705,12 @@
705 705 If you say Y here you will get support for the RTC found on
706 706 Starfire systems.
707 707  
  708 +config RTC_DRV_TX4939
  709 + tristate "TX4939 SoC"
  710 + depends on SOC_TX4939
  711 + help
  712 + Driver for the internal RTC (Realtime Clock) module found on
  713 + Toshiba TX4939 SoC.
  714 +
708 715 endif # RTC_CLASS
drivers/rtc/Makefile
... ... @@ -68,6 +68,7 @@
68 68 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
69 69 obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
70 70 obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl4030.o
  71 +obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
71 72 obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
72 73 obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
73 74 obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
drivers/rtc/rtc-tx4939.c
  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 +
  17 +struct tx4939rtc_plat_data {
  18 + struct rtc_device *rtc;
  19 + struct tx4939_rtc_reg __iomem *rtcreg;
  20 +};
  21 +
  22 +static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev)
  23 +{
  24 + return platform_get_drvdata(to_platform_device(dev));
  25 +}
  26 +
  27 +static 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 +
  42 +static 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 +
  66 +static 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 +
  91 +static 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 +
  123 +static 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 +
  152 +static 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 +
  164 +static 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 +
  180 +static 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 +
  188 +static 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 +
  207 +static 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 +
  226 +static 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 +
  236 +static 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 +
  279 +static 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 +
  293 +static 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 +
  301 +static int __init tx4939rtc_init(void)
  302 +{
  303 + return platform_driver_probe(&tx4939_rtc_driver, tx4939_rtc_probe);
  304 +}
  305 +
  306 +static void __exit tx4939rtc_exit(void)
  307 +{
  308 + platform_driver_unregister(&tx4939_rtc_driver);
  309 +}
  310 +
  311 +module_init(tx4939rtc_init);
  312 +module_exit(tx4939rtc_exit);
  313 +
  314 +MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
  315 +MODULE_DESCRIPTION("TX4939 internal RTC driver");
  316 +MODULE_LICENSE("GPL");
  317 +MODULE_ALIAS("platform:tx4939rtc");