vserver 1.9.5.x5
[linux-2.6.git] / drivers / serial / serial_lh7a40x.c
1 /* 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
30 #include <linux/config.h>
31
32 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33 #define SUPPORT_SYSRQ
34 #endif
35
36 #include <linux/module.h>
37 #include <linux/ioport.h>
38 #include <linux/init.h>
39 #include <linux/console.h>
40 #include <linux/sysrq.h>
41 #include <linux/tty.h>
42 #include <linux/tty_flip.h>
43 #include <linux/serial_core.h>
44 #include <linux/serial.h>
45
46 #include <asm/io.h>
47 #include <asm/irq.h>
48
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
110 struct uart_port_lh7a40x {
111         struct uart_port port;
112         unsigned int statusPrev; /* Most recently read modem status */
113 };
114
115 static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
116 {
117         BIT_CLR (port, UART_R_INTEN, TxInt);
118 }
119
120 static void lh7a40xuart_start_tx (struct uart_port* port,
121                                   unsigned int tty_start)
122 {
123         BIT_SET (port, UART_R_INTEN, TxInt);
124
125         /* *** FIXME: do I need to check for startup of the
126                       transmitter?  The old driver did, but AMBA
127                       doesn't . */
128 }
129
130 static void lh7a40xuart_stop_rx (struct uart_port* port)
131 {
132         BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
133 }
134
135 static void lh7a40xuart_enable_ms (struct uart_port* port)
136 {
137         BIT_SET (port, UART_R_INTEN, ModemInt);
138 }
139
140 static void
141 #ifdef SUPPORT_SYSRQ
142 lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
143 #else
144 lh7a40xuart_rx_chars (struct uart_port* port)
145 #endif
146 {
147         struct tty_struct* tty = port->info->tty;
148         int cbRxMax = 256;      /* (Gross) limit on receive */
149         unsigned int data, flag;/* Received data and status */
150
151         while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
152                 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
153                         if (tty->low_latency)
154                                 tty_flip_buffer_push(tty);
155                         /*
156                          * If this failed then we will throw away the
157                          * bytes but must do so to clear interrupts
158                          */
159                 }
160
161                 data = UR (port, UART_R_DATA);
162                 flag = TTY_NORMAL;
163                 ++port->icount.rx;
164
165                 if (data & RxError) {   /* Quick check, short-circuit */
166                         if (data & RxBreak) {
167                                 data &= ~(RxFramingError | RxParityError);
168                                 ++port->icount.brk;
169                                 if (uart_handle_break (port))
170                                         continue;
171                         }
172                         else if (data & RxParityError)
173                                 ++port->icount.parity;
174                         else if (data & RxFramingError)
175                                 ++port->icount.frame;
176                         if (data & RxOverrunError)
177                                 ++port->icount.overrun;
178
179                                 /* Mask by termios, leave Rx'd byte */
180                         data &= port->read_status_mask | 0xff;
181
182                         if (data & RxBreak)
183                                 flag = TTY_BREAK;
184                         else if (data & RxParityError)
185                                 flag = TTY_PARITY;
186                         else if (data & RxFramingError)
187                                 flag = TTY_FRAME;
188                 }
189
190                 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
191                         continue;
192
193                 if ((data & port->ignore_status_mask) == 0) {
194                         tty_insert_flip_char(tty, data, flag);
195                 }
196                 if ((data & RxOverrunError)
197                     && tty->flip.count < TTY_FLIPBUF_SIZE) {
198                         /*
199                          * Overrun is special, since it's reported
200                          * immediately, and doesn't affect the current
201                          * character
202                          */
203                         tty_insert_flip_char(tty, 0, TTY_OVERRUN);
204                 }
205         }
206         tty_flip_buffer_push (tty);
207         return;
208 }
209
210 static void lh7a40xuart_tx_chars (struct uart_port* port)
211 {
212         struct circ_buf* xmit = &port->info->xmit;
213         int cbTxMax = port->fifosize;
214
215         if (port->x_char) {
216                 UR (port, UART_R_DATA) = port->x_char;
217                 ++port->icount.tx;
218                 port->x_char = 0;
219                 return;
220         }
221         if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
222                 lh7a40xuart_stop_tx (port, 0);
223                 return;
224         }
225
226         /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
227            that at least half of the FIFO is empty.  Instead, we check
228            status for every character.  Using the AMBA method causes
229            the transmitter to drop characters. */
230
231         do {
232                 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
233                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
234                 ++port->icount.tx;
235                 if (uart_circ_empty(xmit))
236                         break;
237         } while (!(UR (port, UART_R_STATUS) & nTxRdy)
238                  && cbTxMax--);
239
240         if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
241                 uart_write_wakeup (port);
242
243         if (uart_circ_empty (xmit))
244                 lh7a40xuart_stop_tx (port, 0);
245 }
246
247 static void lh7a40xuart_modem_status (struct uart_port* port)
248 {
249         unsigned int status = UR (port, UART_R_STATUS);
250         unsigned int delta
251                 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
252
253         BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
254
255         if (!delta)             /* Only happens if we missed 2 transitions */
256                 return;
257
258         ((struct uart_port_lh7a40x*) port)->statusPrev = status;
259
260         if (delta & DCD)
261                 uart_handle_dcd_change (port, status & DCD);
262
263         if (delta & DSR)
264                 ++port->icount.dsr;
265
266         if (delta & CTS)
267                 uart_handle_cts_change (port, status & CTS);
268
269         wake_up_interruptible (&port->info->delta_msr_wait);
270 }
271
272 static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
273                                     struct pt_regs* regs)
274 {
275         struct uart_port* port = dev_id;
276         unsigned int cLoopLimit = ISR_LOOP_LIMIT;
277         unsigned int isr = UR (port, UART_R_ISR);
278
279
280         do {
281                 if (isr & (RxInt | RxTimeoutInt))
282 #ifdef SUPPORT_SYSRQ
283                         lh7a40xuart_rx_chars(port, regs);
284 #else
285                         lh7a40xuart_rx_chars(port);
286 #endif
287                 if (isr & ModemInt)
288                         lh7a40xuart_modem_status (port);
289                 if (isr & TxInt)
290                         lh7a40xuart_tx_chars (port);
291
292                 if (--cLoopLimit == 0)
293                         break;
294
295                 isr = UR (port, UART_R_ISR);
296         } while (isr & (RxInt | TxInt | RxTimeoutInt));
297
298         return IRQ_HANDLED;
299 }
300
301 static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
302 {
303         return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
304 }
305
306 static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
307 {
308         unsigned int result = 0;
309         unsigned int status = UR (port, UART_R_STATUS);
310
311         if (status & DCD)
312                 result |= TIOCM_CAR;
313         if (status & DSR)
314                 result |= TIOCM_DSR;
315         if (status & CTS)
316                 result |= TIOCM_CTS;
317
318         return result;
319 }
320
321 static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
322 {
323         /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
324         /* Note, kernel appears to be setting DTR and RTS on console. */
325
326         /* *** FIXME: this deserves more work.  There's some work in
327                tracing all of the IO pins. */
328 #if 0
329         if( port->mapbase == UART1_PHYS) {
330                 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
331
332                 if (mctrl & TIOCM_RTS)
333                         gpio->pbdr &= ~GPIOB_UART1_RTS;
334                 else
335                         gpio->pbdr |= GPIOB_UART1_RTS;
336         }
337 #endif
338 }
339
340 static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
341 {
342         unsigned long flags;
343
344         spin_lock_irqsave(&port->lock, flags);
345         if (break_state == -1)
346                 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
347         else
348                 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
349         spin_unlock_irqrestore(&port->lock, flags);
350 }
351
352 static int lh7a40xuart_startup (struct uart_port* port)
353 {
354         int retval;
355
356         retval = request_irq (port->irq, lh7a40xuart_int, 0,
357                               "serial_lh7a40x", port);
358         if (retval)
359                 return retval;
360
361                                 /* Initial modem control-line settings */
362         ((struct uart_port_lh7a40x*) port)->statusPrev
363                 = UR (port, UART_R_STATUS);
364
365         /* There is presently no configuration option to enable IR.
366            Thus, we always disable it. */
367
368         BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
369         BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
370
371         return 0;
372 }
373
374 static void lh7a40xuart_shutdown (struct uart_port* port)
375 {
376         free_irq (port->irq, port);
377         BIT_CLR (port, UART_R_FCON, BRK | FEN);
378         BIT_CLR (port, UART_R_CON, UARTEN);
379 }
380
381 static void lh7a40xuart_set_termios (struct uart_port* port,
382                                      struct termios* termios,
383                                      struct termios* old)
384 {
385         unsigned int con;
386         unsigned int inten;
387         unsigned int fcon;
388         unsigned long flags;
389         unsigned int baud;
390         unsigned int quot;
391
392         baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
393         quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
394
395         switch (termios->c_cflag & CSIZE) {
396         case CS5:
397                 fcon = WLEN_5;
398                 break;
399         case CS6:
400                 fcon = WLEN_6;
401                 break;
402         case CS7:
403                 fcon = WLEN_7;
404                 break;
405         case CS8:
406         default:
407                 fcon = WLEN_8;
408                 break;
409         }
410         if (termios->c_cflag & CSTOPB)
411                 fcon |= STP2;
412         if (termios->c_cflag & PARENB) {
413                 fcon |= PEN;
414                 if (!(termios->c_cflag & PARODD))
415                         fcon |= EPS;
416         }
417         if (port->fifosize > 1)
418                 fcon |= FEN;
419
420         spin_lock_irqsave (&port->lock, flags);
421
422         uart_update_timeout (port, termios->c_cflag, baud);
423
424         port->read_status_mask = RxOverrunError;
425         if (termios->c_iflag & INPCK)
426                 port->read_status_mask |= RxFramingError | RxParityError;
427         if (termios->c_iflag & (BRKINT | PARMRK))
428                 port->read_status_mask |= RxBreak;
429
430                 /* Figure mask for status we ignore */
431         port->ignore_status_mask = 0;
432         if (termios->c_iflag & IGNPAR)
433                 port->ignore_status_mask |= RxFramingError | RxParityError;
434         if (termios->c_iflag & IGNBRK) {
435                 port->ignore_status_mask |= RxBreak;
436                 /* Ignore overrun when ignorning parity */
437                 /* *** FIXME: is this in the right place? */
438                 if (termios->c_iflag & IGNPAR)
439                         port->ignore_status_mask |= RxOverrunError;
440         }
441
442                 /* Ignore all receive errors when receive disabled */
443         if ((termios->c_cflag & CREAD) == 0)
444                 port->ignore_status_mask |= RxError;
445
446         con   = UR (port, UART_R_CON);
447         inten = (UR (port, UART_R_INTEN) & ~ModemInt);
448
449         if (UART_ENABLE_MS (port, termios->c_cflag))
450                 inten |= ModemInt;
451
452         BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
453         UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
454         UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
455         UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
456         UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
457         UR (port, UART_R_CON)   = con;          /* Restore UART mode */
458
459         spin_unlock_irqrestore(&port->lock, flags);
460 }
461
462 static const char* lh7a40xuart_type (struct uart_port* port)
463 {
464         return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
465 }
466
467 static void lh7a40xuart_release_port (struct uart_port* port)
468 {
469         release_mem_region (port->mapbase, UART_REG_SIZE);
470 }
471
472 static int lh7a40xuart_request_port (struct uart_port* port)
473 {
474         return request_mem_region (port->mapbase, UART_REG_SIZE,
475                                    "serial_lh7a40x") != NULL
476                 ? 0 : -EBUSY;
477 }
478
479 static void lh7a40xuart_config_port (struct uart_port* port, int flags)
480 {
481         if (flags & UART_CONFIG_TYPE) {
482                 port->type = PORT_LH7A40X;
483                 lh7a40xuart_request_port (port);
484         }
485 }
486
487 static int lh7a40xuart_verify_port (struct uart_port* port,
488                                     struct serial_struct* ser)
489 {
490         int ret = 0;
491
492         if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
493                 ret = -EINVAL;
494         if (ser->irq < 0 || ser->irq >= NR_IRQS)
495                 ret = -EINVAL;
496         if (ser->baud_base < 9600) /* *** FIXME: is this true? */
497                 ret = -EINVAL;
498         return ret;
499 }
500
501 static struct uart_ops lh7a40x_uart_ops = {
502         .tx_empty       = lh7a40xuart_tx_empty,
503         .set_mctrl      = lh7a40xuart_set_mctrl,
504         .get_mctrl      = lh7a40xuart_get_mctrl,
505         .stop_tx        = lh7a40xuart_stop_tx,
506         .start_tx       = lh7a40xuart_start_tx,
507         .stop_rx        = lh7a40xuart_stop_rx,
508         .enable_ms      = lh7a40xuart_enable_ms,
509         .break_ctl      = lh7a40xuart_break_ctl,
510         .startup        = lh7a40xuart_startup,
511         .shutdown       = lh7a40xuart_shutdown,
512         .set_termios    = lh7a40xuart_set_termios,
513         .type           = lh7a40xuart_type,
514         .release_port   = lh7a40xuart_release_port,
515         .request_port   = lh7a40xuart_request_port,
516         .config_port    = lh7a40xuart_config_port,
517         .verify_port    = lh7a40xuart_verify_port,
518 };
519
520 static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
521         {
522                 .port = {
523                         .membase        = (void*) io_p2v (UART1_PHYS),
524                         .mapbase        = UART1_PHYS,
525                         .iotype         = SERIAL_IO_MEM,
526                         .irq            = IRQ_UART1INTR,
527                         .uartclk        = 14745600/2,
528                         .fifosize       = 16,
529                         .ops            = &lh7a40x_uart_ops,
530                         .flags          = ASYNC_BOOT_AUTOCONF,
531                         .line           = 0,
532                 },
533         },
534         {
535                 .port = {
536                         .membase        = (void*) io_p2v (UART2_PHYS),
537                         .mapbase        = UART2_PHYS,
538                         .iotype         = SERIAL_IO_MEM,
539                         .irq            = IRQ_UART2INTR,
540                         .uartclk        = 14745600/2,
541                         .fifosize       = 16,
542                         .ops            = &lh7a40x_uart_ops,
543                         .flags          = ASYNC_BOOT_AUTOCONF,
544                         .line           = 1,
545                 },
546         },
547         {
548                 .port = {
549                         .membase        = (void*) io_p2v (UART3_PHYS),
550                         .mapbase        = UART3_PHYS,
551                         .iotype         = SERIAL_IO_MEM,
552                         .irq            = IRQ_UART3INTR,
553                         .uartclk        = 14745600/2,
554                         .fifosize       = 16,
555                         .ops            = &lh7a40x_uart_ops,
556                         .flags          = ASYNC_BOOT_AUTOCONF,
557                         .line           = 2,
558                 },
559         },
560 };
561
562 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
563 # define LH7A40X_CONSOLE NULL
564 #else
565 # define LH7A40X_CONSOLE &lh7a40x_console
566
567
568 static void lh7a40xuart_console_write (struct console* co,
569                                        const char* s,
570                                        unsigned int count)
571 {
572         struct uart_port* port = &lh7a40x_ports[co->index].port;
573         unsigned int con = UR (port, UART_R_CON);
574         unsigned int inten = UR (port, UART_R_INTEN);
575
576
577         UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
578         BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
579
580         for (; count-- > 0; ++s) {
581                 while (UR (port, UART_R_STATUS) & nTxRdy)
582                         ;
583                 UR (port, UART_R_DATA) = *s;
584                 if (*s == '\n') {
585                         while ((UR (port, UART_R_STATUS) & TxBusy))
586                                 ;
587                         UR (port, UART_R_DATA) = '\r';
588                 }
589         }
590
591                                 /* Wait until all characters are sent */
592         while (UR (port, UART_R_STATUS) & TxBusy)
593                 ;
594
595                                 /* Restore control and interrupt mask */
596         UR (port, UART_R_CON) = con;
597         UR (port, UART_R_INTEN) = inten;
598 }
599
600 static void __init lh7a40xuart_console_get_options (struct uart_port* port,
601                                                     int* baud,
602                                                     int* parity,
603                                                     int* bits)
604 {
605         if (UR (port, UART_R_CON) & UARTEN) {
606                 unsigned int fcon = UR (port, UART_R_FCON);
607                 unsigned int quot = UR (port, UART_R_BRCON) + 1;
608
609                 switch (fcon & (PEN | EPS)) {
610                 default:        *parity = 'n'; break;
611                 case PEN:       *parity = 'o'; break;
612                 case PEN | EPS: *parity = 'e'; break;
613                 }
614
615                 switch (fcon & WLEN) {
616                 default:
617                 case WLEN_8: *bits = 8; break;
618                 case WLEN_7: *bits = 7; break;
619                 case WLEN_6: *bits = 6; break;
620                 case WLEN_5: *bits = 5; break;
621                 }
622
623                 *baud = port->uartclk/(16*quot);
624         }
625 }
626
627 static int __init lh7a40xuart_console_setup (struct console* co, char* options)
628 {
629         struct uart_port* port;
630         int baud = 38400;
631         int bits = 8;
632         int parity = 'n';
633         int flow = 'n';
634
635         if (co->index >= DEV_NR) /* Bounds check on device number */
636                 co->index = 0;
637         port = &lh7a40x_ports[co->index].port;
638
639         if (options)
640                 uart_parse_options (options, &baud, &parity, &bits, &flow);
641         else
642                 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
643
644         return uart_set_options (port, co, baud, parity, bits, flow);
645 }
646
647 extern struct uart_driver lh7a40x_reg;
648 static struct console lh7a40x_console = {
649         .name           = "ttyAM",
650         .write          = lh7a40xuart_console_write,
651         .device         = uart_console_device,
652         .setup          = lh7a40xuart_console_setup,
653         .flags          = CON_PRINTBUFFER,
654         .index          = -1,
655         .data           = &lh7a40x_reg,
656 };
657
658 static int __init lh7a40xuart_console_init(void)
659 {
660         register_console (&lh7a40x_console);
661         return 0;
662 }
663
664 console_initcall (lh7a40xuart_console_init);
665
666 #endif
667
668 static struct uart_driver lh7a40x_reg = {
669         .owner                  = THIS_MODULE,
670         .driver_name            = "ttyAM",
671         .dev_name               = "ttyAM",
672         .major                  = DEV_MAJOR,
673         .minor                  = DEV_MINOR,
674         .nr                     = DEV_NR,
675         .cons                   = LH7A40X_CONSOLE,
676 };
677
678 static int __init lh7a40xuart_init(void)
679 {
680         int ret;
681
682         printk (KERN_INFO "serial: LH7A40X serial driver\n");
683
684         ret = uart_register_driver (&lh7a40x_reg);
685
686         if (ret == 0) {
687                 int i;
688
689                 for (i = 0; i < DEV_NR; i++)
690                         uart_add_one_port (&lh7a40x_reg,
691                                            &lh7a40x_ports[i].port);
692         }
693         return ret;
694 }
695
696 static void __exit lh7a40xuart_exit(void)
697 {
698         int i;
699
700         for (i = 0; i < DEV_NR; i++)
701                 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
702
703         uart_unregister_driver (&lh7a40x_reg);
704 }
705
706 module_init (lh7a40xuart_init);
707 module_exit (lh7a40xuart_exit);
708
709 MODULE_AUTHOR ("Marc Singer");
710 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
711 MODULE_LICENSE ("GPL");