diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2011-02-14 13:08:53 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-02-14 13:08:53 -0500 |
commit | b214b7bbffca8ac6a6f1dad46408f7a9d4219098 (patch) | |
tree | 2ef03e062e2a04ea9f2d5439b0daea5274a1bc98 /drivers/tty/serial/mcf.c | |
parent | 7d48ec3698e7b747efa744fd340b0f2d1dbfd3e0 (diff) | |
parent | 100b33c8bd8a3235fd0b7948338d6cbb3db3c63d (diff) |
Merge commit 'v2.6.38-rc4' into spi/next
Diffstat (limited to 'drivers/tty/serial/mcf.c')
-rw-r--r-- | drivers/tty/serial/mcf.c | 662 |
1 files changed, 662 insertions, 0 deletions
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c new file mode 100644 index 000000000000..3394b7cc1722 --- /dev/null +++ b/drivers/tty/serial/mcf.c | |||
@@ -0,0 +1,662 @@ | |||
1 | /****************************************************************************/ | ||
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 | */ | ||
54 | struct 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 | |||
62 | static 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 | |||
70 | static unsigned int mcf_get_mctrl(struct uart_port *port) | ||
71 | { | ||
72 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
73 | unsigned int sigs; | ||
74 | |||
75 | sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? | ||
76 | 0 : TIOCM_CTS; | ||
77 | sigs |= (pp->sigs & TIOCM_RTS); | ||
78 | sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); | ||
79 | sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); | ||
80 | |||
81 | return sigs; | ||
82 | } | ||
83 | |||
84 | /****************************************************************************/ | ||
85 | |||
86 | static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs) | ||
87 | { | ||
88 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
89 | |||
90 | pp->sigs = sigs; | ||
91 | mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); | ||
92 | if (sigs & TIOCM_RTS) | ||
93 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); | ||
94 | else | ||
95 | writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); | ||
96 | } | ||
97 | |||
98 | /****************************************************************************/ | ||
99 | |||
100 | static void mcf_start_tx(struct uart_port *port) | ||
101 | { | ||
102 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
103 | |||
104 | pp->imr |= MCFUART_UIR_TXREADY; | ||
105 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
106 | } | ||
107 | |||
108 | /****************************************************************************/ | ||
109 | |||
110 | static void mcf_stop_tx(struct uart_port *port) | ||
111 | { | ||
112 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
113 | |||
114 | pp->imr &= ~MCFUART_UIR_TXREADY; | ||
115 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
116 | } | ||
117 | |||
118 | /****************************************************************************/ | ||
119 | |||
120 | static void mcf_stop_rx(struct uart_port *port) | ||
121 | { | ||
122 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
123 | |||
124 | pp->imr &= ~MCFUART_UIR_RXREADY; | ||
125 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
126 | } | ||
127 | |||
128 | /****************************************************************************/ | ||
129 | |||
130 | static void mcf_break_ctl(struct uart_port *port, int break_state) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | |||
134 | spin_lock_irqsave(&port->lock, flags); | ||
135 | if (break_state == -1) | ||
136 | writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); | ||
137 | else | ||
138 | writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); | ||
139 | spin_unlock_irqrestore(&port->lock, flags); | ||
140 | } | ||
141 | |||
142 | /****************************************************************************/ | ||
143 | |||
144 | static void mcf_enable_ms(struct uart_port *port) | ||
145 | { | ||
146 | } | ||
147 | |||
148 | /****************************************************************************/ | ||
149 | |||
150 | static int mcf_startup(struct uart_port *port) | ||
151 | { | ||
152 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&port->lock, flags); | ||
156 | |||
157 | /* Reset UART, get it into known state... */ | ||
158 | writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); | ||
159 | writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); | ||
160 | |||
161 | /* Enable the UART transmitter and receiver */ | ||
162 | writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, | ||
163 | port->membase + MCFUART_UCR); | ||
164 | |||
165 | /* Enable RX interrupts now */ | ||
166 | pp->imr = MCFUART_UIR_RXREADY; | ||
167 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
168 | |||
169 | spin_unlock_irqrestore(&port->lock, flags); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /****************************************************************************/ | ||
175 | |||
176 | static void mcf_shutdown(struct uart_port *port) | ||
177 | { | ||
178 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
179 | unsigned long flags; | ||
180 | |||
181 | spin_lock_irqsave(&port->lock, flags); | ||
182 | |||
183 | /* Disable all interrupts now */ | ||
184 | pp->imr = 0; | ||
185 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
186 | |||
187 | /* Disable UART transmitter and receiver */ | ||
188 | writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); | ||
189 | writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); | ||
190 | |||
191 | spin_unlock_irqrestore(&port->lock, flags); | ||
192 | } | ||
193 | |||
194 | /****************************************************************************/ | ||
195 | |||
196 | static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, | ||
197 | struct ktermios *old) | ||
198 | { | ||
199 | unsigned long flags; | ||
200 | unsigned int baud, baudclk; | ||
201 | #if defined(CONFIG_M5272) | ||
202 | unsigned int baudfr; | ||
203 | #endif | ||
204 | unsigned char mr1, mr2; | ||
205 | |||
206 | baud = uart_get_baud_rate(port, termios, old, 0, 230400); | ||
207 | #if defined(CONFIG_M5272) | ||
208 | baudclk = (MCF_BUSCLK / baud) / 32; | ||
209 | baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16; | ||
210 | #else | ||
211 | baudclk = ((MCF_BUSCLK / baud) + 16) / 32; | ||
212 | #endif | ||
213 | |||
214 | mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; | ||
215 | mr2 = 0; | ||
216 | |||
217 | switch (termios->c_cflag & CSIZE) { | ||
218 | case CS5: mr1 |= MCFUART_MR1_CS5; break; | ||
219 | case CS6: mr1 |= MCFUART_MR1_CS6; break; | ||
220 | case CS7: mr1 |= MCFUART_MR1_CS7; break; | ||
221 | case CS8: | ||
222 | default: mr1 |= MCFUART_MR1_CS8; break; | ||
223 | } | ||
224 | |||
225 | if (termios->c_cflag & PARENB) { | ||
226 | if (termios->c_cflag & CMSPAR) { | ||
227 | if (termios->c_cflag & PARODD) | ||
228 | mr1 |= MCFUART_MR1_PARITYMARK; | ||
229 | else | ||
230 | mr1 |= MCFUART_MR1_PARITYSPACE; | ||
231 | } else { | ||
232 | if (termios->c_cflag & PARODD) | ||
233 | mr1 |= MCFUART_MR1_PARITYODD; | ||
234 | else | ||
235 | mr1 |= MCFUART_MR1_PARITYEVEN; | ||
236 | } | ||
237 | } else { | ||
238 | mr1 |= MCFUART_MR1_PARITYNONE; | ||
239 | } | ||
240 | |||
241 | if (termios->c_cflag & CSTOPB) | ||
242 | mr2 |= MCFUART_MR2_STOP2; | ||
243 | else | ||
244 | mr2 |= MCFUART_MR2_STOP1; | ||
245 | |||
246 | if (termios->c_cflag & CRTSCTS) { | ||
247 | mr1 |= MCFUART_MR1_RXRTS; | ||
248 | mr2 |= MCFUART_MR2_TXCTS; | ||
249 | } | ||
250 | |||
251 | spin_lock_irqsave(&port->lock, flags); | ||
252 | uart_update_timeout(port, termios->c_cflag, baud); | ||
253 | writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); | ||
254 | writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); | ||
255 | writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR); | ||
256 | writeb(mr1, port->membase + MCFUART_UMR); | ||
257 | writeb(mr2, port->membase + MCFUART_UMR); | ||
258 | writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1); | ||
259 | writeb((baudclk & 0xff), port->membase + MCFUART_UBG2); | ||
260 | #if defined(CONFIG_M5272) | ||
261 | writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD); | ||
262 | #endif | ||
263 | writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER, | ||
264 | port->membase + MCFUART_UCSR); | ||
265 | writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, | ||
266 | port->membase + MCFUART_UCR); | ||
267 | spin_unlock_irqrestore(&port->lock, flags); | ||
268 | } | ||
269 | |||
270 | /****************************************************************************/ | ||
271 | |||
272 | static void mcf_rx_chars(struct mcf_uart *pp) | ||
273 | { | ||
274 | struct uart_port *port = &pp->port; | ||
275 | unsigned char status, ch, flag; | ||
276 | |||
277 | while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { | ||
278 | ch = readb(port->membase + MCFUART_URB); | ||
279 | flag = TTY_NORMAL; | ||
280 | port->icount.rx++; | ||
281 | |||
282 | if (status & MCFUART_USR_RXERR) { | ||
283 | writeb(MCFUART_UCR_CMDRESETERR, | ||
284 | port->membase + MCFUART_UCR); | ||
285 | |||
286 | if (status & MCFUART_USR_RXBREAK) { | ||
287 | port->icount.brk++; | ||
288 | if (uart_handle_break(port)) | ||
289 | continue; | ||
290 | } else if (status & MCFUART_USR_RXPARITY) { | ||
291 | port->icount.parity++; | ||
292 | } else if (status & MCFUART_USR_RXOVERRUN) { | ||
293 | port->icount.overrun++; | ||
294 | } else if (status & MCFUART_USR_RXFRAMING) { | ||
295 | port->icount.frame++; | ||
296 | } | ||
297 | |||
298 | status &= port->read_status_mask; | ||
299 | |||
300 | if (status & MCFUART_USR_RXBREAK) | ||
301 | flag = TTY_BREAK; | ||
302 | else if (status & MCFUART_USR_RXPARITY) | ||
303 | flag = TTY_PARITY; | ||
304 | else if (status & MCFUART_USR_RXFRAMING) | ||
305 | flag = TTY_FRAME; | ||
306 | } | ||
307 | |||
308 | if (uart_handle_sysrq_char(port, ch)) | ||
309 | continue; | ||
310 | uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); | ||
311 | } | ||
312 | |||
313 | tty_flip_buffer_push(port->state->port.tty); | ||
314 | } | ||
315 | |||
316 | /****************************************************************************/ | ||
317 | |||
318 | static void mcf_tx_chars(struct mcf_uart *pp) | ||
319 | { | ||
320 | struct uart_port *port = &pp->port; | ||
321 | struct circ_buf *xmit = &port->state->xmit; | ||
322 | |||
323 | if (port->x_char) { | ||
324 | /* Send special char - probably flow control */ | ||
325 | writeb(port->x_char, port->membase + MCFUART_UTB); | ||
326 | port->x_char = 0; | ||
327 | port->icount.tx++; | ||
328 | return; | ||
329 | } | ||
330 | |||
331 | while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { | ||
332 | if (xmit->head == xmit->tail) | ||
333 | break; | ||
334 | writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); | ||
335 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); | ||
336 | port->icount.tx++; | ||
337 | } | ||
338 | |||
339 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
340 | uart_write_wakeup(port); | ||
341 | |||
342 | if (xmit->head == xmit->tail) { | ||
343 | pp->imr &= ~MCFUART_UIR_TXREADY; | ||
344 | writeb(pp->imr, port->membase + MCFUART_UIMR); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | /****************************************************************************/ | ||
349 | |||
350 | static irqreturn_t mcf_interrupt(int irq, void *data) | ||
351 | { | ||
352 | struct uart_port *port = data; | ||
353 | struct mcf_uart *pp = container_of(port, struct mcf_uart, port); | ||
354 | unsigned int isr; | ||
355 | irqreturn_t ret = IRQ_NONE; | ||
356 | |||
357 | isr = readb(port->membase + MCFUART_UISR) & pp->imr; | ||
358 | |||
359 | spin_lock(&port->lock); | ||
360 | if (isr & MCFUART_UIR_RXREADY) { | ||
361 | mcf_rx_chars(pp); | ||
362 | ret = IRQ_HANDLED; | ||
363 | } | ||
364 | if (isr & MCFUART_UIR_TXREADY) { | ||
365 | mcf_tx_chars(pp); | ||
366 | ret = IRQ_HANDLED; | ||
367 | } | ||
368 | spin_unlock(&port->lock); | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | /****************************************************************************/ | ||
374 | |||
375 | static void mcf_config_port(struct uart_port *port, int flags) | ||
376 | { | ||
377 | port->type = PORT_MCF; | ||
378 | port->fifosize = MCFUART_TXFIFOSIZE; | ||
379 | |||
380 | /* Clear mask, so no surprise interrupts. */ | ||
381 | writeb(0, port->membase + MCFUART_UIMR); | ||
382 | |||
383 | if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port)) | ||
384 | printk(KERN_ERR "MCF: unable to attach ColdFire UART %d " | ||
385 | "interrupt vector=%d\n", port->line, port->irq); | ||
386 | } | ||
387 | |||
388 | /****************************************************************************/ | ||
389 | |||
390 | static const char *mcf_type(struct uart_port *port) | ||
391 | { | ||
392 | return (port->type == PORT_MCF) ? "ColdFire UART" : NULL; | ||
393 | } | ||
394 | |||
395 | /****************************************************************************/ | ||
396 | |||
397 | static int mcf_request_port(struct uart_port *port) | ||
398 | { | ||
399 | /* UARTs always present */ | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /****************************************************************************/ | ||
404 | |||
405 | static void mcf_release_port(struct uart_port *port) | ||
406 | { | ||
407 | /* Nothing to release... */ | ||
408 | } | ||
409 | |||
410 | /****************************************************************************/ | ||
411 | |||
412 | static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) | ||
413 | { | ||
414 | if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF)) | ||
415 | return -EINVAL; | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /****************************************************************************/ | ||
420 | |||
421 | /* | ||
422 | * Define the basic serial functions we support. | ||
423 | */ | ||
424 | static const struct uart_ops mcf_uart_ops = { | ||
425 | .tx_empty = mcf_tx_empty, | ||
426 | .get_mctrl = mcf_get_mctrl, | ||
427 | .set_mctrl = mcf_set_mctrl, | ||
428 | .start_tx = mcf_start_tx, | ||
429 | .stop_tx = mcf_stop_tx, | ||
430 | .stop_rx = mcf_stop_rx, | ||
431 | .enable_ms = mcf_enable_ms, | ||
432 | .break_ctl = mcf_break_ctl, | ||
433 | .startup = mcf_startup, | ||
434 | .shutdown = mcf_shutdown, | ||
435 | .set_termios = mcf_set_termios, | ||
436 | .type = mcf_type, | ||
437 | .request_port = mcf_request_port, | ||
438 | .release_port = mcf_release_port, | ||
439 | .config_port = mcf_config_port, | ||
440 | .verify_port = mcf_verify_port, | ||
441 | }; | ||
442 | |||
443 | static struct mcf_uart mcf_ports[4]; | ||
444 | |||
445 | #define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) | ||
446 | |||
447 | /****************************************************************************/ | ||
448 | #if defined(CONFIG_SERIAL_MCF_CONSOLE) | ||
449 | /****************************************************************************/ | ||
450 | |||
451 | int __init early_mcf_setup(struct mcf_platform_uart *platp) | ||
452 | { | ||
453 | struct uart_port *port; | ||
454 | int i; | ||
455 | |||
456 | for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { | ||
457 | port = &mcf_ports[i].port; | ||
458 | |||
459 | port->line = i; | ||
460 | port->type = PORT_MCF; | ||
461 | port->mapbase = platp[i].mapbase; | ||
462 | port->membase = (platp[i].membase) ? platp[i].membase : | ||
463 | (unsigned char __iomem *) port->mapbase; | ||
464 | port->iotype = SERIAL_IO_MEM; | ||
465 | port->irq = platp[i].irq; | ||
466 | port->uartclk = MCF_BUSCLK; | ||
467 | port->flags = ASYNC_BOOT_AUTOCONF; | ||
468 | port->ops = &mcf_uart_ops; | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /****************************************************************************/ | ||
475 | |||
476 | static void mcf_console_putc(struct console *co, const char c) | ||
477 | { | ||
478 | struct uart_port *port = &(mcf_ports + co->index)->port; | ||
479 | int i; | ||
480 | |||
481 | for (i = 0; (i < 0x10000); i++) { | ||
482 | if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) | ||
483 | break; | ||
484 | } | ||
485 | writeb(c, port->membase + MCFUART_UTB); | ||
486 | for (i = 0; (i < 0x10000); i++) { | ||
487 | if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) | ||
488 | break; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | /****************************************************************************/ | ||
493 | |||
494 | static void mcf_console_write(struct console *co, const char *s, unsigned int count) | ||
495 | { | ||
496 | for (; (count); count--, s++) { | ||
497 | mcf_console_putc(co, *s); | ||
498 | if (*s == '\n') | ||
499 | mcf_console_putc(co, '\r'); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | /****************************************************************************/ | ||
504 | |||
505 | static int __init mcf_console_setup(struct console *co, char *options) | ||
506 | { | ||
507 | struct uart_port *port; | ||
508 | int baud = CONFIG_SERIAL_MCF_BAUDRATE; | ||
509 | int bits = 8; | ||
510 | int parity = 'n'; | ||
511 | int flow = 'n'; | ||
512 | |||
513 | if ((co->index < 0) || (co->index >= MCF_MAXPORTS)) | ||
514 | co->index = 0; | ||
515 | port = &mcf_ports[co->index].port; | ||
516 | if (port->membase == 0) | ||
517 | return -ENODEV; | ||
518 | |||
519 | if (options) | ||
520 | uart_parse_options(options, &baud, &parity, &bits, &flow); | ||
521 | |||
522 | return uart_set_options(port, co, baud, parity, bits, flow); | ||
523 | } | ||
524 | |||
525 | /****************************************************************************/ | ||
526 | |||
527 | static struct uart_driver mcf_driver; | ||
528 | |||
529 | static struct console mcf_console = { | ||
530 | .name = "ttyS", | ||
531 | .write = mcf_console_write, | ||
532 | .device = uart_console_device, | ||
533 | .setup = mcf_console_setup, | ||
534 | .flags = CON_PRINTBUFFER, | ||
535 | .index = -1, | ||
536 | .data = &mcf_driver, | ||
537 | }; | ||
538 | |||
539 | static int __init mcf_console_init(void) | ||
540 | { | ||
541 | register_console(&mcf_console); | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | console_initcall(mcf_console_init); | ||
546 | |||
547 | #define MCF_CONSOLE &mcf_console | ||
548 | |||
549 | /****************************************************************************/ | ||
550 | #else | ||
551 | /****************************************************************************/ | ||
552 | |||
553 | #define MCF_CONSOLE NULL | ||
554 | |||
555 | /****************************************************************************/ | ||
556 | #endif /* CONFIG_MCF_CONSOLE */ | ||
557 | /****************************************************************************/ | ||
558 | |||
559 | /* | ||
560 | * Define the mcf UART driver structure. | ||
561 | */ | ||
562 | static struct uart_driver mcf_driver = { | ||
563 | .owner = THIS_MODULE, | ||
564 | .driver_name = "mcf", | ||
565 | .dev_name = "ttyS", | ||
566 | .major = TTY_MAJOR, | ||
567 | .minor = 64, | ||
568 | .nr = MCF_MAXPORTS, | ||
569 | .cons = MCF_CONSOLE, | ||
570 | }; | ||
571 | |||
572 | /****************************************************************************/ | ||
573 | |||
574 | static int __devinit mcf_probe(struct platform_device *pdev) | ||
575 | { | ||
576 | struct mcf_platform_uart *platp = pdev->dev.platform_data; | ||
577 | struct uart_port *port; | ||
578 | int i; | ||
579 | |||
580 | for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) { | ||
581 | port = &mcf_ports[i].port; | ||
582 | |||
583 | port->line = i; | ||
584 | port->type = PORT_MCF; | ||
585 | port->mapbase = platp[i].mapbase; | ||
586 | port->membase = (platp[i].membase) ? platp[i].membase : | ||
587 | (unsigned char __iomem *) platp[i].mapbase; | ||
588 | port->iotype = SERIAL_IO_MEM; | ||
589 | port->irq = platp[i].irq; | ||
590 | port->uartclk = MCF_BUSCLK; | ||
591 | port->ops = &mcf_uart_ops; | ||
592 | port->flags = ASYNC_BOOT_AUTOCONF; | ||
593 | |||
594 | uart_add_one_port(&mcf_driver, port); | ||
595 | } | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /****************************************************************************/ | ||
601 | |||
602 | static int __devexit mcf_remove(struct platform_device *pdev) | ||
603 | { | ||
604 | struct uart_port *port; | ||
605 | int i; | ||
606 | |||
607 | for (i = 0; (i < MCF_MAXPORTS); i++) { | ||
608 | port = &mcf_ports[i].port; | ||
609 | if (port) | ||
610 | uart_remove_one_port(&mcf_driver, port); | ||
611 | } | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | /****************************************************************************/ | ||
617 | |||
618 | static struct platform_driver mcf_platform_driver = { | ||
619 | .probe = mcf_probe, | ||
620 | .remove = __devexit_p(mcf_remove), | ||
621 | .driver = { | ||
622 | .name = "mcfuart", | ||
623 | .owner = THIS_MODULE, | ||
624 | }, | ||
625 | }; | ||
626 | |||
627 | /****************************************************************************/ | ||
628 | |||
629 | static int __init mcf_init(void) | ||
630 | { | ||
631 | int rc; | ||
632 | |||
633 | printk("ColdFire internal UART serial driver\n"); | ||
634 | |||
635 | rc = uart_register_driver(&mcf_driver); | ||
636 | if (rc) | ||
637 | return rc; | ||
638 | rc = platform_driver_register(&mcf_platform_driver); | ||
639 | if (rc) | ||
640 | return rc; | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | /****************************************************************************/ | ||
645 | |||
646 | static void __exit mcf_exit(void) | ||
647 | { | ||
648 | platform_driver_unregister(&mcf_platform_driver); | ||
649 | uart_unregister_driver(&mcf_driver); | ||
650 | } | ||
651 | |||
652 | /****************************************************************************/ | ||
653 | |||
654 | module_init(mcf_init); | ||
655 | module_exit(mcf_exit); | ||
656 | |||
657 | MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>"); | ||
658 | MODULE_DESCRIPTION("Freescale ColdFire UART driver"); | ||
659 | MODULE_LICENSE("GPL"); | ||
660 | MODULE_ALIAS("platform:mcfuart"); | ||
661 | |||
662 | /****************************************************************************/ | ||