aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-omap.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-12-06 23:38:36 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:39:40 -0500
commitdb68b189f4b8026b2f532e1b1bbdba5fcb36638c (patch)
treeca0327319fb88fc12fa3c46ca1d24f5b5210cd3d /drivers/rtc/rtc-omap.c
parentda015a6744f3648d34b83d1c4e015e6a798b8c56 (diff)
[PATCH] add rtc-omap driver
This creates a new RTC-framework driver for the RTC/calendar module found in various OMAP1 chips. (OMAP2 and OMAP3 use external RTCs, like those in TI's multifunction PM companion chips.) It's been in the Linux-OMAP tree for several months now, and other trees before that, so it's quite stable. The most notable issue is that the OMAP IRQ code doesn't yet support the RTC IRQ as a wakeup event. Once that's fixed, a patch will be needed. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
-rw-r--r--drivers/rtc/rtc-omap.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
new file mode 100644
index 000000000000..eac5fb1fc02f
--- /dev/null
+++ b/drivers/rtc/rtc-omap.c
@@ -0,0 +1,572 @@
1/*
2 * TI OMAP1 Real Time Clock interface for Linux
3 *
4 * Copyright (C) 2003 MontaVista Software, Inc.
5 * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
6 *
7 * Copyright (C) 2006 David Brownell (new RTC framework)
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 */
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/ioport.h>
19#include <linux/delay.h>
20#include <linux/rtc.h>
21#include <linux/bcd.h>
22#include <linux/platform_device.h>
23
24#include <asm/io.h>
25#include <asm/mach/time.h>
26
27
28/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
29 * with century-range alarm matching, driven by the 32kHz clock.
30 *
31 * The main user-visible ways it differs from PC RTCs are by omitting
32 * "don't care" alarm fields and sub-second periodic IRQs, and having
33 * an autoadjust mechanism to calibrate to the true oscillator rate.
34 *
35 * Board-specific wiring options include using split power mode with
36 * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
37 * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
38 * low power modes). See the BOARD-SPECIFIC CUSTOMIZATION comment.
39 */
40
41#define OMAP_RTC_BASE 0xfffb4800
42
43/* RTC registers */
44#define OMAP_RTC_SECONDS_REG 0x00
45#define OMAP_RTC_MINUTES_REG 0x04
46#define OMAP_RTC_HOURS_REG 0x08
47#define OMAP_RTC_DAYS_REG 0x0C
48#define OMAP_RTC_MONTHS_REG 0x10
49#define OMAP_RTC_YEARS_REG 0x14
50#define OMAP_RTC_WEEKS_REG 0x18
51
52#define OMAP_RTC_ALARM_SECONDS_REG 0x20
53#define OMAP_RTC_ALARM_MINUTES_REG 0x24
54#define OMAP_RTC_ALARM_HOURS_REG 0x28
55#define OMAP_RTC_ALARM_DAYS_REG 0x2c
56#define OMAP_RTC_ALARM_MONTHS_REG 0x30
57#define OMAP_RTC_ALARM_YEARS_REG 0x34
58
59#define OMAP_RTC_CTRL_REG 0x40
60#define OMAP_RTC_STATUS_REG 0x44
61#define OMAP_RTC_INTERRUPTS_REG 0x48
62
63#define OMAP_RTC_COMP_LSB_REG 0x4c
64#define OMAP_RTC_COMP_MSB_REG 0x50
65#define OMAP_RTC_OSC_REG 0x54
66
67/* OMAP_RTC_CTRL_REG bit fields: */
68#define OMAP_RTC_CTRL_SPLIT (1<<7)
69#define OMAP_RTC_CTRL_DISABLE (1<<6)
70#define OMAP_RTC_CTRL_SET_32_COUNTER (1<<5)
71#define OMAP_RTC_CTRL_TEST (1<<4)
72#define OMAP_RTC_CTRL_MODE_12_24 (1<<3)
73#define OMAP_RTC_CTRL_AUTO_COMP (1<<2)
74#define OMAP_RTC_CTRL_ROUND_30S (1<<1)
75#define OMAP_RTC_CTRL_STOP (1<<0)
76
77/* OMAP_RTC_STATUS_REG bit fields: */
78#define OMAP_RTC_STATUS_POWER_UP (1<<7)
79#define OMAP_RTC_STATUS_ALARM (1<<6)
80#define OMAP_RTC_STATUS_1D_EVENT (1<<5)
81#define OMAP_RTC_STATUS_1H_EVENT (1<<4)
82#define OMAP_RTC_STATUS_1M_EVENT (1<<3)
83#define OMAP_RTC_STATUS_1S_EVENT (1<<2)
84#define OMAP_RTC_STATUS_RUN (1<<1)
85#define OMAP_RTC_STATUS_BUSY (1<<0)
86
87/* OMAP_RTC_INTERRUPTS_REG bit fields: */
88#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3)
89#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2)
90
91
92#define rtc_read(addr) omap_readb(OMAP_RTC_BASE + (addr))
93#define rtc_write(val, addr) omap_writeb(val, OMAP_RTC_BASE + (addr))
94
95
96/* platform_bus isn't hotpluggable, so for static linkage it'd be safe
97 * to get rid of probe() and remove() code ... too bad the driver struct
98 * remembers probe(), that's about 25% of the runtime footprint!!
99 */
100#ifndef MODULE
101#undef __devexit
102#undef __devexit_p
103#define __devexit __exit
104#define __devexit_p __exit_p
105#endif
106
107
108/* we rely on the rtc framework to handle locking (rtc->ops_lock),
109 * so the only other requirement is that register accesses which
110 * require BUSY to be clear are made with IRQs locally disabled
111 */
112static void rtc_wait_not_busy(void)
113{
114 int count = 0;
115 u8 status;
116
117 /* BUSY may stay active for 1/32768 second (~30 usec) */
118 for (count = 0; count < 50; count++) {
119 status = rtc_read(OMAP_RTC_STATUS_REG);
120 if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0)
121 break;
122 udelay(1);
123 }
124 /* now we have ~15 usec to read/write various registers */
125}
126
127static irqreturn_t rtc_irq(int irq, void *class_dev)
128{
129 unsigned long events = 0;
130 u8 irq_data;
131
132 irq_data = rtc_read(OMAP_RTC_STATUS_REG);
133
134 /* alarm irq? */
135 if (irq_data & OMAP_RTC_STATUS_ALARM) {
136 rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
137 events |= RTC_IRQF | RTC_AF;
138 }
139
140 /* 1/sec periodic/update irq? */
141 if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
142 events |= RTC_IRQF | RTC_UF;
143
144 rtc_update_irq(class_dev, 1, events);
145
146 return IRQ_HANDLED;
147}
148
149#ifdef CONFIG_RTC_INTF_DEV
150
151static int
152omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
153{
154 u8 reg;
155
156 switch (cmd) {
157 case RTC_AIE_OFF:
158 case RTC_AIE_ON:
159 case RTC_UIE_OFF:
160 case RTC_UIE_ON:
161 break;
162 default:
163 return -ENOIOCTLCMD;
164 }
165
166 local_irq_disable();
167 rtc_wait_not_busy();
168 reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
169 switch (cmd) {
170 /* AIE = Alarm Interrupt Enable */
171 case RTC_AIE_OFF:
172 reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
173 break;
174 case RTC_AIE_ON:
175 reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
176 break;
177 /* UIE = Update Interrupt Enable (1/second) */
178 case RTC_UIE_OFF:
179 reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER;
180 break;
181 case RTC_UIE_ON:
182 reg |= OMAP_RTC_INTERRUPTS_IT_TIMER;
183 break;
184 }
185 rtc_wait_not_busy();
186 rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
187 local_irq_enable();
188
189 return 0;
190}
191
192#else
193#define omap_rtc_ioctl NULL
194#endif
195
196/* this hardware doesn't support "don't care" alarm fields */
197static int tm2bcd(struct rtc_time *tm)
198{
199 if (rtc_valid_tm(tm) != 0)
200 return -EINVAL;
201
202 tm->tm_sec = BIN2BCD(tm->tm_sec);
203 tm->tm_min = BIN2BCD(tm->tm_min);
204 tm->tm_hour = BIN2BCD(tm->tm_hour);
205 tm->tm_mday = BIN2BCD(tm->tm_mday);
206
207 tm->tm_mon = BIN2BCD(tm->tm_mon + 1);
208
209 /* epoch == 1900 */
210 if (tm->tm_year < 100 || tm->tm_year > 199)
211 return -EINVAL;
212 tm->tm_year = BIN2BCD(tm->tm_year - 100);
213
214 return 0;
215}
216
217static void bcd2tm(struct rtc_time *tm)
218{
219 tm->tm_sec = BCD2BIN(tm->tm_sec);
220 tm->tm_min = BCD2BIN(tm->tm_min);
221 tm->tm_hour = BCD2BIN(tm->tm_hour);
222 tm->tm_mday = BCD2BIN(tm->tm_mday);
223 tm->tm_mon = BCD2BIN(tm->tm_mon) - 1;
224 /* epoch == 1900 */
225 tm->tm_year = BCD2BIN(tm->tm_year) + 100;
226}
227
228
229static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
230{
231 /* we don't report wday/yday/isdst ... */
232 local_irq_disable();
233 rtc_wait_not_busy();
234
235 tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
236 tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
237 tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
238 tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
239 tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
240 tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);
241
242 local_irq_enable();
243
244 bcd2tm(tm);
245 return 0;
246}
247
248static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
249{
250 if (tm2bcd(tm) < 0)
251 return -EINVAL;
252 local_irq_disable();
253 rtc_wait_not_busy();
254
255 rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
256 rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
257 rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
258 rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
259 rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
260 rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);
261
262 local_irq_enable();
263
264 return 0;
265}
266
267static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
268{
269 local_irq_disable();
270 rtc_wait_not_busy();
271
272 alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG);
273 alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG);
274 alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG);
275 alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG);
276 alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG);
277 alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG);
278
279 local_irq_enable();
280
281 bcd2tm(&alm->time);
282 alm->pending = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
283 & OMAP_RTC_INTERRUPTS_IT_ALARM);
284 alm->enabled = alm->pending && device_may_wakeup(dev);
285
286 return 0;
287}
288
289static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
290{
291 u8 reg;
292
293 /* Much userspace code uses RTC_ALM_SET, thus "don't care" for
294 * day/month/year specifies alarms up to 24 hours in the future.
295 * So we need to handle that ... but let's ignore the "don't care"
296 * values for hours/minutes/seconds.
297 */
298 if (alm->time.tm_mday <= 0
299 && alm->time.tm_mon < 0
300 && alm->time.tm_year < 0) {
301 struct rtc_time tm;
302 unsigned long now, then;
303
304 omap_rtc_read_time(dev, &tm);
305 rtc_tm_to_time(&tm, &now);
306
307 alm->time.tm_mday = tm.tm_mday;
308 alm->time.tm_mon = tm.tm_mon;
309 alm->time.tm_year = tm.tm_year;
310 rtc_tm_to_time(&alm->time, &then);
311
312 /* sometimes the alarm wraps into tomorrow */
313 if (then < now) {
314 rtc_time_to_tm(now + 24 * 60 * 60, &tm);
315 alm->time.tm_mday = tm.tm_mday;
316 alm->time.tm_mon = tm.tm_mon;
317 alm->time.tm_year = tm.tm_year;
318 }
319 }
320
321 if (tm2bcd(&alm->time) < 0)
322 return -EINVAL;
323
324 local_irq_disable();
325 rtc_wait_not_busy();
326
327 rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG);
328 rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
329 rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
330 rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
331 rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
332 rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
333
334 reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
335 if (alm->enabled)
336 reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
337 else
338 reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
339 rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
340
341 local_irq_enable();
342
343 return 0;
344}
345
346static struct rtc_class_ops omap_rtc_ops = {
347 .ioctl = omap_rtc_ioctl,
348 .read_time = omap_rtc_read_time,
349 .set_time = omap_rtc_set_time,
350 .read_alarm = omap_rtc_read_alarm,
351 .set_alarm = omap_rtc_set_alarm,
352};
353
354static int omap_rtc_alarm;
355static int omap_rtc_timer;
356
357static int __devinit omap_rtc_probe(struct platform_device *pdev)
358{
359 struct resource *res, *mem;
360 struct rtc_device *rtc;
361 u8 reg, new_ctrl;
362
363 omap_rtc_timer = platform_get_irq(pdev, 0);
364 if (omap_rtc_timer <= 0) {
365 pr_debug("%s: no update irq?\n", pdev->name);
366 return -ENOENT;
367 }
368
369 omap_rtc_alarm = platform_get_irq(pdev, 1);
370 if (omap_rtc_alarm <= 0) {
371 pr_debug("%s: no alarm irq?\n", pdev->name);
372 return -ENOENT;
373 }
374
375 /* NOTE: using static mapping for RTC registers */
376 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
377 if (res && res->start != OMAP_RTC_BASE) {
378 pr_debug("%s: RTC registers at %08x, expected %08x\n",
379 pdev->name, (unsigned) res->start, OMAP_RTC_BASE);
380 return -ENOENT;
381 }
382
383 if (res)
384 mem = request_mem_region(res->start,
385 res->end - res->start + 1,
386 pdev->name);
387 else
388 mem = NULL;
389 if (!mem) {
390 pr_debug("%s: RTC registers at %08x are not free\n",
391 pdev->name, OMAP_RTC_BASE);
392 return -EBUSY;
393 }
394
395 rtc = rtc_device_register(pdev->name, &pdev->dev,
396 &omap_rtc_ops, THIS_MODULE);
397 if (IS_ERR(rtc)) {
398 pr_debug("%s: can't register RTC device, err %ld\n",
399 pdev->name, PTR_ERR(rtc));
400 goto fail;
401 }
402 platform_set_drvdata(pdev, rtc);
403 class_set_devdata(&rtc->class_dev, mem);
404
405 /* clear pending irqs, and set 1/second periodic,
406 * which we'll use instead of update irqs
407 */
408 rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
409
410 /* clear old status */
411 reg = rtc_read(OMAP_RTC_STATUS_REG);
412 if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
413 pr_info("%s: RTC power up reset detected\n",
414 pdev->name);
415 rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
416 }
417 if (reg & (u8) OMAP_RTC_STATUS_ALARM)
418 rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
419
420 /* handle periodic and alarm irqs */
421 if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT,
422 rtc->class_dev.class_id, &rtc->class_dev)) {
423 pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
424 pdev->name, omap_rtc_timer);
425 goto fail0;
426 }
427 if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT,
428 rtc->class_dev.class_id, &rtc->class_dev)) {
429 pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
430 pdev->name, omap_rtc_alarm);
431 goto fail1;
432 }
433
434 /* On boards with split power, RTC_ON_NOFF won't reset the RTC */
435 reg = rtc_read(OMAP_RTC_CTRL_REG);
436 if (reg & (u8) OMAP_RTC_CTRL_STOP)
437 pr_info("%s: already running\n", pdev->name);
438
439 /* force to 24 hour mode */
440 new_ctrl = reg & ~(OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
441 new_ctrl |= OMAP_RTC_CTRL_STOP;
442
443 /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
444 *
445 * - Boards wired so that RTC_WAKE_INT does something, and muxed
446 * right (W13_1610_RTC_WAKE_INT is the default after chip reset),
447 * should initialize the device wakeup flag appropriately.
448 *
449 * - Boards wired so RTC_ON_nOFF is used as the reset signal,
450 * rather than nPWRON_RESET, should forcibly enable split
451 * power mode. (Some chip errata report that RTC_CTRL_SPLIT
452 * is write-only, and always reads as zero...)
453 */
454 device_init_wakeup(&pdev->dev, 0);
455
456 if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
457 pr_info("%s: split power mode\n", pdev->name);
458
459 if (reg != new_ctrl)
460 rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);
461
462 return 0;
463
464fail1:
465 free_irq(omap_rtc_timer, NULL);
466fail0:
467 rtc_device_unregister(rtc);
468fail:
469 release_resource(mem);
470 return -EIO;
471}
472
473static int __devexit omap_rtc_remove(struct platform_device *pdev)
474{
475 struct rtc_device *rtc = platform_get_drvdata(pdev);;
476
477 device_init_wakeup(&pdev->dev, 0);
478
479 /* leave rtc running, but disable irqs */
480 rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
481
482 free_irq(omap_rtc_timer, rtc);
483 free_irq(omap_rtc_alarm, rtc);
484
485 release_resource(class_get_devdata(&rtc->class_dev));
486 rtc_device_unregister(rtc);
487 return 0;
488}
489
490#ifdef CONFIG_PM
491
492static struct timespec rtc_delta;
493static u8 irqstat;
494
495static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
496{
497 struct rtc_time rtc_tm;
498 struct timespec time;
499
500 time.tv_nsec = 0;
501 omap_rtc_read_time(NULL, &rtc_tm);
502 rtc_tm_to_time(&rtc_tm, &time.tv_sec);
503
504 save_time_delta(&rtc_delta, &time);
505 irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
506
507 /* FIXME the RTC alarm is not currently acting as a wakeup event
508 * source, and in fact this enable() call is just saving a flag
509 * that's never used...
510 */
511 if (device_may_wakeup(&pdev->dev))
512 enable_irq_wake(omap_rtc_alarm);
513 else
514 rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
515
516 return 0;
517}
518
519static int omap_rtc_resume(struct platform_device *pdev)
520{
521 struct rtc_time rtc_tm;
522 struct timespec time;
523
524 time.tv_nsec = 0;
525 omap_rtc_read_time(NULL, &rtc_tm);
526 rtc_tm_to_time(&rtc_tm, &time.tv_sec);
527
528 restore_time_delta(&rtc_delta, &time);
529 if (device_may_wakeup(&pdev->dev))
530 disable_irq_wake(omap_rtc_alarm);
531 else
532 rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
533 return 0;
534}
535
536#else
537#define omap_rtc_suspend NULL
538#define omap_rtc_resume NULL
539#endif
540
541static void omap_rtc_shutdown(struct platform_device *pdev)
542{
543 rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
544}
545
546MODULE_ALIAS("omap_rtc");
547static struct platform_driver omap_rtc_driver = {
548 .probe = omap_rtc_probe,
549 .remove = __devexit_p(omap_rtc_remove),
550 .suspend = omap_rtc_suspend,
551 .resume = omap_rtc_resume,
552 .shutdown = omap_rtc_shutdown,
553 .driver = {
554 .name = "omap_rtc",
555 .owner = THIS_MODULE,
556 },
557};
558
559static int __init rtc_init(void)
560{
561 return platform_driver_register(&omap_rtc_driver);
562}
563module_init(rtc_init);
564
565static void __exit rtc_exit(void)
566{
567 platform_driver_unregister(&omap_rtc_driver);
568}
569module_exit(rtc_exit);
570
571MODULE_AUTHOR("George G. Davis (and others)");
572MODULE_LICENSE("GPL");