blob: ea744707c4d6a243f0aa0c195a5422ec966420d1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* drivers/serial/serial_lh7a40x.c
2 *
3 * Copyright (C) 2004 Coastal Environmental Systems
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
8 *
9 */
10
11/* Driver for Sharp LH7A40X embedded serial ports
12 *
13 * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
14 * Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
15 *
16 * ---
17 *
18 * This driver supports the embedded UARTs of the Sharp LH7A40X series
19 * CPUs. While similar to the 16550 and other UART chips, there is
20 * nothing close to register compatibility. Moreover, some of the
21 * modem control lines are not available, either in the chip or they
22 * are lacking in the board-level implementation.
23 *
24 * - Use of SIRDIS
25 * For simplicity, we disable the IR functions of any UART whenever
26 * we enable it.
27 *
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
32#define SUPPORT_SYSRQ
33#endif
34
35#include <linux/module.h>
36#include <linux/ioport.h>
37#include <linux/init.h>
38#include <linux/console.h>
39#include <linux/sysrq.h>
40#include <linux/tty.h>
41#include <linux/tty_flip.h>
42#include <linux/serial_core.h>
43#include <linux/serial.h>
Russell Kingfa44c9e2008-11-28 16:13:44 +000044#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <asm/irq.h>
Russell Kingfa44c9e2008-11-28 16:13:44 +000047#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define DEV_MAJOR 204
50#define DEV_MINOR 16
51#define DEV_NR 3
52
53#define ISR_LOOP_LIMIT 256
54
55#define UR(p,o) _UR ((p)->membase, o)
56#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
57#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
58#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
59
60#define UART_REG_SIZE 32
61
62#define UART_R_DATA (0x00)
63#define UART_R_FCON (0x04)
64#define UART_R_BRCON (0x08)
65#define UART_R_CON (0x0c)
66#define UART_R_STATUS (0x10)
67#define UART_R_RAWISR (0x14)
68#define UART_R_INTEN (0x18)
69#define UART_R_ISR (0x1c)
70
71#define UARTEN (0x01) /* UART enable */
72#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
73
74#define RxEmpty (0x10)
75#define TxEmpty (0x80)
76#define TxFull (0x20)
77#define nRxRdy RxEmpty
78#define nTxRdy TxFull
79#define TxBusy (0x08)
80
81#define RxBreak (0x0800)
82#define RxOverrunError (0x0400)
83#define RxParityError (0x0200)
84#define RxFramingError (0x0100)
85#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
86
87#define DCD (0x04)
88#define DSR (0x02)
89#define CTS (0x01)
90
91#define RxInt (0x01)
92#define TxInt (0x02)
93#define ModemInt (0x04)
94#define RxTimeoutInt (0x08)
95
96#define MSEOI (0x10)
97
98#define WLEN_8 (0x60)
99#define WLEN_7 (0x40)
100#define WLEN_6 (0x20)
101#define WLEN_5 (0x00)
102#define WLEN (0x60) /* Mask for all word-length bits */
103#define STP2 (0x08)
104#define PEN (0x02) /* Parity Enable */
105#define EPS (0x04) /* Even Parity Set */
106#define FEN (0x10) /* FIFO Enable */
107#define BRK (0x01) /* Send Break */
108
109
110struct uart_port_lh7a40x {
111 struct uart_port port;
112 unsigned int statusPrev; /* Most recently read modem status */
113};
114
Russell Kingb129a8c2005-08-31 10:12:14 +0100115static void lh7a40xuart_stop_tx (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
117 BIT_CLR (port, UART_R_INTEN, TxInt);
118}
119
Russell Kingb129a8c2005-08-31 10:12:14 +0100120static void lh7a40xuart_start_tx (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 BIT_SET (port, UART_R_INTEN, TxInt);
123
124 /* *** FIXME: do I need to check for startup of the
125 transmitter? The old driver did, but AMBA
126 doesn't . */
127}
128
129static void lh7a40xuart_stop_rx (struct uart_port* port)
130{
131 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
132}
133
134static void lh7a40xuart_enable_ms (struct uart_port* port)
135{
136 BIT_SET (port, UART_R_INTEN, ModemInt);
137}
138
David Howells7d12e782006-10-05 14:55:46 +0100139static void lh7a40xuart_rx_chars (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Alan Coxebd2c8f2009-09-19 13:13:28 -0700141 struct tty_struct* tty = port->state->port.tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 int cbRxMax = 256; /* (Gross) limit on receive */
Marc Singerfb62c5a2006-05-16 11:41:29 +0100143 unsigned int data; /* Received data and status */
144 unsigned int flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 data = UR (port, UART_R_DATA);
148 flag = TTY_NORMAL;
149 ++port->icount.rx;
150
Marc Singerfb62c5a2006-05-16 11:41:29 +0100151 if (unlikely(data & RxError)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 if (data & RxBreak) {
153 data &= ~(RxFramingError | RxParityError);
154 ++port->icount.brk;
155 if (uart_handle_break (port))
156 continue;
157 }
158 else if (data & RxParityError)
159 ++port->icount.parity;
160 else if (data & RxFramingError)
161 ++port->icount.frame;
162 if (data & RxOverrunError)
163 ++port->icount.overrun;
164
165 /* Mask by termios, leave Rx'd byte */
166 data &= port->read_status_mask | 0xff;
167
168 if (data & RxBreak)
169 flag = TTY_BREAK;
170 else if (data & RxParityError)
171 flag = TTY_PARITY;
172 else if (data & RxFramingError)
173 flag = TTY_FRAME;
174 }
175
David Howells7d12e782006-10-05 14:55:46 +0100176 if (uart_handle_sysrq_char (port, (unsigned char) data))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 continue;
178
Russell King05ab3012005-05-09 23:21:59 +0100179 uart_insert_char(port, data, RxOverrunError, data, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181 tty_flip_buffer_push (tty);
182 return;
183}
184
185static void lh7a40xuart_tx_chars (struct uart_port* port)
186{
Alan Coxebd2c8f2009-09-19 13:13:28 -0700187 struct circ_buf* xmit = &port->state->xmit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 int cbTxMax = port->fifosize;
189
190 if (port->x_char) {
191 UR (port, UART_R_DATA) = port->x_char;
192 ++port->icount.tx;
193 port->x_char = 0;
194 return;
195 }
196 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
Russell King1cd98552005-09-06 23:14:59 +0100197 lh7a40xuart_stop_tx (port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 return;
199 }
200
201 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
202 that at least half of the FIFO is empty. Instead, we check
203 status for every character. Using the AMBA method causes
204 the transmitter to drop characters. */
205
206 do {
207 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
208 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
209 ++port->icount.tx;
210 if (uart_circ_empty(xmit))
211 break;
212 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
213 && cbTxMax--);
214
215 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
216 uart_write_wakeup (port);
217
218 if (uart_circ_empty (xmit))
Russell King1cd98552005-09-06 23:14:59 +0100219 lh7a40xuart_stop_tx (port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222static void lh7a40xuart_modem_status (struct uart_port* port)
223{
224 unsigned int status = UR (port, UART_R_STATUS);
225 unsigned int delta
226 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
227
228 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
229
230 if (!delta) /* Only happens if we missed 2 transitions */
231 return;
232
233 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
234
235 if (delta & DCD)
236 uart_handle_dcd_change (port, status & DCD);
237
238 if (delta & DSR)
239 ++port->icount.dsr;
240
241 if (delta & CTS)
242 uart_handle_cts_change (port, status & CTS);
243
Alan Coxbdc04e32009-09-19 13:13:31 -0700244 wake_up_interruptible (&port->state->port.delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245}
246
David Howells7d12e782006-10-05 14:55:46 +0100247static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
249 struct uart_port* port = dev_id;
250 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
251 unsigned int isr = UR (port, UART_R_ISR);
252
253
254 do {
255 if (isr & (RxInt | RxTimeoutInt))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 lh7a40xuart_rx_chars(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 if (isr & ModemInt)
258 lh7a40xuart_modem_status (port);
259 if (isr & TxInt)
260 lh7a40xuart_tx_chars (port);
261
262 if (--cLoopLimit == 0)
263 break;
264
265 isr = UR (port, UART_R_ISR);
266 } while (isr & (RxInt | TxInt | RxTimeoutInt));
267
268 return IRQ_HANDLED;
269}
270
271static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
272{
273 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
274}
275
276static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
277{
278 unsigned int result = 0;
279 unsigned int status = UR (port, UART_R_STATUS);
280
281 if (status & DCD)
282 result |= TIOCM_CAR;
283 if (status & DSR)
284 result |= TIOCM_DSR;
285 if (status & CTS)
286 result |= TIOCM_CTS;
287
288 return result;
289}
290
291static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
292{
293 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
294 /* Note, kernel appears to be setting DTR and RTS on console. */
295
296 /* *** FIXME: this deserves more work. There's some work in
Marc Singerfb62c5a2006-05-16 11:41:29 +0100297 tracing all of the IO pins. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298#if 0
299 if( port->mapbase == UART1_PHYS) {
300 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
301
302 if (mctrl & TIOCM_RTS)
303 gpio->pbdr &= ~GPIOB_UART1_RTS;
304 else
305 gpio->pbdr |= GPIOB_UART1_RTS;
306 }
307#endif
308}
309
310static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
311{
312 unsigned long flags;
313
314 spin_lock_irqsave(&port->lock, flags);
315 if (break_state == -1)
316 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
317 else
318 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
319 spin_unlock_irqrestore(&port->lock, flags);
320}
321
322static int lh7a40xuart_startup (struct uart_port* port)
323{
324 int retval;
325
326 retval = request_irq (port->irq, lh7a40xuart_int, 0,
327 "serial_lh7a40x", port);
328 if (retval)
329 return retval;
330
331 /* Initial modem control-line settings */
332 ((struct uart_port_lh7a40x*) port)->statusPrev
333 = UR (port, UART_R_STATUS);
334
335 /* There is presently no configuration option to enable IR.
336 Thus, we always disable it. */
337
338 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
339 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
340
341 return 0;
342}
343
344static void lh7a40xuart_shutdown (struct uart_port* port)
345{
346 free_irq (port->irq, port);
347 BIT_CLR (port, UART_R_FCON, BRK | FEN);
348 BIT_CLR (port, UART_R_CON, UARTEN);
349}
350
351static void lh7a40xuart_set_termios (struct uart_port* port,
Alan Cox606d0992006-12-08 02:38:45 -0800352 struct ktermios* termios,
353 struct ktermios* old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 unsigned int con;
356 unsigned int inten;
357 unsigned int fcon;
358 unsigned long flags;
359 unsigned int baud;
360 unsigned int quot;
361
362 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
363 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
364
365 switch (termios->c_cflag & CSIZE) {
366 case CS5:
367 fcon = WLEN_5;
368 break;
369 case CS6:
370 fcon = WLEN_6;
371 break;
372 case CS7:
373 fcon = WLEN_7;
374 break;
375 case CS8:
376 default:
377 fcon = WLEN_8;
378 break;
379 }
380 if (termios->c_cflag & CSTOPB)
381 fcon |= STP2;
382 if (termios->c_cflag & PARENB) {
383 fcon |= PEN;
384 if (!(termios->c_cflag & PARODD))
385 fcon |= EPS;
386 }
387 if (port->fifosize > 1)
388 fcon |= FEN;
389
390 spin_lock_irqsave (&port->lock, flags);
391
392 uart_update_timeout (port, termios->c_cflag, baud);
393
394 port->read_status_mask = RxOverrunError;
395 if (termios->c_iflag & INPCK)
396 port->read_status_mask |= RxFramingError | RxParityError;
397 if (termios->c_iflag & (BRKINT | PARMRK))
398 port->read_status_mask |= RxBreak;
399
400 /* Figure mask for status we ignore */
401 port->ignore_status_mask = 0;
402 if (termios->c_iflag & IGNPAR)
403 port->ignore_status_mask |= RxFramingError | RxParityError;
404 if (termios->c_iflag & IGNBRK) {
405 port->ignore_status_mask |= RxBreak;
406 /* Ignore overrun when ignorning parity */
407 /* *** FIXME: is this in the right place? */
408 if (termios->c_iflag & IGNPAR)
409 port->ignore_status_mask |= RxOverrunError;
410 }
411
412 /* Ignore all receive errors when receive disabled */
413 if ((termios->c_cflag & CREAD) == 0)
414 port->ignore_status_mask |= RxError;
415
416 con = UR (port, UART_R_CON);
417 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
418
419 if (UART_ENABLE_MS (port, termios->c_cflag))
420 inten |= ModemInt;
421
422 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
423 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
424 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
425 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
426 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
427 UR (port, UART_R_CON) = con; /* Restore UART mode */
428
429 spin_unlock_irqrestore(&port->lock, flags);
430}
431
432static const char* lh7a40xuart_type (struct uart_port* port)
433{
434 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
435}
436
437static void lh7a40xuart_release_port (struct uart_port* port)
438{
439 release_mem_region (port->mapbase, UART_REG_SIZE);
440}
441
442static int lh7a40xuart_request_port (struct uart_port* port)
443{
444 return request_mem_region (port->mapbase, UART_REG_SIZE,
445 "serial_lh7a40x") != NULL
446 ? 0 : -EBUSY;
447}
448
449static void lh7a40xuart_config_port (struct uart_port* port, int flags)
450{
451 if (flags & UART_CONFIG_TYPE) {
452 port->type = PORT_LH7A40X;
453 lh7a40xuart_request_port (port);
454 }
455}
456
457static int lh7a40xuart_verify_port (struct uart_port* port,
458 struct serial_struct* ser)
459{
460 int ret = 0;
461
462 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
463 ret = -EINVAL;
Yinghai Lua62c4132008-08-19 20:49:55 -0700464 if (ser->irq < 0 || ser->irq >= nr_irqs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 ret = -EINVAL;
466 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
467 ret = -EINVAL;
468 return ret;
469}
470
471static struct uart_ops lh7a40x_uart_ops = {
472 .tx_empty = lh7a40xuart_tx_empty,
473 .set_mctrl = lh7a40xuart_set_mctrl,
474 .get_mctrl = lh7a40xuart_get_mctrl,
475 .stop_tx = lh7a40xuart_stop_tx,
476 .start_tx = lh7a40xuart_start_tx,
477 .stop_rx = lh7a40xuart_stop_rx,
478 .enable_ms = lh7a40xuart_enable_ms,
479 .break_ctl = lh7a40xuart_break_ctl,
480 .startup = lh7a40xuart_startup,
481 .shutdown = lh7a40xuart_shutdown,
482 .set_termios = lh7a40xuart_set_termios,
483 .type = lh7a40xuart_type,
484 .release_port = lh7a40xuart_release_port,
485 .request_port = lh7a40xuart_request_port,
486 .config_port = lh7a40xuart_config_port,
487 .verify_port = lh7a40xuart_verify_port,
488};
489
490static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
491 {
492 .port = {
493 .membase = (void*) io_p2v (UART1_PHYS),
494 .mapbase = UART1_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000495 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 .irq = IRQ_UART1INTR,
497 .uartclk = 14745600/2,
498 .fifosize = 16,
499 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000500 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 .line = 0,
502 },
503 },
504 {
505 .port = {
506 .membase = (void*) io_p2v (UART2_PHYS),
507 .mapbase = UART2_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000508 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 .irq = IRQ_UART2INTR,
510 .uartclk = 14745600/2,
511 .fifosize = 16,
512 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000513 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 .line = 1,
515 },
516 },
517 {
518 .port = {
519 .membase = (void*) io_p2v (UART3_PHYS),
520 .mapbase = UART3_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000521 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 .irq = IRQ_UART3INTR,
523 .uartclk = 14745600/2,
524 .fifosize = 16,
525 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000526 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 .line = 2,
528 },
529 },
530};
531
532#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
533# define LH7A40X_CONSOLE NULL
534#else
535# define LH7A40X_CONSOLE &lh7a40x_console
536
Russell Kingd3587882006-03-20 20:00:09 +0000537static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
538{
539 while (UR(port, UART_R_STATUS) & nTxRdy)
540 ;
541 UR(port, UART_R_DATA) = ch;
542}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544static void lh7a40xuart_console_write (struct console* co,
545 const char* s,
546 unsigned int count)
547{
548 struct uart_port* port = &lh7a40x_ports[co->index].port;
549 unsigned int con = UR (port, UART_R_CON);
550 unsigned int inten = UR (port, UART_R_INTEN);
551
552
553 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
554 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
555
Russell Kingd3587882006-03-20 20:00:09 +0000556 uart_console_write(port, s, count, lh7a40xuart_console_putchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558 /* Wait until all characters are sent */
559 while (UR (port, UART_R_STATUS) & TxBusy)
560 ;
561
562 /* Restore control and interrupt mask */
563 UR (port, UART_R_CON) = con;
564 UR (port, UART_R_INTEN) = inten;
565}
566
567static void __init lh7a40xuart_console_get_options (struct uart_port* port,
568 int* baud,
569 int* parity,
570 int* bits)
571{
572 if (UR (port, UART_R_CON) & UARTEN) {
573 unsigned int fcon = UR (port, UART_R_FCON);
574 unsigned int quot = UR (port, UART_R_BRCON) + 1;
575
576 switch (fcon & (PEN | EPS)) {
577 default: *parity = 'n'; break;
578 case PEN: *parity = 'o'; break;
579 case PEN | EPS: *parity = 'e'; break;
580 }
581
582 switch (fcon & WLEN) {
583 default:
584 case WLEN_8: *bits = 8; break;
585 case WLEN_7: *bits = 7; break;
586 case WLEN_6: *bits = 6; break;
587 case WLEN_5: *bits = 5; break;
588 }
589
590 *baud = port->uartclk/(16*quot);
591 }
592}
593
594static int __init lh7a40xuart_console_setup (struct console* co, char* options)
595{
596 struct uart_port* port;
597 int baud = 38400;
598 int bits = 8;
599 int parity = 'n';
600 int flow = 'n';
601
602 if (co->index >= DEV_NR) /* Bounds check on device number */
603 co->index = 0;
604 port = &lh7a40x_ports[co->index].port;
605
606 if (options)
607 uart_parse_options (options, &baud, &parity, &bits, &flow);
608 else
609 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
610
611 return uart_set_options (port, co, baud, parity, bits, flow);
612}
613
Vincent Sanders2d934862005-09-14 22:36:03 +0100614static struct uart_driver lh7a40x_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615static struct console lh7a40x_console = {
616 .name = "ttyAM",
617 .write = lh7a40xuart_console_write,
618 .device = uart_console_device,
619 .setup = lh7a40xuart_console_setup,
620 .flags = CON_PRINTBUFFER,
621 .index = -1,
622 .data = &lh7a40x_reg,
623};
624
625static int __init lh7a40xuart_console_init(void)
626{
627 register_console (&lh7a40x_console);
628 return 0;
629}
630
631console_initcall (lh7a40xuart_console_init);
632
633#endif
634
635static struct uart_driver lh7a40x_reg = {
636 .owner = THIS_MODULE,
637 .driver_name = "ttyAM",
638 .dev_name = "ttyAM",
639 .major = DEV_MAJOR,
640 .minor = DEV_MINOR,
641 .nr = DEV_NR,
642 .cons = LH7A40X_CONSOLE,
643};
644
645static int __init lh7a40xuart_init(void)
646{
647 int ret;
648
649 printk (KERN_INFO "serial: LH7A40X serial driver\n");
650
651 ret = uart_register_driver (&lh7a40x_reg);
652
653 if (ret == 0) {
654 int i;
655
Marc Singerfb62c5a2006-05-16 11:41:29 +0100656 for (i = 0; i < DEV_NR; i++) {
657 /* UART3, when used, requires GPIO pin reallocation */
658 if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
659 GPIO_PINMUX |= 1<<3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 uart_add_one_port (&lh7a40x_reg,
661 &lh7a40x_ports[i].port);
Marc Singerfb62c5a2006-05-16 11:41:29 +0100662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
664 return ret;
665}
666
667static void __exit lh7a40xuart_exit(void)
668{
669 int i;
670
671 for (i = 0; i < DEV_NR; i++)
672 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
673
674 uart_unregister_driver (&lh7a40x_reg);
675}
676
677module_init (lh7a40xuart_init);
678module_exit (lh7a40xuart_exit);
679
680MODULE_AUTHOR ("Marc Singer");
681MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
682MODULE_LICENSE ("GPL");