blob: b5aaef965f24e904e179a4a579fa4bcafbf92809 [file] [log] [blame]
Greg Ungerer49aa49b2007-10-23 14:37:54 +10001/****************************************************************************/
2
3/*
4 * mcf.c -- Freescale ColdFire UART driver
5 *
6 * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14/****************************************************************************/
15
16#include <linux/kernel.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/module.h>
20#include <linux/console.h>
21#include <linux/tty.h>
22#include <linux/tty_flip.h>
23#include <linux/serial.h>
24#include <linux/serial_core.h>
25#include <linux/io.h>
26#include <asm/coldfire.h>
27#include <asm/mcfsim.h>
28#include <asm/mcfuart.h>
29#include <asm/nettel.h>
30
31/****************************************************************************/
32
33/*
34 * Some boards implement the DTR/DCD lines using GPIO lines, most
35 * don't. Dummy out the access macros for those that don't. Those
36 * that do should define these macros somewhere in there board
37 * specific inlude files.
38 */
39#if !defined(mcf_getppdcd)
40#define mcf_getppdcd(p) (1)
41#endif
42#if !defined(mcf_getppdtr)
43#define mcf_getppdtr(p) (1)
44#endif
45#if !defined(mcf_setppdtr)
46#define mcf_setppdtr(p, v) do { } while (0)
47#endif
48
49/****************************************************************************/
50
51/*
52 * Local per-uart structure.
53 */
54struct mcf_uart {
55 struct uart_port port;
56 unsigned int sigs; /* Local copy of line sigs */
57 unsigned char imr; /* Local IMR mirror */
58};
59
60/****************************************************************************/
61
62static unsigned int mcf_tx_empty(struct uart_port *port)
63{
64 return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
65 TIOCSER_TEMT : 0;
66}
67
68/****************************************************************************/
69
70static unsigned int mcf_get_mctrl(struct uart_port *port)
71{
Greg Ungerer9f69ba82008-02-01 17:38:34 +100072 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +100073 unsigned long flags;
74 unsigned int sigs;
75
76 spin_lock_irqsave(&port->lock, flags);
77 sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
78 0 : TIOCM_CTS;
79 sigs |= (pp->sigs & TIOCM_RTS);
80 sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
81 sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
82 spin_unlock_irqrestore(&port->lock, flags);
83 return sigs;
84}
85
86/****************************************************************************/
87
88static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
89{
Greg Ungerer9f69ba82008-02-01 17:38:34 +100090 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +100091 unsigned long flags;
92
93 spin_lock_irqsave(&port->lock, flags);
94 pp->sigs = sigs;
95 mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
96 if (sigs & TIOCM_RTS)
97 writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
98 else
99 writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
100 spin_unlock_irqrestore(&port->lock, flags);
101}
102
103/****************************************************************************/
104
105static void mcf_start_tx(struct uart_port *port)
106{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000107 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000108 unsigned long flags;
109
110 spin_lock_irqsave(&port->lock, flags);
111 pp->imr |= MCFUART_UIR_TXREADY;
112 writeb(pp->imr, port->membase + MCFUART_UIMR);
113 spin_unlock_irqrestore(&port->lock, flags);
114}
115
116/****************************************************************************/
117
118static void mcf_stop_tx(struct uart_port *port)
119{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000120 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000121 unsigned long flags;
122
123 spin_lock_irqsave(&port->lock, flags);
124 pp->imr &= ~MCFUART_UIR_TXREADY;
125 writeb(pp->imr, port->membase + MCFUART_UIMR);
126 spin_unlock_irqrestore(&port->lock, flags);
127}
128
129/****************************************************************************/
130
131static void mcf_stop_rx(struct uart_port *port)
132{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000133 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000134 unsigned long flags;
135
136 spin_lock_irqsave(&port->lock, flags);
137 pp->imr &= ~MCFUART_UIR_RXREADY;
138 writeb(pp->imr, port->membase + MCFUART_UIMR);
139 spin_unlock_irqrestore(&port->lock, flags);
140}
141
142/****************************************************************************/
143
144static void mcf_break_ctl(struct uart_port *port, int break_state)
145{
146 unsigned long flags;
147
148 spin_lock_irqsave(&port->lock, flags);
149 if (break_state == -1)
150 writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
151 else
152 writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
153 spin_unlock_irqrestore(&port->lock, flags);
154}
155
156/****************************************************************************/
157
158static void mcf_enable_ms(struct uart_port *port)
159{
160}
161
162/****************************************************************************/
163
164static int mcf_startup(struct uart_port *port)
165{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000166 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000167 unsigned long flags;
168
169 spin_lock_irqsave(&port->lock, flags);
170
171 /* Reset UART, get it into known state... */
172 writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
173 writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
174
175 /* Enable the UART transmitter and receiver */
176 writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
177 port->membase + MCFUART_UCR);
178
179 /* Enable RX interrupts now */
180 pp->imr = MCFUART_UIR_RXREADY;
181 writeb(pp->imr, port->membase + MCFUART_UIMR);
182
183 spin_unlock_irqrestore(&port->lock, flags);
184
185 return 0;
186}
187
188/****************************************************************************/
189
190static void mcf_shutdown(struct uart_port *port)
191{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000192 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000193 unsigned long flags;
194
195 spin_lock_irqsave(&port->lock, flags);
196
197 /* Disable all interrupts now */
198 pp->imr = 0;
199 writeb(pp->imr, port->membase + MCFUART_UIMR);
200
201 /* Disable UART transmitter and receiver */
202 writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
203 writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
204
205 spin_unlock_irqrestore(&port->lock, flags);
206}
207
208/****************************************************************************/
209
210static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
211 struct ktermios *old)
212{
213 unsigned long flags;
214 unsigned int baud, baudclk;
John Adamson26a4bc62008-08-22 16:43:49 +1000215#if defined(CONFIG_M5272)
216 unsigned int baudfr;
217#endif
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000218 unsigned char mr1, mr2;
219
220 baud = uart_get_baud_rate(port, termios, old, 0, 230400);
John Adamson26a4bc62008-08-22 16:43:49 +1000221#if defined(CONFIG_M5272)
222 baudclk = (MCF_BUSCLK / baud) / 32;
223 baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
224#else
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000225 baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
John Adamson26a4bc62008-08-22 16:43:49 +1000226#endif
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000227
228 mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
229 mr2 = 0;
230
231 switch (termios->c_cflag & CSIZE) {
232 case CS5: mr1 |= MCFUART_MR1_CS5; break;
233 case CS6: mr1 |= MCFUART_MR1_CS6; break;
234 case CS7: mr1 |= MCFUART_MR1_CS7; break;
235 case CS8:
236 default: mr1 |= MCFUART_MR1_CS8; break;
237 }
238
239 if (termios->c_cflag & PARENB) {
240 if (termios->c_cflag & CMSPAR) {
241 if (termios->c_cflag & PARODD)
242 mr1 |= MCFUART_MR1_PARITYMARK;
243 else
244 mr1 |= MCFUART_MR1_PARITYSPACE;
245 } else {
246 if (termios->c_cflag & PARODD)
247 mr1 |= MCFUART_MR1_PARITYODD;
248 else
249 mr1 |= MCFUART_MR1_PARITYEVEN;
250 }
251 } else {
252 mr1 |= MCFUART_MR1_PARITYNONE;
253 }
254
255 if (termios->c_cflag & CSTOPB)
256 mr2 |= MCFUART_MR2_STOP2;
257 else
258 mr2 |= MCFUART_MR2_STOP1;
259
260 if (termios->c_cflag & CRTSCTS) {
261 mr1 |= MCFUART_MR1_RXRTS;
262 mr2 |= MCFUART_MR2_TXCTS;
263 }
264
265 spin_lock_irqsave(&port->lock, flags);
Philippe De Muyter3732b68f2010-04-02 17:56:08 +0200266 uart_update_timeout(port, termios->c_cflag, baud);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000267 writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
268 writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
269 writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
270 writeb(mr1, port->membase + MCFUART_UMR);
271 writeb(mr2, port->membase + MCFUART_UMR);
272 writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
273 writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
John Adamson26a4bc62008-08-22 16:43:49 +1000274#if defined(CONFIG_M5272)
275 writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
276#endif
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000277 writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
278 port->membase + MCFUART_UCSR);
279 writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
280 port->membase + MCFUART_UCR);
281 spin_unlock_irqrestore(&port->lock, flags);
282}
283
284/****************************************************************************/
285
286static void mcf_rx_chars(struct mcf_uart *pp)
287{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000288 struct uart_port *port = &pp->port;
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000289 unsigned char status, ch, flag;
290
291 while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
292 ch = readb(port->membase + MCFUART_URB);
293 flag = TTY_NORMAL;
294 port->icount.rx++;
295
296 if (status & MCFUART_USR_RXERR) {
297 writeb(MCFUART_UCR_CMDRESETERR,
298 port->membase + MCFUART_UCR);
299
300 if (status & MCFUART_USR_RXBREAK) {
301 port->icount.brk++;
302 if (uart_handle_break(port))
303 continue;
304 } else if (status & MCFUART_USR_RXPARITY) {
305 port->icount.parity++;
306 } else if (status & MCFUART_USR_RXOVERRUN) {
307 port->icount.overrun++;
308 } else if (status & MCFUART_USR_RXFRAMING) {
309 port->icount.frame++;
310 }
311
312 status &= port->read_status_mask;
313
314 if (status & MCFUART_USR_RXBREAK)
315 flag = TTY_BREAK;
316 else if (status & MCFUART_USR_RXPARITY)
317 flag = TTY_PARITY;
318 else if (status & MCFUART_USR_RXFRAMING)
319 flag = TTY_FRAME;
320 }
321
322 if (uart_handle_sysrq_char(port, ch))
323 continue;
324 uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
325 }
326
Alan Coxebd2c8f2009-09-19 13:13:28 -0700327 tty_flip_buffer_push(port->state->port.tty);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000328}
329
330/****************************************************************************/
331
332static void mcf_tx_chars(struct mcf_uart *pp)
333{
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000334 struct uart_port *port = &pp->port;
Alan Coxebd2c8f2009-09-19 13:13:28 -0700335 struct circ_buf *xmit = &port->state->xmit;
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000336
337 if (port->x_char) {
338 /* Send special char - probably flow control */
339 writeb(port->x_char, port->membase + MCFUART_UTB);
340 port->x_char = 0;
341 port->icount.tx++;
342 return;
343 }
344
345 while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
346 if (xmit->head == xmit->tail)
347 break;
348 writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
349 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
350 port->icount.tx++;
351 }
352
353 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
354 uart_write_wakeup(port);
355
356 if (xmit->head == xmit->tail) {
357 pp->imr &= ~MCFUART_UIR_TXREADY;
358 writeb(pp->imr, port->membase + MCFUART_UIMR);
359 }
360}
361
362/****************************************************************************/
363
364static irqreturn_t mcf_interrupt(int irq, void *data)
365{
366 struct uart_port *port = data;
Greg Ungerer9f69ba82008-02-01 17:38:34 +1000367 struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000368 unsigned int isr;
369
370 isr = readb(port->membase + MCFUART_UISR) & pp->imr;
371 if (isr & MCFUART_UIR_RXREADY)
372 mcf_rx_chars(pp);
373 if (isr & MCFUART_UIR_TXREADY)
374 mcf_tx_chars(pp);
375 return IRQ_HANDLED;
376}
377
378/****************************************************************************/
379
380static void mcf_config_port(struct uart_port *port, int flags)
381{
382 port->type = PORT_MCF;
Philippe De Muyter3732b68f2010-04-02 17:56:08 +0200383 port->fifosize = MCFUART_TXFIFOSIZE;
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000384
385 /* Clear mask, so no surprise interrupts. */
386 writeb(0, port->membase + MCFUART_UIMR);
387
388 if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
389 printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
390 "interrupt vector=%d\n", port->line, port->irq);
391}
392
393/****************************************************************************/
394
395static const char *mcf_type(struct uart_port *port)
396{
397 return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
398}
399
400/****************************************************************************/
401
402static int mcf_request_port(struct uart_port *port)
403{
404 /* UARTs always present */
405 return 0;
406}
407
408/****************************************************************************/
409
410static void mcf_release_port(struct uart_port *port)
411{
412 /* Nothing to release... */
413}
414
415/****************************************************************************/
416
417static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
418{
419 if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
420 return -EINVAL;
421 return 0;
422}
423
424/****************************************************************************/
425
426/*
427 * Define the basic serial functions we support.
428 */
Philippe De Muyter3732b68f2010-04-02 17:56:08 +0200429static const struct uart_ops mcf_uart_ops = {
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000430 .tx_empty = mcf_tx_empty,
431 .get_mctrl = mcf_get_mctrl,
432 .set_mctrl = mcf_set_mctrl,
433 .start_tx = mcf_start_tx,
434 .stop_tx = mcf_stop_tx,
435 .stop_rx = mcf_stop_rx,
436 .enable_ms = mcf_enable_ms,
437 .break_ctl = mcf_break_ctl,
438 .startup = mcf_startup,
439 .shutdown = mcf_shutdown,
440 .set_termios = mcf_set_termios,
441 .type = mcf_type,
442 .request_port = mcf_request_port,
443 .release_port = mcf_release_port,
444 .config_port = mcf_config_port,
445 .verify_port = mcf_verify_port,
446};
447
Philippe De Muyter2545cf62010-03-18 11:37:13 +0100448static struct mcf_uart mcf_ports[4];
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000449
Greg Ungerer16791962008-02-04 22:29:56 -0800450#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000451
452/****************************************************************************/
453#if defined(CONFIG_SERIAL_MCF_CONSOLE)
454/****************************************************************************/
455
456int __init early_mcf_setup(struct mcf_platform_uart *platp)
457{
458 struct uart_port *port;
459 int i;
460
461 for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
462 port = &mcf_ports[i].port;
463
464 port->line = i;
465 port->type = PORT_MCF;
466 port->mapbase = platp[i].mapbase;
467 port->membase = (platp[i].membase) ? platp[i].membase :
468 (unsigned char __iomem *) port->mapbase;
469 port->iotype = SERIAL_IO_MEM;
470 port->irq = platp[i].irq;
471 port->uartclk = MCF_BUSCLK;
472 port->flags = ASYNC_BOOT_AUTOCONF;
473 port->ops = &mcf_uart_ops;
474 }
475
476 return 0;
477}
478
479/****************************************************************************/
480
481static void mcf_console_putc(struct console *co, const char c)
482{
483 struct uart_port *port = &(mcf_ports + co->index)->port;
484 int i;
485
486 for (i = 0; (i < 0x10000); i++) {
487 if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
488 break;
489 }
490 writeb(c, port->membase + MCFUART_UTB);
491 for (i = 0; (i < 0x10000); i++) {
492 if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
493 break;
494 }
495}
496
497/****************************************************************************/
498
499static void mcf_console_write(struct console *co, const char *s, unsigned int count)
500{
501 for (; (count); count--, s++) {
502 mcf_console_putc(co, *s);
503 if (*s == '\n')
504 mcf_console_putc(co, '\r');
505 }
506}
507
508/****************************************************************************/
509
510static int __init mcf_console_setup(struct console *co, char *options)
511{
512 struct uart_port *port;
513 int baud = CONFIG_SERIAL_MCF_BAUDRATE;
514 int bits = 8;
515 int parity = 'n';
516 int flow = 'n';
517
Len Sorensen4330e172009-02-05 10:11:24 +1000518 if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000519 co->index = 0;
520 port = &mcf_ports[co->index].port;
521 if (port->membase == 0)
522 return -ENODEV;
523
524 if (options)
525 uart_parse_options(options, &baud, &parity, &bits, &flow);
526
527 return uart_set_options(port, co, baud, parity, bits, flow);
528}
529
530/****************************************************************************/
531
532static struct uart_driver mcf_driver;
533
534static struct console mcf_console = {
535 .name = "ttyS",
536 .write = mcf_console_write,
537 .device = uart_console_device,
538 .setup = mcf_console_setup,
539 .flags = CON_PRINTBUFFER,
540 .index = -1,
541 .data = &mcf_driver,
542};
543
544static int __init mcf_console_init(void)
545{
546 register_console(&mcf_console);
547 return 0;
548}
549
550console_initcall(mcf_console_init);
551
552#define MCF_CONSOLE &mcf_console
553
554/****************************************************************************/
555#else
556/****************************************************************************/
557
558#define MCF_CONSOLE NULL
559
560/****************************************************************************/
561#endif /* CONFIG_MCF_CONSOLE */
562/****************************************************************************/
563
564/*
565 * Define the mcf UART driver structure.
566 */
567static struct uart_driver mcf_driver = {
568 .owner = THIS_MODULE,
569 .driver_name = "mcf",
570 .dev_name = "ttyS",
571 .major = TTY_MAJOR,
572 .minor = 64,
573 .nr = MCF_MAXPORTS,
574 .cons = MCF_CONSOLE,
575};
576
577/****************************************************************************/
578
579static int __devinit mcf_probe(struct platform_device *pdev)
580{
581 struct mcf_platform_uart *platp = pdev->dev.platform_data;
582 struct uart_port *port;
583 int i;
584
585 for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
586 port = &mcf_ports[i].port;
587
588 port->line = i;
589 port->type = PORT_MCF;
590 port->mapbase = platp[i].mapbase;
591 port->membase = (platp[i].membase) ? platp[i].membase :
592 (unsigned char __iomem *) platp[i].mapbase;
593 port->iotype = SERIAL_IO_MEM;
594 port->irq = platp[i].irq;
595 port->uartclk = MCF_BUSCLK;
596 port->ops = &mcf_uart_ops;
597 port->flags = ASYNC_BOOT_AUTOCONF;
598
599 uart_add_one_port(&mcf_driver, port);
600 }
601
602 return 0;
603}
604
605/****************************************************************************/
606
Uwe Kleine-Königd6f80e32009-10-01 10:28:15 +0200607static int __devexit mcf_remove(struct platform_device *pdev)
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000608{
609 struct uart_port *port;
610 int i;
611
612 for (i = 0; (i < MCF_MAXPORTS); i++) {
613 port = &mcf_ports[i].port;
614 if (port)
615 uart_remove_one_port(&mcf_driver, port);
616 }
617
618 return 0;
619}
620
621/****************************************************************************/
622
623static struct platform_driver mcf_platform_driver = {
624 .probe = mcf_probe,
625 .remove = __devexit_p(mcf_remove),
626 .driver = {
627 .name = "mcfuart",
628 .owner = THIS_MODULE,
629 },
630};
631
632/****************************************************************************/
633
634static int __init mcf_init(void)
635{
636 int rc;
637
638 printk("ColdFire internal UART serial driver\n");
639
640 rc = uart_register_driver(&mcf_driver);
641 if (rc)
642 return rc;
643 rc = platform_driver_register(&mcf_platform_driver);
644 if (rc)
645 return rc;
646 return 0;
647}
648
649/****************************************************************************/
650
651static void __exit mcf_exit(void)
652{
653 platform_driver_unregister(&mcf_platform_driver);
654 uart_unregister_driver(&mcf_driver);
655}
656
657/****************************************************************************/
658
659module_init(mcf_init);
660module_exit(mcf_exit);
661
662MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
663MODULE_DESCRIPTION("Freescale ColdFire UART driver");
664MODULE_LICENSE("GPL");
Kay Sieverse169c132008-04-15 14:34:35 -0700665MODULE_ALIAS("platform:mcfuart");
Greg Ungerer49aa49b2007-10-23 14:37:54 +1000666
667/****************************************************************************/