Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 Jan 2011 00:39:23 +0000 (16:39 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 Jan 2011 00:39:23 +0000 (16:39 -0800)
* 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6:
  tty: update MAINTAINERS file due to driver movement
  tty: move drivers/serial/ to drivers/tty/serial/
  tty: move hvc drivers to drivers/tty/hvc/

1  2 
MAINTAINERS
drivers/Makefile
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h

diff --cc MAINTAINERS
@@@ -3527,15 -3505,8 +3527,15 @@@ JSM Neo PCI based serial car
  M:    Breno Leitao <leitao@linux.vnet.ibm.com>
  L:    linux-serial@vger.kernel.org
  S:    Maintained
- F:    drivers/serial/jsm/
+ F:    drivers/tty/serial/jsm/
  
 +K10TEMP HARDWARE MONITORING DRIVER
 +M:    Clemens Ladisch <clemens@ladisch.de>
 +L:    lm-sensors@lm-sensors.org
 +S:    Maintained
 +F:    Documentation/hwmon/k10temp
 +F:    drivers/hwmon/k10temp.c
 +
  K8TEMP HARDWARE MONITORING DRIVER
  M:    Rudolf Marek <r.marek@assembler.cz>
  L:    lm-sensors@lm-sensors.org
Simple merge
index 0000000,3892666..2a1d52f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1808 +1,1813 @@@
+ /*
+  *  linux/drivers/char/atmel_serial.c
+  *
+  *  Driver for Atmel AT91 / AT32 Serial ports
+  *  Copyright (C) 2003 Rick Bronson
+  *
+  *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+  *
+  *  DMA support added by Chip Coldwell.
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  *
+  */
+ #include <linux/module.h>
+ #include <linux/tty.h>
+ #include <linux/ioport.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+ #include <linux/serial.h>
+ #include <linux/clk.h>
+ #include <linux/console.h>
+ #include <linux/sysrq.h>
+ #include <linux/tty_flip.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/atmel_pdc.h>
+ #include <linux/atmel_serial.h>
+ #include <linux/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/ioctls.h>
+ #include <asm/mach/serial_at91.h>
+ #include <mach/board.h>
+ #ifdef CONFIG_ARM
+ #include <mach/cpu.h>
+ #include <mach/gpio.h>
+ #endif
+ #define PDC_BUFFER_SIZE               512
+ /* Revisit: We should calculate this based on the actual port settings */
+ #define PDC_RX_TIMEOUT                (3 * 10)                /* 3 bytes */
+ #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+ #include <linux/serial_core.h>
+ static void atmel_start_rx(struct uart_port *port);
+ static void atmel_stop_rx(struct uart_port *port);
+ #ifdef CONFIG_SERIAL_ATMEL_TTYAT
+ /* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
+  * should coexist with the 8250 driver, such as if we have an external 16C550
+  * UART. */
+ #define SERIAL_ATMEL_MAJOR    204
+ #define MINOR_START           154
+ #define ATMEL_DEVICENAME      "ttyAT"
+ #else
+ /* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
+  * name, but it is legally reserved for the 8250 driver. */
+ #define SERIAL_ATMEL_MAJOR    TTY_MAJOR
+ #define MINOR_START           64
+ #define ATMEL_DEVICENAME      "ttyS"
+ #endif
+ #define ATMEL_ISR_PASS_LIMIT  256
+ /* UART registers. CR is write-only, hence no GET macro */
+ #define UART_PUT_CR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_CR)
+ #define UART_GET_MR(port)     __raw_readl((port)->membase + ATMEL_US_MR)
+ #define UART_PUT_MR(port,v)   __raw_writel(v, (port)->membase + ATMEL_US_MR)
+ #define UART_PUT_IER(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_IER)
+ #define UART_PUT_IDR(port,v)  __raw_writel(v, (port)->membase + ATMEL_US_IDR)
+ #define UART_GET_IMR(port)    __raw_readl((port)->membase + ATMEL_US_IMR)
+ #define UART_GET_CSR(port)    __raw_readl((port)->membase + ATMEL_US_CSR)
+ #define UART_GET_CHAR(port)   __raw_readl((port)->membase + ATMEL_US_RHR)
+ #define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR)
+ #define UART_GET_BRGR(port)   __raw_readl((port)->membase + ATMEL_US_BRGR)
+ #define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
+ #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
+ #define UART_PUT_TTGR(port, v)        __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+  /* PDC registers */
+ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
+ #define UART_GET_PTSR(port)   __raw_readl((port)->membase + ATMEL_PDC_PTSR)
+ #define UART_PUT_RPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
+ #define UART_GET_RPR(port)    __raw_readl((port)->membase + ATMEL_PDC_RPR)
+ #define UART_PUT_RCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
+ #define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
+ #define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
+ #define UART_PUT_TPR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
+ #define UART_PUT_TCR(port,v)  __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
+ #define UART_GET_TCR(port)    __raw_readl((port)->membase + ATMEL_PDC_TCR)
+ static int (*atmel_open_hook)(struct uart_port *);
+ static void (*atmel_close_hook)(struct uart_port *);
+ struct atmel_dma_buffer {
+       unsigned char   *buf;
+       dma_addr_t      dma_addr;
+       unsigned int    dma_size;
+       unsigned int    ofs;
+ };
+ struct atmel_uart_char {
+       u16             status;
+       u16             ch;
+ };
+ #define ATMEL_SERIAL_RINGSIZE 1024
+ /*
+  * We wrap our port structure around the generic uart_port.
+  */
+ struct atmel_uart_port {
+       struct uart_port        uart;           /* uart */
+       struct clk              *clk;           /* uart clock */
+       int                     may_wakeup;     /* cached value of device_may_wakeup for times we need to disable it */
+       u32                     backup_imr;     /* IMR saved during suspend */
+       int                     break_active;   /* break being received */
+       short                   use_dma_rx;     /* enable PDC receiver */
+       short                   pdc_rx_idx;     /* current PDC RX buffer */
+       struct atmel_dma_buffer pdc_rx[2];      /* PDC receier */
+       short                   use_dma_tx;     /* enable PDC transmitter */
+       struct atmel_dma_buffer pdc_tx;         /* PDC transmitter */
+       struct tasklet_struct   tasklet;
+       unsigned int            irq_status;
+       unsigned int            irq_status_prev;
+       struct circ_buf         rx_ring;
+       struct serial_rs485     rs485;          /* rs485 settings */
+       unsigned int            tx_done_mask;
+ };
+ static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+ #ifdef SUPPORT_SYSRQ
+ static struct console atmel_console;
+ #endif
+ static inline struct atmel_uart_port *
+ to_atmel_uart_port(struct uart_port *uart)
+ {
+       return container_of(uart, struct atmel_uart_port, uart);
+ }
+ #ifdef CONFIG_SERIAL_ATMEL_PDC
+ static bool atmel_use_dma_rx(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       return atmel_port->use_dma_rx;
+ }
+ static bool atmel_use_dma_tx(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       return atmel_port->use_dma_tx;
+ }
+ #else
+ static bool atmel_use_dma_rx(struct uart_port *port)
+ {
+       return false;
+ }
+ static bool atmel_use_dma_tx(struct uart_port *port)
+ {
+       return false;
+ }
+ #endif
+ /* Enable or disable the rs485 support */
+ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int mode;
+       spin_lock(&port->lock);
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+       mode = UART_GET_MR(port);
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+       atmel_port->rs485 = *rs485conf;
+       if (rs485conf->flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+               if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port, rs485conf->delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+               if (atmel_use_dma_tx(port))
+                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+                               ATMEL_US_TXBUFE;
+               else
+                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+       UART_PUT_MR(port, mode);
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+       spin_unlock(&port->lock);
+ }
+ /*
+  * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+  */
+ static u_int atmel_tx_empty(struct uart_port *port)
+ {
+       return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+ }
+ /*
+  * Set state of the modem control output lines
+  */
+ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
+ {
+       unsigned int control = 0;
+       unsigned int mode;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ #ifdef CONFIG_ARCH_AT91RM9200
+       if (cpu_is_at91rm9200()) {
+               /*
+                * AT91RM9200 Errata #39: RTS0 is not internally connected
+                * to PA21. We need to drive the pin manually.
+                */
+               if (port->mapbase == AT91RM9200_BASE_US0) {
+                       if (mctrl & TIOCM_RTS)
+                               at91_set_gpio_value(AT91_PIN_PA21, 0);
+                       else
+                               at91_set_gpio_value(AT91_PIN_PA21, 1);
+               }
+       }
+ #endif
+       if (mctrl & TIOCM_RTS)
+               control |= ATMEL_US_RTSEN;
+       else
+               control |= ATMEL_US_RTSDIS;
+       if (mctrl & TIOCM_DTR)
+               control |= ATMEL_US_DTREN;
+       else
+               control |= ATMEL_US_DTRDIS;
+       UART_PUT_CR(port, control);
+       /* Local loopback mode? */
+       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+       if (mctrl & TIOCM_LOOP)
+               mode |= ATMEL_US_CHMODE_LOC_LOOP;
+       else
+               mode |= ATMEL_US_CHMODE_NORMAL;
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+       UART_PUT_MR(port, mode);
+ }
+ /*
+  * Get state of the modem control input lines
+  */
+ static u_int atmel_get_mctrl(struct uart_port *port)
+ {
+       unsigned int status, ret = 0;
+       status = UART_GET_CSR(port);
+       /*
+        * The control signals are active low.
+        */
+       if (!(status & ATMEL_US_DCD))
+               ret |= TIOCM_CD;
+       if (!(status & ATMEL_US_CTS))
+               ret |= TIOCM_CTS;
+       if (!(status & ATMEL_US_DSR))
+               ret |= TIOCM_DSR;
+       if (!(status & ATMEL_US_RI))
+               ret |= TIOCM_RI;
+       return ret;
+ }
+ /*
+  * Stop transmitting.
+  */
+ static void atmel_stop_tx(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (atmel_use_dma_tx(port)) {
+               /* disable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+       }
+       /* Disable interrupts */
+       UART_PUT_IDR(port, atmel_port->tx_done_mask);
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_start_rx(port);
+ }
+ /*
+  * Start transmitting.
+  */
+ static void atmel_start_tx(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (atmel_use_dma_tx(port)) {
+               if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+                       /* The transmitter is already running.  Yes, we
+                          really need this.*/
+                       return;
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+                       atmel_stop_rx(port);
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+       }
+       /* Enable interrupts */
+       UART_PUT_IER(port, atmel_port->tx_done_mask);
+ }
+ /*
+  * start receiving - port is in process of being opened.
+  */
+ static void atmel_start_rx(struct uart_port *port)
+ {
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);  /* reset status and receiver */
+       if (atmel_use_dma_rx(port)) {
+               /* enable PDC controller */
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+ }
+ /*
+  * Stop receiving - port is in process of being closed.
+  */
+ static void atmel_stop_rx(struct uart_port *port)
+ {
+       if (atmel_use_dma_rx(port)) {
+               /* disable PDC receive */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
+               UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+                       port->read_status_mask);
+       } else {
+               UART_PUT_IDR(port, ATMEL_US_RXRDY);
+       }
+ }
+ /*
+  * Enable modem status interrupts
+  */
+ static void atmel_enable_ms(struct uart_port *port)
+ {
+       UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
+                       | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+ }
+ /*
+  * Control the transmission of a break signal
+  */
+ static void atmel_break_ctl(struct uart_port *port, int break_state)
+ {
+       if (break_state != 0)
+               UART_PUT_CR(port, ATMEL_US_STTBRK);     /* start break */
+       else
+               UART_PUT_CR(port, ATMEL_US_STPBRK);     /* stop break */
+ }
+ /*
+  * Stores the incoming character in the ring buffer
+  */
+ static void
+ atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
+                    unsigned int ch)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       struct atmel_uart_char *c;
+       if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
+               /* Buffer overflow, ignore char */
+               return;
+       c = &((struct atmel_uart_char *)ring->buf)[ring->head];
+       c->status       = status;
+       c->ch           = ch;
+       /* Make sure the character is stored before we update head. */
+       smp_wmb();
+       ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+ }
+ /*
+  * Deal with parity, framing and overrun errors.
+  */
+ static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
+ {
+       /* clear error */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+       if (status & ATMEL_US_RXBRK) {
+               /* ignore side-effect */
+               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+               port->icount.brk++;
+       }
+       if (status & ATMEL_US_PARE)
+               port->icount.parity++;
+       if (status & ATMEL_US_FRAME)
+               port->icount.frame++;
+       if (status & ATMEL_US_OVRE)
+               port->icount.overrun++;
+ }
+ /*
+  * Characters received (called from interrupt handler)
+  */
+ static void atmel_rx_chars(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, ch;
+       status = UART_GET_CSR(port);
+       while (status & ATMEL_US_RXRDY) {
+               ch = UART_GET_CHAR(port);
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+                            || atmel_port->break_active)) {
+                       /* clear error */
+                       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+                       if (status & ATMEL_US_RXBRK
+                           && !atmel_port->break_active) {
+                               atmel_port->break_active = 1;
+                               UART_PUT_IER(port, ATMEL_US_RXBRK);
+                       } else {
+                               /*
+                                * This is either the end-of-break
+                                * condition or we've received at
+                                * least one character without RXBRK
+                                * being set. In both cases, the next
+                                * RXBRK will indicate start-of-break.
+                                */
+                               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+                               status &= ~ATMEL_US_RXBRK;
+                               atmel_port->break_active = 0;
+                       }
+               }
+               atmel_buffer_rx_char(port, status, ch);
+               status = UART_GET_CSR(port);
+       }
+       tasklet_schedule(&atmel_port->tasklet);
+ }
+ /*
+  * Transmit characters (called from tasklet with TXRDY interrupt
+  * disabled)
+  */
+ static void atmel_tx_chars(struct uart_port *port)
+ {
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+       }
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+       while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
+               UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (!uart_circ_empty(xmit))
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+ }
+ /*
+  * receive interrupt handler.
+  */
+ static void
+ atmel_handle_receive(struct uart_port *port, unsigned int pending)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (atmel_use_dma_rx(port)) {
+               /*
+                * PDC receive. Just schedule the tasklet and let it
+                * figure out the details.
+                *
+                * TODO: We're not handling error flags correctly at
+                * the moment.
+                */
+               if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) {
+                       UART_PUT_IDR(port, (ATMEL_US_ENDRX
+                                               | ATMEL_US_TIMEOUT));
+                       tasklet_schedule(&atmel_port->tasklet);
+               }
+               if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE |
+                               ATMEL_US_FRAME | ATMEL_US_PARE))
+                       atmel_pdc_rxerr(port, pending);
+       }
+       /* Interrupt receive */
+       if (pending & ATMEL_US_RXRDY)
+               atmel_rx_chars(port);
+       else if (pending & ATMEL_US_RXBRK) {
+               /*
+                * End of break detected. If it came along with a
+                * character, atmel_rx_chars will handle it.
+                */
+               UART_PUT_CR(port, ATMEL_US_RSTSTA);
+               UART_PUT_IDR(port, ATMEL_US_RXBRK);
+               atmel_port->break_active = 0;
+       }
+ }
+ /*
+  * transmit interrupt handler. (Transmit is IRQF_NODELAY safe)
+  */
+ static void
+ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (pending & atmel_port->tx_done_mask) {
+               /* Either PDC or interrupt transmission */
+               UART_PUT_IDR(port, atmel_port->tx_done_mask);
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+ }
+ /*
+  * status flags interrupt handler.
+  */
+ static void
+ atmel_handle_status(struct uart_port *port, unsigned int pending,
+                   unsigned int status)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC
+                               | ATMEL_US_CTSIC)) {
+               atmel_port->irq_status = status;
+               tasklet_schedule(&atmel_port->tasklet);
+       }
+ }
+ /*
+  * Interrupt handler
+  */
+ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+ {
+       struct uart_port *port = dev_id;
+       unsigned int status, pending, pass_counter = 0;
+       do {
+               status = UART_GET_CSR(port);
+               pending = status & UART_GET_IMR(port);
+               if (!pending)
+                       break;
+               atmel_handle_receive(port, pending);
+               atmel_handle_status(port, pending, status);
+               atmel_handle_transmit(port, pending);
+       } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT);
+       return pass_counter ? IRQ_HANDLED : IRQ_NONE;
+ }
+ /*
+  * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
+  */
+ static void atmel_tx_dma(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *xmit = &port->state->xmit;
+       struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+       int count;
+       /* nothing left to transmit? */
+       if (UART_GET_TCR(port))
+               return;
+       xmit->tail += pdc->ofs;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+       port->icount.tx += pdc->ofs;
+       pdc->ofs = 0;
+       /* more to transmit - setup next transfer */
+       /* disable PDC transmit */
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+               dma_sync_single_for_device(port->dev,
+                                          pdc->dma_addr,
+                                          pdc->dma_size,
+                                          DMA_TO_DEVICE);
+               count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+               pdc->ofs = count;
+               UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
+               UART_PUT_TCR(port, count);
+               /* re-enable PDC transmit */
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+               /* Enable interrupts */
+               UART_PUT_IER(port, atmel_port->tx_done_mask);
+       } else {
+               if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+                       /* DMA done, stop TX, start RX for RS485 */
+                       atmel_start_rx(port);
+               }
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+ }
+ static void atmel_rx_from_ring(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct circ_buf *ring = &atmel_port->rx_ring;
+       unsigned int flg;
+       unsigned int status;
+       while (ring->head != ring->tail) {
+               struct atmel_uart_char c;
+               /* Make sure c is loaded after head. */
+               smp_rmb();
+               c = ((struct atmel_uart_char *)ring->buf)[ring->tail];
+               ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
+               port->icount.rx++;
+               status = c.status;
+               flg = TTY_NORMAL;
+               /*
+                * note that the error handling code is
+                * out of the main execution path
+                */
+               if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+                                      | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+                       if (status & ATMEL_US_RXBRK) {
+                               /* ignore side-effect */
+                               status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                       continue;
+                       }
+                       if (status & ATMEL_US_PARE)
+                               port->icount.parity++;
+                       if (status & ATMEL_US_FRAME)
+                               port->icount.frame++;
+                       if (status & ATMEL_US_OVRE)
+                               port->icount.overrun++;
+                       status &= port->read_status_mask;
+                       if (status & ATMEL_US_RXBRK)
+                               flg = TTY_BREAK;
+                       else if (status & ATMEL_US_PARE)
+                               flg = TTY_PARITY;
+                       else if (status & ATMEL_US_FRAME)
+                               flg = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(port, c.ch))
+                       continue;
+               uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg);
+       }
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(port->state->port.tty);
+       spin_lock(&port->lock);
+ }
+ static void atmel_rx_from_dma(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       struct atmel_dma_buffer *pdc;
+       int rx_idx = atmel_port->pdc_rx_idx;
+       unsigned int head;
+       unsigned int tail;
+       unsigned int count;
+       do {
+               /* Reset the UART timeout early so that we don't miss one */
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+               pdc = &atmel_port->pdc_rx[rx_idx];
+               head = UART_GET_RPR(port) - pdc->dma_addr;
+               tail = pdc->ofs;
+               /* If the PDC has switched buffers, RPR won't contain
+                * any address within the current buffer. Since head
+                * is unsigned, we just need a one-way comparison to
+                * find out.
+                *
+                * In this case, we just need to consume the entire
+                * buffer and resubmit it for DMA. This will clear the
+                * ENDRX bit as well, so that we can safely re-enable
+                * all interrupts below.
+                */
+               head = min(head, pdc->dma_size);
+               if (likely(head != tail)) {
+                       dma_sync_single_for_cpu(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+                       /*
+                        * head will only wrap around when we recycle
+                        * the DMA buffer, and when that happens, we
+                        * explicitly set tail to 0. So head will
+                        * always be greater than tail.
+                        */
+                       count = head - tail;
+                       tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+                       dma_sync_single_for_device(port->dev, pdc->dma_addr,
+                                       pdc->dma_size, DMA_FROM_DEVICE);
+                       port->icount.rx += count;
+                       pdc->ofs = head;
+               }
+               /*
+                * If the current buffer is full, we need to check if
+                * the next one contains any additional data.
+                */
+               if (head >= pdc->dma_size) {
+                       pdc->ofs = 0;
+                       UART_PUT_RNPR(port, pdc->dma_addr);
+                       UART_PUT_RNCR(port, pdc->dma_size);
+                       rx_idx = !rx_idx;
+                       atmel_port->pdc_rx_idx = rx_idx;
+               }
+       } while (head >= pdc->dma_size);
+       /*
+        * Drop the lock here since it might end up calling
+        * uart_start(), which takes the lock.
+        */
+       spin_unlock(&port->lock);
+       tty_flip_buffer_push(tty);
+       spin_lock(&port->lock);
+       UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+ }
+ /*
+  * tasklet handling tty stuff outside the interrupt handler.
+  */
+ static void atmel_tasklet_func(unsigned long data)
+ {
+       struct uart_port *port = (struct uart_port *)data;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status;
+       unsigned int status_change;
+       /* The interrupt handler does not take the lock */
+       spin_lock(&port->lock);
+       if (atmel_use_dma_tx(port))
+               atmel_tx_dma(port);
+       else
+               atmel_tx_chars(port);
+       status = atmel_port->irq_status;
+       status_change = status ^ atmel_port->irq_status_prev;
+       if (status_change & (ATMEL_US_RI | ATMEL_US_DSR
+                               | ATMEL_US_DCD | ATMEL_US_CTS)) {
+               /* TODO: All reads to CSR will clear these interrupts! */
+               if (status_change & ATMEL_US_RI)
+                       port->icount.rng++;
+               if (status_change & ATMEL_US_DSR)
+                       port->icount.dsr++;
+               if (status_change & ATMEL_US_DCD)
+                       uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+               if (status_change & ATMEL_US_CTS)
+                       uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+               atmel_port->irq_status_prev = status;
+       }
+       if (atmel_use_dma_rx(port))
+               atmel_rx_from_dma(port);
+       else
+               atmel_rx_from_ring(port);
+       spin_unlock(&port->lock);
+ }
+ /*
+  * Perform initialization and enable port for reception
+  */
+ static int atmel_startup(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int retval;
+       /*
+        * Ensure that no interrupts are enabled otherwise when
+        * request_irq() is called we could get stuck trying to
+        * handle an unexpected interrupt
+        */
+       UART_PUT_IDR(port, -1);
+       /*
+        * Allocate the IRQ
+        */
+       retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED,
+                       tty ? tty->name : "atmel_serial", port);
+       if (retval) {
+               printk("atmel_serial: atmel_startup - Can't get irq\n");
+               return retval;
+       }
+       /*
+        * Initialize DMA (if necessary)
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+                       pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+                       if (pdc->buf == NULL) {
+                               if (i != 0) {
+                                       dma_unmap_single(port->dev,
+                                               atmel_port->pdc_rx[0].dma_addr,
+                                               PDC_BUFFER_SIZE,
+                                               DMA_FROM_DEVICE);
+                                       kfree(atmel_port->pdc_rx[0].buf);
+                               }
+                               free_irq(port->irq, port);
+                               return -ENOMEM;
+                       }
+                       pdc->dma_addr = dma_map_single(port->dev,
+                                                      pdc->buf,
+                                                      PDC_BUFFER_SIZE,
+                                                      DMA_FROM_DEVICE);
+                       pdc->dma_size = PDC_BUFFER_SIZE;
+                       pdc->ofs = 0;
+               }
+               atmel_port->pdc_rx_idx = 0;
+               UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+               UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+               UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+               UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+               struct circ_buf *xmit = &port->state->xmit;
+               pdc->buf = xmit->buf;
+               pdc->dma_addr = dma_map_single(port->dev,
+                                              pdc->buf,
+                                              UART_XMIT_SIZE,
+                                              DMA_TO_DEVICE);
+               pdc->dma_size = UART_XMIT_SIZE;
+               pdc->ofs = 0;
+       }
+       /*
+        * If there is a specific "open" function (to register
+        * control line interrupts)
+        */
+       if (atmel_open_hook) {
+               retval = atmel_open_hook(port);
+               if (retval) {
+                       free_irq(port->irq, port);
+                       return retval;
+               }
+       }
+       /* Save current CSR for comparison in atmel_tasklet_func() */
+       atmel_port->irq_status_prev = UART_GET_CSR(port);
+       atmel_port->irq_status = atmel_port->irq_status_prev;
+       /*
+        * Finally, enable the serial port
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       /* enable xmit & rcvr */
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+       if (atmel_use_dma_rx(port)) {
+               /* set UART timeout */
+               UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+               UART_PUT_CR(port, ATMEL_US_STTTO);
+               UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+               /* enable PDC controller */
+               UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+       } else {
+               /* enable receive only */
+               UART_PUT_IER(port, ATMEL_US_RXRDY);
+       }
+       return 0;
+ }
+ /*
+  * Disable the port
+  */
+ static void atmel_shutdown(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       /*
+        * Ensure everything is stopped.
+        */
+       atmel_stop_rx(port);
+       atmel_stop_tx(port);
+       /*
+        * Shut-down the DMA.
+        */
+       if (atmel_use_dma_rx(port)) {
+               int i;
+               for (i = 0; i < 2; i++) {
+                       struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+                       dma_unmap_single(port->dev,
+                                        pdc->dma_addr,
+                                        pdc->dma_size,
+                                        DMA_FROM_DEVICE);
+                       kfree(pdc->buf);
+               }
+       }
+       if (atmel_use_dma_tx(port)) {
+               struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+               dma_unmap_single(port->dev,
+                                pdc->dma_addr,
+                                pdc->dma_size,
+                                DMA_TO_DEVICE);
+       }
+       /*
+        * Disable all interrupts, port and break condition.
+        */
+       UART_PUT_CR(port, ATMEL_US_RSTSTA);
+       UART_PUT_IDR(port, -1);
+       /*
+        * Free the interrupt
+        */
+       free_irq(port->irq, port);
+       /*
+        * If there is a specific "close" function (to unregister
+        * control line interrupts)
+        */
+       if (atmel_close_hook)
+               atmel_close_hook(port);
+ }
+ /*
+  * Flush any TX data submitted for DMA. Called when the TX circular
+  * buffer is reset.
+  */
+ static void atmel_flush_buffer(struct uart_port *port)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (atmel_use_dma_tx(port)) {
+               UART_PUT_TCR(port, 0);
+               atmel_port->pdc_tx.ofs = 0;
+       }
+ }
+ /*
+  * Power / Clock management.
+  */
+ static void atmel_serial_pm(struct uart_port *port, unsigned int state,
+                           unsigned int oldstate)
+ {
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       switch (state) {
+       case 0:
+               /*
+                * Enable the peripheral clock for this serial port.
+                * This is called on uart_open() or a resume event.
+                */
+               clk_enable(atmel_port->clk);
+               /* re-enable interrupts if we disabled some on suspend */
+               UART_PUT_IER(port, atmel_port->backup_imr);
+               break;
+       case 3:
+               /* Back up the interrupt mask and disable all interrupts */
+               atmel_port->backup_imr = UART_GET_IMR(port);
+               UART_PUT_IDR(port, -1);
+               /*
+                * Disable the peripheral clock for this serial port.
+                * This is called on uart_close() or a suspend event.
+                */
+               clk_disable(atmel_port->clk);
+               break;
+       default:
+               printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+       }
+ }
+ /*
+  * Change the port parameters
+  */
+ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
+                             struct ktermios *old)
+ {
+       unsigned long flags;
+       unsigned int mode, imr, quot, baud;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       /* Get current mode register */
+       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
+                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
+                                       | ATMEL_US_USMODE);
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+       quot = uart_get_divisor(port, baud);
+       if (quot > 65535) {     /* BRGR is 16-bit, so switch to slower clock */
+               quot /= 8;
+               mode |= ATMEL_US_USCLKS_MCK_DIV8;
+       }
+       /* byte size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               mode |= ATMEL_US_CHRL_5;
+               break;
+       case CS6:
+               mode |= ATMEL_US_CHRL_6;
+               break;
+       case CS7:
+               mode |= ATMEL_US_CHRL_7;
+               break;
+       default:
+               mode |= ATMEL_US_CHRL_8;
+               break;
+       }
+       /* stop bits */
+       if (termios->c_cflag & CSTOPB)
+               mode |= ATMEL_US_NBSTOP_2;
+       /* parity */
+       if (termios->c_cflag & PARENB) {
+               /* Mark or Space parity */
+               if (termios->c_cflag & CMSPAR) {
+                       if (termios->c_cflag & PARODD)
+                               mode |= ATMEL_US_PAR_MARK;
+                       else
+                               mode |= ATMEL_US_PAR_SPACE;
+               } else if (termios->c_cflag & PARODD)
+                       mode |= ATMEL_US_PAR_ODD;
+               else
+                       mode |= ATMEL_US_PAR_EVEN;
+       } else
+               mode |= ATMEL_US_PAR_NONE;
+       /* hardware handshake (RTS/CTS) */
+       if (termios->c_cflag & CRTSCTS)
+               mode |= ATMEL_US_USMODE_HWHS;
+       else
+               mode |= ATMEL_US_USMODE_NORMAL;
+       spin_lock_irqsave(&port->lock, flags);
+       port->read_status_mask = ATMEL_US_OVRE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= ATMEL_US_RXBRK;
+       if (atmel_use_dma_rx(port))
+               /* need to enable error interrupts */
+               UART_PUT_IER(port, port->read_status_mask);
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= ATMEL_US_RXBRK;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= ATMEL_US_OVRE;
+       }
+       /* TODO: Ignore all characters if CREAD is set.*/
+       /* update the per-port timeout */
+       uart_update_timeout(port, termios->c_cflag, baud);
+       /*
+        * save/disable interrupts. The tty layer will ensure that the
+        * transmitter is empty if requested by the caller, so there's
+        * no need to wait for it here.
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, -1);
+       /* disable receiver and transmitter */
+       UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+       /* Resetting serial mode to RS232 (0x0) */
+       mode &= ~ATMEL_US_USMODE;
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+               dev_dbg(port->dev, "Setting UART to RS485\n");
+               if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+                       UART_PUT_TTGR(port,
+                                       atmel_port->rs485.delay_rts_after_send);
+               mode |= ATMEL_US_USMODE_RS485;
+       } else {
+               dev_dbg(port->dev, "Setting UART to RS232\n");
+       }
+       /* set the parity, stop bits and data size */
+       UART_PUT_MR(port, mode);
+       /* set the baud rate */
+       UART_PUT_BRGR(port, quot);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+       /* restore interrupts */
+       UART_PUT_IER(port, imr);
+       /* CTS flow-control and modem-status interrupts */
+       if (UART_ENABLE_MS(port, termios->c_cflag))
+               port->ops->enable_ms(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ /*
+  * Return string describing the specified port
+  */
+ static const char *atmel_type(struct uart_port *port)
+ {
+       return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
+ }
+ /*
+  * Release the memory region(s) being used by 'port'.
+  */
+ static void atmel_release_port(struct uart_port *port)
+ {
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+       release_mem_region(port->mapbase, size);
+       if (port->flags & UPF_IOREMAP) {
+               iounmap(port->membase);
+               port->membase = NULL;
+       }
+ }
+ /*
+  * Request the memory region(s) being used by 'port'.
+  */
+ static int atmel_request_port(struct uart_port *port)
+ {
+       struct platform_device *pdev = to_platform_device(port->dev);
+       int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+       if (!request_mem_region(port->mapbase, size, "atmel_serial"))
+               return -EBUSY;
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap(port->mapbase, size);
+               if (port->membase == NULL) {
+                       release_mem_region(port->mapbase, size);
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+ }
+ /*
+  * Configure/autoconfigure the port.
+  */
+ static void atmel_config_port(struct uart_port *port, int flags)
+ {
+       if (flags & UART_CONFIG_TYPE) {
+               port->type = PORT_ATMEL;
+               atmel_request_port(port);
+       }
+ }
+ /*
+  * Verify the new serial_struct (for TIOCSSERIAL).
+  */
+ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
+ {
+       int ret = 0;
+       if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
+               ret = -EINVAL;
+       if (port->irq != ser->irq)
+               ret = -EINVAL;
+       if (ser->io_type != SERIAL_IO_MEM)
+               ret = -EINVAL;
+       if (port->uartclk / 16 != ser->baud_base)
+               ret = -EINVAL;
+       if ((void *)port->mapbase != ser->iomem_base)
+               ret = -EINVAL;
+       if (port->iobase != ser->port)
+               ret = -EINVAL;
+       if (ser->hub6 != 0)
+               ret = -EINVAL;
+       return ret;
+ }
+ #ifdef CONFIG_CONSOLE_POLL
+ static int atmel_poll_get_char(struct uart_port *port)
+ {
+       while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY))
+               cpu_relax();
+       return UART_GET_CHAR(port);
+ }
+ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
+ {
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+       UART_PUT_CHAR(port, ch);
+ }
+ #endif
+ static int
+ atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+ {
+       struct serial_rs485 rs485conf;
+       switch (cmd) {
+       case TIOCSRS485:
+               if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+               atmel_config_rs485(port, &rs485conf);
+               break;
+       case TIOCGRS485:
+               if (copy_to_user((struct serial_rs485 *) arg,
+                                       &(to_atmel_uart_port(port)->rs485),
+                                       sizeof(rs485conf)))
+                       return -EFAULT;
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+ }
+ static struct uart_ops atmel_pops = {
+       .tx_empty       = atmel_tx_empty,
+       .set_mctrl      = atmel_set_mctrl,
+       .get_mctrl      = atmel_get_mctrl,
+       .stop_tx        = atmel_stop_tx,
+       .start_tx       = atmel_start_tx,
+       .stop_rx        = atmel_stop_rx,
+       .enable_ms      = atmel_enable_ms,
+       .break_ctl      = atmel_break_ctl,
+       .startup        = atmel_startup,
+       .shutdown       = atmel_shutdown,
+       .flush_buffer   = atmel_flush_buffer,
+       .set_termios    = atmel_set_termios,
+       .type           = atmel_type,
+       .release_port   = atmel_release_port,
+       .request_port   = atmel_request_port,
+       .config_port    = atmel_config_port,
+       .verify_port    = atmel_verify_port,
+       .pm             = atmel_serial_pm,
+       .ioctl          = atmel_ioctl,
+ #ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = atmel_poll_get_char,
+       .poll_put_char  = atmel_poll_put_char,
+ #endif
+ };
+ /*
+  * Configure the port from the platform device resource info.
+  */
+ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
+                                     struct platform_device *pdev)
+ {
+       struct uart_port *port = &atmel_port->uart;
+       struct atmel_uart_data *data = pdev->dev.platform_data;
+       port->iotype            = UPIO_MEM;
+       port->flags             = UPF_BOOT_AUTOCONF;
+       port->ops               = &atmel_pops;
+       port->fifosize          = 1;
+       port->line              = pdev->id;
+       port->dev               = &pdev->dev;
+       port->mapbase   = pdev->resource[0].start;
+       port->irq       = pdev->resource[1].start;
+       tasklet_init(&atmel_port->tasklet, atmel_tasklet_func,
+                       (unsigned long)port);
+       memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
+       if (data->regs)
+               /* Already mapped by setup code */
+               port->membase = data->regs;
+       else {
+               port->flags     |= UPF_IOREMAP;
+               port->membase   = NULL;
+       }
+       /* for console, the clock could already be configured */
+       if (!atmel_port->clk) {
+               atmel_port->clk = clk_get(&pdev->dev, "usart");
+               clk_enable(atmel_port->clk);
+               port->uartclk = clk_get_rate(atmel_port->clk);
+               clk_disable(atmel_port->clk);
+               /* only enable clock when USART is in use */
+       }
+       atmel_port->use_dma_rx = data->use_dma_rx;
+       atmel_port->use_dma_tx = data->use_dma_tx;
+       atmel_port->rs485       = data->rs485;
+       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
+       if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+       else if (atmel_use_dma_tx(port)) {
+               port->fifosize = PDC_BUFFER_SIZE;
+               atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
+       } else {
+               atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+ }
+ /*
+  * Register board-specific modem-control line handlers.
+  */
+ void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
+ {
+       if (fns->enable_ms)
+               atmel_pops.enable_ms = fns->enable_ms;
+       if (fns->get_mctrl)
+               atmel_pops.get_mctrl = fns->get_mctrl;
+       if (fns->set_mctrl)
+               atmel_pops.set_mctrl = fns->set_mctrl;
+       atmel_open_hook         = fns->open;
+       atmel_close_hook        = fns->close;
+       atmel_pops.pm           = fns->pm;
+       atmel_pops.set_wake     = fns->set_wake;
+ }
+ #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+ static void atmel_console_putchar(struct uart_port *port, int ch)
+ {
+       while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+               cpu_relax();
+       UART_PUT_CHAR(port, ch);
+ }
+ /*
+  * Interrupts are disabled on entering
+  */
+ static void atmel_console_write(struct console *co, const char *s, u_int count)
+ {
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int status, imr;
+       unsigned int pdc_tx;
+       /*
+        * First, save IMR and then disable interrupts
+        */
+       imr = UART_GET_IMR(port);
+       UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
+       /* Store PDC transmit status and disable it */
+       pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
+       UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
+       uart_console_write(port, s, count, atmel_console_putchar);
+       /*
+        * Finally, wait for transmitter to become empty
+        * and restore IMR
+        */
+       do {
+               status = UART_GET_CSR(port);
+       } while (!(status & ATMEL_US_TXRDY));
+       /* Restore PDC transmit status */
+       if (pdc_tx)
+               UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
+       /* set interrupts back the way they were */
+       UART_PUT_IER(port, imr);
+ }
+ /*
+  * If the port was already initialised (eg, by a boot loader),
+  * try to determine the current setup.
+  */
+ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
+                                            int *parity, int *bits)
+ {
+       unsigned int mr, quot;
+       /*
+        * If the baud rate generator isn't running, the port wasn't
+        * initialized by the boot loader.
+        */
+       quot = UART_GET_BRGR(port) & ATMEL_US_CD;
+       if (!quot)
+               return;
+       mr = UART_GET_MR(port) & ATMEL_US_CHRL;
+       if (mr == ATMEL_US_CHRL_8)
+               *bits = 8;
+       else
+               *bits = 7;
+       mr = UART_GET_MR(port) & ATMEL_US_PAR;
+       if (mr == ATMEL_US_PAR_EVEN)
+               *parity = 'e';
+       else if (mr == ATMEL_US_PAR_ODD)
+               *parity = 'o';
+       /*
+        * The serial core only rounds down when matching this to a
+        * supported baud rate. Make sure we don't end up slightly
+        * lower than one of those, as it would make us fall through
+        * to a much lower baud rate than we really want.
+        */
+       *baud = port->uartclk / (16 * (quot - 1));
+ }
+ static int __init atmel_console_setup(struct console *co, char *options)
+ {
+       struct uart_port *port = &atmel_ports[co->index].uart;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       if (port->membase == NULL) {
+               /* Port not initialized yet - delay setup */
+               return -ENODEV;
+       }
+       clk_enable(atmel_ports[co->index].clk);
+       UART_PUT_IDR(port, -1);
+       UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+       UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               atmel_console_get_options(port, &baud, &parity, &bits);
+       return uart_set_options(port, co, baud, parity, bits, flow);
+ }
+ static struct uart_driver atmel_uart;
+ static struct console atmel_console = {
+       .name           = ATMEL_DEVICENAME,
+       .write          = atmel_console_write,
+       .device         = uart_console_device,
+       .setup          = atmel_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &atmel_uart,
+ };
+ #define ATMEL_CONSOLE_DEVICE  (&atmel_console)
+ /*
+  * Early console initialization (before VM subsystem initialized).
+  */
+ static int __init atmel_console_init(void)
+ {
+       if (atmel_default_console_device) {
+               add_preferred_console(ATMEL_DEVICENAME,
+                                     atmel_default_console_device->id, NULL);
+               atmel_init_port(&atmel_ports[atmel_default_console_device->id],
+                               atmel_default_console_device);
+               register_console(&atmel_console);
+       }
+       return 0;
+ }
+ console_initcall(atmel_console_init);
+ /*
+  * Late console initialization.
+  */
+ static int __init atmel_late_console_init(void)
+ {
+       if (atmel_default_console_device
+           && !(atmel_console.flags & CON_ENABLED))
+               register_console(&atmel_console);
+       return 0;
+ }
+ core_initcall(atmel_late_console_init);
+ static inline bool atmel_is_console_port(struct uart_port *port)
+ {
+       return port->cons && port->cons->index == port->line;
+ }
+ #else
+ #define ATMEL_CONSOLE_DEVICE  NULL
+ static inline bool atmel_is_console_port(struct uart_port *port)
+ {
+       return false;
+ }
+ #endif
+ static struct uart_driver atmel_uart = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "atmel_serial",
+       .dev_name       = ATMEL_DEVICENAME,
+       .major          = SERIAL_ATMEL_MAJOR,
+       .minor          = MINOR_START,
+       .nr             = ATMEL_MAX_UART,
+       .cons           = ATMEL_CONSOLE_DEVICE,
+ };
+ #ifdef CONFIG_PM
+ static bool atmel_serial_clk_will_stop(void)
+ {
+ #ifdef CONFIG_ARCH_AT91
+       return at91_suspend_entering_slow_clock();
+ #else
+       return false;
+ #endif
+ }
+ static int atmel_serial_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+ {
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       if (atmel_is_console_port(port) && console_suspend_enabled) {
+               /* Drain the TX shifter */
+               while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
+                       cpu_relax();
+       }
+       /* we can not wake up if we're running on slow clock */
+       atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
+       if (atmel_serial_clk_will_stop())
+               device_set_wakeup_enable(&pdev->dev, 0);
+       uart_suspend_port(&atmel_uart, port);
+       return 0;
+ }
+ static int atmel_serial_resume(struct platform_device *pdev)
+ {
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       uart_resume_port(&atmel_uart, port);
+       device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
+       return 0;
+ }
+ #else
+ #define atmel_serial_suspend NULL
+ #define atmel_serial_resume NULL
+ #endif
+ static int __devinit atmel_serial_probe(struct platform_device *pdev)
+ {
+       struct atmel_uart_port *port;
+       void *data;
+       int ret;
+       BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
+       port = &atmel_ports[pdev->id];
+       port->backup_imr = 0;
+       atmel_init_port(port, pdev);
+       if (!atmel_use_dma_rx(&port->uart)) {
+               ret = -ENOMEM;
+               data = kmalloc(sizeof(struct atmel_uart_char)
+                               * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
+               if (!data)
+                       goto err_alloc_ring;
+               port->rx_ring.buf = data;
+       }
+       ret = uart_add_one_port(&atmel_uart, &port->uart);
+       if (ret)
+               goto err_add_port;
+ #ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+       if (atmel_is_console_port(&port->uart)
+                       && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
+               /*
+                * The serial core enabled the clock for us, so undo
+                * the clk_enable() in atmel_console_setup()
+                */
+               clk_disable(port->clk);
+       }
+ #endif
+       device_init_wakeup(&pdev->dev, 1);
+       platform_set_drvdata(pdev, port);
++      if (port->rs485.flags & SER_RS485_ENABLED) {
++              UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
++              UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
++      }
++
+       return 0;
+ err_add_port:
+       kfree(port->rx_ring.buf);
+       port->rx_ring.buf = NULL;
+ err_alloc_ring:
+       if (!atmel_is_console_port(&port->uart)) {
+               clk_put(port->clk);
+               port->clk = NULL;
+       }
+       return ret;
+ }
+ static int __devexit atmel_serial_remove(struct platform_device *pdev)
+ {
+       struct uart_port *port = platform_get_drvdata(pdev);
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       int ret = 0;
+       device_init_wakeup(&pdev->dev, 0);
+       platform_set_drvdata(pdev, NULL);
+       ret = uart_remove_one_port(&atmel_uart, port);
+       tasklet_kill(&atmel_port->tasklet);
+       kfree(atmel_port->rx_ring.buf);
+       /* "port" is allocated statically, so we shouldn't free it */
+       clk_put(atmel_port->clk);
+       return ret;
+ }
+ static struct platform_driver atmel_serial_driver = {
+       .probe          = atmel_serial_probe,
+       .remove         = __devexit_p(atmel_serial_remove),
+       .suspend        = atmel_serial_suspend,
+       .resume         = atmel_serial_resume,
+       .driver         = {
+               .name   = "atmel_usart",
+               .owner  = THIS_MODULE,
+       },
+ };
+ static int __init atmel_serial_init(void)
+ {
+       int ret;
+       ret = uart_register_driver(&atmel_uart);
+       if (ret)
+               return ret;
+       ret = platform_driver_register(&atmel_serial_driver);
+       if (ret)
+               uart_unregister_driver(&atmel_uart);
+       return ret;
+ }
+ static void __exit atmel_serial_exit(void)
+ {
+       platform_driver_unregister(&atmel_serial_driver);
+       uart_unregister_driver(&atmel_uart);
+ }
+ module_init(atmel_serial_init);
+ module_exit(atmel_serial_exit);
+ MODULE_AUTHOR("Rick Bronson");
+ MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS("platform:atmel_usart");
index 0000000,7ac2bf5..2335eda
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1487 +1,1487 @@@
+ /* linux/drivers/serial/samsuing.c
+  *
+  * Driver core for Samsung SoC onboard UARTs.
+  *
+  * Ben Dooks, Copyright (c) 2003-2008 Simtec Electronics
+  *    http://armlinux.simtec.co.uk/
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+ */
+ /* Hote on 2410 error handling
+  *
+  * The s3c2410 manual has a love/hate affair with the contents of the
+  * UERSTAT register in the UART blocks, and keeps marking some of the
+  * error bits as reserved. Having checked with the s3c2410x01,
+  * it copes with BREAKs properly, so I am happy to ignore the RESERVED
+  * feature from the latter versions of the manual.
+  *
+  * If it becomes aparrent that latter versions of the 2410 remove these
+  * bits, then action will have to be taken to differentiate the versions
+  * and change the policy on BREAK
+  *
+  * BJD, 04-Nov-2004
+ */
+ #if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+ #include <linux/module.h>
+ #include <linux/ioport.h>
+ #include <linux/io.h>
+ #include <linux/platform_device.h>
+ #include <linux/init.h>
+ #include <linux/sysrq.h>
+ #include <linux/console.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
+ #include <linux/serial_core.h>
+ #include <linux/serial.h>
+ #include <linux/delay.h>
+ #include <linux/clk.h>
+ #include <linux/cpufreq.h>
+ #include <asm/irq.h>
+ #include <mach/hardware.h>
+ #include <mach/map.h>
+ #include <plat/regs-serial.h>
+ #include "samsung.h"
+ /* UART name and device definitions */
+ #define S3C24XX_SERIAL_NAME   "ttySAC"
+ #define S3C24XX_SERIAL_MAJOR  204
+ #define S3C24XX_SERIAL_MINOR  64
+ /* macros to change one thing to another */
+ #define tx_enabled(port) ((port)->unused[0])
+ #define rx_enabled(port) ((port)->unused[1])
+ /* flag to ignore all characters comming in */
+ #define RXSTAT_DUMMY_READ (0x10000000)
+ static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
+ {
+       return container_of(port, struct s3c24xx_uart_port, port);
+ }
+ /* translate a port to the device name */
+ static inline const char *s3c24xx_serial_portname(struct uart_port *port)
+ {
+       return to_platform_device(port->dev)->name;
+ }
+ static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
+ {
+       return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
+ }
+ static void s3c24xx_serial_rx_enable(struct uart_port *port)
+ {
+       unsigned long flags;
+       unsigned int ucon, ufcon;
+       int count = 10000;
+       spin_lock_irqsave(&port->lock, flags);
+       while (--count && !s3c24xx_serial_txempty_nofifo(port))
+               udelay(100);
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon |= S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+       rx_enabled(port) = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ static void s3c24xx_serial_rx_disable(struct uart_port *port)
+ {
+       unsigned long flags;
+       unsigned int ucon;
+       spin_lock_irqsave(&port->lock, flags);
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~S3C2410_UCON_RXIRQMODE;
+       wr_regl(port, S3C2410_UCON, ucon);
+       rx_enabled(port) = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ static void s3c24xx_serial_stop_tx(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (tx_enabled(port)) {
+               disable_irq_nosync(ourport->tx_irq);
+               tx_enabled(port) = 0;
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_enable(port);
+       }
+ }
+ static void s3c24xx_serial_start_tx(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (!tx_enabled(port)) {
+               if (port->flags & UPF_CONS_FLOW)
+                       s3c24xx_serial_rx_disable(port);
+               enable_irq(ourport->tx_irq);
+               tx_enabled(port) = 1;
+       }
+ }
+ static void s3c24xx_serial_stop_rx(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (rx_enabled(port)) {
+               dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
+               disable_irq_nosync(ourport->rx_irq);
+               rx_enabled(port) = 0;
+       }
+ }
+ static void s3c24xx_serial_enable_ms(struct uart_port *port)
+ {
+ }
+ static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
+ {
+       return to_ourport(port)->info;
+ }
+ static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
+ {
+       if (port->dev == NULL)
+               return NULL;
+       return (struct s3c2410_uartcfg *)port->dev->platform_data;
+ }
+ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat)
+ {
+       struct s3c24xx_uart_info *info = ourport->info;
+       if (ufstat & info->rx_fifofull)
+               return info->fifosize;
+       return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
+ }
+ /* ? - where has parity gone?? */
+ #define S3C2410_UERSTAT_PARITY (0x1000)
+ static irqreturn_t
+ s3c24xx_serial_rx_chars(int irq, void *dev_id)
+ {
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned int ufcon, ch, flag, ufstat, uerstat;
+       int max_count = 64;
+       while (max_count-- > 0) {
+               ufcon = rd_regl(port, S3C2410_UFCON);
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+               if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
+                       break;
+               uerstat = rd_regl(port, S3C2410_UERSTAT);
+               ch = rd_regb(port, S3C2410_URXH);
+               if (port->flags & UPF_CONS_FLOW) {
+                       int txe = s3c24xx_serial_txempty_nofifo(port);
+                       if (rx_enabled(port)) {
+                               if (!txe) {
+                                       rx_enabled(port) = 0;
+                                       continue;
+                               }
+                       } else {
+                               if (txe) {
+                                       ufcon |= S3C2410_UFCON_RESETRX;
+                                       wr_regl(port, S3C2410_UFCON, ufcon);
+                                       rx_enabled(port) = 1;
+                                       goto out;
+                               }
+                               continue;
+                       }
+               }
+               /* insert the character into the buffer */
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+               if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
+                       dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
+                           ch, uerstat);
+                       /* check for break */
+                       if (uerstat & S3C2410_UERSTAT_BREAK) {
+                               dbg("break!\n");
+                               port->icount.brk++;
+                               if (uart_handle_break(port))
+                                   goto ignore_char;
+                       }
+                       if (uerstat & S3C2410_UERSTAT_FRAME)
+                               port->icount.frame++;
+                       if (uerstat & S3C2410_UERSTAT_OVERRUN)
+                               port->icount.overrun++;
+                       uerstat &= port->read_status_mask;
+                       if (uerstat & S3C2410_UERSTAT_BREAK)
+                               flag = TTY_BREAK;
+                       else if (uerstat & S3C2410_UERSTAT_PARITY)
+                               flag = TTY_PARITY;
+                       else if (uerstat & (S3C2410_UERSTAT_FRAME |
+                                           S3C2410_UERSTAT_OVERRUN))
+                               flag = TTY_FRAME;
+               }
+               if (uart_handle_sysrq_char(port, ch))
+                       goto ignore_char;
+               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
+                                ch, flag);
+  ignore_char:
+               continue;
+       }
+       tty_flip_buffer_push(tty);
+  out:
+       return IRQ_HANDLED;
+ }
+ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
+ {
+       struct s3c24xx_uart_port *ourport = id;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       int count = 256;
+       if (port->x_char) {
+               wr_regb(port, S3C2410_UTXH, port->x_char);
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+       /* if there isnt anything more to transmit, or the uart is now
+        * stopped, disable the uart and exit
+       */
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               s3c24xx_serial_stop_tx(port);
+               goto out;
+       }
+       /* try and drain the buffer... */
+       while (!uart_circ_empty(xmit) && count-- > 0) {
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+                       break;
+               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+       }
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (uart_circ_empty(xmit))
+               s3c24xx_serial_stop_tx(port);
+  out:
+       return IRQ_HANDLED;
+ }
+ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT);
+       unsigned long ufcon = rd_regl(port, S3C2410_UFCON);
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               if ((ufstat & info->tx_fifomask) != 0 ||
+                   (ufstat & info->tx_fifofull))
+                       return 0;
+               return 1;
+       }
+       return s3c24xx_serial_txempty_nofifo(port);
+ }
+ /* no modem control lines */
+ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
+ {
+       unsigned int umstat = rd_regb(port, S3C2410_UMSTAT);
+       if (umstat & S3C2410_UMSTAT_CTS)
+               return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+       else
+               return TIOCM_CAR | TIOCM_DSR;
+ }
+ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+ {
+       /* todo - possibly remove AFC and do manual CTS */
+ }
+ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
+ {
+       unsigned long flags;
+       unsigned int ucon;
+       spin_lock_irqsave(&port->lock, flags);
+       ucon = rd_regl(port, S3C2410_UCON);
+       if (break_state)
+               ucon |= S3C2410_UCON_SBREAK;
+       else
+               ucon &= ~S3C2410_UCON_SBREAK;
+       wr_regl(port, S3C2410_UCON, ucon);
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ static void s3c24xx_serial_shutdown(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (ourport->tx_claimed) {
+               free_irq(ourport->tx_irq, ourport);
+               tx_enabled(port) = 0;
+               ourport->tx_claimed = 0;
+       }
+       if (ourport->rx_claimed) {
+               free_irq(ourport->rx_irq, ourport);
+               ourport->rx_claimed = 0;
+               rx_enabled(port) = 0;
+       }
+ }
+ static int s3c24xx_serial_startup(struct uart_port *port)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       int ret;
+       dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
+           port->mapbase, port->membase);
+       rx_enabled(port) = 1;
+       ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+       if (ret != 0) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
+               return ret;
+       }
+       ourport->rx_claimed = 1;
+       dbg("requesting tx irq...\n");
+       tx_enabled(port) = 1;
+       ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
+                         s3c24xx_serial_portname(port), ourport);
+       if (ret) {
+               printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
+               goto err;
+       }
+       ourport->tx_claimed = 1;
+       dbg("s3c24xx_serial_startup ok\n");
+       /* the port reset code should have done the correct
+        * register setup for the port controls */
+       return ret;
+  err:
+       s3c24xx_serial_shutdown(port);
+       return ret;
+ }
+ /* power power management control */
+ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
+                             unsigned int old)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       ourport->pm_level = level;
+       switch (level) {
+       case 3:
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_disable(ourport->baudclk);
+               clk_disable(ourport->clk);
+               break;
+       case 0:
+               clk_enable(ourport->clk);
+               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+                       clk_enable(ourport->baudclk);
+               break;
+       default:
+               printk(KERN_ERR "s3c24xx_serial: unknown pm %d\n", level);
+       }
+ }
+ /* baud rate calculation
+  *
+  * The UARTs on the S3C2410/S3C2440 can take their clocks from a number
+  * of different sources, including the peripheral clock ("pclk") and an
+  * external clock ("uclk"). The S3C2440 also adds the core clock ("fclk")
+  * with a programmable extra divisor.
+  *
+  * The following code goes through the clock sources, and calculates the
+  * baud clocks (and the resultant actual baud rates) and then tries to
+  * pick the closest one and select that.
+  *
+ */
+ #define MAX_CLKS (8)
+ static struct s3c24xx_uart_clksrc tmp_clksrc = {
+       .name           = "pclk",
+       .min_baud       = 0,
+       .max_baud       = 0,
+       .divisor        = 1,
+ };
+ static inline int
+ s3c24xx_serial_getsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       return (info->get_clksrc)(port, c);
+ }
+ static inline int
+ s3c24xx_serial_setsource(struct uart_port *port, struct s3c24xx_uart_clksrc *c)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       return (info->set_clksrc)(port, c);
+ }
+ struct baud_calc {
+       struct s3c24xx_uart_clksrc      *clksrc;
+       unsigned int                     calc;
+       unsigned int                     divslot;
+       unsigned int                     quot;
+       struct clk                      *src;
+ };
+ static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
+                                  struct uart_port *port,
+                                  struct s3c24xx_uart_clksrc *clksrc,
+                                  unsigned int baud)
+ {
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long rate;
+       calc->src = clk_get(port->dev, clksrc->name);
+       if (calc->src == NULL || IS_ERR(calc->src))
+               return 0;
+       rate = clk_get_rate(calc->src);
+       rate /= clksrc->divisor;
+       calc->clksrc = clksrc;
+       if (ourport->info->has_divslot) {
+               unsigned long div = rate / baud;
+               /* The UDIVSLOT register on the newer UARTs allows us to
+                * get a divisor adjustment of 1/16th on the baud clock.
+                *
+                * We don't keep the UDIVSLOT value (the 16ths we calculated
+                * by not multiplying the baud by 16) as it is easy enough
+                * to recalculate.
+                */
+               calc->quot = div / 16;
+               calc->calc = rate / div;
+       } else {
+               calc->quot = (rate + (8 * baud)) / (16 * baud);
+               calc->calc = (rate / (calc->quot * 16));
+       }
+       calc->quot--;
+       return 1;
+ }
+ static unsigned int s3c24xx_serial_getclk(struct uart_port *port,
+                                         struct s3c24xx_uart_clksrc **clksrc,
+                                         struct clk **clk,
+                                         unsigned int baud)
+ {
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_clksrc *clkp;
+       struct baud_calc res[MAX_CLKS];
+       struct baud_calc *resptr, *best, *sptr;
+       int i;
+       clkp = cfg->clocks;
+       best = NULL;
+       if (cfg->clocks_size < 2) {
+               if (cfg->clocks_size == 0)
+                       clkp = &tmp_clksrc;
+               /* check to see if we're sourcing fclk, and if so we're
+                * going to have to update the clock source
+                */
+               if (strcmp(clkp->name, "fclk") == 0) {
+                       struct s3c24xx_uart_clksrc src;
+                       s3c24xx_serial_getsource(port, &src);
+                       /* check that the port already using fclk, and if
+                        * not, then re-select fclk
+                        */
+                       if (strcmp(src.name, clkp->name) == 0) {
+                               s3c24xx_serial_setsource(port, clkp);
+                               s3c24xx_serial_getsource(port, &src);
+                       }
+                       clkp->divisor = src.divisor;
+               }
+               s3c24xx_serial_calcbaud(res, port, clkp, baud);
+               best = res;
+               resptr = best + 1;
+       } else {
+               resptr = res;
+               for (i = 0; i < cfg->clocks_size; i++, clkp++) {
+                       if (s3c24xx_serial_calcbaud(resptr, port, clkp, baud))
+                               resptr++;
+               }
+       }
+       /* ok, we now need to select the best clock we found */
+       if (!best) {
+               unsigned int deviation = (1<<30)|((1<<30)-1);
+               int calc_deviation;
+               for (sptr = res; sptr < resptr; sptr++) {
+                       calc_deviation = baud - sptr->calc;
+                       if (calc_deviation < 0)
+                               calc_deviation = -calc_deviation;
+                       if (calc_deviation < deviation) {
+                               best = sptr;
+                               deviation = calc_deviation;
+                       }
+               }
+       }
+       /* store results to pass back */
+       *clksrc = best->clksrc;
+       *clk    = best->src;
+       return best->quot;
+ }
+ /* udivslot_table[]
+  *
+  * This table takes the fractional value of the baud divisor and gives
+  * the recommended setting for the UDIVSLOT register.
+  */
+ static u16 udivslot_table[16] = {
+       [0] = 0x0000,
+       [1] = 0x0080,
+       [2] = 0x0808,
+       [3] = 0x0888,
+       [4] = 0x2222,
+       [5] = 0x4924,
+       [6] = 0x4A52,
+       [7] = 0x54AA,
+       [8] = 0x5555,
+       [9] = 0xD555,
+       [10] = 0xD5D5,
+       [11] = 0xDDD5,
+       [12] = 0xDDDD,
+       [13] = 0xDFDD,
+       [14] = 0xDFDF,
+       [15] = 0xFFDF,
+ };
+ static void s3c24xx_serial_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+ {
+       struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_clksrc *clksrc = NULL;
+       struct clk *clk = NULL;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned int ulcon;
+       unsigned int umcon;
+       unsigned int udivslot = 0;
+       /*
+        * We don't support modem control lines.
+        */
+       termios->c_cflag &= ~(HUPCL | CMSPAR);
+       termios->c_cflag |= CLOCAL;
+       /*
+        * Ask the core to calculate the divisor for us.
+        */
+       baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
+       if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
+               quot = port->custom_divisor;
+       else
+               quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
+       /* check to see if we need  to change clock source */
+       if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
+               dbg("selecting clock %p\n", clk);
+               s3c24xx_serial_setsource(port, clksrc);
+               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+                       clk_disable(ourport->baudclk);
+                       ourport->baudclk  = NULL;
+               }
+               clk_enable(clk);
+               ourport->clksrc = clksrc;
+               ourport->baudclk = clk;
+               ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
+       }
+       if (ourport->info->has_divslot) {
+               unsigned int div = ourport->baudclk_rate / baud;
+               if (cfg->has_fracval) {
+                       udivslot = (div & 15);
+                       dbg("fracval = %04x\n", udivslot);
+               } else {
+                       udivslot = udivslot_table[div & 15];
+                       dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);
+               }
+       }
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               dbg("config: 5bits/char\n");
+               ulcon = S3C2410_LCON_CS5;
+               break;
+       case CS6:
+               dbg("config: 6bits/char\n");
+               ulcon = S3C2410_LCON_CS6;
+               break;
+       case CS7:
+               dbg("config: 7bits/char\n");
+               ulcon = S3C2410_LCON_CS7;
+               break;
+       case CS8:
+       default:
+               dbg("config: 8bits/char\n");
+               ulcon = S3C2410_LCON_CS8;
+               break;
+       }
+       /* preserve original lcon IR settings */
+       ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
+       if (termios->c_cflag & CSTOPB)
+               ulcon |= S3C2410_LCON_STOPB;
+       umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
+       if (termios->c_cflag & PARENB) {
+               if (termios->c_cflag & PARODD)
+                       ulcon |= S3C2410_LCON_PODD;
+               else
+                       ulcon |= S3C2410_LCON_PEVEN;
+       } else {
+               ulcon |= S3C2410_LCON_PNONE;
+       }
+       spin_lock_irqsave(&port->lock, flags);
+       dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
+           ulcon, quot, udivslot);
+       wr_regl(port, S3C2410_ULCON, ulcon);
+       wr_regl(port, S3C2410_UBRDIV, quot);
+       wr_regl(port, S3C2410_UMCON, umcon);
+       if (ourport->info->has_divslot)
+               wr_regl(port, S3C2443_DIVSLOT, udivslot);
+       dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
+           rd_regl(port, S3C2410_ULCON),
+           rd_regl(port, S3C2410_UCON),
+           rd_regl(port, S3C2410_UFCON));
+       /*
+        * Update the per-port timeout.
+        */
+       uart_update_timeout(port, termios->c_cflag, baud);
+       /*
+        * Which character status flags are we interested in?
+        */
+       port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
+       /*
+        * Which character status flags should we ignore?
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
+       if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
+       /*
+        * Ignore all characters if CREAD is not set.
+        */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |= RXSTAT_DUMMY_READ;
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ static const char *s3c24xx_serial_type(struct uart_port *port)
+ {
+       switch (port->type) {
+       case PORT_S3C2410:
+               return "S3C2410";
+       case PORT_S3C2440:
+               return "S3C2440";
+       case PORT_S3C2412:
+               return "S3C2412";
+       case PORT_S3C6400:
+               return "S3C6400/10";
+       default:
+               return NULL;
+       }
+ }
+ #define MAP_SIZE (0x100)
+ static void s3c24xx_serial_release_port(struct uart_port *port)
+ {
+       release_mem_region(port->mapbase, MAP_SIZE);
+ }
+ static int s3c24xx_serial_request_port(struct uart_port *port)
+ {
+       const char *name = s3c24xx_serial_portname(port);
+       return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
+ }
+ static void s3c24xx_serial_config_port(struct uart_port *port, int flags)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       if (flags & UART_CONFIG_TYPE &&
+           s3c24xx_serial_request_port(port) == 0)
+               port->type = info->type;
+ }
+ /*
+  * verify the new serial_struct (for TIOCSSERIAL).
+  */
+ static int
+ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       if (ser->type != PORT_UNKNOWN && ser->type != info->type)
+               return -EINVAL;
+       return 0;
+ }
+ #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+ static struct console s3c24xx_serial_console;
+ #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
+ #else
+ #define S3C24XX_SERIAL_CONSOLE NULL
+ #endif
+ static struct uart_ops s3c24xx_serial_ops = {
+       .pm             = s3c24xx_serial_pm,
+       .tx_empty       = s3c24xx_serial_tx_empty,
+       .get_mctrl      = s3c24xx_serial_get_mctrl,
+       .set_mctrl      = s3c24xx_serial_set_mctrl,
+       .stop_tx        = s3c24xx_serial_stop_tx,
+       .start_tx       = s3c24xx_serial_start_tx,
+       .stop_rx        = s3c24xx_serial_stop_rx,
+       .enable_ms      = s3c24xx_serial_enable_ms,
+       .break_ctl      = s3c24xx_serial_break_ctl,
+       .startup        = s3c24xx_serial_startup,
+       .shutdown       = s3c24xx_serial_shutdown,
+       .set_termios    = s3c24xx_serial_set_termios,
+       .type           = s3c24xx_serial_type,
+       .release_port   = s3c24xx_serial_release_port,
+       .request_port   = s3c24xx_serial_request_port,
+       .config_port    = s3c24xx_serial_config_port,
+       .verify_port    = s3c24xx_serial_verify_port,
+ };
+ static struct uart_driver s3c24xx_uart_drv = {
+       .owner          = THIS_MODULE,
 -      .dev_name       = "s3c2410_serial",
++      .driver_name    = "s3c2410_serial",
+       .nr             = CONFIG_SERIAL_SAMSUNG_UARTS,
+       .cons           = S3C24XX_SERIAL_CONSOLE,
 -      .driver_name    = S3C24XX_SERIAL_NAME,
++      .dev_name       = S3C24XX_SERIAL_NAME,
+       .major          = S3C24XX_SERIAL_MAJOR,
+       .minor          = S3C24XX_SERIAL_MINOR,
+ };
+ static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
+       [0] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX0,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 0,
+               }
+       },
+       [1] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX1,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 1,
+               }
+       },
+ #if CONFIG_SERIAL_SAMSUNG_UARTS > 2
+       [2] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX2,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 2,
+               }
+       },
+ #endif
+ #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+       [3] = {
+               .port = {
+                       .lock           = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
+                       .iotype         = UPIO_MEM,
+                       .irq            = IRQ_S3CUART_RX3,
+                       .uartclk        = 0,
+                       .fifosize       = 16,
+                       .ops            = &s3c24xx_serial_ops,
+                       .flags          = UPF_BOOT_AUTOCONF,
+                       .line           = 3,
+               }
+       }
+ #endif
+ };
+ /* s3c24xx_serial_resetport
+  *
+  * wrapper to call the specific reset for this port (reset the fifos
+  * and the settings)
+ */
+ static inline int s3c24xx_serial_resetport(struct uart_port *port,
+                                          struct s3c2410_uartcfg *cfg)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       return (info->reset_port)(port, cfg);
+ }
+ #ifdef CONFIG_CPU_FREQ
+ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+                                            unsigned long val, void *data)
+ {
+       struct s3c24xx_uart_port *port;
+       struct uart_port *uport;
+       port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+       uport = &port->port;
+       /* check to see if port is enabled */
+       if (port->pm_level != 0)
+               return 0;
+       /* try and work out if the baudrate is changing, we can detect
+        * a change in rate, but we do not have support for detecting
+        * a disturbance in the clock-rate over the change.
+        */
+       if (IS_ERR(port->clk))
+               goto exit;
+       if (port->baudclk_rate == clk_get_rate(port->clk))
+               goto exit;
+       if (val == CPUFREQ_PRECHANGE) {
+               /* we should really shut the port down whilst the
+                * frequency change is in progress. */
+       } else if (val == CPUFREQ_POSTCHANGE) {
+               struct ktermios *termios;
+               struct tty_struct *tty;
+               if (uport->state == NULL)
+                       goto exit;
+               tty = uport->state->port.tty;
+               if (tty == NULL)
+                       goto exit;
+               termios = tty->termios;
+               if (termios == NULL) {
+                       printk(KERN_WARNING "%s: no termios?\n", __func__);
+                       goto exit;
+               }
+               s3c24xx_serial_set_termios(uport, termios, NULL);
+       }
+  exit:
+       return 0;
+ }
+ static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+ {
+       port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+       return cpufreq_register_notifier(&port->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+ }
+ static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+ {
+       cpufreq_unregister_notifier(&port->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+ }
+ #else
+ static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+ {
+       return 0;
+ }
+ static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+ {
+ }
+ #endif
+ /* s3c24xx_serial_init_port
+  *
+  * initialise a single serial port from the platform device given
+  */
+ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
+                                   struct s3c24xx_uart_info *info,
+                                   struct platform_device *platdev)
+ {
+       struct uart_port *port = &ourport->port;
+       struct s3c2410_uartcfg *cfg;
+       struct resource *res;
+       int ret;
+       dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
+       if (platdev == NULL)
+               return -ENODEV;
+       cfg = s3c24xx_dev_to_cfg(&platdev->dev);
+       if (port->mapbase != 0)
+               return 0;
+       if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
+               printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
+                      cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
+               return -ERANGE;
+       }
+       /* setup info for port */
+       port->dev       = &platdev->dev;
+       ourport->info   = info;
+       /* copy the info in from provided structure */
+       ourport->port.fifosize = info->fifosize;
+       dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
+       port->uartclk = 1;
+       if (cfg->uart_flags & UPF_CONS_FLOW) {
+               dbg("s3c24xx_serial_init_port: enabling flow control\n");
+               port->flags |= UPF_CONS_FLOW;
+       }
+       /* sort our the physical and virtual addresses for each UART */
+       res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               printk(KERN_ERR "failed to find memory resource for uart\n");
+               return -EINVAL;
+       }
+       dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
+       port->mapbase = res->start;
+       port->membase = S3C_VA_UART + (res->start & 0xfffff);
+       ret = platform_get_irq(platdev, 0);
+       if (ret < 0)
+               port->irq = 0;
+       else {
+               port->irq = ret;
+               ourport->rx_irq = ret;
+               ourport->tx_irq = ret + 1;
+       }
+       
+       ret = platform_get_irq(platdev, 1);
+       if (ret > 0)
+               ourport->tx_irq = ret;
+       ourport->clk    = clk_get(&platdev->dev, "uart");
+       dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
+           port->mapbase, port->membase, port->irq,
+           ourport->rx_irq, ourport->tx_irq, port->uartclk);
+       /* reset the fifos (and setup the uart) */
+       s3c24xx_serial_resetport(port, cfg);
+       return 0;
+ }
+ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+ {
+       struct uart_port *port = s3c24xx_dev_to_port(dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->clksrc->name);
+ }
+ static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
+ /* Device driver serial port probe */
+ static int probe_index;
+ int s3c24xx_serial_probe(struct platform_device *dev,
+                        struct s3c24xx_uart_info *info)
+ {
+       struct s3c24xx_uart_port *ourport;
+       int ret;
+       dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
+       ourport = &s3c24xx_serial_ports[probe_index];
+       probe_index++;
+       dbg("%s: initialising port %p...\n", __func__, ourport);
+       ret = s3c24xx_serial_init_port(ourport, info, dev);
+       if (ret < 0)
+               goto probe_err;
+       dbg("%s: adding port\n", __func__);
+       uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
+       platform_set_drvdata(dev, &ourport->port);
+       ret = device_create_file(&dev->dev, &dev_attr_clock_source);
+       if (ret < 0)
+               printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
+       ret = s3c24xx_serial_cpufreq_register(ourport);
+       if (ret < 0)
+               dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+       return 0;
+  probe_err:
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(s3c24xx_serial_probe);
+ int __devexit s3c24xx_serial_remove(struct platform_device *dev)
+ {
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+       if (port) {
+               s3c24xx_serial_cpufreq_deregister(to_ourport(port));
+               device_remove_file(&dev->dev, &dev_attr_clock_source);
+               uart_remove_one_port(&s3c24xx_uart_drv, port);
+       }
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(s3c24xx_serial_remove);
+ /* UART power management code */
+ #ifdef CONFIG_PM
+ static int s3c24xx_serial_suspend(struct platform_device *dev, pm_message_t state)
+ {
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+       if (port)
+               uart_suspend_port(&s3c24xx_uart_drv, port);
+       return 0;
+ }
+ static int s3c24xx_serial_resume(struct platform_device *dev)
+ {
+       struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
+       struct s3c24xx_uart_port *ourport = to_ourport(port);
+       if (port) {
+               clk_enable(ourport->clk);
+               s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               clk_disable(ourport->clk);
+               uart_resume_port(&s3c24xx_uart_drv, port);
+       }
+       return 0;
+ }
+ #endif
+ int s3c24xx_serial_init(struct platform_driver *drv,
+                       struct s3c24xx_uart_info *info)
+ {
+       dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
+ #ifdef CONFIG_PM
+       drv->suspend = s3c24xx_serial_suspend;
+       drv->resume = s3c24xx_serial_resume;
+ #endif
+       return platform_driver_register(drv);
+ }
+ EXPORT_SYMBOL_GPL(s3c24xx_serial_init);
+ /* module initialisation code */
+ static int __init s3c24xx_serial_modinit(void)
+ {
+       int ret;
+       ret = uart_register_driver(&s3c24xx_uart_drv);
+       if (ret < 0) {
+               printk(KERN_ERR "failed to register UART driver\n");
+               return -1;
+       }
+       return 0;
+ }
+ static void __exit s3c24xx_serial_modexit(void)
+ {
+       uart_unregister_driver(&s3c24xx_uart_drv);
+ }
+ module_init(s3c24xx_serial_modinit);
+ module_exit(s3c24xx_serial_modexit);
+ /* Console code */
+ #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+ static struct uart_port *cons_uart;
+ static int
+ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
+ {
+       struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
+       unsigned long ufstat, utrstat;
+       if (ufcon & S3C2410_UFCON_FIFOMODE) {
+               /* fifo mode - check amount of data in fifo registers... */
+               ufstat = rd_regl(port, S3C2410_UFSTAT);
+               return (ufstat & info->tx_fifofull) ? 0 : 1;
+       }
+       /* in non-fifo mode, we go and use the tx buffer empty */
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
+ }
+ static void
+ s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
+ {
+       unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
+       while (!s3c24xx_serial_console_txrdy(port, ufcon))
+               barrier();
+       wr_regb(cons_uart, S3C2410_UTXH, ch);
+ }
+ static void
+ s3c24xx_serial_console_write(struct console *co, const char *s,
+                            unsigned int count)
+ {
+       uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
+ }
+ static void __init
+ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
+                          int *parity, int *bits)
+ {
+       struct s3c24xx_uart_clksrc clksrc;
+       struct clk *clk;
+       unsigned int ulcon;
+       unsigned int ucon;
+       unsigned int ubrdiv;
+       unsigned long rate;
+       ulcon  = rd_regl(port, S3C2410_ULCON);
+       ucon   = rd_regl(port, S3C2410_UCON);
+       ubrdiv = rd_regl(port, S3C2410_UBRDIV);
+       dbg("s3c24xx_serial_get_options: port=%p\n"
+           "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
+           port, ulcon, ucon, ubrdiv);
+       if ((ucon & 0xf) != 0) {
+               /* consider the serial port configured if the tx/rx mode set */
+               switch (ulcon & S3C2410_LCON_CSMASK) {
+               case S3C2410_LCON_CS5:
+                       *bits = 5;
+                       break;
+               case S3C2410_LCON_CS6:
+                       *bits = 6;
+                       break;
+               case S3C2410_LCON_CS7:
+                       *bits = 7;
+                       break;
+               default:
+               case S3C2410_LCON_CS8:
+                       *bits = 8;
+                       break;
+               }
+               switch (ulcon & S3C2410_LCON_PMASK) {
+               case S3C2410_LCON_PEVEN:
+                       *parity = 'e';
+                       break;
+               case S3C2410_LCON_PODD:
+                       *parity = 'o';
+                       break;
+               case S3C2410_LCON_PNONE:
+               default:
+                       *parity = 'n';
+               }
+               /* now calculate the baud rate */
+               s3c24xx_serial_getsource(port, &clksrc);
+               clk = clk_get(port->dev, clksrc.name);
+               if (!IS_ERR(clk) && clk != NULL)
+                       rate = clk_get_rate(clk) / clksrc.divisor;
+               else
+                       rate = 1;
+               *baud = rate / (16 * (ubrdiv + 1));
+               dbg("calculated baud %d\n", *baud);
+       }
+ }
+ /* s3c24xx_serial_init_ports
+  *
+  * initialise the serial ports from the machine provided initialisation
+  * data.
+ */
+ static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info **info)
+ {
+       struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
+       struct platform_device **platdev_ptr;
+       int i;
+       dbg("s3c24xx_serial_init_ports: initialising ports...\n");
+       platdev_ptr = s3c24xx_uart_devs;
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
+               s3c24xx_serial_init_port(ptr, info[i], *platdev_ptr);
+       }
+       return 0;
+ }
+ static int __init
+ s3c24xx_serial_console_setup(struct console *co, char *options)
+ {
+       struct uart_port *port;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
+           co, co->index, options);
+       /* is this a valid port */
+       if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
+               co->index = 0;
+       port = &s3c24xx_serial_ports[co->index].port;
+       /* is the port configured? */
+       if (port->mapbase == 0x0) {
+               co->index = 0;
+               port = &s3c24xx_serial_ports[co->index].port;
+       }
+       cons_uart = port;
+       dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               s3c24xx_serial_get_options(port, &baud, &parity, &bits);
+       dbg("s3c24xx_serial_console_setup: baud %d\n", baud);
+       return uart_set_options(port, co, baud, parity, bits, flow);
+ }
+ /* s3c24xx_serial_initconsole
+  *
+  * initialise the console from one of the uart drivers
+ */
+ static struct console s3c24xx_serial_console = {
+       .name           = S3C24XX_SERIAL_NAME,
+       .device         = uart_console_device,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .write          = s3c24xx_serial_console_write,
+       .setup          = s3c24xx_serial_console_setup
+ };
+ int s3c24xx_serial_initconsole(struct platform_driver *drv,
+                              struct s3c24xx_uart_info **info)
+ {
+       struct platform_device *dev = s3c24xx_uart_devs[0];
+       dbg("s3c24xx_serial_initconsole\n");
+       /* select driver based on the cpu */
+       if (dev == NULL) {
+               printk(KERN_ERR "s3c24xx: no devices for console init\n");
+               return 0;
+       }
+       if (strcmp(dev->name, drv->driver.name) != 0)
+               return 0;
+       s3c24xx_serial_console.data = &s3c24xx_uart_drv;
+       s3c24xx_serial_init_ports(info);
+       register_console(&s3c24xx_serial_console);
+       return 0;
+ }
+ #endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
+ MODULE_DESCRIPTION("Samsung SoC Serial port driver");
+ MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+ MODULE_LICENSE("GPL v2");
index 0000000,c291b3a..92c91c8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,2027 +1,2079 @@@
+ /*
+  * drivers/serial/sh-sci.c
+  *
+  * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+  *
 - *  Copyright (C) 2002 - 2008  Paul Mundt
++ *  Copyright (C) 2002 - 2011  Paul Mundt
+  *  Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
+  *
+  * based off of the old drivers/char/sh-sci.c by:
+  *
+  *   Copyright (C) 1999, 2000  Niibe Yutaka
+  *   Copyright (C) 2000  Sugioka Toshinobu
+  *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
+  *   Modified to support SecureEdge. David McCullough (2002)
+  *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+  *   Removed SH7300 support (Jul 2007).
+  *
+  * This file is subject to the terms and conditions of the GNU General Public
+  * License.  See the file "COPYING" in the main directory of this archive
+  * for more details.
+  */
+ #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+ #undef DEBUG
+ #include <linux/module.h>
+ #include <linux/errno.h>
+ #include <linux/timer.h>
+ #include <linux/interrupt.h>
+ #include <linux/tty.h>
+ #include <linux/tty_flip.h>
+ #include <linux/serial.h>
+ #include <linux/major.h>
+ #include <linux/string.h>
+ #include <linux/sysrq.h>
+ #include <linux/ioport.h>
+ #include <linux/mm.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/console.h>
+ #include <linux/platform_device.h>
+ #include <linux/serial_sci.h>
+ #include <linux/notifier.h>
+ #include <linux/cpufreq.h>
+ #include <linux/clk.h>
+ #include <linux/ctype.h>
+ #include <linux/err.h>
+ #include <linux/list.h>
+ #include <linux/dmaengine.h>
+ #include <linux/scatterlist.h>
+ #include <linux/slab.h>
+ #ifdef CONFIG_SUPERH
+ #include <asm/sh_bios.h>
+ #endif
+ #ifdef CONFIG_H8300
+ #include <asm/gpio.h>
+ #endif
+ #include "sh-sci.h"
+ struct sci_port {
+       struct uart_port        port;
+       /* Port type */
+       unsigned int            type;
+       /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
+       unsigned int            irqs[SCIx_NR_IRQS];
+       /* Port enable callback */
+       void                    (*enable)(struct uart_port *port);
+       /* Port disable callback */
+       void                    (*disable)(struct uart_port *port);
+       /* Break timer */
+       struct timer_list       break_timer;
+       int                     break_flag;
++      /* SCSCR initialization */
++      unsigned int            scscr;
++
++      /* SCBRR calculation algo */
++      unsigned int            scbrr_algo_id;
++
+       /* Interface clock */
+       struct clk              *iclk;
+       /* Function clock */
+       struct clk              *fclk;
+       struct list_head        node;
++
+       struct dma_chan                 *chan_tx;
+       struct dma_chan                 *chan_rx;
++
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct device                   *dma_dev;
+       unsigned int                    slave_tx;
+       unsigned int                    slave_rx;
+       struct dma_async_tx_descriptor  *desc_tx;
+       struct dma_async_tx_descriptor  *desc_rx[2];
+       dma_cookie_t                    cookie_tx;
+       dma_cookie_t                    cookie_rx[2];
+       dma_cookie_t                    active_rx;
+       struct scatterlist              sg_tx;
+       unsigned int                    sg_len_tx;
+       struct scatterlist              sg_rx[2];
+       size_t                          buf_len_rx;
+       struct sh_dmae_slave            param_tx;
+       struct sh_dmae_slave            param_rx;
+       struct work_struct              work_tx;
+       struct work_struct              work_rx;
+       struct timer_list               rx_timer;
+       unsigned int                    rx_timeout;
+ #endif
+ };
+ struct sh_sci_priv {
+       spinlock_t lock;
+       struct list_head ports;
+       struct notifier_block clk_nb;
+ };
+ /* Function prototypes */
+ static void sci_stop_tx(struct uart_port *port);
+ #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
+ static struct sci_port sci_ports[SCI_NPORTS];
+ static struct uart_driver sci_uart_driver;
+ static inline struct sci_port *
+ to_sci_port(struct uart_port *uart)
+ {
+       return container_of(uart, struct sci_port, port);
+ }
+ #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+ #ifdef CONFIG_CONSOLE_POLL
+ static inline void handle_error(struct uart_port *port)
+ {
+       /* Clear error flags */
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+ }
+ static int sci_poll_get_char(struct uart_port *port)
+ {
+       unsigned short status;
+       int c;
+       do {
+               status = sci_in(port, SCxSR);
+               if (status & SCxSR_ERRORS(port)) {
+                       handle_error(port);
+                       continue;
+               }
+               break;
+       } while (1);
+       if (!(status & SCxSR_RDxF(port)))
+               return NO_POLL_CHAR;
+       c = sci_in(port, SCxRDR);
+       /* Dummy read */
+       sci_in(port, SCxSR);
+       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       return c;
+ }
+ #endif
+ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
+ {
+       unsigned short status;
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TDxE(port)));
+       sci_out(port, SCxTDR, c);
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+ }
+ #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
+ #if defined(__H8300H__) || defined(__H8300S__)
+ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       int ch = (port->mapbase - SMR0) >> 3;
+       /* set DDR regs */
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].rx,
+                      H8300_GPIO_INPUT);
+       H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+                      h8300_sci_pins[ch].tx,
+                      H8300_GPIO_OUTPUT);
+       /* tx mark output*/
+       H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       if (port->mapbase == 0xA4400000) {
+               __raw_writew(__raw_readw(PACR) & 0xffc0, PACR);
+               __raw_writew(__raw_readw(PBCR) & 0x0fff, PBCR);
+       } else if (port->mapbase == 0xA4410000)
+               __raw_writew(__raw_readw(PBCR) & 0xf003, PBCR);
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721)
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       unsigned short data;
+       if (cflag & CRTSCTS) {
+               /* enable RTS/CTS */
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 9-2; enable all scif pins but sck */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xfc03), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 9-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xfc03), PORT_PVCR);
+               }
+       } else {
+               if (port->mapbase == 0xa4430000) { /* SCIF0 */
+                       /* Clear PTCR bit 5-2; enable only tx and rx  */
+                       data = __raw_readw(PORT_PTCR);
+                       __raw_writew((data & 0xffc3), PORT_PTCR);
+               } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+                       /* Clear PVCR bit 5-2 */
+                       data = __raw_readw(PORT_PVCR);
+                       __raw_writew((data & 0xffc3), PORT_PVCR);
+               }
+       }
+ }
+ #elif defined(CONFIG_CPU_SH3)
+ /* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       unsigned short data;
+       /* We need to set SCPCR to enable RTS/CTS */
+       data = __raw_readw(SCPCR);
+       /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+       __raw_writew(data & 0x0fcf, SCPCR);
+       if (!(cflag & CRTSCTS)) {
+               /* We need to set SCPCR to enable RTS/CTS */
+               data = __raw_readw(SCPCR);
+               /* Clear out SCP7MD1,0, SCP4MD1,0,
+                  Set SCP6MD1,0 = {01} (output)  */
+               __raw_writew((data & 0x0fcf) | 0x1000, SCPCR);
+               data = __raw_readb(SCPDR);
+               /* Set /RTS2 (bit6) = 0 */
+               __raw_writeb(data & 0xbf, SCPDR);
+       }
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       unsigned short data;
+       if (port->mapbase == 0xffe00000) {
+               data = __raw_readw(PSCR);
+               data &= ~0x03cf;
+               if (!(cflag & CRTSCTS))
+                       data |= 0x0340;
+               __raw_writew(data, PSCR);
+       }
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7757) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7786) || \
+       defined(CONFIG_CPU_SUBTYPE_SHX3)
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR0); /* Set RTS = 1 */
+ }
+ #elif defined(CONFIG_CPU_SH4) && !defined(CONFIG_CPU_SH4A)
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       if (!(cflag & CRTSCTS))
+               __raw_writew(0x0080, SCSPTR2); /* Set RTS = 1 */
+ }
+ #else
+ static inline void sci_init_pins(struct uart_port *port, unsigned int cflag)
+ {
+       /* Nothing to do */
+ }
+ #endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7786)
+ static int scif_txfill(struct uart_port *port)
+ {
+       return sci_in(port, SCTFDR) & 0xff;
+ }
+ static int scif_txroom(struct uart_port *port)
+ {
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+ }
+ static int scif_rxfill(struct uart_port *port)
+ {
+       return sci_in(port, SCRFDR) & 0xff;
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+ static int scif_txfill(struct uart_port *port)
+ {
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return sci_in(port, SCTFDR) & 0xff;
+       else
+               /* SCIF2 */
+               return sci_in(port, SCFDR) >> 8;
+ }
+ static int scif_txroom(struct uart_port *port)
+ {
+       if (port->mapbase == 0xffe00000 ||
+           port->mapbase == 0xffe08000)
+               /* SCIF0/1*/
+               return SCIF_TXROOM_MAX - scif_txfill(port);
+       else
+               /* SCIF2 */
+               return SCIF2_TXROOM_MAX - scif_txfill(port);
+ }
+ static int scif_rxfill(struct uart_port *port)
+ {
+       if ((port->mapbase == 0xffe00000) ||
+           (port->mapbase == 0xffe08000)) {
+               /* SCIF0/1*/
+               return sci_in(port, SCRFDR) & 0xff;
+       } else {
+               /* SCIF2 */
+               return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
+       }
+ }
+ #elif defined(CONFIG_ARCH_SH7372)
+ static int scif_txfill(struct uart_port *port)
+ {
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) >> 8;
+       else
+               return sci_in(port, SCTFDR);
+ }
+ static int scif_txroom(struct uart_port *port)
+ {
+       return port->fifosize - scif_txfill(port);
+ }
+ static int scif_rxfill(struct uart_port *port)
+ {
+       if (port->type == PORT_SCIFA)
+               return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+       else
+               return sci_in(port, SCRFDR);
+ }
+ #else
+ static int scif_txfill(struct uart_port *port)
+ {
+       return sci_in(port, SCFDR) >> 8;
+ }
+ static int scif_txroom(struct uart_port *port)
+ {
+       return SCIF_TXROOM_MAX - scif_txfill(port);
+ }
+ static int scif_rxfill(struct uart_port *port)
+ {
+       return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+ }
+ #endif
+ static int sci_txfill(struct uart_port *port)
+ {
+       return !(sci_in(port, SCxSR) & SCI_TDRE);
+ }
+ static int sci_txroom(struct uart_port *port)
+ {
+       return !sci_txfill(port);
+ }
+ static int sci_rxfill(struct uart_port *port)
+ {
+       return (sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0;
+ }
+ /* ********************************************************************** *
+  *                   the interrupt related routines                       *
+  * ********************************************************************** */
+ static void sci_transmit_chars(struct uart_port *port)
+ {
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int stopped = uart_tx_stopped(port);
+       unsigned short status;
+       unsigned short ctrl;
+       int count;
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_TDxE(port))) {
+               ctrl = sci_in(port, SCSCR);
+               if (uart_circ_empty(xmit))
 -                      ctrl &= ~SCI_CTRL_FLAGS_TIE;
++                      ctrl &= ~SCSCR_TIE;
+               else
 -                      ctrl |= SCI_CTRL_FLAGS_TIE;
++                      ctrl |= SCSCR_TIE;
+               sci_out(port, SCSCR, ctrl);
+               return;
+       }
+       if (port->type == PORT_SCI)
+               count = sci_txroom(port);
+       else
+               count = scif_txroom(port);
+       do {
+               unsigned char c;
+               if (port->x_char) {
+                       c = port->x_char;
+                       port->x_char = 0;
+               } else if (!uart_circ_empty(xmit) && !stopped) {
+                       c = xmit->buf[xmit->tail];
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               } else {
+                       break;
+               }
+               sci_out(port, SCxTDR, c);
+               port->icount.tx++;
+       } while (--count > 0);
+       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (uart_circ_empty(xmit)) {
+               sci_stop_tx(port);
+       } else {
+               ctrl = sci_in(port, SCSCR);
+               if (port->type != PORT_SCI) {
+                       sci_in(port, SCxSR); /* Dummy read */
+                       sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+               }
 -              ctrl |= SCI_CTRL_FLAGS_TIE;
++              ctrl |= SCSCR_TIE;
+               sci_out(port, SCSCR, ctrl);
+       }
+ }
+ /* On SH3, SCIF may read end-of-break as a space->mark char */
+ #define STEPFN(c)  ({int __c = (c); (((__c-1)|(__c)) == -1); })
+ static inline void sci_receive_chars(struct uart_port *port)
+ {
+       struct sci_port *sci_port = to_sci_port(port);
+       struct tty_struct *tty = port->state->port.tty;
+       int i, count, copied = 0;
+       unsigned short status;
+       unsigned char flag;
+       status = sci_in(port, SCxSR);
+       if (!(status & SCxSR_RDxF(port)))
+               return;
+       while (1) {
+               if (port->type == PORT_SCI)
+                       count = sci_rxfill(port);
+               else
+                       count = scif_rxfill(port);
+               /* Don't copy more bytes than there is room for in the buffer */
+               count = tty_buffer_request_room(tty, count);
+               /* If for any reason we can't copy more data, we're done! */
+               if (count == 0)
+                       break;
+               if (port->type == PORT_SCI) {
+                       char c = sci_in(port, SCxRDR);
+                       if (uart_handle_sysrq_char(port, c) ||
+                           sci_port->break_flag)
+                               count = 0;
+                       else
+                               tty_insert_flip_char(tty, c, TTY_NORMAL);
+               } else {
+                       for (i = 0; i < count; i++) {
+                               char c = sci_in(port, SCxRDR);
+                               status = sci_in(port, SCxSR);
+ #if defined(CONFIG_CPU_SH3)
+                               /* Skip "chars" during break */
+                               if (sci_port->break_flag) {
+                                       if ((c == 0) &&
+                                           (status & SCxSR_FER(port))) {
+                                               count--; i--;
+                                               continue;
+                                       }
+                                       /* Nonzero => end-of-break */
+                                       dev_dbg(port->dev, "debounce<%02x>\n", c);
+                                       sci_port->break_flag = 0;
+                                       if (STEPFN(c)) {
+                                               count--; i--;
+                                               continue;
+                                       }
+                               }
+ #endif /* CONFIG_CPU_SH3 */
+                               if (uart_handle_sysrq_char(port, c)) {
+                                       count--; i--;
+                                       continue;
+                               }
+                               /* Store data and status */
+                               if (status & SCxSR_FER(port)) {
+                                       flag = TTY_FRAME;
+                                       dev_notice(port->dev, "frame error\n");
+                               } else if (status & SCxSR_PER(port)) {
+                                       flag = TTY_PARITY;
+                                       dev_notice(port->dev, "parity error\n");
+                               } else
+                                       flag = TTY_NORMAL;
+                               tty_insert_flip_char(tty, c, flag);
+                       }
+               }
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               copied += count;
+               port->icount.rx += count;
+       }
+       if (copied) {
+               /* Tell the rest of the system the news. New characters! */
+               tty_flip_buffer_push(tty);
+       } else {
+               sci_in(port, SCxSR); /* dummy read */
+               sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       }
+ }
+ #define SCI_BREAK_JIFFIES (HZ/20)
+ /* The sci generates interrupts during the break,
+  * 1 per millisecond or so during the break period, for 9600 baud.
+  * So dont bother disabling interrupts.
+  * But dont want more than 1 break event.
+  * Use a kernel timer to periodically poll the rx line until
+  * the break is finished.
+  */
+ static void sci_schedule_break_timer(struct sci_port *port)
+ {
+       port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
+       add_timer(&port->break_timer);
+ }
+ /* Ensure that two consecutive samples find the break over. */
+ static void sci_break_timer(unsigned long data)
+ {
+       struct sci_port *port = (struct sci_port *)data;
+       if (sci_rxd_in(&port->port) == 0) {
+               port->break_flag = 1;
+               sci_schedule_break_timer(port);
+       } else if (port->break_flag == 1) {
+               /* break is over. */
+               port->break_flag = 2;
+               sci_schedule_break_timer(port);
+       } else
+               port->break_flag = 0;
+ }
+ static inline int sci_handle_errors(struct uart_port *port)
+ {
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+       if (status & SCxSR_ORER(port)) {
+               /* overrun error */
+               if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+                       copied++;
+               dev_notice(port->dev, "overrun error");
+       }
+       if (status & SCxSR_FER(port)) {
+               if (sci_rxd_in(port) == 0) {
+                       /* Notify of BREAK */
+                       struct sci_port *sci_port = to_sci_port(port);
+                       if (!sci_port->break_flag) {
+                               sci_port->break_flag = 1;
+                               sci_schedule_break_timer(sci_port);
+                               /* Do sysrq handling. */
+                               if (uart_handle_break(port))
+                                       return 0;
+                               dev_dbg(port->dev, "BREAK detected\n");
+                               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                                       copied++;
+                       }
+               } else {
+                       /* frame error */
+                       if (tty_insert_flip_char(tty, 0, TTY_FRAME))
+                               copied++;
+                       dev_notice(port->dev, "frame error\n");
+               }
+       }
+       if (status & SCxSR_PER(port)) {
+               /* parity error */
+               if (tty_insert_flip_char(tty, 0, TTY_PARITY))
+                       copied++;
+               dev_notice(port->dev, "parity error");
+       }
+       if (copied)
+               tty_flip_buffer_push(tty);
+       return copied;
+ }
+ static inline int sci_handle_fifo_overrun(struct uart_port *port)
+ {
+       struct tty_struct *tty = port->state->port.tty;
+       int copied = 0;
+       if (port->type != PORT_SCIF)
+               return 0;
+       if ((sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+               sci_out(port, SCLSR, 0);
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               tty_flip_buffer_push(tty);
+               dev_notice(port->dev, "overrun error\n");
+               copied++;
+       }
+       return copied;
+ }
+ static inline int sci_handle_breaks(struct uart_port *port)
+ {
+       int copied = 0;
+       unsigned short status = sci_in(port, SCxSR);
+       struct tty_struct *tty = port->state->port.tty;
+       struct sci_port *s = to_sci_port(port);
+       if (uart_handle_break(port))
+               return 0;
+       if (!s->break_flag && status & SCxSR_BRK(port)) {
+ #if defined(CONFIG_CPU_SH3)
+               /* Debounce break */
+               s->break_flag = 1;
+ #endif
+               /* Notify of BREAK */
+               if (tty_insert_flip_char(tty, 0, TTY_BREAK))
+                       copied++;
+               dev_dbg(port->dev, "BREAK detected\n");
+       }
+       if (copied)
+               tty_flip_buffer_push(tty);
+       copied += sci_handle_fifo_overrun(port);
+       return copied;
+ }
+ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
+ {
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       if (s->chan_rx) {
+               u16 scr = sci_in(port, SCSCR);
+               u16 ssr = sci_in(port, SCxSR);
+               /* Disable future Rx interrupts */
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       disable_irq_nosync(irq);
+                       scr |= 0x4000;
+               } else {
 -                      scr &= ~SCI_CTRL_FLAGS_RIE;
++                      scr &= ~SCSCR_RIE;
+               }
+               sci_out(port, SCSCR, scr);
+               /* Clear current interrupt */
+               sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+               return IRQ_HANDLED;
+       }
+ #endif
+       /* I think sci_receive_chars has to be called irrespective
+        * of whether the I_IXOFF is set, otherwise, how is the interrupt
+        * to be disabled?
+        */
+       sci_receive_chars(ptr);
+       return IRQ_HANDLED;
+ }
+ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
+ {
+       struct uart_port *port = ptr;
+       unsigned long flags;
+       spin_lock_irqsave(&port->lock, flags);
+       sci_transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return IRQ_HANDLED;
+ }
+ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+ {
+       struct uart_port *port = ptr;
+       /* Handle errors */
+       if (port->type == PORT_SCI) {
+               if (sci_handle_errors(port)) {
+                       /* discard character in rx buffer */
+                       sci_in(port, SCxSR);
+                       sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               }
+       } else {
+               sci_handle_fifo_overrun(port);
+               sci_rx_interrupt(irq, ptr);
+       }
+       sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+       /* Kick the transmission */
+       sci_tx_interrupt(irq, ptr);
+       return IRQ_HANDLED;
+ }
+ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+ {
+       struct uart_port *port = ptr;
+       /* Handle BREAKs */
+       sci_handle_breaks(port);
+       sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+       return IRQ_HANDLED;
+ }
++static inline unsigned long port_rx_irq_mask(struct uart_port *port)
++{
++      /*
++       * Not all ports (such as SCIFA) will support REIE. Rather than
++       * special-casing the port type, we check the port initialization
++       * IRQ enable mask to see whether the IRQ is desired at all. If
++       * it's unset, it's logically inferred that there's no point in
++       * testing for it.
++       */
++      return SCSCR_RIE | (to_sci_port(port)->scscr & SCSCR_REIE);
++}
++
+ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+ {
+       unsigned short ssr_status, scr_status, err_enabled;
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       irqreturn_t ret = IRQ_NONE;
+       ssr_status = sci_in(port, SCxSR);
+       scr_status = sci_in(port, SCSCR);
 -      err_enabled = scr_status & (SCI_CTRL_FLAGS_REIE | SCI_CTRL_FLAGS_RIE);
++      err_enabled = scr_status & port_rx_irq_mask(port);
+       /* Tx Interrupt */
 -      if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCI_CTRL_FLAGS_TIE) &&
