aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-rs5c348.c9
-rw-r--r--drivers/rtc/rtc-sh.c467
4 files changed, 487 insertions, 2 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 7ff1d88094b6..62c804af9fbe 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -27,7 +27,7 @@ config RTC_HCTOSYS
27 help 27 help
28 If you say yes here, the system time will be set using 28 If you say yes here, the system time will be set using
29 the value read from the specified RTC device. This is useful 29 the value read from the specified RTC device. This is useful
30 in order to avoid unnecessary fschk runs. 30 in order to avoid unnecessary fsck runs.
31 31
32config RTC_HCTOSYS_DEVICE 32config RTC_HCTOSYS_DEVICE
33 string "The RTC to read the time from" 33 string "The RTC to read the time from"
@@ -238,6 +238,16 @@ config RTC_DRV_SA1100
238 To compile this driver as a module, choose M here: the 238 To compile this driver as a module, choose M here: the
239 module will be called rtc-sa1100. 239 module will be called rtc-sa1100.
240 240
241config RTC_DRV_SH
242 tristate "SuperH On-Chip RTC"
243 depends on RTC_CLASS && SUPERH
244 help
245 Say Y here to enable support for the on-chip RTC found in
246 most SuperH processors.
247
248 To compile this driver as a module, choose M here: the
249 module will be called rtc-sh.
250
241config RTC_DRV_VR41XX 251config RTC_DRV_VR41XX
242 tristate "NEC VR41XX" 252 tristate "NEC VR41XX"
243 depends on RTC_CLASS && CPU_VR41XX 253 depends on RTC_CLASS && CPU_VR41XX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index bbcfb09d81d9..e72d467ab214 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -31,3 +31,4 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
31obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o 31obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
32obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o 32obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
33obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o 33obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
34obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 0964d1dba925..25589061f931 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -23,7 +23,7 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/spi/spi.h> 24#include <linux/spi/spi.h>
25 25
26#define DRV_VERSION "0.1" 26#define DRV_VERSION "0.2"
27 27
28#define RS5C348_REG_SECS 0 28#define RS5C348_REG_SECS 0
29#define RS5C348_REG_MINS 1 29#define RS5C348_REG_MINS 1
@@ -175,8 +175,15 @@ static int __devinit rs5c348_probe(struct spi_device *spi)
175 goto kfree_exit; 175 goto kfree_exit;
176 if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) { 176 if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
177 u8 buf[2]; 177 u8 buf[2];
178 struct rtc_time tm;
178 if (ret & RS5C348_BIT_VDET) 179 if (ret & RS5C348_BIT_VDET)
179 dev_warn(&spi->dev, "voltage-low detected.\n"); 180 dev_warn(&spi->dev, "voltage-low detected.\n");
181 if (ret & RS5C348_BIT_XSTP)
182 dev_warn(&spi->dev, "oscillator-stop detected.\n");
183 rtc_time_to_tm(0, &tm); /* 1970/1/1 */
184 ret = rs5c348_rtc_set_time(&spi->dev, &tm);
185 if (ret < 0)
186 goto kfree_exit;
180 buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2); 187 buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
181 buf[1] = 0; 188 buf[1] = 0;
182 ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0); 189 ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
new file mode 100644
index 000000000000..d2ce0c8bb8f3
--- /dev/null
+++ b/drivers/rtc/rtc-sh.c
@@ -0,0 +1,467 @@
1/*
2 * SuperH On-Chip RTC Support
3 *
4 * Copyright (C) 2006 Paul Mundt
5 *
6 * Based on the old arch/sh/kernel/cpu/rtc.c by:
7 *
8 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
9 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
10 *
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file "COPYING" in the main directory of this archive
13 * for more details.
14 */
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/bcd.h>
18#include <linux/rtc.h>
19#include <linux/init.h>
20#include <linux/platform_device.h>
21#include <linux/seq_file.h>
22#include <linux/interrupt.h>
23#include <linux/spinlock.h>
24#include <asm/io.h>
25
26#ifdef CONFIG_CPU_SH3
27#define rtc_reg_size sizeof(u16)
28#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
29#elif defined(CONFIG_CPU_SH4)
30#define rtc_reg_size sizeof(u32)
31#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
32#endif
33
34#define RTC_REG(r) ((r) * rtc_reg_size)
35
36#define R64CNT RTC_REG(0)
37#define RSECCNT RTC_REG(1)
38#define RMINCNT RTC_REG(2)
39#define RHRCNT RTC_REG(3)
40#define RWKCNT RTC_REG(4)
41#define RDAYCNT RTC_REG(5)
42#define RMONCNT RTC_REG(6)
43#define RYRCNT RTC_REG(7)
44#define RSECAR RTC_REG(8)
45#define RMINAR RTC_REG(9)
46#define RHRAR RTC_REG(10)
47#define RWKAR RTC_REG(11)
48#define RDAYAR RTC_REG(12)
49#define RMONAR RTC_REG(13)
50#define RCR1 RTC_REG(14)
51#define RCR2 RTC_REG(15)
52
53/* RCR1 Bits */
54#define RCR1_CF 0x80 /* Carry Flag */
55#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
56#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
57#define RCR1_AF 0x01 /* Alarm Flag */
58
59/* RCR2 Bits */
60#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
61#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
62#define RCR2_RTCEN 0x08 /* ENable RTC */
63#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
64#define RCR2_RESET 0x02 /* Reset bit */
65#define RCR2_START 0x01 /* Start bit */
66
67struct sh_rtc {
68 void __iomem *regbase;
69 unsigned long regsize;
70 struct resource *res;
71 unsigned int alarm_irq, periodic_irq, carry_irq;
72 struct rtc_device *rtc_dev;
73 spinlock_t lock;
74};
75
76static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs)
77{
78 struct platform_device *pdev = id;
79 struct sh_rtc *rtc = platform_get_drvdata(pdev);
80 unsigned int tmp, events = 0;
81
82 spin_lock(&rtc->lock);
83
84 tmp = readb(rtc->regbase + RCR1);
85
86 if (tmp & RCR1_AF)
87 events |= RTC_AF | RTC_IRQF;
88
89 tmp &= ~(RCR1_CF | RCR1_AF);
90
91 writeb(tmp, rtc->regbase + RCR1);
92
93 rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
94
95 spin_unlock(&rtc->lock);
96
97 return IRQ_HANDLED;
98}
99
100static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs)
101{
102 struct sh_rtc *rtc = dev_get_drvdata(id);
103
104 spin_lock(&rtc->lock);
105
106 rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
107
108 spin_unlock(&rtc->lock);
109
110 return IRQ_HANDLED;
111}
112
113static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
114{
115 struct sh_rtc *rtc = dev_get_drvdata(dev);
116 unsigned int tmp;
117
118 spin_lock_irq(&rtc->lock);
119
120 tmp = readb(rtc->regbase + RCR2);
121
122 if (enable) {
123 tmp &= ~RCR2_PESMASK;
124 tmp |= RCR2_PEF | (2 << 4);
125 } else
126 tmp &= ~(RCR2_PESMASK | RCR2_PEF);
127
128 writeb(tmp, rtc->regbase + RCR2);
129
130 spin_unlock_irq(&rtc->lock);
131}
132
133static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
134{
135 struct sh_rtc *rtc = dev_get_drvdata(dev);
136 unsigned int tmp;
137
138 spin_lock_irq(&rtc->lock);
139
140 tmp = readb(rtc->regbase + RCR1);
141
142 if (enable)
143 tmp |= RCR1_AIE;
144 else
145 tmp &= ~RCR1_AIE;
146
147 writeb(tmp, rtc->regbase + RCR1);
148
149 spin_unlock_irq(&rtc->lock);
150}
151
152static int sh_rtc_open(struct device *dev)
153{
154 struct sh_rtc *rtc = dev_get_drvdata(dev);
155 unsigned int tmp;
156 int ret;
157
158 tmp = readb(rtc->regbase + RCR1);
159 tmp &= ~RCR1_CF;
160 tmp |= RCR1_CIE;
161 writeb(tmp, rtc->regbase + RCR1);
162
163 ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT,
164 "sh-rtc period", dev);
165 if (unlikely(ret)) {
166 dev_err(dev, "request period IRQ failed with %d, IRQ %d\n",
167 ret, rtc->periodic_irq);
168 return ret;
169 }
170
171 ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT,
172 "sh-rtc carry", dev);
173 if (unlikely(ret)) {
174 dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n",
175 ret, rtc->carry_irq);
176 free_irq(rtc->periodic_irq, dev);
177 goto err_bad_carry;
178 }
179
180 ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT,
181 "sh-rtc alarm", dev);
182 if (unlikely(ret)) {
183 dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
184 ret, rtc->alarm_irq);
185 goto err_bad_alarm;
186 }
187
188 return 0;
189
190err_bad_alarm:
191 free_irq(rtc->carry_irq, dev);
192err_bad_carry:
193 free_irq(rtc->periodic_irq, dev);
194
195 return ret;
196}
197
198static void sh_rtc_release(struct device *dev)
199{
200 struct sh_rtc *rtc = dev_get_drvdata(dev);
201
202 sh_rtc_setpie(dev, 0);
203
204 free_irq(rtc->periodic_irq, dev);
205 free_irq(rtc->carry_irq, dev);
206 free_irq(rtc->alarm_irq, dev);
207}
208
209static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
210{
211 struct sh_rtc *rtc = dev_get_drvdata(dev);
212 unsigned int tmp;
213
214 tmp = readb(rtc->regbase + RCR1);
215 seq_printf(seq, "alarm_IRQ\t: %s\n",
216 (tmp & RCR1_AIE) ? "yes" : "no");
217 seq_printf(seq, "carry_IRQ\t: %s\n",
218 (tmp & RCR1_CIE) ? "yes" : "no");
219
220 tmp = readb(rtc->regbase + RCR2);
221 seq_printf(seq, "periodic_IRQ\t: %s\n",
222 (tmp & RCR2_PEF) ? "yes" : "no");
223
224 return 0;
225}
226
227static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
228{
229 unsigned int ret = -ENOIOCTLCMD;
230
231 switch (cmd) {
232 case RTC_PIE_OFF:
233 case RTC_PIE_ON:
234 sh_rtc_setpie(dev, cmd == RTC_PIE_ON);
235 ret = 0;
236 break;
237 case RTC_AIE_OFF:
238 case RTC_AIE_ON:
239 sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
240 ret = 0;
241 break;
242 }
243
244 return ret;
245}
246
247static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
248{
249 struct platform_device *pdev = to_platform_device(dev);
250 struct sh_rtc *rtc = platform_get_drvdata(pdev);
251 unsigned int sec128, sec2, yr, yr100, cf_bit;
252
253 do {
254 unsigned int tmp;
255
256 spin_lock_irq(&rtc->lock);
257
258 tmp = readb(rtc->regbase + RCR1);
259 tmp &= ~RCR1_CF; /* Clear CF-bit */
260 tmp |= RCR1_CIE;
261 writeb(tmp, rtc->regbase + RCR1);
262
263 sec128 = readb(rtc->regbase + R64CNT);
264
265 tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
266 tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
267 tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
268 tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
269 tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
270 tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT));
271
272#if defined(CONFIG_CPU_SH4)
273 yr = readw(rtc->regbase + RYRCNT);
274 yr100 = BCD2BIN(yr >> 8);
275 yr &= 0xff;
276#else
277 yr = readb(rtc->regbase + RYRCNT);
278 yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
279#endif
280
281 tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
282
283 sec2 = readb(rtc->regbase + R64CNT);
284 cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;
285
286 spin_unlock_irq(&rtc->lock);
287 } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
288
289#if RTC_BIT_INVERTED != 0
290 if ((sec128 & RTC_BIT_INVERTED))
291 tm->tm_sec--;
292#endif
293
294 dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
295 "mday=%d, mon=%d, year=%d, wday=%d\n",
296 __FUNCTION__,
297 tm->tm_sec, tm->tm_min, tm->tm_hour,
298 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
299
300 if (rtc_valid_tm(tm) < 0)
301 dev_err(dev, "invalid date\n");
302
303 return 0;
304}
305
306static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
307{
308 struct platform_device *pdev = to_platform_device(dev);
309 struct sh_rtc *rtc = platform_get_drvdata(pdev);
310 unsigned int tmp;
311 int year;
312
313 spin_lock_irq(&rtc->lock);
314
315 /* Reset pre-scaler & stop RTC */
316 tmp = readb(rtc->regbase + RCR2);
317 tmp |= RCR2_RESET;
318 writeb(tmp, rtc->regbase + RCR2);
319
320 writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
321 writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
322 writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
323 writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
324 writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
325 writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT);
326
327#ifdef CONFIG_CPU_SH3
328 year = tm->tm_year % 100;
329 writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
330#else
331 year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
332 BIN2BCD(tm->tm_year % 100);
333 writew(year, rtc->regbase + RYRCNT);
334#endif
335
336 /* Start RTC */
337 tmp = readb(rtc->regbase + RCR2);
338 tmp &= ~RCR2_RESET;
339 tmp |= RCR2_RTCEN | RCR2_START;
340 writeb(tmp, rtc->regbase + RCR2);
341
342 spin_unlock_irq(&rtc->lock);
343
344 return 0;
345}
346
347static struct rtc_class_ops sh_rtc_ops = {
348 .open = sh_rtc_open,
349 .release = sh_rtc_release,
350 .ioctl = sh_rtc_ioctl,
351 .read_time = sh_rtc_read_time,
352 .set_time = sh_rtc_set_time,
353 .proc = sh_rtc_proc,
354};
355
356static int __devinit sh_rtc_probe(struct platform_device *pdev)
357{
358 struct sh_rtc *rtc;
359 struct resource *res;
360 int ret = -ENOENT;
361
362 rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
363 if (unlikely(!rtc))
364 return -ENOMEM;
365
366 spin_lock_init(&rtc->lock);
367
368 rtc->periodic_irq = platform_get_irq(pdev, 0);
369 if (unlikely(rtc->periodic_irq < 0)) {
370 dev_err(&pdev->dev, "No IRQ for period\n");
371 goto err_badres;
372 }
373
374 rtc->carry_irq = platform_get_irq(pdev, 1);
375 if (unlikely(rtc->carry_irq < 0)) {
376 dev_err(&pdev->dev, "No IRQ for carry\n");
377 goto err_badres;
378 }
379
380 rtc->alarm_irq = platform_get_irq(pdev, 2);
381 if (unlikely(rtc->alarm_irq < 0)) {
382 dev_err(&pdev->dev, "No IRQ for alarm\n");
383 goto err_badres;
384 }
385
386 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
387 if (unlikely(res == NULL)) {
388 dev_err(&pdev->dev, "No IO resource\n");
389 goto err_badres;
390 }
391
392 rtc->regsize = res->end - res->start + 1;
393
394 rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);
395 if (unlikely(!rtc->res)) {
396 ret = -EBUSY;
397 goto err_badres;
398 }
399
400 rtc->regbase = (void __iomem *)rtc->res->start;
401 if (unlikely(!rtc->regbase)) {
402 ret = -EINVAL;
403 goto err_badmap;
404 }
405
406 rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
407 &sh_rtc_ops, THIS_MODULE);
408 if (IS_ERR(rtc)) {
409 ret = PTR_ERR(rtc->rtc_dev);
410 goto err_badmap;
411 }
412
413 platform_set_drvdata(pdev, rtc);
414
415 return 0;
416
417err_badmap:
418 release_resource(rtc->res);
419err_badres:
420 kfree(rtc);
421
422 return ret;
423}
424
425static int __devexit sh_rtc_remove(struct platform_device *pdev)
426{
427 struct sh_rtc *rtc = platform_get_drvdata(pdev);
428
429 if (likely(rtc->rtc_dev))
430 rtc_device_unregister(rtc->rtc_dev);
431
432 sh_rtc_setpie(&pdev->dev, 0);
433 sh_rtc_setaie(&pdev->dev, 0);
434
435 release_resource(rtc->res);
436
437 platform_set_drvdata(pdev, NULL);
438
439 kfree(rtc);
440
441 return 0;
442}
443static struct platform_driver sh_rtc_platform_driver = {
444 .driver = {
445 .name = "sh-rtc",
446 .owner = THIS_MODULE,
447 },
448 .probe = sh_rtc_probe,
449 .remove = __devexit_p(sh_rtc_remove),
450};
451
452static int __init sh_rtc_init(void)
453{
454 return platform_driver_register(&sh_rtc_platform_driver);
455}
456
457static void __exit sh_rtc_exit(void)
458{
459 platform_driver_unregister(&sh_rtc_platform_driver);
460}
461
462module_init(sh_rtc_init);
463module_exit(sh_rtc_exit);
464
465MODULE_DESCRIPTION("SuperH on-chip RTC driver");
466MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
467MODULE_LICENSE("GPL");