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