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