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