++      if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
+           !s->chan_tx)
+               ret = sci_tx_interrupt(irq, ptr);
++
+       /*
+        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+        * DR flags
+        */
+       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
 -          (scr_status & SCI_CTRL_FLAGS_RIE))
++          (scr_status & SCSCR_RIE))
+               ret = sci_rx_interrupt(irq, ptr);
++
+       /* Error Interrupt */
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
+               ret = sci_er_interrupt(irq, ptr);
++
+       /* Break Interrupt */
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+               ret = sci_br_interrupt(irq, ptr);
+       return ret;
+ }
+ /*
+  * Here we define a transistion notifier so that we can update all of our
+  * ports' baud rate when the peripheral clock changes.
+  */
+ static int sci_notifier(struct notifier_block *self,
+                       unsigned long phase, void *p)
+ {
+       struct sh_sci_priv *priv = container_of(self,
+                                               struct sh_sci_priv, clk_nb);
+       struct sci_port *sci_port;
+       unsigned long flags;
+       if ((phase == CPUFREQ_POSTCHANGE) ||
+           (phase == CPUFREQ_RESUMECHANGE)) {
+               spin_lock_irqsave(&priv->lock, flags);
+               list_for_each_entry(sci_port, &priv->ports, node)
+                       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+       return NOTIFY_OK;
+ }
+ static void sci_clk_enable(struct uart_port *port)
+ {
+       struct sci_port *sci_port = to_sci_port(port);
+       clk_enable(sci_port->iclk);
+       sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+       clk_enable(sci_port->fclk);
+ }
+ static void sci_clk_disable(struct uart_port *port)
+ {
+       struct sci_port *sci_port = to_sci_port(port);
+       clk_disable(sci_port->fclk);
+       clk_disable(sci_port->iclk);
+ }
+ static int sci_request_irq(struct sci_port *port)
+ {
+       int i;
+       irqreturn_t (*handlers[4])(int irq, void *ptr) = {
+               sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+               sci_br_interrupt,
+       };
+       const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
+                              "SCI Transmit Data Empty", "SCI Break" };
+       if (port->irqs[0] == port->irqs[1]) {
+               if (unlikely(!port->irqs[0]))
+                       return -ENODEV;
+               if (request_irq(port->irqs[0], sci_mpxed_interrupt,
+                               IRQF_DISABLED, "sci", port)) {
+                       dev_err(port->port.dev, "Can't allocate IRQ\n");
+                       return -ENODEV;
+               }
+       } else {
+               for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+                       if (unlikely(!port->irqs[i]))
+                               continue;
+                       if (request_irq(port->irqs[i], handlers[i],
+                                       IRQF_DISABLED, desc[i], port)) {
+                               dev_err(port->port.dev, "Can't allocate IRQ\n");
+                               return -ENODEV;
+                       }
+               }
+       }
+       return 0;
+ }
+ static void sci_free_irq(struct sci_port *port)
+ {
+       int i;
+       if (port->irqs[0] == port->irqs[1])
+               free_irq(port->irqs[0], port);
+       else {
+               for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
+                       if (!port->irqs[i])
+                               continue;
+                       free_irq(port->irqs[i], port);
+               }
+       }
+ }
+ static unsigned int sci_tx_empty(struct uart_port *port)
+ {
+       unsigned short status = sci_in(port, SCxSR);
+       unsigned short in_tx_fifo = scif_txfill(port);
+       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
+ }
+ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
+ {
+       /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
+       /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
+       /* If you have signals for DTR and DCD, please implement here. */
+ }
+ static unsigned int sci_get_mctrl(struct uart_port *port)
+ {
+       /* This routine is used for getting signals of: DTR, DCD, DSR, RI,
+          and CTS/RTS */
+       return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+ }
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+ static void sci_dma_tx_complete(void *arg)
+ {
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+       spin_lock_irqsave(&port->lock, flags);
+       xmit->tail += sg_dma_len(&s->sg_tx);
+       xmit->tail &= UART_XMIT_SIZE - 1;
+       port->icount.tx += sg_dma_len(&s->sg_tx);
+       async_tx_ack(s->desc_tx);
+       s->cookie_tx = -EINVAL;
+       s->desc_tx = NULL;
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+       if (!uart_circ_empty(xmit)) {
+               schedule_work(&s->work_tx);
+       } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 ctrl = sci_in(port, SCSCR);
 -              sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
++              sci_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+ }
+ /* Locking: called with port lock held */
+ static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
+                          size_t count)
+ {
+       struct uart_port *port = &s->port;
+       int i, active, room;
+       room = tty_buffer_request_room(tty, count);
+       if (s->active_rx == s->cookie_rx[0]) {
+               active = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               active = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return 0;
+       }
+       if (room < count)
+               dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
+                        count - room);
+       if (!room)
+               return room;
+       for (i = 0; i < room; i++)
+               tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
+                                    TTY_NORMAL);
+       port->icount.rx += room;
+       return room;
+ }
+ static void sci_dma_rx_complete(void *arg)
+ {
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct tty_struct *tty = port->state->port.tty;
+       unsigned long flags;
+       int count;
+       dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
+       spin_lock_irqsave(&port->lock, flags);
+       count = sci_dma_rx_push(s, tty, s->buf_len_rx);
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+       spin_unlock_irqrestore(&port->lock, flags);
+       if (count)
+               tty_flip_buffer_push(tty);
+       schedule_work(&s->work_rx);
+ }
+ static void sci_start_rx(struct uart_port *port);
+ static void sci_start_tx(struct uart_port *port);
+ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+ {
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       s->chan_rx = NULL;
+       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+       dma_release_channel(chan);
+       if (sg_dma_address(&s->sg_rx[0]))
+               dma_free_coherent(port->dev, s->buf_len_rx * 2,
+                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
+       if (enable_pio)
+               sci_start_rx(port);
+ }
+ static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+ {
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       s->chan_tx = NULL;
+       s->cookie_tx = -EINVAL;
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_tx(port);
+ }
+ static void sci_submit_rx(struct sci_port *s)
+ {
+       struct dma_chan *chan = s->chan_rx;
+       int i;
+       for (i = 0; i < 2; i++) {
+               struct scatterlist *sg = &s->sg_rx[i];
+               struct dma_async_tx_descriptor *desc;
+               desc = chan->device->device_prep_slave_sg(chan,
+                       sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT);
+               if (desc) {
+                       s->desc_rx[i] = desc;
+                       desc->callback = sci_dma_rx_complete;
+                       desc->callback_param = s;
+                       s->cookie_rx[i] = desc->tx_submit(desc);
+               }
+               if (!desc || s->cookie_rx[i] < 0) {
+                       if (i) {
+                               async_tx_ack(s->desc_rx[0]);
+                               s->cookie_rx[0] = -EINVAL;
+                       }
+                       if (desc) {
+                               async_tx_ack(desc);
+                               s->cookie_rx[i] = -EINVAL;
+                       }
+                       dev_warn(s->port.dev,
+                                "failed to re-start DMA, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
+       }
+       s->active_rx = s->cookie_rx[0];
+       dma_async_issue_pending(chan);
+ }
+ static void work_fn_rx(struct work_struct *work)
+ {
+       struct sci_port *s = container_of(work, struct sci_port, work_rx);
+       struct uart_port *port = &s->port;
+       struct dma_async_tx_descriptor *desc;
+       int new;
+       if (s->active_rx == s->cookie_rx[0]) {
+               new = 0;
+       } else if (s->active_rx == s->cookie_rx[1]) {
+               new = 1;
+       } else {
+               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
+               return;
+       }
+       desc = s->desc_rx[new];
+       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
+           DMA_SUCCESS) {
+               /* Handle incomplete DMA receive */
+               struct tty_struct *tty = port->state->port.tty;
+               struct dma_chan *chan = s->chan_rx;
+               struct sh_desc *sh_desc = container_of(desc, struct sh_desc,
+                                                      async_tx);
+               unsigned long flags;
+               int count;
+               chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+               dev_dbg(port->dev, "Read %u bytes with cookie %d\n",
+                       sh_desc->partial, sh_desc->cookie);
+               spin_lock_irqsave(&port->lock, flags);
+               count = sci_dma_rx_push(s, tty, sh_desc->partial);
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (count)
+                       tty_flip_buffer_push(tty);
+               sci_submit_rx(s);
+               return;
+       }
+       s->cookie_rx[new] = desc->tx_submit(desc);
+       if (s->cookie_rx[new] < 0) {
+               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+               sci_rx_dma_release(s, true);
+               return;
+       }
+       s->active_rx = s->cookie_rx[!new];
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
+               s->cookie_rx[new], new, s->active_rx);
+ }
+ static void work_fn_tx(struct work_struct *work)
+ {
+       struct sci_port *s = container_of(work, struct sci_port, work_tx);
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct scatterlist *sg = &s->sg_tx;
+       /*
+        * DMA is idle now.
+        * Port xmit buffer is already mapped, and it is one page... Just adjust
+        * offsets and lengths. Since it is a circular buffer, we have to
+        * transmit till the end, and then the rest. Take the port lock to get a
+        * consistent xmit buffer state.
+        */
+       spin_lock_irq(&port->lock);
+       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+               sg->offset;
+       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+       spin_unlock_irq(&port->lock);
+       BUG_ON(!sg_dma_len(sg));
+       desc = chan->device->device_prep_slave_sg(chan,
+                       sg, s->sg_len_tx, DMA_TO_DEVICE,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+       spin_lock_irq(&port->lock);
+       s->desc_tx = desc;
+       desc->callback = sci_dma_tx_complete;
+       desc->callback_param = s;
+       spin_unlock_irq(&port->lock);
+       s->cookie_tx = desc->tx_submit(desc);
+       if (s->cookie_tx < 0) {
+               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
+       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", __func__,
+               xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+       dma_async_issue_pending(chan);
+ }
+ #endif
+ static void sci_start_tx(struct uart_port *port)
+ {
+       struct sci_port *s = to_sci_port(port);
+       unsigned short ctrl;
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 new, scr = sci_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | 0x8000;
+               else
+                       new = scr & ~0x8000;
+               if (new != scr)
+                       sci_out(port, SCSCR, new);
+       }
++
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           s->cookie_tx < 0)
+               schedule_work(&s->work_tx);
+ #endif
++
+       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = sci_in(port, SCSCR);
 -              sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
++              sci_out(port, SCSCR, ctrl | SCSCR_TIE);
+       }
+ }
+ static void sci_stop_tx(struct uart_port *port)
+ {
+       unsigned short ctrl;
+       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+       ctrl = sci_in(port, SCSCR);
++
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x8000;
 -      ctrl &= ~SCI_CTRL_FLAGS_TIE;
++
++      ctrl &= ~SCSCR_TIE;
++
+       sci_out(port, SCSCR, ctrl);
+ }
+ static void sci_start_rx(struct uart_port *port)
+ {
 -      unsigned short ctrl = SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
++      unsigned short ctrl;
++
++      ctrl = sci_in(port, SCSCR) | port_rx_irq_mask(port);
 -      /* Set RIE (Receive Interrupt Enable) bit in SCSCR */
 -      ctrl |= sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
++
+       sci_out(port, SCSCR, ctrl);
+ }
+ static void sci_stop_rx(struct uart_port *port)
+ {
+       unsigned short ctrl;
 -      /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
+       ctrl = sci_in(port, SCSCR);
++
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~0x4000;
 -      ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
++
++      ctrl &= ~port_rx_irq_mask(port);
++
+       sci_out(port, SCSCR, ctrl);
+ }
+ static void sci_enable_ms(struct uart_port *port)
+ {
+       /* Nothing here yet .. */
+ }
+ static void sci_break_ctl(struct uart_port *port, int break_state)
+ {
+       /* Nothing here yet .. */
+ }
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+ static bool filter(struct dma_chan *chan, void *slave)
+ {
+       struct sh_dmae_slave *param = slave;
+       dev_dbg(chan->device->dev, "%s: slave ID %d\n", __func__,
+               param->slave_id);
+       if (param->dma_dev == chan->device->dev) {
+               chan->private = param;
+               return true;
+       } else {
+               return false;
+       }
+ }
+ static void rx_timer_fn(unsigned long arg)
+ {
+       struct sci_port *s = (struct sci_port *)arg;
+       struct uart_port *port = &s->port;
+       u16 scr = sci_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               scr &= ~0x4000;
+               enable_irq(s->irqs[1]);
+       }
 -      sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
