aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Dooks <ben@fluff.org.uk>2006-07-01 07:36:26 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-01 12:56:03 -0400
commit1add6781c85d7e2ee512315113a16193b3e3937d (patch)
tree583d64952133fcd3b169f190890369238de6f15c /drivers
parentfa79837d5b562766a3e3cfad4753a3df8e0a1319 (diff)
[PATCH] RTC: class driver for Samsung S3C series SoC
This is a renamed and tested version of the previous S3C24XX RTC class driver. The driver has been renamed from the original s3c2410-rtc, which is now too narrow for the range of devices supported. The rtc-s3c has been chosen as there is the distinct possibility of this driver being carried forward into newer Samsung SoC silicon. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/Kconfig16
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-s3c.c607
3 files changed, 624 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index d51afbe014e5..f5b9f187a930 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -182,6 +182,22 @@ config RTC_DRV_RS5C372
182 This driver can also be built as a module. If so, the module 182 This driver can also be built as a module. If so, the module
183 will be called rtc-rs5c372. 183 will be called rtc-rs5c372.
184 184
185config RTC_DRV_S3C
186 tristate "Samsung S3C series SoC RTC"
187 depends on RTC_CLASS && ARCH_S3C2410
188 help
189 RTC (Realtime Clock) driver for the clock inbuilt into the
190 Samsung S3C24XX series of SoCs. This can provide periodic
191 interrupt rates from 1Hz to 64Hz for user programs, and
192 wakeup from Alarm.
193
194 The driver currently supports the common features on all the
195 S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440
196 and S3C2442.
197
198 This driver can also be build as a module. If so, the module
199 will be called rtc-s3c.
200
185config RTC_DRV_M48T86 201config RTC_DRV_M48T86
186 tristate "ST M48T86/Dallas DS12887" 202 tristate "ST M48T86/Dallas DS12887"
187 depends on RTC_CLASS 203 depends on RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index da5e38774e13..54220714ff49 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
19obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o 19obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
20obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o 20obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
21obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o 21obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
22obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
22obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o 23obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
23obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o 24obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
24obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o 25obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
new file mode 100644
index 000000000000..d6d1bff52b8e
--- /dev/null
+++ b/drivers/rtc/rtc-s3c.c
@@ -0,0 +1,607 @@
1/* drivers/rtc/rtc-s3c.c
2 *
3 * Copyright (c) 2004,2006 Simtec Electronics
4 * Ben Dooks, <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * S3C2410/S3C2440/S3C24XX Internal RTC Driver
12*/
13
14#include <linux/module.h>
15#include <linux/fs.h>
16#include <linux/string.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/interrupt.h>
20#include <linux/rtc.h>
21#include <linux/bcd.h>
22#include <linux/clk.h>
23
24#include <asm/hardware.h>
25#include <asm/uaccess.h>
26#include <asm/io.h>
27#include <asm/irq.h>
28#include <asm/rtc.h>
29
30#include <asm/mach/time.h>
31
32#include <asm/arch/regs-rtc.h>
33
34/* I have yet to find an S3C implementation with more than one
35 * of these rtc blocks in */
36
37static struct resource *s3c_rtc_mem;
38
39static void __iomem *s3c_rtc_base;
40static int s3c_rtc_alarmno = NO_IRQ;
41static int s3c_rtc_tickno = NO_IRQ;
42static int s3c_rtc_freq = 1;
43
44static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
45static unsigned int tick_count;
46
47/* IRQ Handlers */
48
49static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
50{
51 struct rtc_device *rdev = id;
52
53 rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF);
54 return IRQ_HANDLED;
55}
56
57static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r)
58{
59 struct rtc_device *rdev = id;
60
61 rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
62 return IRQ_HANDLED;
63}
64
65/* Update control registers */
66static void s3c_rtc_setaie(int to)
67{
68 unsigned int tmp;
69
70 pr_debug("%s: aie=%d\n", __FUNCTION__, to);
71
72 tmp = readb(S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
73
74 if (to)
75 tmp |= S3C2410_RTCALM_ALMEN;
76
77 writeb(tmp, S3C2410_RTCALM);
78}
79
80static void s3c_rtc_setpie(int to)
81{
82 unsigned int tmp;
83
84 pr_debug("%s: pie=%d\n", __FUNCTION__, to);
85
86 spin_lock_irq(&s3c_rtc_pie_lock);
87 tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
88
89 if (to)
90 tmp |= S3C2410_TICNT_ENABLE;
91
92 writeb(tmp, S3C2410_TICNT);
93 spin_unlock_irq(&s3c_rtc_pie_lock);
94}
95
96static void s3c_rtc_setfreq(int freq)
97{
98 unsigned int tmp;
99
100 spin_lock_irq(&s3c_rtc_pie_lock);
101 tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
102
103 s3c_rtc_freq = freq;
104
105 tmp |= (128 / freq)-1;
106
107 writeb(tmp, S3C2410_TICNT);
108 spin_unlock_irq(&s3c_rtc_pie_lock);
109}
110
111/* Time read/write */
112
113static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
114{
115 unsigned int have_retried = 0;
116
117 retry_get_time:
118 rtc_tm->tm_min = readb(S3C2410_RTCMIN);
119 rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
120 rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
121 rtc_tm->tm_mon = readb(S3C2410_RTCMON);
122 rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
123 rtc_tm->tm_sec = readb(S3C2410_RTCSEC);
124
125 /* the only way to work out wether the system was mid-update
126 * when we read it is to check the second counter, and if it
127 * is zero, then we re-try the entire read
128 */
129
130 if (rtc_tm->tm_sec == 0 && !have_retried) {
131 have_retried = 1;
132 goto retry_get_time;
133 }
134
135 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
136 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
137 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
138
139 BCD_TO_BIN(rtc_tm->tm_sec);
140 BCD_TO_BIN(rtc_tm->tm_min);
141 BCD_TO_BIN(rtc_tm->tm_hour);
142 BCD_TO_BIN(rtc_tm->tm_mday);
143 BCD_TO_BIN(rtc_tm->tm_mon);
144 BCD_TO_BIN(rtc_tm->tm_year);
145
146 rtc_tm->tm_year += 100;
147 rtc_tm->tm_mon -= 1;
148
149 return 0;
150}
151
152static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
153{
154 /* the rtc gets round the y2k problem by just not supporting it */
155
156 if (tm->tm_year < 100)
157 return -EINVAL;
158
159 writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC);
160 writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN);
161 writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
162 writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
163 writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
164 writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
165
166 return 0;
167}
168
169static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
170{
171 struct rtc_time *alm_tm = &alrm->time;
172 unsigned int alm_en;
173
174 alm_tm->tm_sec = readb(S3C2410_ALMSEC);
175 alm_tm->tm_min = readb(S3C2410_ALMMIN);
176 alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
177 alm_tm->tm_mon = readb(S3C2410_ALMMON);
178 alm_tm->tm_mday = readb(S3C2410_ALMDATE);
179 alm_tm->tm_year = readb(S3C2410_ALMYEAR);
180
181 alm_en = readb(S3C2410_RTCALM);
182
183 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
184 alm_en,
185 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
186 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
187
188
189 /* decode the alarm enable field */
190
191 if (alm_en & S3C2410_RTCALM_SECEN)
192 BCD_TO_BIN(alm_tm->tm_sec);
193 else
194 alm_tm->tm_sec = 0xff;
195
196 if (alm_en & S3C2410_RTCALM_MINEN)
197 BCD_TO_BIN(alm_tm->tm_min);
198 else
199 alm_tm->tm_min = 0xff;
200
201 if (alm_en & S3C2410_RTCALM_HOUREN)
202 BCD_TO_BIN(alm_tm->tm_hour);
203 else
204 alm_tm->tm_hour = 0xff;
205
206 if (alm_en & S3C2410_RTCALM_DAYEN)
207 BCD_TO_BIN(alm_tm->tm_mday);
208 else
209 alm_tm->tm_mday = 0xff;
210
211 if (alm_en & S3C2410_RTCALM_MONEN) {
212 BCD_TO_BIN(alm_tm->tm_mon);
213 alm_tm->tm_mon -= 1;
214 } else {
215 alm_tm->tm_mon = 0xff;
216 }
217
218 if (alm_en & S3C2410_RTCALM_YEAREN)
219 BCD_TO_BIN(alm_tm->tm_year);
220 else
221 alm_tm->tm_year = 0xffff;
222
223 return 0;
224}
225
226static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
227{
228 struct rtc_time *tm = &alrm->time;
229 unsigned int alrm_en;
230
231 pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
232 alrm->enabled,
233 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
234 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
235
236
237 alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
238 writeb(0x00, S3C2410_RTCALM);
239
240 if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
241 alrm_en |= S3C2410_RTCALM_SECEN;
242 writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
243 }
244
245 if (tm->tm_min < 60 && tm->tm_min >= 0) {
246 alrm_en |= S3C2410_RTCALM_MINEN;
247 writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
248 }
249
250 if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
251 alrm_en |= S3C2410_RTCALM_HOUREN;
252 writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
253 }
254
255 pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
256
257 writeb(alrm_en, S3C2410_RTCALM);
258
259 if (0) {
260 alrm_en = readb(S3C2410_RTCALM);
261 alrm_en &= ~S3C2410_RTCALM_ALMEN;
262 writeb(alrm_en, S3C2410_RTCALM);
263 disable_irq_wake(s3c_rtc_alarmno);
264 }
265
266 if (alrm->enabled)
267 enable_irq_wake(s3c_rtc_alarmno);
268 else
269 disable_irq_wake(s3c_rtc_alarmno);
270
271 return 0;
272}
273
274static int s3c_rtc_ioctl(struct device *dev,
275 unsigned int cmd, unsigned long arg)
276{
277 unsigned int ret = -ENOIOCTLCMD;
278
279 switch (cmd) {
280 case RTC_AIE_OFF:
281 case RTC_AIE_ON:
282 s3c_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
283 ret = 0;
284 break;
285
286 case RTC_PIE_OFF:
287 case RTC_PIE_ON:
288 tick_count = 0;
289 s3c_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
290 ret = 0;
291 break;
292
293 case RTC_IRQP_READ:
294 ret = put_user(s3c_rtc_freq, (unsigned long __user *)arg);
295 break;
296
297 case RTC_IRQP_SET:
298 /* check for power of 2 */
299
300 if ((arg & (arg-1)) != 0 || arg < 1) {
301 ret = -EINVAL;
302 goto exit;
303 }
304
305 pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
306
307 s3c_rtc_setfreq(arg);
308 ret = 0;
309 break;
310
311 case RTC_UIE_ON:
312 case RTC_UIE_OFF:
313 ret = -EINVAL;
314 }
315
316 exit:
317 return ret;
318}
319
320static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
321{
322 unsigned int rtcalm = readb(S3C2410_RTCALM);
323 unsigned int ticnt = readb (S3C2410_TICNT);
324
325 seq_printf(seq, "alarm_IRQ\t: %s\n",
326 (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
327
328 seq_printf(seq, "periodic_IRQ\t: %s\n",
329 (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
330
331 seq_printf(seq, "periodic_freq\t: %d\n", s3c_rtc_freq);
332
333 return 0;
334}
335
336static int s3c_rtc_open(struct device *dev)
337{
338 struct platform_device *pdev = to_platform_device(dev);
339 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
340 int ret;
341
342 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
343 SA_INTERRUPT, "s3c2410-rtc alarm", rtc_dev);
344
345 if (ret) {
346 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
347 return ret;
348 }
349
350 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
351 SA_INTERRUPT, "s3c2410-rtc tick", rtc_dev);
352
353 if (ret) {
354 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
355 goto tick_err;
356 }
357
358 return ret;
359
360 tick_err:
361 free_irq(s3c_rtc_alarmno, rtc_dev);
362 return ret;
363}
364
365static void s3c_rtc_release(struct device *dev)
366{
367 struct platform_device *pdev = to_platform_device(dev);
368 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
369
370 /* do not clear AIE here, it may be needed for wake */
371
372 s3c_rtc_setpie(0);
373 free_irq(s3c_rtc_alarmno, rtc_dev);
374 free_irq(s3c_rtc_tickno, rtc_dev);
375}
376
377static struct rtc_class_ops s3c_rtcops = {
378 .open = s3c_rtc_open,
379 .release = s3c_rtc_release,
380 .ioctl = s3c_rtc_ioctl,
381 .read_time = s3c_rtc_gettime,
382 .set_time = s3c_rtc_settime,
383 .read_alarm = s3c_rtc_getalarm,
384 .set_alarm = s3c_rtc_setalarm,
385 .proc = s3c_rtc_proc,
386};
387
388static void s3c_rtc_enable(struct platform_device *pdev, int en)
389{
390 unsigned int tmp;
391
392 if (s3c_rtc_base == NULL)
393 return;
394
395 if (!en) {
396 tmp = readb(S3C2410_RTCCON);
397 writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
398
399 tmp = readb(S3C2410_TICNT);
400 writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
401 } else {
402 /* re-enable the device, and check it is ok */
403
404 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
405 dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
406
407 tmp = readb(S3C2410_RTCCON);
408 writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
409 }
410
411 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
412 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
413
414 tmp = readb(S3C2410_RTCCON);
415 writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
416 }
417
418 if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
419 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
420
421 tmp = readb(S3C2410_RTCCON);
422 writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
423 }
424 }
425}
426
427static int s3c_rtc_remove(struct platform_device *dev)
428{
429 struct rtc_device *rtc = platform_get_drvdata(dev);
430
431 platform_set_drvdata(dev, NULL);
432 rtc_device_unregister(rtc);
433
434 s3c_rtc_setpie(0);
435 s3c_rtc_setaie(0);
436
437 iounmap(s3c_rtc_base);
438 release_resource(s3c_rtc_mem);
439 kfree(s3c_rtc_mem);
440
441 return 0;
442}
443
444static int s3c_rtc_probe(struct platform_device *pdev)
445{
446 struct rtc_device *rtc;
447 struct resource *res;
448 int ret;
449
450 pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
451
452 /* find the IRQs */
453
454 s3c_rtc_tickno = platform_get_irq(pdev, 1);
455 if (s3c_rtc_tickno < 0) {
456 dev_err(&pdev->dev, "no irq for rtc tick\n");
457 return -ENOENT;
458 }
459
460 s3c_rtc_alarmno = platform_get_irq(pdev, 0);
461 if (s3c_rtc_alarmno < 0) {
462 dev_err(&pdev->dev, "no irq for alarm\n");
463 return -ENOENT;
464 }
465
466 pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
467 s3c_rtc_tickno, s3c_rtc_alarmno);
468
469 /* get the memory region */
470
471 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
472 if (res == NULL) {
473 dev_err(&pdev->dev, "failed to get memory region resource\n");
474 return -ENOENT;
475 }
476
477 s3c_rtc_mem = request_mem_region(res->start,
478 res->end-res->start+1,
479 pdev->name);
480
481 if (s3c_rtc_mem == NULL) {
482 dev_err(&pdev->dev, "failed to reserve memory region\n");
483 ret = -ENOENT;
484 goto err_nores;
485 }
486
487 s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
488 if (s3c_rtc_base == NULL) {
489 dev_err(&pdev->dev, "failed ioremap()\n");
490 ret = -EINVAL;
491 goto err_nomap;
492 }
493
494 /* check to see if everything is setup correctly */
495
496 s3c_rtc_enable(pdev, 1);
497
498 pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
499
500 s3c_rtc_setfreq(s3c_rtc_freq);
501
502 /* register RTC and exit */
503
504 rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
505 THIS_MODULE);
506
507 if (IS_ERR(rtc)) {
508 dev_err(&pdev->dev, "cannot attach rtc\n");
509 ret = PTR_ERR(rtc);
510 goto err_nortc;
511 }
512
513 rtc->max_user_freq = 128;
514
515 platform_set_drvdata(pdev, rtc);
516 return 0;
517
518 err_nortc:
519 s3c_rtc_enable(pdev, 0);
520 iounmap(s3c_rtc_base);
521
522 err_nomap:
523 release_resource(s3c_rtc_mem);
524
525 err_nores:
526 return ret;
527}
528
529#ifdef CONFIG_PM
530
531/* RTC Power management control */
532
533static struct timespec s3c_rtc_delta;
534
535static int ticnt_save;
536
537static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
538{
539 struct rtc_time tm;
540 struct timespec time;
541
542 time.tv_nsec = 0;
543
544 /* save TICNT for anyone using periodic interrupts */
545
546 ticnt_save = readb(S3C2410_TICNT);
547
548 /* calculate time delta for suspend */
549
550 s3c_rtc_gettime(&pdev->dev, &tm);
551 rtc_tm_to_time(&tm, &time.tv_sec);
552 save_time_delta(&s3c_rtc_delta, &time);
553 s3c_rtc_enable(pdev, 0);
554
555 return 0;
556}
557
558static int s3c_rtc_resume(struct platform_device *pdev)
559{
560 struct rtc_time tm;
561 struct timespec time;
562
563 time.tv_nsec = 0;
564
565 s3c_rtc_enable(pdev, 1);
566 s3c_rtc_gettime(&pdev->dev, &tm);
567 rtc_tm_to_time(&tm, &time.tv_sec);
568 restore_time_delta(&s3c_rtc_delta, &time);
569
570 writeb(ticnt_save, S3C2410_TICNT);
571 return 0;
572}
573#else
574#define s3c_rtc_suspend NULL
575#define s3c_rtc_resume NULL
576#endif
577
578static struct platform_driver s3c2410_rtcdrv = {
579 .probe = s3c_rtc_probe,
580 .remove = s3c_rtc_remove,
581 .suspend = s3c_rtc_suspend,
582 .resume = s3c_rtc_resume,
583 .driver = {
584 .name = "s3c2410-rtc",
585 .owner = THIS_MODULE,
586 },
587};
588
589static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
590
591static int __init s3c_rtc_init(void)
592{
593 printk(banner);
594 return platform_driver_register(&s3c2410_rtcdrv);
595}
596
597static void __exit s3c_rtc_exit(void)
598{
599 platform_driver_unregister(&s3c2410_rtcdrv);
600}
601
602module_init(s3c_rtc_init);
603module_exit(s3c_rtc_exit);
604
605MODULE_DESCRIPTION("Samsung S3C RTC Driver");
606MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
607MODULE_LICENSE("GPL");