aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2008-02-06 04:38:59 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-06 13:41:14 -0500
commit4cdf854f7d60498bbda436068a118b95059b244b (patch)
treee7d5169176a48a9b5dd980baa42c9083244736e7
parentf618258ad8af0413f08af60bd0eb050562e700fa (diff)
rtc: at91sam9 RTC support (RTT and/or RTC)
AT91sam9 RTC support, primarily in the form of an RTT-as-RTC driver that was extracted from 2.6.23-at91 patch and updated: - Relies on now-merged platform updates, which associate the RTT hardware address with each RTT and use the "at91_rtt" name. - RTC framework related fixes and cleanups, notably: * removed now-needless suspend/resume clock offset logic * alarm read/write now respects the "enabled" flag * suspend always disables update irqs * shutdown (and startup) disables all irqs - Misc cleanup: * use dev_*() messaging * add comments * remove globals, * ... etc - Don't force use of RTT0 and GPBR0. Either resource may need to be used for other purposes (like NO_HZ support). - Update "AT91RM9200 RTC" Kconfig to allow it on SAM9RL chips (it has both RTT and RTC). Driver binding uses bus_find_device() to avoid needing any kind of "timer library" code when there's more than one RTT module. (This timer can be used as an RTC, to support NO_HZ operation, or potentially for other stuff. The choice is a per-system policy.) Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Cc: Michel Benoit <murpme@gmail.com> Cc: Nicolas Ferre <nicolas.ferre@rfo.atmel.com> Cc: Andrew Victor <linux@maxim.org.za> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rtc/Kconfig45
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-at91sam9.c520
3 files changed, 562 insertions, 4 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 484de8e4c5ae..6402d699072b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -469,10 +469,47 @@ config RTC_DRV_AT32AP700X
469 AT32AP700x family processors. 469 AT32AP700x family processors.
470 470
471config RTC_DRV_AT91RM9200 471config RTC_DRV_AT91RM9200
472 tristate "AT91RM9200" 472 tristate "AT91RM9200 or AT91SAM9RL"
473 depends on ARCH_AT91RM9200 473 depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL
474 help 474 help
475 Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock). 475 Driver for the internal RTC (Realtime Clock) module found on
476 Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips
477 this is powered by the backup power supply.
478
479config RTC_DRV_AT91SAM9
480 tristate "AT91SAM9x"
481 depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
482 help
483 RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer).
484 These timers are powered by the backup power supply (such as a
485 small coin cell battery), but do not need to be used as RTCs.
486
487 (On AT91SAM9rl chips you probably want to use the dedicated RTC
488 module and leave the RTT available for other uses.)
489
490config RTC_DRV_AT91SAM9_RTT
491 int
492 range 0 1
493 default 0
494 prompt "RTT module Number" if ARCH_AT91SAM9263
495 depends on RTC_DRV_AT91SAM9
496 help
497 More than one RTT module is available. You can choose which
498 one will be used as an RTC. The default of zero is normally
499 OK to use, though some systems use that for non-RTC purposes.
500
501config RTC_DRV_AT91SAM9_GPBR
502 int
503 range 0 3 if !ARCH_AT91SAM9263
504 range 0 15 if ARCH_AT91SAM9263
505 default 0
506 prompt "Backup Register Number"
507 depends on RTC_DRV_AT91SAM9
508 help
509 The RTC driver needs to use one of the General Purpose Backup
510 Registers (GPBRs) as well as the RTT. You can choose which one
511 will be used. The default of zero is normally OK to use, but
512 on some systems other software needs to use that register.
476 513
477config RTC_DRV_BFIN 514config RTC_DRV_BFIN
478 tristate "Blackfin On-Chip RTC" 515 tristate "Blackfin On-Chip RTC"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 81f7c9a05a4a..ec703f34ab86 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,6 +19,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
19 19
20obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o 20obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
21obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o 21obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
22obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
22obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o 23obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
23obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o 24obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
24obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o 25obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
new file mode 100644
index 000000000000..bbf10ecf416c
--- /dev/null
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -0,0 +1,520 @@
1/*
2 * "RTT as Real Time Clock" driver for AT91SAM9 SoC family
3 *
4 * (C) 2007 Michel Benoit
5 *
6 * Based on rtc-at91rm9200.c by Rick Bronson
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/platform_device.h>
17#include <linux/time.h>
18#include <linux/rtc.h>
19#include <linux/interrupt.h>
20#include <linux/ioctl.h>
21
22#include <asm/mach/time.h>
23#include <asm/arch/board.h>
24#include <asm/arch/at91_rtt.h>
25
26
27/*
28 * This driver uses two configurable hardware resources that live in the
29 * AT91SAM9 backup power domain (intended to be powered at all times)
30 * to implement the Real Time Clock interfaces
31 *
32 * - A "Real-time Timer" (RTT) counts up in seconds from a base time.
33 * We can't assign the counter value (CRTV) ... but we can reset it.
34 *
35 * - One of the "General Purpose Backup Registers" (GPBRs) holds the
36 * base time, normally an offset from the beginning of the POSIX
37 * epoch (1970-Jan-1 00:00:00 UTC). Some systems also include the
38 * local timezone's offset.
39 *
40 * The RTC's value is the RTT counter plus that offset. The RTC's alarm
41 * is likewise a base (ALMV) plus that offset.
42 *
43 * Not all RTTs will be used as RTCs; some systems have multiple RTTs to
44 * choose from, or a "real" RTC module. All systems have multiple GPBR
45 * registers available, likewise usable for more than "RTC" support.
46 */
47
48/*
49 * We store ALARM_DISABLED in ALMV to record that no alarm is set.
50 * It's also the reset value for that field.
51 */
52#define ALARM_DISABLED ((u32)~0)
53
54
55struct sam9_rtc {
56 void __iomem *rtt;
57 struct rtc_device *rtcdev;
58 u32 imr;
59};
60
61#define rtt_readl(rtc, field) \
62 __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
63#define rtt_writel(rtc, field, val) \
64 __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
65
66#define gpbr_readl(rtc) \
67 at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
68#define gpbr_writel(rtc, val) \
69 at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
70
71/*
72 * Read current time and date in RTC
73 */
74static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
75{
76 struct sam9_rtc *rtc = dev_get_drvdata(dev);
77 u32 secs, secs2;
78 u32 offset;
79
80 /* read current time offset */
81 offset = gpbr_readl(rtc);
82 if (offset == 0)
83 return -EILSEQ;
84
85 /* reread the counter to help sync the two clock domains */
86 secs = rtt_readl(rtc, VR);
87 secs2 = rtt_readl(rtc, VR);
88 if (secs != secs2)
89 secs = rtt_readl(rtc, VR);
90
91 rtc_time_to_tm(offset + secs, tm);
92
93 dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime",
94 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
95 tm->tm_hour, tm->tm_min, tm->tm_sec);
96
97 return 0;
98}
99
100/*
101 * Set current time and date in RTC
102 */
103static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
104{
105 struct sam9_rtc *rtc = dev_get_drvdata(dev);
106 int err;
107 u32 offset, alarm, mr;
108 unsigned long secs;
109
110 dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
111 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
112 tm->tm_hour, tm->tm_min, tm->tm_sec);
113
114 err = rtc_tm_to_time(tm, &secs);
115 if (err != 0)
116 return err;
117
118 mr = rtt_readl(rtc, MR);
119
120 /* disable interrupts */
121 rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
122
123 /* read current time offset */
124 offset = gpbr_readl(rtc);
125
126 /* store the new base time in a battery backup register */
127 secs += 1;
128 gpbr_writel(rtc, secs);
129
130 /* adjust the alarm time for the new base */
131 alarm = rtt_readl(rtc, AR);
132 if (alarm != ALARM_DISABLED) {
133 if (offset > secs) {
134 /* time jumped backwards, increase time until alarm */
135 alarm += (offset - secs);
136 } else if ((alarm + offset) > secs) {
137 /* time jumped forwards, decrease time until alarm */
138 alarm -= (secs - offset);
139 } else {
140 /* time jumped past the alarm, disable alarm */
141 alarm = ALARM_DISABLED;
142 mr &= ~AT91_RTT_ALMIEN;
143 }
144 rtt_writel(rtc, AR, alarm);
145 }
146
147 /* reset the timer, and re-enable interrupts */
148 rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
149
150 return 0;
151}
152
153static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
154{
155 struct sam9_rtc *rtc = dev_get_drvdata(dev);
156 struct rtc_time *tm = &alrm->time;
157 u32 alarm = rtt_readl(rtc, AR);
158 u32 offset;
159
160 offset = gpbr_readl(rtc);
161 if (offset == 0)
162 return -EILSEQ;
163
164 memset(alrm, 0, sizeof(alrm));
165 if (alarm != ALARM_DISABLED && offset != 0) {
166 rtc_time_to_tm(offset + alarm, tm);
167
168 dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm",
169 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
170 tm->tm_hour, tm->tm_min, tm->tm_sec);
171
172 if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN)
173 alrm->enabled = 1;
174 }
175
176 return 0;
177}
178
179static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
180{
181 struct sam9_rtc *rtc = dev_get_drvdata(dev);
182 struct rtc_time *tm = &alrm->time;
183 unsigned long secs;
184 u32 offset;
185 u32 mr;
186 int err;
187
188 err = rtc_tm_to_time(tm, &secs);
189 if (err != 0)
190 return err;
191
192 offset = gpbr_readl(rtc);
193 if (offset == 0) {
194 /* time is not set */
195 return -EILSEQ;
196 }
197 mr = rtt_readl(rtc, MR);
198 rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
199
200 /* alarm in the past? finish and leave disabled */
201 if (secs <= offset) {
202 rtt_writel(rtc, AR, ALARM_DISABLED);
203 return 0;
204 }
205
206 /* else set alarm and maybe enable it */
207 rtt_writel(rtc, AR, secs - offset);
208 if (alrm->enabled)
209 rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
210
211 dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm",
212 tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
213 tm->tm_min, tm->tm_sec);
214
215 return 0;
216}
217
218/*
219 * Handle commands from user-space
220 */
221static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
222 unsigned long arg)
223{
224 struct sam9_rtc *rtc = dev_get_drvdata(dev);
225 int ret = 0;
226 u32 mr = rtt_readl(rtc, MR);
227
228 dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr);
229
230 switch (cmd) {
231 case RTC_AIE_OFF: /* alarm off */
232 rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN);
233 break;
234 case RTC_AIE_ON: /* alarm on */
235 rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN);
236 break;
237 case RTC_UIE_OFF: /* update off */
238 rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
239 break;
240 case RTC_UIE_ON: /* update on */
241 rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN);
242 break;
243 default:
244 ret = -ENOIOCTLCMD;
245 break;
246 }
247
248 return ret;
249}
250
251/*
252 * Provide additional RTC information in /proc/driver/rtc
253 */
254static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
255{
256 struct sam9_rtc *rtc = dev_get_drvdata(dev);
257 u32 mr = mr = rtt_readl(rtc, MR);
258
259 seq_printf(seq, "update_IRQ\t: %s\n",
260 (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
261 return 0;
262}
263
264/*
265 * IRQ handler for the RTC
266 */
267static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc)
268{
269 struct sam9_rtc *rtc = _rtc;
270 u32 sr, mr;
271 unsigned long events = 0;
272
273 /* Shared interrupt may be for another device. Note: reading
274 * SR clears it, so we must only read it in this irq handler!
275 */
276 mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
277 sr = rtt_readl(rtc, SR) & mr;
278 if (!sr)
279 return IRQ_NONE;
280
281 /* alarm status */
282 if (sr & AT91_RTT_ALMS)
283 events |= (RTC_AF | RTC_IRQF);
284
285 /* timer update/increment */
286 if (sr & AT91_RTT_RTTINC)
287 events |= (RTC_UF | RTC_IRQF);
288
289 rtc_update_irq(rtc->rtcdev, 1, events);
290
291 pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__,
292 events >> 8, events & 0x000000FF);
293
294 return IRQ_HANDLED;
295}
296
297static const struct rtc_class_ops at91_rtc_ops = {
298 .ioctl = at91_rtc_ioctl,
299 .read_time = at91_rtc_readtime,
300 .set_time = at91_rtc_settime,
301 .read_alarm = at91_rtc_readalarm,
302 .set_alarm = at91_rtc_setalarm,
303 .proc = at91_rtc_proc,
304};
305
306/*
307 * Initialize and install RTC driver
308 */
309static int __init at91_rtc_probe(struct platform_device *pdev)
310{
311 struct resource *r;
312 struct sam9_rtc *rtc;
313 int ret;
314 u32 mr;
315
316 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
317 if (!r)
318 return -ENODEV;
319
320 rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
321 if (!rtc)
322 return -ENOMEM;
323
324 platform_set_drvdata(pdev, rtc);
325 rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
326 rtc->rtt += r->start;
327
328 mr = rtt_readl(rtc, MR);
329
330 /* unless RTT is counting at 1 Hz, re-initialize it */
331 if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
332 mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
333 gpbr_writel(rtc, 0);
334 }
335
336 /* disable all interrupts (same as on shutdown path) */
337 mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
338 rtt_writel(rtc, MR, mr);
339
340 rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
341 &at91_rtc_ops, THIS_MODULE);
342 if (IS_ERR(rtc->rtcdev)) {
343 ret = PTR_ERR(rtc->rtcdev);
344 goto fail;
345 }
346
347 /* register irq handler after we know what name we'll use */
348 ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
349 IRQF_DISABLED | IRQF_SHARED,
350 rtc->rtcdev->dev.bus_id, rtc);
351 if (ret) {
352 dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
353 rtc_device_unregister(rtc->rtcdev);
354 goto fail;
355 }
356
357 /* NOTE: sam9260 rev A silicon has a ROM bug which resets the
358 * RTT on at least some reboots. If you have that chip, you must
359 * initialize the time from some external source like a GPS, wall
360 * clock, discrete RTC, etc
361 */
362
363 if (gpbr_readl(rtc) == 0)
364 dev_warn(&pdev->dev, "%s: SET TIME!\n",
365 rtc->rtcdev->dev.bus_id);
366
367 return 0;
368
369fail:
370 platform_set_drvdata(pdev, NULL);
371 kfree(rtc);
372 return ret;
373}
374
375/*
376 * Disable and remove the RTC driver
377 */
378static int __exit at91_rtc_remove(struct platform_device *pdev)
379{
380 struct sam9_rtc *rtc = platform_get_drvdata(pdev);
381 u32 mr = rtt_readl(rtc, MR);
382
383 /* disable all interrupts */
384 rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
385 free_irq(AT91_ID_SYS, rtc);
386
387 rtc_device_unregister(rtc->rtcdev);
388
389 platform_set_drvdata(pdev, NULL);
390 kfree(rtc);
391 return 0;
392}
393
394static void at91_rtc_shutdown(struct platform_device *pdev)
395{
396 struct sam9_rtc *rtc = platform_get_drvdata(pdev);
397 u32 mr = rtt_readl(rtc, MR);
398
399 rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
400 rtt_writel(rtc, MR, mr & ~rtc->imr);
401}
402
403#ifdef CONFIG_PM
404
405/* AT91SAM9 RTC Power management control */
406
407static int at91_rtc_suspend(struct platform_device *pdev,
408 pm_message_t state)
409{
410 struct sam9_rtc *rtc = platform_get_drvdata(pdev);
411 u32 mr = rtt_readl(rtc, MR);
412
413 /*
414 * This IRQ is shared with DBGU and other hardware which isn't
415 * necessarily a wakeup event source.
416 */
417 rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
418 if (rtc->imr) {
419 if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
420 enable_irq_wake(AT91_ID_SYS);
421 /* don't let RTTINC cause wakeups */
422 if (mr & AT91_RTT_RTTINCIEN)
423 rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
424 } else
425 rtt_writel(rtc, MR, mr & ~rtc->imr);
426 }
427
428 return 0;
429}
430
431static int at91_rtc_resume(struct platform_device *pdev)
432{
433 struct sam9_rtc *rtc = platform_get_drvdata(pdev);
434 u32 mr;
435
436 if (rtc->imr) {
437 if (device_may_wakeup(&pdev->dev))
438 disable_irq_wake(AT91_ID_SYS);
439 mr = rtt_readl(rtc, MR);
440 rtt_writel(rtc, MR, mr | rtc->imr);
441 }
442
443 return 0;
444}
445#else
446#define at91_rtc_suspend NULL
447#define at91_rtc_resume NULL
448#endif
449
450static struct platform_driver at91_rtc_driver = {
451 .driver.name = "rtc-at91sam9",
452 .driver.owner = THIS_MODULE,
453 .remove = __exit_p(at91_rtc_remove),
454 .shutdown = at91_rtc_shutdown,
455 .suspend = at91_rtc_suspend,
456 .resume = at91_rtc_resume,
457};
458
459/* Chips can have more than one RTT module, and they can be used for more
460 * than just RTCs. So we can't just register as "the" RTT driver.
461 *
462 * A normal approach in such cases is to create a library to allocate and
463 * free the modules. Here we just use bus_find_device() as like such a
464 * library, binding directly ... no runtime "library" footprint is needed.
465 */
466static int __init at91_rtc_match(struct device *dev, void *v)
467{
468 struct platform_device *pdev = to_platform_device(dev);
469 int ret;
470
471 /* continue searching if this isn't the RTT we need */
472 if (strcmp("at91_rtt", pdev->name) != 0
473 || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
474 goto fail;
475
476 /* else we found it ... but fail unless we can bind to the RTC driver */
477 if (dev->driver) {
478 dev_dbg(dev, "busy, can't use as RTC!\n");
479 goto fail;
480 }
481 dev->driver = &at91_rtc_driver.driver;
482 if (device_attach(dev) == 0) {
483 dev_dbg(dev, "can't attach RTC!\n");
484 goto fail;
485 }
486 ret = at91_rtc_probe(pdev);
487 if (ret == 0)
488 return true;
489
490 dev_dbg(dev, "RTC probe err %d!\n", ret);
491fail:
492 return false;
493}
494
495static int __init at91_rtc_init(void)
496{
497 int status;
498 struct device *rtc;
499
500 status = platform_driver_register(&at91_rtc_driver);
501 if (status)
502 return status;
503 rtc = bus_find_device(&platform_bus_type, NULL,
504 NULL, at91_rtc_match);
505 if (!rtc)
506 platform_driver_unregister(&at91_rtc_driver);
507 return rtc ? 0 : -ENODEV;
508}
509module_init(at91_rtc_init);
510
511static void __exit at91_rtc_exit(void)
512{
513 platform_driver_unregister(&at91_rtc_driver);
514}
515module_exit(at91_rtc_exit);
516
517
518MODULE_AUTHOR("Michel Benoit");
519MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
520MODULE_LICENSE("GPL");