++      sci_out(port, SCSCR, scr | SCSCR_RIE);
+       dev_dbg(port->dev, "DMA Rx timed out\n");
+       schedule_work(&s->work_rx);
+ }
+ static void sci_request_dma(struct uart_port *port)
+ {
+       struct sci_port *s = to_sci_port(port);
+       struct sh_dmae_slave *param;
+       struct dma_chan *chan;
+       dma_cap_mask_t mask;
+       int nent;
+       dev_dbg(port->dev, "%s: port %d DMA %p\n", __func__,
+               port->line, s->dma_dev);
+       if (!s->dma_dev)
+               return;
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       param = &s->param_tx;
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
+       param->slave_id = s->slave_tx;
+       param->dma_dev = s->dma_dev;
+       s->cookie_tx = -EINVAL;
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+       if (chan) {
+               s->chan_tx = chan;
+               sg_init_table(&s->sg_tx, 1);
+               /* UART circular tx buffer is an aligned page. */
+               BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
+                           UART_XMIT_SIZE, (int)port->state->xmit.buf & ~PAGE_MASK);
+               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
+               if (!nent)
+                       sci_tx_dma_release(s, false);
+               else
+                       dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+                               sg_dma_len(&s->sg_tx),
+                               port->state->xmit.buf, sg_dma_address(&s->sg_tx));
+               s->sg_len_tx = nent;
+               INIT_WORK(&s->work_tx, work_fn_tx);
+       }
+       param = &s->param_rx;
+       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
+       param->slave_id = s->slave_rx;
+       param->dma_dev = s->dma_dev;
+       chan = dma_request_channel(mask, filter, param);
+       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+       if (chan) {
+               dma_addr_t dma[2];
+               void *buf[2];
+               int i;
+               s->chan_rx = chan;
+               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
+               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
+                                           &dma[0], GFP_KERNEL);
+               if (!buf[0]) {
+                       dev_warn(port->dev,
+                                "failed to allocate dma buffer, using PIO\n");
+                       sci_rx_dma_release(s, true);
+                       return;
+               }
+               buf[1] = buf[0] + s->buf_len_rx;
+               dma[1] = dma[0] + s->buf_len_rx;
+               for (i = 0; i < 2; i++) {
+                       struct scatterlist *sg = &s->sg_rx[i];
+                       sg_init_table(sg, 1);
+                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
+                                   (int)buf[i] & ~PAGE_MASK);
+                       sg_dma_address(sg) = dma[i];
+               }
+               INIT_WORK(&s->work_rx, work_fn_rx);
+               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
+               sci_submit_rx(s);
+       }
+ }
+ static void sci_free_dma(struct uart_port *port)
+ {
+       struct sci_port *s = to_sci_port(port);
+       if (!s->dma_dev)
+               return;
+       if (s->chan_tx)
+               sci_tx_dma_release(s, false);
+       if (s->chan_rx)
+               sci_rx_dma_release(s, false);
+ }
+ #endif
+ static int sci_startup(struct uart_port *port)
+ {
+       struct sci_port *s = to_sci_port(port);
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+       if (s->enable)
+               s->enable(port);
+       sci_request_irq(s);
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_request_dma(port);
+ #endif
+       sci_start_tx(port);
+       sci_start_rx(port);
+       return 0;
+ }
+ static void sci_shutdown(struct uart_port *port)
+ {
+       struct sci_port *s = to_sci_port(port);
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+       sci_stop_rx(port);
+       sci_stop_tx(port);
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_free_dma(port);
+ #endif
+       sci_free_irq(s);
+       if (s->disable)
+               s->disable(port);
+ }
++static unsigned int sci_scbrr_calc(unsigned int algo_id, unsigned int bps,
++                                 unsigned long freq)
++{
++      switch (algo_id) {
++      case SCBRR_ALGO_1:
++              return ((freq + 16 * bps) / (16 * bps) - 1);
++      case SCBRR_ALGO_2:
++              return ((freq + 16 * bps) / (32 * bps) - 1);
++      case SCBRR_ALGO_3:
++              return (((freq * 2) + 16 * bps) / (16 * bps) - 1);
++      case SCBRR_ALGO_4:
++              return (((freq * 2) + 16 * bps) / (32 * bps) - 1);
++      case SCBRR_ALGO_5:
++              return (((freq * 1000 / 32) / bps) - 1);
++      }
++
++      /* Warn, but use a safe default */
++      WARN_ON(1);
++      return ((freq + 16 * bps) / (32 * bps) - 1);
++}
++
+ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
+                           struct ktermios *old)
+ {
 -#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct sci_port *s = to_sci_port(port);
 -#endif
+       unsigned int status, baud, smr_val, max_baud;
+       int t = -1;
+       u16 scfcr = 0;
+       /*
+        * earlyprintk comes here early on with port->uartclk set to zero.
+        * the clock framework is not up and running at this point so here
+        * we assume that 115200 is the maximum baud rate. please note that
+        * the baud rate is not programmed during earlyprintk - it is assumed
+        * that the previous boot loader has enabled required clocks and
+        * setup the baud rate generator hardware for us already.
+        */
+       max_baud = port->uartclk ? port->uartclk / 16 : 115200;
+       baud = uart_get_baud_rate(port, termios, old, 0, max_baud);
+       if (likely(baud && port->uartclk))
 -              t = SCBRR_VALUE(baud, port->uartclk);
++              t = sci_scbrr_calc(s->scbrr_algo_id, baud, port->uartclk);
+       do {
+               status = sci_in(port, SCxSR);
+       } while (!(status & SCxSR_TEND(port)));
+       sci_out(port, SCSCR, 0x00);     /* TE=0, RE=0, CKE1=0 */
+       if (port->type != PORT_SCI)
+               sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
+       smr_val = sci_in(port, SCSMR) & 3;
+       if ((termios->c_cflag & CSIZE) == CS7)
+               smr_val |= 0x40;
+       if (termios->c_cflag & PARENB)
+               smr_val |= 0x20;
+       if (termios->c_cflag & PARODD)
+               smr_val |= 0x30;
+       if (termios->c_cflag & CSTOPB)
+               smr_val |= 0x08;
+       uart_update_timeout(port, termios->c_cflag, baud);
+       sci_out(port, SCSMR, smr_val);
+       dev_dbg(port->dev, "%s: SMR %x, t %x, SCSCR %x\n", __func__, smr_val, t,
 -              SCSCR_INIT(port));
++              s->scscr);
+       if (t > 0) {
+               if (t >= 256) {
+                       sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
+                       t >>= 2;
+               } else
+                       sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
+               sci_out(port, SCBRR, t);
+               udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
+       }
+       sci_init_pins(port, termios->c_cflag);
+       sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
 -      sci_out(port, SCSCR, SCSCR_INIT(port));
