aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/s3c2410-rtc.c591
3 files changed, 0 insertions, 600 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 1b21c3a911d9..4cc619edf424 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -831,14 +831,6 @@ config DS1302
831 will get access to the real time clock (or hardware clock) built 831 will get access to the real time clock (or hardware clock) built
832 into your computer. 832 into your computer.
833 833
834config S3C2410_RTC
835 bool "S3C2410 RTC Driver"
836 depends on ARCH_S3C2410
837 help
838 RTC (Realtime Clock) driver for the clock inbuilt into the
839 Samsung S3C2410. This can provide periodic interrupt rates
840 from 1Hz to 64Hz for user programs, and wakeup from Alarm.
841
842config COBALT_LCD 834config COBALT_LCD
843 bool "Support for Cobalt LCD" 835 bool "Support for Cobalt LCD"
844 depends on MIPS_COBALT 836 depends on MIPS_COBALT
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b583d0cd9fbe..19114df59bbd 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -69,7 +69,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
69obj-$(CONFIG_SGI_DS1286) += ds1286.o 69obj-$(CONFIG_SGI_DS1286) += ds1286.o
70obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o 70obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
71obj-$(CONFIG_DS1302) += ds1302.o 71obj-$(CONFIG_DS1302) += ds1302.o
72obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
73ifeq ($(CONFIG_GENERIC_NVRAM),y) 72ifeq ($(CONFIG_GENERIC_NVRAM),y)
74 obj-$(CONFIG_NVRAM) += generic_nvram.o 73 obj-$(CONFIG_NVRAM) += generic_nvram.o
75else 74else
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
deleted file mode 100644
index 5458ef1634e5..000000000000
--- a/drivers/char/s3c2410-rtc.c
+++ /dev/null
@@ -1,591 +0,0 @@
1/* drivers/char/s3c2410_rtc.c
2 *
3 * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
4 * http://www.simtec.co.uk/products/SWLINUX/
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * S3C2410 Internal RTC Driver
11 *
12 * Changelog:
13 * 08-Nov-2004 BJD Initial creation
14 * 12-Nov-2004 BJD Added periodic IRQ and PM code
15 * 22-Nov-2004 BJD Sign-test on alarm code to check for <0
16 * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
17*/
18
19#include <linux/module.h>
20#include <linux/fs.h>
21#include <linux/string.h>
22#include <linux/init.h>
23#include <linux/platform_device.h>
24#include <linux/interrupt.h>
25#include <linux/rtc.h>
26#include <linux/bcd.h>
27#include <linux/clk.h>
28
29#include <asm/hardware.h>
30#include <asm/uaccess.h>
31#include <asm/io.h>
32#include <asm/irq.h>
33#include <asm/rtc.h>
34
35#include <asm/mach/time.h>
36
37#include <asm/arch/regs-rtc.h>
38
39/* need this for the RTC_AF definitions */
40#include <linux/mc146818rtc.h>
41
42#undef S3C24XX_VA_RTC
43#define S3C24XX_VA_RTC s3c2410_rtc_base
44
45static struct resource *s3c2410_rtc_mem;
46
47static void __iomem *s3c2410_rtc_base;
48static int s3c2410_rtc_alarmno = NO_IRQ;
49static int s3c2410_rtc_tickno = NO_IRQ;
50static int s3c2410_rtc_freq = 1;
51
52static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock);
53
54/* IRQ Handlers */
55
56static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
57{
58 rtc_update(1, RTC_AF | RTC_IRQF);
59 return IRQ_HANDLED;
60}
61
62static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
63{
64 rtc_update(1, RTC_PF | RTC_IRQF);
65 return IRQ_HANDLED;
66}
67
68/* Update control registers */
69static void s3c2410_rtc_setaie(int to)
70{
71 unsigned int tmp;
72
73 pr_debug("%s: aie=%d\n", __FUNCTION__, to);
74
75 tmp = readb(S3C2410_RTCALM);
76
77 if (to)
78 tmp |= S3C2410_RTCALM_ALMEN;
79 else
80 tmp &= ~S3C2410_RTCALM_ALMEN;
81
82
83 writeb(tmp, S3C2410_RTCALM);
84}
85
86static void s3c2410_rtc_setpie(int to)
87{
88 unsigned int tmp;
89
90 pr_debug("%s: pie=%d\n", __FUNCTION__, to);
91
92 spin_lock_irq(&s3c2410_rtc_pie_lock);
93 tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
94
95 if (to)
96 tmp |= S3C2410_TICNT_ENABLE;
97
98 writeb(tmp, S3C2410_TICNT);
99 spin_unlock_irq(&s3c2410_rtc_pie_lock);
100}
101
102static void s3c2410_rtc_setfreq(int freq)
103{
104 unsigned int tmp;
105
106 spin_lock_irq(&s3c2410_rtc_pie_lock);
107 tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
108
109 s3c2410_rtc_freq = freq;
110
111 tmp |= (128 / freq)-1;
112
113 writeb(tmp, S3C2410_TICNT);
114 spin_unlock_irq(&s3c2410_rtc_pie_lock);
115}
116
117/* Time read/write */
118
119static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
120{
121 unsigned int have_retried = 0;
122
123 retry_get_time:
124 rtc_tm->tm_min = readb(S3C2410_RTCMIN);
125 rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
126 rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
127 rtc_tm->tm_mon = readb(S3C2410_RTCMON);
128 rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
129 rtc_tm->tm_sec = readb(S3C2410_RTCSEC);
130
131 /* the only way to work out wether the system was mid-update
132 * when we read it is to check the second counter, and if it
133 * is zero, then we re-try the entire read
134 */
135
136 if (rtc_tm->tm_sec == 0 && !have_retried) {
137 have_retried = 1;
138 goto retry_get_time;
139 }
140
141 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
142 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
143 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
144
145 BCD_TO_BIN(rtc_tm->tm_sec);
146 BCD_TO_BIN(rtc_tm->tm_min);
147 BCD_TO_BIN(rtc_tm->tm_hour);
148 BCD_TO_BIN(rtc_tm->tm_mday);
149 BCD_TO_BIN(rtc_tm->tm_mon);
150 BCD_TO_BIN(rtc_tm->tm_year);
151
152 rtc_tm->tm_year += 100;
153 rtc_tm->tm_mon -= 1;
154
155 return 0;
156}
157
158
159static int s3c2410_rtc_settime(struct rtc_time *tm)
160{
161 /* the rtc gets round the y2k problem by just not supporting it */
162
163 if (tm->tm_year < 100)
164 return -EINVAL;
165
166 writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC);
167 writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN);
168 writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
169 writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
170 writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
171 writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
172
173 return 0;
174}
175
176static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
177{
178 struct rtc_time *alm_tm = &alrm->time;
179 unsigned int alm_en;
180
181 alm_tm->tm_sec = readb(S3C2410_ALMSEC);
182 alm_tm->tm_min = readb(S3C2410_ALMMIN);
183 alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
184 alm_tm->tm_mon = readb(S3C2410_ALMMON);
185 alm_tm->tm_mday = readb(S3C2410_ALMDATE);
186 alm_tm->tm_year = readb(S3C2410_ALMYEAR);
187
188 alm_en = readb(S3C2410_RTCALM);
189
190 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
191 alm_en,
192 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
193 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
194
195
196 /* decode the alarm enable field */
197
198 if (alm_en & S3C2410_RTCALM_SECEN) {
199 BCD_TO_BIN(alm_tm->tm_sec);
200 } else {
201 alm_tm->tm_sec = 0xff;
202 }
203
204 if (alm_en & S3C2410_RTCALM_MINEN) {
205 BCD_TO_BIN(alm_tm->tm_min);
206 } else {
207 alm_tm->tm_min = 0xff;
208 }
209
210 if (alm_en & S3C2410_RTCALM_HOUREN) {
211 BCD_TO_BIN(alm_tm->tm_hour);
212 } else {
213 alm_tm->tm_hour = 0xff;
214 }
215
216 if (alm_en & S3C2410_RTCALM_DAYEN) {
217 BCD_TO_BIN(alm_tm->tm_mday);
218 } else {
219 alm_tm->tm_mday = 0xff;
220 }
221
222 if (alm_en & S3C2410_RTCALM_MONEN) {
223 BCD_TO_BIN(alm_tm->tm_mon);
224 alm_tm->tm_mon -= 1;
225 } else {
226 alm_tm->tm_mon = 0xff;
227 }
228
229 if (alm_en & S3C2410_RTCALM_YEAREN) {
230 BCD_TO_BIN(alm_tm->tm_year);
231 } else {
232 alm_tm->tm_year = 0xffff;
233 }
234
235 /* todo - set alrm->enabled ? */
236
237 return 0;
238}
239
240static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
241{
242 struct rtc_time *tm = &alrm->time;
243 unsigned int alrm_en;
244
245 pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
246 alrm->enabled,
247 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
248 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
249
250 if (alrm->enabled || 1) {
251 alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
252 writeb(0x00, S3C2410_RTCALM);
253
254 if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
255 alrm_en |= S3C2410_RTCALM_SECEN;
256 writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
257 }
258
259 if (tm->tm_min < 60 && tm->tm_min >= 0) {
260 alrm_en |= S3C2410_RTCALM_MINEN;
261 writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
262 }
263
264 if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
265 alrm_en |= S3C2410_RTCALM_HOUREN;
266 writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
267 }
268
269 pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
270
271 writeb(alrm_en, S3C2410_RTCALM);
272 enable_irq_wake(s3c2410_rtc_alarmno);
273 } else {
274 alrm_en = readb(S3C2410_RTCALM);
275 alrm_en &= ~S3C2410_RTCALM_ALMEN;
276 writeb(alrm_en, S3C2410_RTCALM);
277 disable_irq_wake(s3c2410_rtc_alarmno);
278 }
279
280 return 0;
281}
282
283static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
284{
285 switch (cmd) {
286 case RTC_AIE_OFF:
287 case RTC_AIE_ON:
288 s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
289 return 0;
290
291 case RTC_PIE_OFF:
292 case RTC_PIE_ON:
293 s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
294 return 0;
295
296 case RTC_IRQP_READ:
297 return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);
298
299 case RTC_IRQP_SET:
300 if (arg < 1 || arg > 64)
301 return -EINVAL;
302
303 if (!capable(CAP_SYS_RESOURCE))
304 return -EACCES;
305
306 /* check for power of 2 */
307
308 if ((arg & (arg-1)) != 0)
309 return -EINVAL;
310
311 pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
312
313 s3c2410_rtc_setfreq(arg);
314 return 0;
315
316 case RTC_UIE_ON:
317 case RTC_UIE_OFF:
318 return -EINVAL;
319 }
320
321 return -EINVAL;
322}
323
324static int s3c2410_rtc_proc(char *buf)
325{
326 unsigned int rtcalm = readb(S3C2410_RTCALM);
327 unsigned int ticnt = readb (S3C2410_TICNT);
328 char *p = buf;
329
330 p += sprintf(p, "alarm_IRQ\t: %s\n",
331 (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
332 p += sprintf(p, "periodic_IRQ\t: %s\n",
333 (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
334 p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);
335
336 return p - buf;
337}
338
339static int s3c2410_rtc_open(void)
340{
341 int ret;
342
343 ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
344 IRQF_DISABLED, "s3c2410-rtc alarm", NULL);
345
346 if (ret)
347 printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);
348
349 ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
350 IRQF_DISABLED, "s3c2410-rtc tick", NULL);
351
352 if (ret) {
353 printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
354 goto tick_err;
355 }
356
357 return ret;
358
359 tick_err:
360 free_irq(s3c2410_rtc_alarmno, NULL);
361 return ret;
362}
363
364static void s3c2410_rtc_release(void)
365{
366 /* do not clear AIE here, it may be needed for wake */
367
368 s3c2410_rtc_setpie(0);
369 free_irq(s3c2410_rtc_alarmno, NULL);
370 free_irq(s3c2410_rtc_tickno, NULL);
371}
372
373static struct rtc_ops s3c2410_rtcops = {
374 .owner = THIS_MODULE,
375 .open = s3c2410_rtc_open,
376 .release = s3c2410_rtc_release,
377 .ioctl = s3c2410_rtc_ioctl,
378 .read_time = s3c2410_rtc_gettime,
379 .set_time = s3c2410_rtc_settime,
380 .read_alarm = s3c2410_rtc_getalarm,
381 .set_alarm = s3c2410_rtc_setalarm,
382 .proc = s3c2410_rtc_proc,
383};
384
385static void s3c2410_rtc_enable(struct platform_device *pdev, int en)
386{
387 unsigned int tmp;
388
389 if (s3c2410_rtc_base == NULL)
390 return;
391
392 if (!en) {
393 tmp = readb(S3C2410_RTCCON);
394 writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
395
396 tmp = readb(S3C2410_TICNT);
397 writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
398 } else {
399 /* re-enable the device, and check it is ok */
400
401 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
402 dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
403
404 tmp = readb(S3C2410_RTCCON);
405 writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
406 }
407
408 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
409 dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n");
410
411 tmp = readb(S3C2410_RTCCON);
412 writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
413 }
414
415 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
416 dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n");
417
418 tmp = readb(S3C2410_RTCCON);
419 writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
420 }
421 }
422}
423
424static int s3c2410_rtc_remove(struct platform_device *dev)
425{
426 unregister_rtc(&s3c2410_rtcops);
427
428 s3c2410_rtc_setpie(0);
429 s3c2410_rtc_setaie(0);
430
431 if (s3c2410_rtc_mem != NULL) {
432 pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
433 iounmap(s3c2410_rtc_base);
434 release_resource(s3c2410_rtc_mem);
435 kfree(s3c2410_rtc_mem);
436 }
437
438 return 0;
439}
440
441static int s3c2410_rtc_probe(struct platform_device *pdev)
442{
443 struct resource *res;
444 int ret;
445
446 pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
447
448 /* find the IRQs */
449
450 s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
451 if (s3c2410_rtc_tickno < 0) {
452 dev_err(&pdev->dev, "no irq for rtc tick\n");
453 return -ENOENT;
454 }
455
456 s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
457 if (s3c2410_rtc_alarmno < 0) {
458 dev_err(&pdev->dev, "no irq for alarm\n");
459 return -ENOENT;
460 }
461
462 pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
463 s3c2410_rtc_tickno, s3c2410_rtc_alarmno);
464
465 /* get the memory region */
466
467 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
468 if (res == NULL) {
469 dev_err(&pdev->dev, "failed to get memory region resource\n");
470 return -ENOENT;
471 }
472
473 s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
474 pdev->name);
475
476 if (s3c2410_rtc_mem == NULL) {
477 dev_err(&pdev->dev, "failed to reserve memory region\n");
478 ret = -ENOENT;
479 goto exit_err;
480 }
481
482 s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
483 if (s3c2410_rtc_base == NULL) {
484 dev_err(&pdev->dev, "failed ioremap()\n");
485 ret = -EINVAL;
486 goto exit_err;
487 }
488
489 s3c2410_rtc_mem = res;
490 pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);
491
492 pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
493
494 /* check to see if everything is setup correctly */
495
496 s3c2410_rtc_enable(pdev, 1);
497
498 pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
499
500 s3c2410_rtc_setfreq(s3c2410_rtc_freq);
501
502 /* register RTC and exit */
503
504 register_rtc(&s3c2410_rtcops);
505 return 0;
506
507 exit_err:
508 dev_err(&pdev->dev, "error %d during initialisation\n", ret);
509
510 return ret;
511}
512
513#ifdef CONFIG_PM
514
515/* S3C2410 RTC Power management control */
516
517static struct timespec s3c2410_rtc_delta;
518
519static int ticnt_save;
520
521static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state)
522{
523 struct rtc_time tm;
524 struct timespec time;
525
526 time.tv_nsec = 0;
527
528 /* save TICNT for anyone using periodic interrupts */
529
530 ticnt_save = readb(S3C2410_TICNT);
531
532 /* calculate time delta for suspend */
533
534 s3c2410_rtc_gettime(&tm);
535 rtc_tm_to_time(&tm, &time.tv_sec);
536 save_time_delta(&s3c2410_rtc_delta, &time);
537 s3c2410_rtc_enable(pdev, 0);
538
539 return 0;
540}
541
542static int s3c2410_rtc_resume(struct platform_device *pdev)
543{
544 struct rtc_time tm;
545 struct timespec time;
546
547 time.tv_nsec = 0;
548
549 s3c2410_rtc_enable(pdev, 1);
550 s3c2410_rtc_gettime(&tm);
551 rtc_tm_to_time(&tm, &time.tv_sec);
552 restore_time_delta(&s3c2410_rtc_delta, &time);
553
554 writeb(ticnt_save, S3C2410_TICNT);
555 return 0;
556}
557#else
558#define s3c2410_rtc_suspend NULL
559#define s3c2410_rtc_resume NULL
560#endif
561
562static struct platform_driver s3c2410_rtcdrv = {
563 .probe = s3c2410_rtc_probe,
564 .remove = s3c2410_rtc_remove,
565 .suspend = s3c2410_rtc_suspend,
566 .resume = s3c2410_rtc_resume,
567 .driver = {
568 .name = "s3c2410-rtc",
569 .owner = THIS_MODULE,
570 },
571};
572
573static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
574
575static int __init s3c2410_rtc_init(void)
576{
577 printk(banner);
578 return platform_driver_register(&s3c2410_rtcdrv);
579}
580
581static void __exit s3c2410_rtc_exit(void)
582{
583 platform_driver_unregister(&s3c2410_rtcdrv);
584}
585
586module_init(s3c2410_rtc_init);
587module_exit(s3c2410_rtc_exit);
588
589MODULE_DESCRIPTION("S3C24XX RTC Driver");
590MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
591MODULE_LICENSE("GPL");