blob: eb18d429752d2d40458eb47234f3fd4649bf39fd [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>
44
45#include <asm/io.h>
46#include <asm/irq.h>
47
48#define DEV_MAJOR 204
49#define DEV_MINOR 16
50#define DEV_NR 3
51
52#define ISR_LOOP_LIMIT 256
53
54#define UR(p,o) _UR ((p)->membase, o)
55#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
56#define BIT_CLR(p,o,m) UR(p,o) = UR(p,o) & (~(unsigned int)m)
57#define BIT_SET(p,o,m) UR(p,o) = UR(p,o) | ( (unsigned int)m)
58
59#define UART_REG_SIZE 32
60
61#define UART_R_DATA (0x00)
62#define UART_R_FCON (0x04)
63#define UART_R_BRCON (0x08)
64#define UART_R_CON (0x0c)
65#define UART_R_STATUS (0x10)
66#define UART_R_RAWISR (0x14)
67#define UART_R_INTEN (0x18)
68#define UART_R_ISR (0x1c)
69
70#define UARTEN (0x01) /* UART enable */
71#define SIRDIS (0x02) /* Serial IR disable (UART1 only) */
72
73#define RxEmpty (0x10)
74#define TxEmpty (0x80)
75#define TxFull (0x20)
76#define nRxRdy RxEmpty
77#define nTxRdy TxFull
78#define TxBusy (0x08)
79
80#define RxBreak (0x0800)
81#define RxOverrunError (0x0400)
82#define RxParityError (0x0200)
83#define RxFramingError (0x0100)
84#define RxError (RxBreak | RxOverrunError | RxParityError | RxFramingError)
85
86#define DCD (0x04)
87#define DSR (0x02)
88#define CTS (0x01)
89
90#define RxInt (0x01)
91#define TxInt (0x02)
92#define ModemInt (0x04)
93#define RxTimeoutInt (0x08)
94
95#define MSEOI (0x10)
96
97#define WLEN_8 (0x60)
98#define WLEN_7 (0x40)
99#define WLEN_6 (0x20)
100#define WLEN_5 (0x00)
101#define WLEN (0x60) /* Mask for all word-length bits */
102#define STP2 (0x08)
103#define PEN (0x02) /* Parity Enable */
104#define EPS (0x04) /* Even Parity Set */
105#define FEN (0x10) /* FIFO Enable */
106#define BRK (0x01) /* Send Break */
107
108
109struct uart_port_lh7a40x {
110 struct uart_port port;
111 unsigned int statusPrev; /* Most recently read modem status */
112};
113
Russell Kingb129a8c2005-08-31 10:12:14 +0100114static void lh7a40xuart_stop_tx (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115{
116 BIT_CLR (port, UART_R_INTEN, TxInt);
117}
118
Russell Kingb129a8c2005-08-31 10:12:14 +0100119static void lh7a40xuart_start_tx (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
121 BIT_SET (port, UART_R_INTEN, TxInt);
122
123 /* *** FIXME: do I need to check for startup of the
124 transmitter? The old driver did, but AMBA
125 doesn't . */
126}
127
128static void lh7a40xuart_stop_rx (struct uart_port* port)
129{
130 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
131}
132
133static void lh7a40xuart_enable_ms (struct uart_port* port)
134{
135 BIT_SET (port, UART_R_INTEN, ModemInt);
136}
137
David Howells7d12e782006-10-05 14:55:46 +0100138static void lh7a40xuart_rx_chars (struct uart_port* port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 struct tty_struct* tty = port->info->tty;
141 int cbRxMax = 256; /* (Gross) limit on receive */
Marc Singerfb62c5a2006-05-16 11:41:29 +0100142 unsigned int data; /* Received data and status */
143 unsigned int flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 data = UR (port, UART_R_DATA);
147 flag = TTY_NORMAL;
148 ++port->icount.rx;
149
Marc Singerfb62c5a2006-05-16 11:41:29 +0100150 if (unlikely(data & RxError)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 if (data & RxBreak) {
152 data &= ~(RxFramingError | RxParityError);
153 ++port->icount.brk;
154 if (uart_handle_break (port))
155 continue;
156 }
157 else if (data & RxParityError)
158 ++port->icount.parity;
159 else if (data & RxFramingError)
160 ++port->icount.frame;
161 if (data & RxOverrunError)
162 ++port->icount.overrun;
163
164 /* Mask by termios, leave Rx'd byte */
165 data &= port->read_status_mask | 0xff;
166
167 if (data & RxBreak)
168 flag = TTY_BREAK;
169 else if (data & RxParityError)
170 flag = TTY_PARITY;
171 else if (data & RxFramingError)
172 flag = TTY_FRAME;
173 }
174
David Howells7d12e782006-10-05 14:55:46 +0100175 if (uart_handle_sysrq_char (port, (unsigned char) data))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 continue;
177
Russell King05ab3012005-05-09 23:21:59 +0100178 uart_insert_char(port, data, RxOverrunError, data, flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 }
180 tty_flip_buffer_push (tty);
181 return;
182}
183
184static void lh7a40xuart_tx_chars (struct uart_port* port)
185{
186 struct circ_buf* xmit = &port->info->xmit;
187 int cbTxMax = port->fifosize;
188
189 if (port->x_char) {
190 UR (port, UART_R_DATA) = port->x_char;
191 ++port->icount.tx;
192 port->x_char = 0;
193 return;
194 }
195 if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
Russell King1cd98552005-09-06 23:14:59 +0100196 lh7a40xuart_stop_tx (port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 return;
198 }
199
200 /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
201 that at least half of the FIFO is empty. Instead, we check
202 status for every character. Using the AMBA method causes
203 the transmitter to drop characters. */
204
205 do {
206 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
207 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
208 ++port->icount.tx;
209 if (uart_circ_empty(xmit))
210 break;
211 } while (!(UR (port, UART_R_STATUS) & nTxRdy)
212 && cbTxMax--);
213
214 if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
215 uart_write_wakeup (port);
216
217 if (uart_circ_empty (xmit))
Russell King1cd98552005-09-06 23:14:59 +0100218 lh7a40xuart_stop_tx (port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219}
220
221static void lh7a40xuart_modem_status (struct uart_port* port)
222{
223 unsigned int status = UR (port, UART_R_STATUS);
224 unsigned int delta
225 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
226
227 BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
228
229 if (!delta) /* Only happens if we missed 2 transitions */
230 return;
231
232 ((struct uart_port_lh7a40x*) port)->statusPrev = status;
233
234 if (delta & DCD)
235 uart_handle_dcd_change (port, status & DCD);
236
237 if (delta & DSR)
238 ++port->icount.dsr;
239
240 if (delta & CTS)
241 uart_handle_cts_change (port, status & CTS);
242
243 wake_up_interruptible (&port->info->delta_msr_wait);
244}
245
David Howells7d12e782006-10-05 14:55:46 +0100246static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247{
248 struct uart_port* port = dev_id;
249 unsigned int cLoopLimit = ISR_LOOP_LIMIT;
250 unsigned int isr = UR (port, UART_R_ISR);
251
252
253 do {
254 if (isr & (RxInt | RxTimeoutInt))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 lh7a40xuart_rx_chars(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 if (isr & ModemInt)
257 lh7a40xuart_modem_status (port);
258 if (isr & TxInt)
259 lh7a40xuart_tx_chars (port);
260
261 if (--cLoopLimit == 0)
262 break;
263
264 isr = UR (port, UART_R_ISR);
265 } while (isr & (RxInt | TxInt | RxTimeoutInt));
266
267 return IRQ_HANDLED;
268}
269
270static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
271{
272 return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
273}
274
275static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
276{
277 unsigned int result = 0;
278 unsigned int status = UR (port, UART_R_STATUS);
279
280 if (status & DCD)
281 result |= TIOCM_CAR;
282 if (status & DSR)
283 result |= TIOCM_DSR;
284 if (status & CTS)
285 result |= TIOCM_CTS;
286
287 return result;
288}
289
290static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
291{
292 /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
293 /* Note, kernel appears to be setting DTR and RTS on console. */
294
295 /* *** FIXME: this deserves more work. There's some work in
Marc Singerfb62c5a2006-05-16 11:41:29 +0100296 tracing all of the IO pins. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297#if 0
298 if( port->mapbase == UART1_PHYS) {
299 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
300
301 if (mctrl & TIOCM_RTS)
302 gpio->pbdr &= ~GPIOB_UART1_RTS;
303 else
304 gpio->pbdr |= GPIOB_UART1_RTS;
305 }
306#endif
307}
308
309static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
310{
311 unsigned long flags;
312
313 spin_lock_irqsave(&port->lock, flags);
314 if (break_state == -1)
315 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
316 else
317 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
318 spin_unlock_irqrestore(&port->lock, flags);
319}
320
321static int lh7a40xuart_startup (struct uart_port* port)
322{
323 int retval;
324
325 retval = request_irq (port->irq, lh7a40xuart_int, 0,
326 "serial_lh7a40x", port);
327 if (retval)
328 return retval;
329
330 /* Initial modem control-line settings */
331 ((struct uart_port_lh7a40x*) port)->statusPrev
332 = UR (port, UART_R_STATUS);
333
334 /* There is presently no configuration option to enable IR.
335 Thus, we always disable it. */
336
337 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
338 BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
339
340 return 0;
341}
342
343static void lh7a40xuart_shutdown (struct uart_port* port)
344{
345 free_irq (port->irq, port);
346 BIT_CLR (port, UART_R_FCON, BRK | FEN);
347 BIT_CLR (port, UART_R_CON, UARTEN);
348}
349
350static void lh7a40xuart_set_termios (struct uart_port* port,
Alan Cox606d0992006-12-08 02:38:45 -0800351 struct ktermios* termios,
352 struct ktermios* old)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
354 unsigned int con;
355 unsigned int inten;
356 unsigned int fcon;
357 unsigned long flags;
358 unsigned int baud;
359 unsigned int quot;
360
361 baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
362 quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
363
364 switch (termios->c_cflag & CSIZE) {
365 case CS5:
366 fcon = WLEN_5;
367 break;
368 case CS6:
369 fcon = WLEN_6;
370 break;
371 case CS7:
372 fcon = WLEN_7;
373 break;
374 case CS8:
375 default:
376 fcon = WLEN_8;
377 break;
378 }
379 if (termios->c_cflag & CSTOPB)
380 fcon |= STP2;
381 if (termios->c_cflag & PARENB) {
382 fcon |= PEN;
383 if (!(termios->c_cflag & PARODD))
384 fcon |= EPS;
385 }
386 if (port->fifosize > 1)
387 fcon |= FEN;
388
389 spin_lock_irqsave (&port->lock, flags);
390
391 uart_update_timeout (port, termios->c_cflag, baud);
392
393 port->read_status_mask = RxOverrunError;
394 if (termios->c_iflag & INPCK)
395 port->read_status_mask |= RxFramingError | RxParityError;
396 if (termios->c_iflag & (BRKINT | PARMRK))
397 port->read_status_mask |= RxBreak;
398
399 /* Figure mask for status we ignore */
400 port->ignore_status_mask = 0;
401 if (termios->c_iflag & IGNPAR)
402 port->ignore_status_mask |= RxFramingError | RxParityError;
403 if (termios->c_iflag & IGNBRK) {
404 port->ignore_status_mask |= RxBreak;
405 /* Ignore overrun when ignorning parity */
406 /* *** FIXME: is this in the right place? */
407 if (termios->c_iflag & IGNPAR)
408 port->ignore_status_mask |= RxOverrunError;
409 }
410
411 /* Ignore all receive errors when receive disabled */
412 if ((termios->c_cflag & CREAD) == 0)
413 port->ignore_status_mask |= RxError;
414
415 con = UR (port, UART_R_CON);
416 inten = (UR (port, UART_R_INTEN) & ~ModemInt);
417
418 if (UART_ENABLE_MS (port, termios->c_cflag))
419 inten |= ModemInt;
420
421 BIT_CLR (port, UART_R_CON, UARTEN); /* Disable UART */
422 UR (port, UART_R_INTEN) = 0; /* Disable interrupts */
423 UR (port, UART_R_BRCON) = quot - 1; /* Set baud rate divisor */
424 UR (port, UART_R_FCON) = fcon; /* Set FIFO and frame ctrl */
425 UR (port, UART_R_INTEN) = inten; /* Enable interrupts */
426 UR (port, UART_R_CON) = con; /* Restore UART mode */
427
428 spin_unlock_irqrestore(&port->lock, flags);
429}
430
431static const char* lh7a40xuart_type (struct uart_port* port)
432{
433 return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
434}
435
436static void lh7a40xuart_release_port (struct uart_port* port)
437{
438 release_mem_region (port->mapbase, UART_REG_SIZE);
439}
440
441static int lh7a40xuart_request_port (struct uart_port* port)
442{
443 return request_mem_region (port->mapbase, UART_REG_SIZE,
444 "serial_lh7a40x") != NULL
445 ? 0 : -EBUSY;
446}
447
448static void lh7a40xuart_config_port (struct uart_port* port, int flags)
449{
450 if (flags & UART_CONFIG_TYPE) {
451 port->type = PORT_LH7A40X;
452 lh7a40xuart_request_port (port);
453 }
454}
455
456static int lh7a40xuart_verify_port (struct uart_port* port,
457 struct serial_struct* ser)
458{
459 int ret = 0;
460
461 if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
462 ret = -EINVAL;
463 if (ser->irq < 0 || ser->irq >= NR_IRQS)
464 ret = -EINVAL;
465 if (ser->baud_base < 9600) /* *** FIXME: is this true? */
466 ret = -EINVAL;
467 return ret;
468}
469
470static struct uart_ops lh7a40x_uart_ops = {
471 .tx_empty = lh7a40xuart_tx_empty,
472 .set_mctrl = lh7a40xuart_set_mctrl,
473 .get_mctrl = lh7a40xuart_get_mctrl,
474 .stop_tx = lh7a40xuart_stop_tx,
475 .start_tx = lh7a40xuart_start_tx,
476 .stop_rx = lh7a40xuart_stop_rx,
477 .enable_ms = lh7a40xuart_enable_ms,
478 .break_ctl = lh7a40xuart_break_ctl,
479 .startup = lh7a40xuart_startup,
480 .shutdown = lh7a40xuart_shutdown,
481 .set_termios = lh7a40xuart_set_termios,
482 .type = lh7a40xuart_type,
483 .release_port = lh7a40xuart_release_port,
484 .request_port = lh7a40xuart_request_port,
485 .config_port = lh7a40xuart_config_port,
486 .verify_port = lh7a40xuart_verify_port,
487};
488
489static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
490 {
491 .port = {
492 .membase = (void*) io_p2v (UART1_PHYS),
493 .mapbase = UART1_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000494 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 .irq = IRQ_UART1INTR,
496 .uartclk = 14745600/2,
497 .fifosize = 16,
498 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000499 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 .line = 0,
501 },
502 },
503 {
504 .port = {
505 .membase = (void*) io_p2v (UART2_PHYS),
506 .mapbase = UART2_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000507 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 .irq = IRQ_UART2INTR,
509 .uartclk = 14745600/2,
510 .fifosize = 16,
511 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000512 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 .line = 1,
514 },
515 },
516 {
517 .port = {
518 .membase = (void*) io_p2v (UART3_PHYS),
519 .mapbase = UART3_PHYS,
Russell King9b4a1612006-02-05 10:48:10 +0000520 .iotype = UPIO_MEM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 .irq = IRQ_UART3INTR,
522 .uartclk = 14745600/2,
523 .fifosize = 16,
524 .ops = &lh7a40x_uart_ops,
Russell Kingce8337c2006-01-21 19:28:15 +0000525 .flags = UPF_BOOT_AUTOCONF,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 .line = 2,
527 },
528 },
529};
530
531#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
532# define LH7A40X_CONSOLE NULL
533#else
534# define LH7A40X_CONSOLE &lh7a40x_console
535
Russell Kingd3587882006-03-20 20:00:09 +0000536static void lh7a40xuart_console_putchar(struct uart_port *port, int ch)
537{
538 while (UR(port, UART_R_STATUS) & nTxRdy)
539 ;
540 UR(port, UART_R_DATA) = ch;
541}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543static void lh7a40xuart_console_write (struct console* co,
544 const char* s,
545 unsigned int count)
546{
547 struct uart_port* port = &lh7a40x_ports[co->index].port;
548 unsigned int con = UR (port, UART_R_CON);
549 unsigned int inten = UR (port, UART_R_INTEN);
550
551
552 UR (port, UART_R_INTEN) = 0; /* Disable all interrupts */
553 BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
554
Russell Kingd3587882006-03-20 20:00:09 +0000555 uart_console_write(port, s, count, lh7a40xuart_console_putchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 /* Wait until all characters are sent */
558 while (UR (port, UART_R_STATUS) & TxBusy)
559 ;
560
561 /* Restore control and interrupt mask */
562 UR (port, UART_R_CON) = con;
563 UR (port, UART_R_INTEN) = inten;
564}
565
566static void __init lh7a40xuart_console_get_options (struct uart_port* port,
567 int* baud,
568 int* parity,
569 int* bits)
570{
571 if (UR (port, UART_R_CON) & UARTEN) {
572 unsigned int fcon = UR (port, UART_R_FCON);
573 unsigned int quot = UR (port, UART_R_BRCON) + 1;
574
575 switch (fcon & (PEN | EPS)) {
576 default: *parity = 'n'; break;
577 case PEN: *parity = 'o'; break;
578 case PEN | EPS: *parity = 'e'; break;
579 }
580
581 switch (fcon & WLEN) {
582 default:
583 case WLEN_8: *bits = 8; break;
584 case WLEN_7: *bits = 7; break;
585 case WLEN_6: *bits = 6; break;
586 case WLEN_5: *bits = 5; break;
587 }
588
589 *baud = port->uartclk/(16*quot);
590 }
591}
592
593static int __init lh7a40xuart_console_setup (struct console* co, char* options)
594{
595 struct uart_port* port;
596 int baud = 38400;
597 int bits = 8;
598 int parity = 'n';
599 int flow = 'n';
600
601 if (co->index >= DEV_NR) /* Bounds check on device number */
602 co->index = 0;
603 port = &lh7a40x_ports[co->index].port;
604
605 if (options)
606 uart_parse_options (options, &baud, &parity, &bits, &flow);
607 else
608 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
609
610 return uart_set_options (port, co, baud, parity, bits, flow);
611}
612
Vincent Sanders2d934862005-09-14 22:36:03 +0100613static struct uart_driver lh7a40x_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614static struct console lh7a40x_console = {
615 .name = "ttyAM",
616 .write = lh7a40xuart_console_write,
617 .device = uart_console_device,
618 .setup = lh7a40xuart_console_setup,
619 .flags = CON_PRINTBUFFER,
620 .index = -1,
621 .data = &lh7a40x_reg,
622};
623
624static int __init lh7a40xuart_console_init(void)
625{
626 register_console (&lh7a40x_console);
627 return 0;
628}
629
630console_initcall (lh7a40xuart_console_init);
631
632#endif
633
634static struct uart_driver lh7a40x_reg = {
635 .owner = THIS_MODULE,
636 .driver_name = "ttyAM",
637 .dev_name = "ttyAM",
638 .major = DEV_MAJOR,
639 .minor = DEV_MINOR,
640 .nr = DEV_NR,
641 .cons = LH7A40X_CONSOLE,
642};
643
644static int __init lh7a40xuart_init(void)
645{
646 int ret;
647
648 printk (KERN_INFO "serial: LH7A40X serial driver\n");
649
650 ret = uart_register_driver (&lh7a40x_reg);
651
652 if (ret == 0) {
653 int i;
654
Marc Singerfb62c5a2006-05-16 11:41:29 +0100655 for (i = 0; i < DEV_NR; i++) {
656 /* UART3, when used, requires GPIO pin reallocation */
657 if (lh7a40x_ports[i].port.mapbase == UART3_PHYS)
658 GPIO_PINMUX |= 1<<3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 uart_add_one_port (&lh7a40x_reg,
660 &lh7a40x_ports[i].port);
Marc Singerfb62c5a2006-05-16 11:41:29 +0100661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
663 return ret;
664}
665
666static void __exit lh7a40xuart_exit(void)
667{
668 int i;
669
670 for (i = 0; i < DEV_NR; i++)
671 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
672
673 uart_unregister_driver (&lh7a40x_reg);
674}
675
676module_init (lh7a40xuart_init);
677module_exit (lh7a40xuart_exit);
678
679MODULE_AUTHOR ("Marc Singer");
680MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
681MODULE_LICENSE ("GPL");