++      sci_out(port, SCSCR, s->scscr);
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       /*
+        * Calculate delay for 1.5 DMA buffers: see
+        * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
+        * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
+        * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
+        * sizes), but it has been found out experimentally, that this is not
+        * enough: the driver too often needlessly runs on a DMA timeout. 20ms
+        * as a minimum seem to work perfectly.
+        */
+       if (s->chan_rx) {
+               s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+                       port->fifosize / 2;
+               dev_dbg(port->dev,
+                       "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+                       s->rx_timeout * 1000 / HZ, port->timeout);
+               if (s->rx_timeout < msecs_to_jiffies(20))
+                       s->rx_timeout = msecs_to_jiffies(20);
+       }
+ #endif
+       if ((termios->c_cflag & CREAD) != 0)
+               sci_start_rx(port);
+ }
+ static const char *sci_type(struct uart_port *port)
+ {
+       switch (port->type) {
+       case PORT_IRDA:
+               return "irda";
+       case PORT_SCI:
+               return "sci";
+       case PORT_SCIF:
+               return "scif";
+       case PORT_SCIFA:
+               return "scifa";
+       case PORT_SCIFB:
+               return "scifb";
+       }
+       return NULL;
+ }
+ static void sci_release_port(struct uart_port *port)
+ {
+       /* Nothing here yet .. */
+ }
+ static int sci_request_port(struct uart_port *port)
+ {
+       /* Nothing here yet .. */
+       return 0;
+ }
+ static void sci_config_port(struct uart_port *port, int flags)
+ {
+       struct sci_port *s = to_sci_port(port);
+       port->type = s->type;
+       if (port->membase)
+               return;
+       if (port->flags & UPF_IOREMAP) {
+               port->membase = ioremap_nocache(port->mapbase, 0x40);
+               if (IS_ERR(port->membase))
+                       dev_err(port->dev, "can't remap port#%d\n", port->line);
+       } else {
+               /*
+                * For the simple (and majority of) cases where we don't
+                * need to do any remapping, just cast the cookie
+                * directly.
+                */
+               port->membase = (void __iomem *)port->mapbase;
+       }
+ }
+ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+ {
+       struct sci_port *s = to_sci_port(port);
+       if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > nr_irqs)
+               return -EINVAL;
+       if (ser->baud_base < 2400)
+               /* No paper tape reader for Mitch.. */
+               return -EINVAL;
+       return 0;
+ }
+ static struct uart_ops sci_uart_ops = {
+       .tx_empty       = sci_tx_empty,
+       .set_mctrl      = sci_set_mctrl,
+       .get_mctrl      = sci_get_mctrl,
+       .start_tx       = sci_start_tx,
+       .stop_tx        = sci_stop_tx,
+       .stop_rx        = sci_stop_rx,
+       .enable_ms      = sci_enable_ms,
+       .break_ctl      = sci_break_ctl,
+       .startup        = sci_startup,
+       .shutdown       = sci_shutdown,
+       .set_termios    = sci_set_termios,
+       .type           = sci_type,
+       .release_port   = sci_release_port,
+       .request_port   = sci_request_port,
+       .config_port    = sci_config_port,
+       .verify_port    = sci_verify_port,
+ #ifdef CONFIG_CONSOLE_POLL
+       .poll_get_char  = sci_poll_get_char,
+       .poll_put_char  = sci_poll_put_char,
+ #endif
+ };
+ static int __devinit sci_init_single(struct platform_device *dev,
+                                    struct sci_port *sci_port,
+                                    unsigned int index,
+                                    struct plat_sci_port *p)
+ {
+       struct uart_port *port = &sci_port->port;
+       port->ops       = &sci_uart_ops;
+       port->iotype    = UPIO_MEM;
+       port->line      = index;
+       switch (p->type) {
+       case PORT_SCIFB:
+               port->fifosize = 256;
+               break;
+       case PORT_SCIFA:
+               port->fifosize = 64;
+               break;
+       case PORT_SCIF:
+               port->fifosize = 16;
+               break;
+       default:
+               port->fifosize = 1;
+               break;
+       }
+       if (dev) {
+               sci_port->iclk = clk_get(&dev->dev, "sci_ick");
+               if (IS_ERR(sci_port->iclk)) {
+                       sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
+                       if (IS_ERR(sci_port->iclk)) {
+                               dev_err(&dev->dev, "can't get iclk\n");
+                               return PTR_ERR(sci_port->iclk);
+                       }
+               }
+               /*
+                * The function clock is optional, ignore it if we can't
+                * find it.
+                */
+               sci_port->fclk = clk_get(&dev->dev, "sci_fck");
+               if (IS_ERR(sci_port->fclk))
+                       sci_port->fclk = NULL;
+               sci_port->enable = sci_clk_enable;
+               sci_port->disable = sci_clk_disable;
+               port->dev = &dev->dev;
+       }
+       sci_port->break_timer.data = (unsigned long)sci_port;
+       sci_port->break_timer.function = sci_break_timer;
+       init_timer(&sci_port->break_timer);
+       port->mapbase   = p->mapbase;
+       port->membase   = p->membase;
 -      port->irq       = p->irqs[SCIx_TXI_IRQ];
 -      port->flags     = p->flags;
 -      sci_port->type  = port->type = p->type;
++      port->irq               = p->irqs[SCIx_TXI_IRQ];
++      port->flags             = p->flags;
++      sci_port->type          = port->type = p->type;
++      sci_port->scscr         = p->scscr;
++      sci_port->scbrr_algo_id = p->scbrr_algo_id;
+ #ifdef CONFIG_SERIAL_SH_SCI_DMA
+       sci_port->dma_dev       = p->dma_dev;
+       sci_port->slave_tx      = p->dma_slave_tx;
+       sci_port->slave_rx      = p->dma_slave_rx;
+       dev_dbg(port->dev, "%s: DMA device %p, tx %d, rx %d\n", __func__,
+               p->dma_dev, p->dma_slave_tx, p->dma_slave_rx);
+ #endif
+       memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
+       return 0;
+ }
+ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ static struct tty_driver *serial_console_device(struct console *co, int *index)
+ {
+       struct uart_driver *p = &sci_uart_driver;
+       *index = co->index;
+       return p->tty_driver;
+ }
+ static void serial_console_putchar(struct uart_port *port, int ch)
+ {
+       sci_poll_put_char(port, ch);
+ }
+ /*
+  *    Print a string to the serial port trying not to disturb
+  *    any possible real use of the port...
+  */
+ static void serial_console_write(struct console *co, const char *s,
+                                unsigned count)
+ {
+       struct uart_port *port = co->data;
+       struct sci_port *sci_port = to_sci_port(port);
+       unsigned short bits;
+       if (sci_port->enable)
+               sci_port->enable(port);
+       uart_console_write(port, s, count, serial_console_putchar);
+       /* wait until fifo is empty and last bit has been transmitted */
+       bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
+       while ((sci_in(port, SCxSR) & bits) != bits)
+               cpu_relax();
+       if (sci_port->disable)
+               sci_port->disable(port);
+ }
+ static int __devinit serial_console_setup(struct console *co, char *options)
+ {
+       struct sci_port *sci_port;
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       int ret;
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index >= SCI_NPORTS)
+               co->index = 0;
+       if (co->data) {
+               port = co->data;
+               sci_port = to_sci_port(port);
+       } else {
+               sci_port = &sci_ports[co->index];
+               port = &sci_port->port;
+               co->data = port;
+       }
+       /*
+        * Also need to check port->type, we don't actually have any
+        * UPIO_PORT ports, but uart_report_port() handily misreports
+        * it anyways if we don't have a port available by the time this is
+        * called.
+        */
+       if (!port->type)
+               return -ENODEV;
+       sci_config_port(port, 0);
+       if (sci_port->enable)
+               sci_port->enable(port);
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       ret = uart_set_options(port, co, baud, parity, bits, flow);
+ #if defined(__H8300H__) || defined(__H8300S__)
+       /* disable rx interrupt */
+       if (ret == 0)
+               sci_stop_rx(port);
+ #endif
+       /* TODO: disable clock */
+       return ret;
+ }
+ static struct console serial_console = {
+       .name           = "ttySC",
+       .device         = serial_console_device,
+       .write          = serial_console_write,
+       .setup          = serial_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+ };
+ static int __init sci_console_init(void)
+ {
+       register_console(&serial_console);
+       return 0;
+ }
+ console_initcall(sci_console_init);
+ static struct sci_port early_serial_port;
+ static struct console early_serial_console = {
+       .name           = "early_ttySC",
+       .write          = serial_console_write,
+       .flags          = CON_PRINTBUFFER,
+ };
+ static char early_serial_buf[32];
+ #endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+ #if defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+ #define SCI_CONSOLE   (&serial_console)
+ #else
+ #define SCI_CONSOLE   0
+ #endif
+ static char banner[] __initdata =
+       KERN_INFO "SuperH SCI(F) driver initialized\n";
+ static struct uart_driver sci_uart_driver = {
+       .owner          = THIS_MODULE,
+       .driver_name    = "sci",
+       .dev_name       = "ttySC",
+       .major          = SCI_MAJOR,
+       .minor          = SCI_MINOR_START,
+       .nr             = SCI_NPORTS,
+       .cons           = SCI_CONSOLE,
+ };
+ static int sci_remove(struct platform_device *dev)
+ {
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+       cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node) {
+               uart_remove_one_port(&sci_uart_driver, &p->port);
+               clk_put(p->iclk);
+               clk_put(p->fclk);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+       kfree(priv);
+       return 0;
+ }
+ static int __devinit sci_probe_single(struct platform_device *dev,
+                                     unsigned int index,
+                                     struct plat_sci_port *p,
+                                     struct sci_port *sciport)
+ {
+       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       unsigned long flags;
+       int ret;
+       /* Sanity check */
+       if (unlikely(index >= SCI_NPORTS)) {
+               dev_notice(&dev->dev, "Attempting to register port "
+                          "%d when only %d are available.\n",
+                          index+1, SCI_NPORTS);
+               dev_notice(&dev->dev, "Consider bumping "
+                          "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+               return 0;
+       }
+       ret = sci_init_single(dev, sciport, index, p);
+       if (ret)
+               return ret;
+       ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
+       if (ret)
+               return ret;
+       INIT_LIST_HEAD(&sciport->node);
+       spin_lock_irqsave(&priv->lock, flags);
+       list_add(&sciport->node, &priv->ports);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+ }
+ /*
+  * Register a set of serial devices attached to a platform device.  The
+  * list is terminated with a zero flags entry, which means we expect
+  * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
+  * remapping (such as sh64) should also set UPF_IOREMAP.
+  */
+ static int __devinit sci_probe(struct platform_device *dev)
+ {
+       struct plat_sci_port *p = dev->dev.platform_data;
+       struct sh_sci_priv *priv;
+       int i, ret = -EINVAL;
+ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+       if (is_early_platform_device(dev)) {
+               if (dev->id == -1)
+                       return -ENOTSUPP;
+               early_serial_console.index = dev->id;
+               early_serial_console.data = &early_serial_port.port;
+               sci_init_single(NULL, &early_serial_port, dev->id, p);
+               serial_console_setup(&early_serial_console, early_serial_buf);
+               if (!strstr(early_serial_buf, "keep"))
+                       early_serial_console.flags |= CON_BOOT;
+               register_console(&early_serial_console);
+               return 0;
+       }
+ #endif
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&priv->ports);
+       spin_lock_init(&priv->lock);
+       platform_set_drvdata(dev, priv);
+       priv->clk_nb.notifier_call = sci_notifier;
+       cpufreq_register_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
+       if (dev->id != -1) {
+               ret = sci_probe_single(dev, dev->id, p, &sci_ports[dev->id]);
+               if (ret)
+                       goto err_unreg;
+       } else {
+               for (i = 0; p && p->flags != 0; p++, i++) {
+                       ret = sci_probe_single(dev, i, p, &sci_ports[i]);
+                       if (ret)
+                               goto err_unreg;
+               }
+       }
+ #ifdef CONFIG_SH_STANDARD_BIOS
+       sh_bios_gdb_detach();
+ #endif
+       return 0;
+ err_unreg:
+       sci_remove(dev);
+       return ret;
+ }
+ static int sci_suspend(struct device *dev)
+ {
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_suspend_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+ }
+ static int sci_resume(struct device *dev)
+ {
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
+       struct sci_port *p;
+       unsigned long flags;
+       spin_lock_irqsave(&priv->lock, flags);
+       list_for_each_entry(p, &priv->ports, node)
+               uart_resume_port(&sci_uart_driver, &p->port);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return 0;
+ }
+ static const struct dev_pm_ops sci_dev_pm_ops = {
+       .suspend        = sci_suspend,
+       .resume         = sci_resume,
+ };
+ static struct platform_driver sci_driver = {
+       .probe          = sci_probe,
+       .remove         = sci_remove,
+       .driver         = {
+               .name   = "sh-sci",
+               .owner  = THIS_MODULE,
+               .pm     = &sci_dev_pm_ops,
+       },
+ };
+ static int __init sci_init(void)
+ {
+       int ret;
+       printk(banner);
+       ret = uart_register_driver(&sci_uart_driver);
+       if (likely(ret == 0)) {
+               ret = platform_driver_register(&sci_driver);
+               if (unlikely(ret))
+                       uart_unregister_driver(&sci_uart_driver);
+       }
+       return ret;
+ }
+ static void __exit sci_exit(void)
+ {
+       platform_driver_unregister(&sci_driver);
+       uart_unregister_driver(&sci_uart_driver);
+ }
+ #ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ early_platform_init_buffer("earlyprintk", &sci_driver,
+                          early_serial_buf, ARRAY_SIZE(early_serial_buf));
+ #endif
+ module_init(sci_init);
+ module_exit(sci_exit);
+ MODULE_LICENSE("GPL");
+ MODULE_ALIAS("platform:sh-sci");
index 0000000,4bc614e..b223d6c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,660 +1,507 @@@
+ #include <linux/serial_core.h>
+ #include <linux/io.h>
+ #include <linux/gpio.h>
+ #if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+ #include <asm/regs306x.h>
+ #endif
+ #if defined(CONFIG_H8S2678)
+ #include <asm/regs267x.h>
+ #endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7709)
+ # define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
+ # define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
 -# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+ # define SCIF0                0xA4400000
