Commit 5f119f29063c9a9bf1ab40112c02710c2db84f29

Authored by Thomas Bogendoerfer
Committed by Ralf Baechle
1 parent 7d81a5e03d

MIPS: DS1286: New RTC driver

This driver replaces the broken DS1286 driver in drivers/char and gives back
RTC support for SGI IP22 and IP28 machines.

Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Acked-by: Alessandro Zummo <alessandro.zummo@towertech.it>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

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

... ... @@ -352,6 +352,11 @@
352 352 help
353 353 If you say yes here you get support for the Dallas DS1216 RTC chips.
354 354  
  355 +config RTC_DRV_DS1286
  356 + tristate "Dallas DS1286"
  357 + help
  358 + If you say yes here you get support for the Dallas DS1286 RTC chips.
  359 +
355 360 config RTC_DRV_DS1302
356 361 tristate "Dallas DS1302"
357 362 depends on SH_SECUREEDGE5410
drivers/rtc/Makefile
... ... @@ -23,6 +23,7 @@
23 23 obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
24 24 obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
25 25 obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
  26 +obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
26 27 obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
27 28 obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
28 29 obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
drivers/rtc/rtc-ds1286.c
  1 +/*
  2 + * DS1286 Real Time Clock interface for Linux
  3 + *
  4 + * Copyright (C) 1998, 1999, 2000 Ralf Baechle
  5 + * Copyright (C) 2008 Thomas Bogendoerfer
  6 + *
  7 + * Based on code written by Paul Gortmaker.
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify it
  10 + * under the terms of the GNU General Public License as published by the
  11 + * Free Software Foundation; either version 2 of the License, or (at your
  12 + * option) any later version.
  13 + */
  14 +
  15 +#include <linux/module.h>
  16 +#include <linux/rtc.h>
  17 +#include <linux/platform_device.h>
  18 +#include <linux/bcd.h>
  19 +#include <linux/ds1286.h>
  20 +
  21 +#define DRV_VERSION "1.0"
  22 +
  23 +struct ds1286_priv {
  24 + struct rtc_device *rtc;
  25 + u32 __iomem *rtcregs;
  26 + size_t size;
  27 + unsigned long baseaddr;
  28 + spinlock_t lock;
  29 +};
  30 +
  31 +static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg)
  32 +{
  33 + return __raw_readl(&priv->rtcregs[reg]) & 0xff;
  34 +}
  35 +
  36 +static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
  37 +{
  38 + __raw_writel(data, &priv->rtcregs[reg]);
  39 +}
  40 +
  41 +#ifdef CONFIG_RTC_INTF_DEV
  42 +
  43 +static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
  44 +{
  45 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  46 + unsigned long flags;
  47 + unsigned char val;
  48 +
  49 + switch (cmd) {
  50 + case RTC_AIE_OFF:
  51 + /* Mask alarm int. enab. bit */
  52 + spin_lock_irqsave(&priv->lock, flags);
  53 + val = ds1286_rtc_read(priv, RTC_CMD);
  54 + val |= RTC_TDM;
  55 + ds1286_rtc_write(priv, val, RTC_CMD);
  56 + spin_unlock_irqrestore(&priv->lock, flags);
  57 + break;
  58 + case RTC_AIE_ON:
  59 + /* Allow alarm interrupts. */
  60 + spin_lock_irqsave(&priv->lock, flags);
  61 + val = ds1286_rtc_read(priv, RTC_CMD);
  62 + val &= ~RTC_TDM;
  63 + ds1286_rtc_write(priv, val, RTC_CMD);
  64 + spin_unlock_irqrestore(&priv->lock, flags);
  65 + break;
  66 + case RTC_WIE_OFF:
  67 + /* Mask watchdog int. enab. bit */
  68 + spin_lock_irqsave(&priv->lock, flags);
  69 + val = ds1286_rtc_read(priv, RTC_CMD);
  70 + val |= RTC_WAM;
  71 + ds1286_rtc_write(priv, val, RTC_CMD);
  72 + spin_unlock_irqrestore(&priv->lock, flags);
  73 + break;
  74 + case RTC_WIE_ON:
  75 + /* Allow watchdog interrupts. */
  76 + spin_lock_irqsave(&priv->lock, flags);
  77 + val = ds1286_rtc_read(priv, RTC_CMD);
  78 + val &= ~RTC_WAM;
  79 + ds1286_rtc_write(priv, val, RTC_CMD);
  80 + spin_unlock_irqrestore(&priv->lock, flags);
  81 + break;
  82 + default:
  83 + return -ENOIOCTLCMD;
  84 + }
  85 + return 0;
  86 +}
  87 +
  88 +#else
  89 +#define ds1286_ioctl NULL
  90 +#endif
  91 +
  92 +#ifdef CONFIG_PROC_FS
  93 +
  94 +static int ds1286_proc(struct device *dev, struct seq_file *seq)
  95 +{
  96 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  97 + unsigned char month, cmd, amode;
  98 + const char *s;
  99 +
  100 + month = ds1286_rtc_read(priv, RTC_MONTH);
  101 + seq_printf(seq,
  102 + "oscillator\t: %s\n"
  103 + "square_wave\t: %s\n",
  104 + (month & RTC_EOSC) ? "disabled" : "enabled",
  105 + (month & RTC_ESQW) ? "disabled" : "enabled");
  106 +
  107 + amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) |
  108 + ((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) |
  109 + ((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7);
  110 + switch (amode) {
  111 + case 7:
  112 + s = "each minute";
  113 + break;
  114 + case 3:
  115 + s = "minutes match";
  116 + break;
  117 + case 1:
  118 + s = "hours and minutes match";
  119 + break;
  120 + case 0:
  121 + s = "days, hours and minutes match";
  122 + break;
  123 + default:
  124 + s = "invalid";
  125 + break;
  126 + }
  127 + seq_printf(seq, "alarm_mode\t: %s\n", s);
  128 +
  129 + cmd = ds1286_rtc_read(priv, RTC_CMD);
  130 + seq_printf(seq,
  131 + "alarm_enable\t: %s\n"
  132 + "wdog_alarm\t: %s\n"
  133 + "alarm_mask\t: %s\n"
  134 + "wdog_alarm_mask\t: %s\n"
  135 + "interrupt_mode\t: %s\n"
  136 + "INTB_mode\t: %s_active\n"
  137 + "interrupt_pins\t: %s\n",
  138 + (cmd & RTC_TDF) ? "yes" : "no",
  139 + (cmd & RTC_WAF) ? "yes" : "no",
  140 + (cmd & RTC_TDM) ? "disabled" : "enabled",
  141 + (cmd & RTC_WAM) ? "disabled" : "enabled",
  142 + (cmd & RTC_PU_LVL) ? "pulse" : "level",
  143 + (cmd & RTC_IBH_LO) ? "low" : "high",
  144 + (cmd & RTC_IPSW) ? "unswapped" : "swapped");
  145 + return 0;
  146 +}
  147 +
  148 +#else
  149 +#define ds1286_proc NULL
  150 +#endif
  151 +
  152 +static int ds1286_read_time(struct device *dev, struct rtc_time *tm)
  153 +{
  154 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  155 + unsigned char save_control;
  156 + unsigned long flags;
  157 + unsigned long uip_watchdog = jiffies;
  158 +
  159 + /*
  160 + * read RTC once any update in progress is done. The update
  161 + * can take just over 2ms. We wait 10 to 20ms. There is no need to
  162 + * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
  163 + * If you need to know *exactly* when a second has started, enable
  164 + * periodic update complete interrupts, (via ioctl) and then
  165 + * immediately read /dev/rtc which will block until you get the IRQ.
  166 + * Once the read clears, read the RTC time (again via ioctl). Easy.
  167 + */
  168 +
  169 + if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE)
  170 + while (time_before(jiffies, uip_watchdog + 2*HZ/100))
  171 + barrier();
  172 +
  173 + /*
  174 + * Only the values that we read from the RTC are set. We leave
  175 + * tm_wday, tm_yday and tm_isdst untouched. Even though the
  176 + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
  177 + * by the RTC when initially set to a non-zero value.
  178 + */
  179 + spin_lock_irqsave(&priv->lock, flags);
  180 + save_control = ds1286_rtc_read(priv, RTC_CMD);
  181 + ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
  182 +
  183 + tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS);
  184 + tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES);
  185 + tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f;
  186 + tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE);
  187 + tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f;
  188 + tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR);
  189 +
  190 + ds1286_rtc_write(priv, save_control, RTC_CMD);
  191 + spin_unlock_irqrestore(&priv->lock, flags);
  192 +
  193 + tm->tm_sec = bcd2bin(tm->tm_sec);
  194 + tm->tm_min = bcd2bin(tm->tm_min);
  195 + tm->tm_hour = bcd2bin(tm->tm_hour);
  196 + tm->tm_mday = bcd2bin(tm->tm_mday);
  197 + tm->tm_mon = bcd2bin(tm->tm_mon);
  198 + tm->tm_year = bcd2bin(tm->tm_year);
  199 +
  200 + /*
  201 + * Account for differences between how the RTC uses the values
  202 + * and how they are defined in a struct rtc_time;
  203 + */
  204 + if (tm->tm_year < 45)
  205 + tm->tm_year += 30;
  206 + tm->tm_year += 40;
  207 + if (tm->tm_year < 70)
  208 + tm->tm_year += 100;
  209 +
  210 + tm->tm_mon--;
  211 +
  212 + return rtc_valid_tm(tm);
  213 +}
  214 +
  215 +static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
  216 +{
  217 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  218 + unsigned char mon, day, hrs, min, sec;
  219 + unsigned char save_control;
  220 + unsigned int yrs;
  221 + unsigned long flags;
  222 +
  223 + yrs = tm->tm_year + 1900;
  224 + mon = tm->tm_mon + 1; /* tm_mon starts at zero */
  225 + day = tm->tm_mday;
  226 + hrs = tm->tm_hour;
  227 + min = tm->tm_min;
  228 + sec = tm->tm_sec;
  229 +
  230 + if (yrs < 1970)
  231 + return -EINVAL;
  232 +
  233 + yrs -= 1940;
  234 + if (yrs > 255) /* They are unsigned */
  235 + return -EINVAL;
  236 +
  237 + if (yrs >= 100)
  238 + yrs -= 100;
  239 +
  240 + sec = bin2bcd(sec);
  241 + min = bin2bcd(min);
  242 + hrs = bin2bcd(hrs);
  243 + day = bin2bcd(day);
  244 + mon = bin2bcd(mon);
  245 + yrs = bin2bcd(yrs);
  246 +
  247 + spin_lock_irqsave(&priv->lock, flags);
  248 + save_control = ds1286_rtc_read(priv, RTC_CMD);
  249 + ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
  250 +
  251 + ds1286_rtc_write(priv, yrs, RTC_YEAR);
  252 + ds1286_rtc_write(priv, mon, RTC_MONTH);
  253 + ds1286_rtc_write(priv, day, RTC_DATE);
  254 + ds1286_rtc_write(priv, hrs, RTC_HOURS);
  255 + ds1286_rtc_write(priv, min, RTC_MINUTES);
  256 + ds1286_rtc_write(priv, sec, RTC_SECONDS);
  257 + ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND);
  258 +
  259 + ds1286_rtc_write(priv, save_control, RTC_CMD);
  260 + spin_unlock_irqrestore(&priv->lock, flags);
  261 + return 0;
  262 +}
  263 +
  264 +static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
  265 +{
  266 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  267 + unsigned char cmd;
  268 + unsigned long flags;
  269 +
  270 + /*
  271 + * Only the values that we read from the RTC are set. That
  272 + * means only tm_wday, tm_hour, tm_min.
  273 + */
  274 + spin_lock_irqsave(&priv->lock, flags);
  275 + alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
  276 + alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f;
  277 + alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07;
  278 + cmd = ds1286_rtc_read(priv, RTC_CMD);
  279 + spin_unlock_irqrestore(&priv->lock, flags);
  280 +
  281 + alm->time.tm_min = bcd2bin(alm->time.tm_min);
  282 + alm->time.tm_hour = bcd2bin(alm->time.tm_hour);
  283 + alm->time.tm_sec = 0;
  284 + return 0;
  285 +}
  286 +
  287 +static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
  288 +{
  289 + struct ds1286_priv *priv = dev_get_drvdata(dev);
  290 + unsigned char hrs, min, sec;
  291 +
  292 + hrs = alm->time.tm_hour;
  293 + min = alm->time.tm_min;
  294 + sec = alm->time.tm_sec;
  295 +
  296 + if (hrs >= 24)
  297 + hrs = 0xff;
  298 +
  299 + if (min >= 60)
  300 + min = 0xff;
  301 +
  302 + if (sec != 0)
  303 + return -EINVAL;
  304 +
  305 + min = bin2bcd(min);
  306 + hrs = bin2bcd(hrs);
  307 +
  308 + spin_lock(&priv->lock);
  309 + ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM);
  310 + ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM);
  311 + spin_unlock(&priv->lock);
  312 +
  313 + return 0;
  314 +}
  315 +
  316 +static const struct rtc_class_ops ds1286_ops = {
  317 + .ioctl = ds1286_ioctl,
  318 + .proc = ds1286_proc,
  319 + .read_time = ds1286_read_time,
  320 + .set_time = ds1286_set_time,
  321 + .read_alarm = ds1286_read_alarm,
  322 + .set_alarm = ds1286_set_alarm,
  323 +};
  324 +
  325 +static int __devinit ds1286_probe(struct platform_device *pdev)
  326 +{
  327 + struct rtc_device *rtc;
  328 + struct resource *res;
  329 + struct ds1286_priv *priv;
  330 + int ret = 0;
  331 +
  332 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  333 + if (!res)
  334 + return -ENODEV;
  335 + priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
  336 + if (!priv)
  337 + return -ENOMEM;
  338 +
  339 + priv->size = res->end - res->start + 1;
  340 + if (!request_mem_region(res->start, priv->size, pdev->name)) {
  341 + ret = -EBUSY;
  342 + goto out;
  343 + }
  344 + priv->baseaddr = res->start;
  345 + priv->rtcregs = ioremap(priv->baseaddr, priv->size);
  346 + if (!priv->rtcregs) {
  347 + ret = -ENOMEM;
  348 + goto out;
  349 + }
  350 + spin_lock_init(&priv->lock);
  351 + rtc = rtc_device_register("ds1286", &pdev->dev,
  352 + &ds1286_ops, THIS_MODULE);
  353 + if (IS_ERR(rtc)) {
  354 + ret = PTR_ERR(rtc);
  355 + goto out;
  356 + }
  357 + priv->rtc = rtc;
  358 + platform_set_drvdata(pdev, priv);
  359 + return 0;
  360 +
  361 +out:
  362 + if (priv->rtc)
  363 + rtc_device_unregister(priv->rtc);
  364 + if (priv->rtcregs)
  365 + iounmap(priv->rtcregs);
  366 + if (priv->baseaddr)
  367 + release_mem_region(priv->baseaddr, priv->size);
  368 + kfree(priv);
  369 + return ret;
  370 +}
  371 +
  372 +static int __devexit ds1286_remove(struct platform_device *pdev)
  373 +{
  374 + struct ds1286_priv *priv = platform_get_drvdata(pdev);
  375 +
  376 + rtc_device_unregister(priv->rtc);
  377 + iounmap(priv->rtcregs);
  378 + release_mem_region(priv->baseaddr, priv->size);
  379 + kfree(priv);
  380 + return 0;
  381 +}
  382 +
  383 +static struct platform_driver ds1286_platform_driver = {
  384 + .driver = {
  385 + .name = "rtc-ds1286",
  386 + .owner = THIS_MODULE,
  387 + },
  388 + .probe = ds1286_probe,
  389 + .remove = __devexit_p(ds1286_remove),
  390 +};
  391 +
  392 +static int __init ds1286_init(void)
  393 +{
  394 + return platform_driver_register(&ds1286_platform_driver);
  395 +}
  396 +
  397 +static void __exit ds1286_exit(void)
  398 +{
  399 + platform_driver_unregister(&ds1286_platform_driver);
  400 +}
  401 +
  402 +MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
  403 +MODULE_DESCRIPTION("DS1286 RTC driver");
  404 +MODULE_LICENSE("GPL");
  405 +MODULE_VERSION(DRV_VERSION);
  406 +MODULE_ALIAS("platform:rtc-ds1286");
  407 +
  408 +module_init(ds1286_init);
  409 +module_exit(ds1286_exit);