+ # define SCIF2                0xA4410000
 -# define SCSMR_Ir     0xA44A0000
 -# define IRDA_SCIF    SCIF0
+ # define SCPCR 0xA4000116
+ # define SCPDR 0xA4000136
 -
 -/* Set the clock source,
 - * SCIF2 (0xA4410000) -> External clock, SCK pin used as clock input
 - * SCIF0 (0xA4400000) -> Internal clock, SCK pin as serial clock output
 - */
 -# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+       defined(CONFIG_ARCH_SH73A0) || \
+       defined(CONFIG_ARCH_SH7367) || \
+       defined(CONFIG_ARCH_SH7377) || \
+       defined(CONFIG_ARCH_SH7372)
 -# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define PORT_PTCR       0xA405011EUL
+ # define PORT_PVCR       0xA4050122UL
+ # define SCIF_ORER       0x0200   /* overrun error bit */
+ #elif defined(CONFIG_SH_RTS7751R2D)
+ # define SCSPTR1 0xFFE0001C /* 8 bit SCIF */
+ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001   /* overrun error bit */
 -# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+ # define SCSPTR1 0xffe0001c /* 8  bit SCI */
+ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001   /* overrun error bit */
 -# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
 -      0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
 -      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+ # define SCSPTR0 0xfe600024 /* 16 bit SCIF */
+ # define SCSPTR1 0xfe610024 /* 16 bit SCIF */
+ # define SCSPTR2 0xfe620024 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+ # define SCSPTR0 0xA4400000     /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001   /* overrun error bit */
+ # define PACR 0xa4050100
+ # define PBCR 0xa4050102
 -# define SCSCR_INIT(port)          0x3B
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+ # define SCSPTR0 0xffe00010   /* 16 bit SCIF */
+ # define SCSPTR1 0xffe10010   /* 16 bit SCIF */
+ # define SCSPTR2 0xffe20010   /* 16 bit SCIF */
+ # define SCSPTR3 0xffe30010   /* 16 bit SCIF */
 -# define SCSCR_INIT(port) 0x32        /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+ # define PADR                 0xA4050120
+ # define PSDR                 0xA405013e
+ # define PWDR                 0xA4050166
+ # define PSCR                 0xA405011E
+ # define SCIF_ORER            0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)     0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7366)
+ # define SCPDR0                       0xA405013E      /* 16 bit SCIF0 PSDR */
+ # define SCSPTR0              SCPDR0
+ # define SCIF_ORER            0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)     0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+ # define SCSPTR0                0xa4050160
+ # define SCSPTR1                0xa405013e
+ # define SCSPTR2                0xa4050160
+ # define SCSPTR3                0xa405013e
+ # define SCSPTR4                0xa4050128
+ # define SCSPTR5                0xa4050128
+ # define SCIF_ORER              0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)       0x0038  /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+ # define SCIF_ORER              0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port) ((port)->type == PORT_SCIFA ? \
 -      0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
 -      0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+ #elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
+ # define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001   /* overrun error bit */
 -# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
 -# define SCIF_BASE_ADDR    0x01030000
 -# define SCIF_ADDR_SH5     PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR
+ # define SCIF_PTR2_OFFS    0x0000020
 -# define SCIF_LSR2_OFFS    0x0000024
+ # define SCSPTR2           ((port->mapbase)+SCIF_PTR2_OFFS) /* 16 bit SCIF */
 -# define SCLSR2            ((port->mapbase)+SCIF_LSR2_OFFS) /* 16 bit SCIF */
 -# define SCSCR_INIT(port)  0x38               /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
 -# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+ #elif defined(CONFIG_H8S2678)
 -# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+ # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7757)
+ # define SCSPTR0 0xfe4b0020
+ # define SCSPTR1 0xfe4b0020
+ # define SCSPTR2 0xfe4b0020
+ # define SCIF_ORER 0x0001
 -# define SCSCR_INIT(port)     0x38
+ # define SCIF_ONLY
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+ # define SCSPTR0 0xffe00024 /* 16 bit SCIF */
+ # define SCSPTR1 0xffe08024 /* 16 bit SCIF */
+ # define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
+ # define SCIF_ORER 0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)     0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7770)
+ # define SCSPTR0 0xff923020 /* 16 bit SCIF */
+ # define SCSPTR1 0xff924020 /* 16 bit SCIF */
+ # define SCSPTR2 0xff925020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)     0x3c /* TIE=0,RIE=0,TE=1,RE=1,REIE=1,cke=2 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ # define SCSPTR0      0xffe00024      /* 16 bit SCIF */
+ # define SCSPTR1      0xffe10024      /* 16 bit SCIF */
+ # define SCIF_ORER    0x0001          /* Overrun error bit */
 -
 -#if defined(CONFIG_SH_SH2007)
 -/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=0 */
 -# define SCSCR_INIT(port)     0x38
 -#else
 -/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
 -# define SCSCR_INIT(port)     0x3a
 -#endif
 -
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7786)
+ # define SCSPTR0      0xffea0024      /* 16 bit SCIF */
+ # define SCSPTR1      0xffeb0024      /* 16 bit SCIF */
+ # define SCSPTR2      0xffec0024      /* 16 bit SCIF */
+ # define SCSPTR3      0xffed0024      /* 16 bit SCIF */
+ # define SCSPTR4      0xffee0024      /* 16 bit SCIF */
+ # define SCSPTR5      0xffef0024      /* 16 bit SCIF */
+ # define SCIF_ORER    0x0001          /* Overrun error bit */
 -# define SCSCR_INIT(port)     0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7203) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7206) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7263)
+ # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
+ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
+ # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */
+ # define SCSPTR3 0xfffe9820 /* 16 bit SCIF */
+ # if defined(CONFIG_CPU_SUBTYPE_SH7201)
+ #  define SCSPTR4 0xfffeA020 /* 16 bit SCIF */
+ #  define SCSPTR5 0xfffeA820 /* 16 bit SCIF */
+ #  define SCSPTR6 0xfffeB020 /* 16 bit SCIF */
+ #  define SCSPTR7 0xfffeB820 /* 16 bit SCIF */
+ # endif
 -# define SCSCR_INIT(port)     0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+ # define SCSPTR0 0xf8400020 /* 16 bit SCIF */
+ # define SCSPTR1 0xf8410020 /* 16 bit SCIF */
+ # define SCSPTR2 0xf8420020 /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001  /* overrun error bit */
 -# define SCSCR_INIT(port)     0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+ # define SCSPTR0 0xffc30020           /* 16 bit SCIF */
+ # define SCSPTR1 0xffc40020           /* 16 bit SCIF */
+ # define SCSPTR2 0xffc50020           /* 16 bit SCIF */
+ # define SCSPTR3 0xffc60020           /* 16 bit SCIF */
+ # define SCIF_ORER 0x0001             /* Overrun error bit */
 -# define SCSCR_INIT(port)     0x38    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+ #else
+ # error CPU subtype not defined
+ #endif
 -/* SCSCR */
 -#define SCI_CTRL_FLAGS_TIE  0x80 /* all */
 -#define SCI_CTRL_FLAGS_RIE  0x40 /* all */
 -#define SCI_CTRL_FLAGS_TE   0x20 /* all */
 -#define SCI_CTRL_FLAGS_RE   0x10 /* all */
 -#if defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7091)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7722)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7763)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SH7786)  || \
 -    defined(CONFIG_CPU_SUBTYPE_SHX3)
 -#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
 -#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
 -#define SCI_CTRL_FLAGS_REIE ((port)->type == PORT_SCIFA ? 0 : 8)
 -#else
 -#define SCI_CTRL_FLAGS_REIE 0
 -#endif
 -/*      SCI_CTRL_FLAGS_MPIE 0x08  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
 -/*      SCI_CTRL_FLAGS_TEIE 0x04  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
 -/*      SCI_CTRL_FLAGS_CKE1 0x02  * all */
 -/*      SCI_CTRL_FLAGS_CKE0 0x01  * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
 -
+ /* SCxSR SCI */
+ #define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ /*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ /*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+ #define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
+ /* SCxSR SCIF */
+ #define SCIF_ER    0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_TEND  0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_TDFE  0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_BRK   0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_FER   0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_PER   0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+     defined(CONFIG_ARCH_SH73A0) || \
+     defined(CONFIG_ARCH_SH7367) || \
+     defined(CONFIG_ARCH_SH7377) || \
+     defined(CONFIG_ARCH_SH7372)
+ # define SCIF_ORER    0x0200
+ # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
+ # define SCIF_RFDC_MASK 0x007f
+ # define SCIF_TXROOM_MAX 64
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+ # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK )
+ # define SCIF_RFDC_MASK 0x007f
+ # define SCIF_TXROOM_MAX 64
+ /* SH7763 SCIF2 support */
+ # define SCIF2_RFDC_MASK 0x001f
+ # define SCIF2_TXROOM_MAX 16
+ #else
+ # define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+ # define SCIF_RFDC_MASK 0x001f
+ # define SCIF_TXROOM_MAX 16
+ #endif
+ #ifndef SCIF_ORER
+ #define SCIF_ORER     0x0000
+ #endif
+ #define SCxSR_TEND(port)      (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
+ #define SCxSR_ERRORS(port)    (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
+ #define SCxSR_RDxF(port)      (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
+ #define SCxSR_TDxE(port)      (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
+ #define SCxSR_FER(port)               (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
+ #define SCxSR_PER(port)               (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
+ #define SCxSR_BRK(port)               (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
+ #define SCxSR_ORER(port)      (((port)->type == PORT_SCI) ? SCI_ORER   : SCIF_ORER)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+     defined(CONFIG_ARCH_SH73A0) || \
+     defined(CONFIG_ARCH_SH7367) || \
+     defined(CONFIG_ARCH_SH7377) || \
+     defined(CONFIG_ARCH_SH7372)
+ # define SCxSR_RDxF_CLEAR(port)        (sci_in(port, SCxSR) & 0xfffc)
+ # define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
+ # define SCxSR_TDxE_CLEAR(port)        (sci_in(port, SCxSR) & 0xffdf)
+ # define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
+ #else
+ # define SCxSR_RDxF_CLEAR(port)        (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
+ # define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
+ # define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
+ # define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+ #endif
+ /* SCFCR */
+ #define SCFCR_RFRST 0x0002
+ #define SCFCR_TFRST 0x0004
 -#define SCFCR_TCRST 0x4000
+ #define SCFCR_MCE   0x0008
+ #define SCI_MAJOR             204
+ #define SCI_MINOR_START               8
 -/* Generic serial flags */
 -#define SCI_RX_THROTTLE               0x0000001
 -
 -#define SCI_MAGIC 0xbabeface
 -
 -/*
 - * Events are used to schedule things to happen at timer-interrupt
 - * time, instead of at rs interrupt time.
 - */
 -#define SCI_EVENT_WRITE_WAKEUP        0
 -
+ #define SCI_IN(size, offset)                                  \
+   if ((size) == 8) {                                          \
+     return ioread8(port->membase + (offset));                 \
+   } else {                                                    \
+     return ioread16(port->membase + (offset));                        \
+   }
+ #define SCI_OUT(size, offset, value)                          \
+   if ((size) == 8) {                                          \
+     iowrite8(value, port->membase + (offset));                        \
+   } else if ((size) == 16) {                                  \
+     iowrite16(value, port->membase + (offset));                       \
+   }
+ #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
+   static inline unsigned int sci_##name##_in(struct uart_port *port)  \
+   {                                                                   \
+     if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {                \
+       SCI_IN(scif_size, scif_offset)                                  \
+     } else {  /* PORT_SCI or PORT_SCIFA */                            \
+       SCI_IN(sci_size, sci_offset);                                   \
+     }                                                                 \
+   }                                                                   \
+   static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+   {                                                                   \
+     if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {                \
+       SCI_OUT(scif_size, scif_offset, value)                          \
+     } else {  /* PORT_SCI or PORT_SCIFA */                            \
+       SCI_OUT(sci_size, sci_offset, value);                           \
+     }                                                                 \
+   }
+ #ifdef CONFIG_H8300
+ /* h8300 don't have SCIF */
+ #define CPU_SCIF_FNS(name)                                            \
+   static inline unsigned int sci_##name##_in(struct uart_port *port)  \
+   {                                                                   \
+     return 0;                                                         \
+   }                                                                   \
+   static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+   {                                                                   \
+   }
+ #else
+ #define CPU_SCIF_FNS(name, scif_offset, scif_size)                    \
+   static inline unsigned int sci_##name##_in(struct uart_port *port)  \
+   {                                                                   \
+     SCI_IN(scif_size, scif_offset);                                   \
+   }                                                                   \
+   static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+   {                                                                   \
+     SCI_OUT(scif_size, scif_offset, value);                           \
+   }
+ #endif
+ #define CPU_SCI_FNS(name, sci_offset, sci_size)                               \
+   static inline unsigned int sci_##name##_in(struct uart_port* port)  \
+   {                                                                   \
+     SCI_IN(sci_size, sci_offset);                                     \
+   }                                                                   \
+   static inline void sci_##name##_out(struct uart_port* port, unsigned int value) \
+   {                                                                   \
+     SCI_OUT(sci_size, sci_offset, value);                             \
+   }
+ #if defined(CONFIG_CPU_SH3) || \
+     defined(CONFIG_ARCH_SH73A0) || \
+     defined(CONFIG_ARCH_SH7367) || \
+     defined(CONFIG_ARCH_SH7377) || \
+     defined(CONFIG_ARCH_SH7372)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+ #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                               sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                                h8_sci_offset, h8_sci_size) \
+   CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+         CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+       defined(CONFIG_ARCH_SH73A0) || \
+       defined(CONFIG_ARCH_SH7367) || \
+       defined(CONFIG_ARCH_SH7377)
+ #define SCIF_FNS(name, scif_offset, scif_size) \
+   CPU_SCIF_FNS(name, scif_offset, scif_size)
+ #elif defined(CONFIG_ARCH_SH7372)
+ #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
+   CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
+ #define SCIF_FNS(name, scif_offset, scif_size) \
+   CPU_SCIF_FNS(name, scif_offset, scif_size)
+ #else
+ #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                  h8_sci_offset, h8_sci_size) \
+   CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
+ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+   CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+ #endif
+ #elif defined(__H8300H__) || defined(__H8300S__)
+ #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                  h8_sci_offset, h8_sci_size) \
+   CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
+ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+   CPU_SCIF_FNS(name)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+       defined(CONFIG_CPU_SUBTYPE_SH7724)
+         #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size) \
+                 CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scif_offset, sh4_scif_size)
+         #define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
+                 CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+ #else
+ #define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+                sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                h8_sci_offset, h8_sci_size) \
+   CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+   CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+ #endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7720) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
+     defined(CONFIG_ARCH_SH73A0) || \
+     defined(CONFIG_ARCH_SH7367) || \
+     defined(CONFIG_ARCH_SH7377)
+ SCIF_FNS(SCSMR,  0x00, 16)
+ SCIF_FNS(SCBRR,  0x04,  8)
+ SCIF_FNS(SCSCR,  0x08, 16)
 -SCIF_FNS(SCTDSR, 0x0c,  8)
 -SCIF_FNS(SCFER,  0x10, 16)
+ SCIF_FNS(SCxSR,  0x14, 16)
+ SCIF_FNS(SCFCR,  0x18, 16)
+ SCIF_FNS(SCFDR,  0x1c, 16)
+ SCIF_FNS(SCxTDR, 0x20,  8)
+ SCIF_FNS(SCxRDR, 0x24,  8)
+ SCIF_FNS(SCLSR,  0x00,  0)
+ #elif defined(CONFIG_ARCH_SH7372)
+ SCIF_FNS(SCSMR,  0x00, 16)
+ SCIF_FNS(SCBRR,  0x04,  8)
+ SCIF_FNS(SCSCR,  0x08, 16)
+ SCIF_FNS(SCTDSR, 0x0c, 16)
+ SCIF_FNS(SCFER,  0x10, 16)
+ SCIF_FNS(SCxSR,  0x14, 16)
+ SCIF_FNS(SCFCR,  0x18, 16)
+ SCIF_FNS(SCFDR,  0x1c, 16)
+ SCIF_FNS(SCTFDR, 0x38, 16)
+ SCIF_FNS(SCRFDR, 0x3c, 16)
+ SCIx_FNS(SCxTDR, 0x20,  8, 0x40,  8)
+ SCIx_FNS(SCxRDR, 0x24,  8, 0x60,  8)
+ SCIF_FNS(SCLSR,  0x00,  0)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
+       defined(CONFIG_CPU_SUBTYPE_SH7724)
+ SCIx_FNS(SCSMR,  0x00, 16, 0x00, 16)
+ SCIx_FNS(SCBRR,  0x04,  8, 0x04,  8)
+ SCIx_FNS(SCSCR,  0x08, 16, 0x08, 16)
+ SCIx_FNS(SCxTDR, 0x20,  8, 0x0c,  8)
+ SCIx_FNS(SCxSR,  0x14, 16, 0x10, 16)
+ SCIx_FNS(SCxRDR, 0x24,  8, 0x14,  8)
+ SCIx_FNS(SCSPTR, 0,     0,    0,  0)
 -SCIF_FNS(SCTDSR, 0x0c,  8)
 -SCIF_FNS(SCFER,  0x10, 16)
+ SCIF_FNS(SCFCR,  0x18, 16)
+ SCIF_FNS(SCFDR,  0x1c, 16)
+ SCIF_FNS(SCLSR,  0x24, 16)
+ #else
+ /*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
+ /*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
+ SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
+ SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
+ SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
+ SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
+ SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
+ SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
+ SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7786)
+ SCIF_FNS(SCFDR,                            0x0e, 16, 0x1C, 16)
+ SCIF_FNS(SCTFDR,                   0x0e, 16, 0x1C, 16)
+ SCIF_FNS(SCRFDR,                   0x0e, 16, 0x20, 16)
+ SCIF_FNS(SCSPTR,                      0,  0, 0x24, 16)
+ SCIF_FNS(SCLSR,                               0,  0, 0x28, 16)
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7763)
+ SCIF_FNS(SCFDR,                               0,  0, 0x1C, 16)
+ SCIF_FNS(SCSPTR2,                     0,  0, 0x20, 16)
 -SCIF_FNS(SCLSR2,                      0,  0, 0x24, 16)
+ SCIF_FNS(SCTFDR,                   0x0e, 16, 0x1C, 16)
+ SCIF_FNS(SCRFDR,                   0x0e, 16, 0x20, 16)
+ SCIF_FNS(SCSPTR,                      0,  0, 0x24, 16)
+ SCIF_FNS(SCLSR,                               0,  0, 0x28, 16)
+ #else
+ SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
+ #if defined(CONFIG_CPU_SUBTYPE_SH7722)
+ SCIF_FNS(SCSPTR,                        0,  0, 0, 0)
+ #else
+ SCIF_FNS(SCSPTR,                        0,  0, 0x20, 16)
+ #endif
+ SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
+ #endif
+ #endif
+ #define sci_in(port, reg) sci_##reg##_in(port)
+ #define sci_out(port, reg, value) sci_##reg##_out(port, value)
+ /* H8/300 series SCI pins assignment */
+ #if defined(__H8300H__) || defined(__H8300S__)
+ static const struct __attribute__((packed)) {
+       int port;             /* GPIO port no */
+       unsigned short rx,tx; /* GPIO bit no */
+ } h8300_sci_pins[] = {
+ #if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P9,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_PB,
+               .rx   = H8300_GPIO_B7,
+               .tx   = H8300_GPIO_B6,
+       }
+ #elif defined(CONFIG_H8S2678)
+       {    /* SCI0 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B2,
+               .tx   = H8300_GPIO_B0,
+       },
+       {    /* SCI1 */
+               .port = H8300_GPIO_P3,
+               .rx   = H8300_GPIO_B3,
+               .tx   = H8300_GPIO_B1,
+       },
+       {    /* SCI2 */
+               .port = H8300_GPIO_P5,
+               .rx   = H8300_GPIO_B1,
+               .tx   = H8300_GPIO_B0,
+       }
+ #endif
+ };
+ #endif
+ #if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7709)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+       if (port->mapbase == 0xfffffe80)
+               return __raw_readb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+ }
+ #elif defined(CONFIG_CPU_SUBTYPE_SH7750)  || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751)  || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+       if (port->mapbase == 0xffe00000)
+               return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+       return 1;
+ }
+ #elif defined(__H8300H__) || defined(__H8300S__)
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+       int ch = (port->mapbase - SMR0) >> 3;
+       return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+ }
+ #else /* default case for non-SCI processors */
+ static inline int sci_rxd_in(struct uart_port *port)
+ {
+       return 1;
+ }
+ #endif
 -
 -/*
 - * Values for the BitRate Register (SCBRR)
 - *
 - * The values are actually divisors for a frequency which can
 - * be internal to the SH3 (14.7456MHz) or derived from an external
 - * clock source.  This driver assumes the internal clock is used;
 - * to support using an external clock source, config options or
 - * possibly command-line options would need to be added.
 - *
 - * Also, to support speeds below 2400 (why?) the lower 2 bits of
 - * the SCSMR register would also need to be set to non-zero values.
 - *
 - * -- Greg Banks 27Feb2000
 - *
 - * Answer: The SCBRR register is only eight bits, and the value in
 - * it gets larger with lower baud rates. At around 2400 (depending on
 - * the peripherial module clock) you run out of bits. However the
 - * lower two bits of SCSMR allow the module clock to be divided down,
 - * scaling the value which is needed in SCBRR.
 - *
 - * -- Stuart Menefy - 23 May 2000
 - *
 - * I meant, why would anyone bother with bitrates below 2400.
 - *
 - * -- Greg Banks - 7Jul2000
 - *
 - * You "speedist"!  How will I use my 110bps ASR-33 teletype with paper
 - * tape reader as a console!
 - *
 - * -- Mitch Davis - 15 Jul 2000
 - */
 -
 -#if (defined(CONFIG_CPU_SUBTYPE_SH7780)  || \
 -     defined(CONFIG_CPU_SUBTYPE_SH7785)  || \
 -     defined(CONFIG_CPU_SUBTYPE_SH7786)) && \
 -    !defined(CONFIG_SH_SH2007)
 -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 -#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
 -      defined(CONFIG_CPU_SUBTYPE_SH7720) || \
 -      defined(CONFIG_CPU_SUBTYPE_SH7721) || \
 -      defined(CONFIG_ARCH_SH73A0) || \
 -      defined(CONFIG_ARCH_SH7367) || \
 -      defined(CONFIG_ARCH_SH7377) || \
 -      defined(CONFIG_ARCH_SH7372)
 -#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
 -#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
 -      defined(CONFIG_CPU_SUBTYPE_SH7724)
 -static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
 -{
 -      if (port->type == PORT_SCIF)
 -              return (clk+16*bps)/(32*bps)-1;
 -      else
 -              return ((clk*2)+16*bps)/(16*bps)-1;
 -}
 -#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
 -#elif defined(__H8300H__) || defined(__H8300S__)
 -#define SCBRR_VALUE(bps, clk) (((clk*1000/32)/bps)-1)
 -#else /* Generic SH */
 -#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
 -#endif