summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig104
-rw-r--r--drivers/serial/Makefile4
-rw-r--r--drivers/serial/mxc_uart.c1957
-rw-r--r--drivers/serial/mxc_uart_early.c184
-rw-r--r--drivers/serial/mxc_uart_reg.h128
-rw-r--r--drivers/serial/mxs-auart.c1108
-rw-r--r--drivers/serial/mxs-duart.c803
-rw-r--r--drivers/serial/regs-duart.h301
-rw-r--r--drivers/serial/regs-uartapp.h307
-rw-r--r--drivers/serial/serial_core.c2
10 files changed, 4897 insertions, 1 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 8b23165bc5dc..17cbbd3e9408 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -304,6 +304,110 @@ config SERIAL_AMBA_PL010_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_MXC
+ tristate "MXC Internal serial port support"
+ depends on ARCH_MXC
+ select SERIAL_CORE
+ help
+ This selects the Freescale Semiconductor MXC Internal UART driver.
+ If unsure, say N.
+
+config SERIAL_MXC_CONSOLE
+ bool "Support for console on a MXC/MX27/MX21 Internal serial port"
+ depends on SERIAL_MXC=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you wish to use an MXC Internal UART as the system
+ console (the system console is the device which receives all kernel
+ messages and warnings and which allows logins in single user mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttymxc". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+config SERIAL_STMP_DBG
+ tristate "STMP debug serial port support"
+ depends on ARCH_STMP3XXX
+ select SERIAL_CORE
+ help
+ Driver for Sigmatel 36XX/37XX internal debug serial port
+
+config SERIAL_STMP_DBG_CONSOLE
+ bool "Support for console on STMP37XX DBG serial port"
+ depends on SERIAL_STMP_DBG=y
+ select SERIAL_CORE_CONSOLE
+ ---help---
+ Say Y here if you wish to use the STMP36XX/37XX debug serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyAM0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+config SERIAL_STMP_APP
+ tristate "STMP app serial port support"
+ depends on ARCH_STMP3XXX
+ select SERIAL_CORE
+ help
+ Driver for Sigmatel 36XX/37XX internal application serial port
+
+config SERIAL_MXS_DUART
+ tristate "i.MXS debug serial port support"
+ depends on ARCH_MXS
+ select SERIAL_CORE
+ help
+ Driver for Freescale i.MXS internal debug serial port
+
+config SERIAL_MXS_AUART
+ tristate "i.MXS Application serial port support"
+ depends on ARCH_MXS
+ select SERIAL_CORE
+ help
+ Driver for Freescale i.MXS internal application serial port
+
+config SERIAL_MXS_AUART_CONSOLE
+ bool "Support for console on i.MXS application serial port"
+ depends on SERIAL_MXS_AUART=y
+ select SERIAL_CORE_CONSOLE
+ ---help---
+ Say Y here if you wish to use the i.MXS app serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttySP1". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
+
+config SERIAL_MXS_DUART_CONSOLE
+ bool "Support for console on i.MXS debug serial port"
+ depends on SERIAL_MXS_DUART=y
+ select SERIAL_CORE_CONSOLE
+ ---help---
+ Say Y here if you wish to use the i.MXS debug serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Even if you say Y here, the currently visible framebuffer console
+ (/dev/tty0) will still be used as the system console by default, but
+ you can alter that using a kernel command line option such as
+ "console=ttyAM0". (Try "man bootparam" or see the documentation of
+ your boot loader (lilo or loadlin) about how to pass options to the
+ kernel at boot time.)
+
config SERIAL_AMBA_PL011
tristate "ARM AMBA PL011 serial port support"
depends on ARM_AMBA
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 208a85572c32..2ed31d54c6c6 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -75,6 +75,10 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
+obj-$(CONFIG_SERIAL_MXC) += mxc_uart.o
+obj-$(CONFIG_SERIAL_MXC_CONSOLE) += mxc_uart_early.o
+obj-$(CONFIG_SERIAL_MXS_DUART) += mxs-duart.o
+obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
diff --git a/drivers/serial/mxc_uart.c b/drivers/serial/mxc_uart.c
new file mode 100644
index 000000000000..347a7462c396
--- /dev/null
+++ b/drivers/serial/mxc_uart.c
@@ -0,0 +1,1957 @@
+/*
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file drivers/serial/mxc_uart.c
+ *
+ * @brief Driver for the Freescale Semiconductor MXC serial ports based on
+ * drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * @ingroup UART
+ */
+
+/*
+ * Include Files
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/sysrq.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/div64.h>
+#include <mach/mxc_uart.h>
+
+#if defined(CONFIG_SERIAL_MXC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+#define SERIAL_MXC_MAJOR 207
+#define SERIAL_MXC_MINOR 16
+#define MXC_ISR_PASS_LIMIT 256
+#define UART_CREAD_BIT 256
+
+#define MXC_UART_NR 8
+
+/* IRDA minimum pulse duration in micro seconds */
+#define MIN_PULSE_DUR 2
+/*
+ * Transmit DMA buffer size is set to 1024 bytes, this is limited
+ * by UART_XMIT_SIZE.
+ */
+#define TXDMA_BUFF_SIZE UART_XMIT_SIZE
+/*
+ * Receive DMA sub-buffer size
+ */
+#define RXDMA_BUFF_SIZE 128
+
+/*!
+ * This structure is used to store the information for DMA data transfer.
+ */
+typedef struct {
+ /*!
+ * Holds the read channel number.
+ */
+ int rd_channel;
+ /*!
+ * Holds the write channel number.
+ */
+ int wr_channel;
+ /*!
+ * UART Transmit Event ID
+ */
+ int tx_event_id;
+ /*!
+ * UART Receive Event ID
+ */
+ int rx_event_id;
+ /*!
+ * DMA Transmit tasklet
+ */
+ struct tasklet_struct dma_tx_tasklet;
+ /*!
+ * Flag indicates if the channel is in use
+ */
+ int dma_txchnl_inuse;
+} dma_info;
+
+/*!
+ * This is used to indicate if we want echo cancellation in the Irda mode.
+ */
+static int echo_cancel;
+extern void gpio_uart_active(int port, int no_irda);
+extern void gpio_uart_inactive(int port, int no_irda);
+extern void config_uartdma_event(int port);
+
+static uart_mxc_port *mxc_ports[MXC_UART_NR];
+
+/*!
+ * This array holds the DMA channel information for each MXC UART
+ */
+static dma_info dma_list[MXC_UART_NR];
+
+/*!
+ * This function is called by the core driver to stop UART transmission.
+ * This might be due to the TTY layer indicating that the user wants to stop
+ * transmission.
+ *
+ * @param port the port structure for the UART passed in by the core
+ * driver
+ */
+static void mxcuart_stop_tx(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ volatile unsigned int cr1;
+
+ cr1 = readl(port->membase + MXC_UARTUCR1);
+ /* Disable Transmitter rdy interrupt */
+ if (umxc->dma_enabled == 1) {
+ cr1 &= ~MXC_UARTUCR1_TXDMAEN;
+ } else {
+ cr1 &= ~MXC_UARTUCR1_TRDYEN;
+ }
+ writel(cr1, port->membase + MXC_UARTUCR1);
+}
+
+/*!
+ * DMA Transmit tasklet method is scheduled on completion of a DMA transmit
+ * to send out any more data that is available in the UART xmit buffer.
+ *
+ * @param arg driver private data
+ */
+static void dma_tx_do_tasklet(unsigned long arg)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) arg;
+ struct circ_buf *xmit = &umxc->port.state->xmit;
+ mxc_dma_requestbuf_t writechnl_request;
+ int tx_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&umxc->port.lock, flags);
+ tx_num = uart_circ_chars_pending(xmit);
+ if (tx_num > 0) {
+ if (xmit->tail > xmit->head) {
+ memcpy(umxc->tx_buf, xmit->buf + xmit->tail,
+ UART_XMIT_SIZE - xmit->tail);
+ memcpy(umxc->tx_buf + (UART_XMIT_SIZE - xmit->tail),
+ xmit->buf, xmit->head);
+ } else {
+ memcpy(umxc->tx_buf, xmit->buf + xmit->tail, tx_num);
+ }
+ umxc->tx_handle = dma_map_single(umxc->port.dev, umxc->tx_buf,
+ TXDMA_BUFF_SIZE,
+ DMA_TO_DEVICE);
+
+ writechnl_request.dst_addr = umxc->port.mapbase + MXC_UARTUTXD;
+ writechnl_request.src_addr = umxc->tx_handle;
+ writechnl_request.num_of_bytes = tx_num;
+
+ if ((mxc_dma_config(dma_list[umxc->port.line].wr_channel,
+ &writechnl_request, 1,
+ MXC_DMA_MODE_WRITE)) == 0) {
+ mxc_dma_enable(dma_list[umxc->port.line].wr_channel);
+ }
+ } else {
+ /* No more data available in the xmit queue, clear the flag */
+ dma_list[umxc->port.line].dma_txchnl_inuse = 0;
+ }
+ spin_unlock_irqrestore(&umxc->port.lock, flags);
+}
+
+/*!
+ * DMA Write callback is called by the SDMA controller after it has sent out all
+ * the data from the user buffer. This function updates the xmit buffer pointers.
+ *
+ * @param arg driver private data
+ * @param error any DMA error
+ * @param count amount of data that was transferred
+ */
+static void mxcuart_dma_writecallback(void *arg, int error, unsigned int count)
+{
+ uart_mxc_port *umxc = arg;
+ struct circ_buf *xmit = &umxc->port.state->xmit;
+ int tx_num;
+
+ if (error != MXC_DMA_TRANSFER_ERROR) {
+ tx_num = count;
+ umxc->port.icount.tx += tx_num;
+ xmit->tail = (xmit->tail + tx_num) & (UART_XMIT_SIZE - 1);
+ }
+
+ dma_unmap_single(umxc->port.dev, umxc->tx_handle, TXDMA_BUFF_SIZE,
+ DMA_TO_DEVICE);
+ tx_num = uart_circ_chars_pending(xmit);
+ /* Schedule a tasklet to send out the pending characters */
+ if (tx_num > 0) {
+ tasklet_schedule(&dma_list[umxc->port.line].dma_tx_tasklet);
+ } else {
+ dma_list[umxc->port.line].dma_txchnl_inuse = 0;
+ }
+ if (tx_num < WAKEUP_CHARS) {
+ uart_write_wakeup(&umxc->port);
+ }
+}
+
+/*!
+ * This function is called by the core driver to start transmitting characters.
+ * This function enables the transmit interrupts.
+ *
+ * @param port the port structure for the UART passed in by the core
+ * driver
+ */
+static void mxcuart_start_tx(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ struct circ_buf *xmit = &umxc->port.state->xmit;
+ volatile unsigned int cr1;
+ mxc_dma_requestbuf_t writechnl_request;
+ int tx_num;
+
+ cr1 = readl(port->membase + MXC_UARTUCR1);
+ /* Enable Transmitter rdy interrupt */
+ if (umxc->dma_enabled == 1) {
+ /*
+ * If the channel is in use then return immediately and use
+ * the dma_tx tasklet to transfer queued data when current DMA
+ * transfer is complete
+ */
+ if (dma_list[umxc->port.line].dma_txchnl_inuse == 1) {
+ return;
+ }
+ tx_num = uart_circ_chars_pending(xmit);
+ if (tx_num > 0) {
+ dma_list[umxc->port.line].dma_txchnl_inuse = 1;
+ if (xmit->tail > xmit->head) {
+ memcpy(umxc->tx_buf, xmit->buf + xmit->tail,
+ UART_XMIT_SIZE - xmit->tail);
+ memcpy(umxc->tx_buf +
+ (UART_XMIT_SIZE - xmit->tail), xmit->buf,
+ xmit->head);
+ } else {
+ memcpy(umxc->tx_buf, xmit->buf + xmit->tail,
+ tx_num);
+ }
+ umxc->tx_handle =
+ dma_map_single(umxc->port.dev, umxc->tx_buf,
+ TXDMA_BUFF_SIZE, DMA_TO_DEVICE);
+
+ writechnl_request.dst_addr =
+ umxc->port.mapbase + MXC_UARTUTXD;
+ writechnl_request.src_addr = umxc->tx_handle;
+ writechnl_request.num_of_bytes = tx_num;
+ if ((mxc_dma_config
+ (dma_list[umxc->port.line].wr_channel,
+ &writechnl_request, 1,
+ MXC_DMA_MODE_WRITE)) == 0) {
+ mxc_dma_enable(dma_list[umxc->port.line].
+ wr_channel);
+ }
+ cr1 |= MXC_UARTUCR1_TXDMAEN;
+ }
+ } else {
+ cr1 |= MXC_UARTUCR1_TRDYEN;
+ }
+ writel(cr1, port->membase + MXC_UARTUCR1);
+}
+
+/*!
+ * This function is called by the core driver to stop receiving characters; the
+ * port is in the process of being closed.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ */
+static void mxcuart_stop_rx(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ volatile unsigned int cr1;
+
+ cr1 = readl(port->membase + MXC_UARTUCR1);
+ if (umxc->dma_enabled == 1) {
+ cr1 &= ~MXC_UARTUCR1_RXDMAEN;
+ } else {
+ cr1 &= ~MXC_UARTUCR1_RRDYEN;
+ }
+ writel(cr1, port->membase + MXC_UARTUCR1);
+}
+
+/*!
+ * This function is called by the core driver to enable the modem status
+ * interrupts. If the port is configured to be in DTE mode then it enables the
+ * DCDDELT and RIDELT interrupts in addition to the DTRDEN interrupt. The RTSDEN
+ * interrupt is enabled only for interrupt-driven hardware flow control.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ */
+static void mxcuart_enable_ms(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ volatile unsigned int cr1, cr3;
+
+ /*
+ * RTS interrupt is enabled only if we are using interrupt-driven
+ * software controlled hardware flow control
+ */
+ if (umxc->hardware_flow == 0) {
+ cr1 = readl(umxc->port.membase + MXC_UARTUCR1);
+ cr1 |= MXC_UARTUCR1_RTSDEN;
+ writel(cr1, umxc->port.membase + MXC_UARTUCR1);
+ }
+ cr3 = readl(umxc->port.membase + MXC_UARTUCR3);
+ cr3 |= MXC_UARTUCR3_DTRDEN;
+ if (umxc->mode == MODE_DTE) {
+ cr3 |= MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI;
+ }
+ writel(cr3, umxc->port.membase + MXC_UARTUCR3);
+}
+
+/*!
+ * This function is called from the interrupt service routine if the status bit
+ * indicates that the receive fifo data level is above the set threshold. The
+ * function reads the character and queues them into the TTY layers read
+ * buffer. The function also looks for break characters, parity and framing
+ * errors in the received character and sets the appropriate flag in the TTY
+ * receive buffer.
+ *
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ */
+static void mxcuart_rx_chars(uart_mxc_port *umxc)
+{
+ volatile unsigned int ch, sr2;
+ unsigned int status, flag, max_count = 256;
+
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+ while (((sr2 & MXC_UARTUSR2_RDR) == 1) && (max_count-- > 0)) {
+ ch = readl(umxc->port.membase + MXC_UARTURXD);
+
+ flag = TTY_NORMAL;
+ status = ch | UART_CREAD_BIT;
+ ch &= 0xFF; /* Clear the upper bits */
+ umxc->port.icount.rx++;
+
+ /*
+ * Check to see if there is an error in the received
+ * character. Perform the appropriate actions based on the
+ * error bit that was set.
+ */
+ if (status & MXC_UARTURXD_ERR) {
+ if (status & MXC_UARTURXD_BRK) {
+ /*
+ * Clear the frame and parity error bits
+ * as these always get set on receiving a
+ * break character
+ */
+ status &= ~(MXC_UARTURXD_FRMERR |
+ MXC_UARTURXD_PRERR);
+ umxc->port.icount.brk++;
+ if (uart_handle_break(&umxc->port)) {
+ goto ignore_char;
+ }
+ } else if (status & MXC_UARTURXD_FRMERR) {
+ umxc->port.icount.frame++;
+ } else if (status & MXC_UARTURXD_PRERR) {
+ umxc->port.icount.parity++;
+ }
+ if (status & MXC_UARTURXD_OVRRUN) {
+ umxc->port.icount.overrun++;
+ }
+
+ status &= umxc->port.read_status_mask;
+
+ if (status & MXC_UARTURXD_BRK) {
+ flag = TTY_BREAK;
+ } else if (status & MXC_UARTURXD_FRMERR) {
+ flag = TTY_FRAME;
+ } else if (status & MXC_UARTURXD_PRERR) {
+ flag = TTY_PARITY;
+ }
+ }
+
+ if (uart_handle_sysrq_char(&umxc->port, ch)) {
+ goto ignore_char;
+ }
+
+ uart_insert_char(&umxc->port, status, MXC_UARTURXD_OVRRUN, ch,
+ flag);
+ ignore_char:
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+ }
+ tty_flip_buffer_push(umxc->port.state->port.tty);
+}
+
+/*!
+ * This function is called from the interrupt service routine if the status bit
+ * indicates that the transmit fifo is emptied below its set threshold and
+ * requires data. The function pulls characters from the TTY layers write
+ * buffer and writes it out to the UART transmit fifo.
+ *
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ */
+static void mxcuart_tx_chars(uart_mxc_port *umxc)
+{
+ struct circ_buf *xmit = &umxc->port.state->xmit;
+ int count;
+
+ /*
+ * Transmit the XON/XOFF character if required
+ */
+ if (umxc->port.x_char) {
+ writel(umxc->port.x_char, umxc->port.membase + MXC_UARTUTXD);
+ umxc->port.icount.tx++;
+ umxc->port.x_char = 0;
+ return;
+ }
+
+ /*
+ * Check to see if there is any data to be sent and that the
+ * port has not been currently stopped by anything.
+ */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&umxc->port)) {
+ mxcuart_stop_tx(&umxc->port);
+ return;
+ }
+
+ count = umxc->port.fifosize - umxc->tx_threshold;
+ do {
+ writel(xmit->buf[xmit->tail],
+ umxc->port.membase + MXC_UARTUTXD);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ umxc->port.icount.tx++;
+ if (uart_circ_empty(xmit)) {
+ break;
+ }
+ } while (--count > 0);
+
+ /*
+ * Check to see if we have flushed enough characters to ask for more
+ * to be sent to us, if so, we notify the user space that we can
+ * accept more data
+ */
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+ uart_write_wakeup(&umxc->port);
+ }
+
+ if (uart_circ_empty(xmit)) {
+ mxcuart_stop_tx(&umxc->port);
+ }
+}
+
+/*!
+ * This function is called from the interrupt service routine if there is a
+ * change in the modem signals. This function handles these signal changes and
+ * also clears the appropriate status register bits.
+ *
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ * @param sr1 contents of status register 1
+ * @param sr2 contents of status register 2
+ */
+static void mxcuart_modem_status(uart_mxc_port *umxc, unsigned int sr1,
+ unsigned int sr2)
+{
+ if (umxc->mode == MODE_DTE) {
+ if (sr2 & MXC_UARTUSR2_DCDDELT) {
+ uart_handle_dcd_change(&umxc->port,
+ !(sr2 & MXC_UARTUSR2_DCDIN));
+ }
+ if (sr2 & MXC_UARTUSR2_RIDELT) {
+ umxc->port.icount.rng++;
+ }
+ }
+ if (sr1 & MXC_UARTUSR1_DTRD) {
+ umxc->port.icount.dsr++;
+ }
+ if ((umxc->hardware_flow == 0) && (sr1 & MXC_UARTUSR1_RTSD)) {
+ uart_handle_cts_change(&umxc->port, sr1 & MXC_UARTUSR1_RTSS);
+ }
+
+ wake_up_interruptible(&umxc->port.state->port.delta_msr_wait);
+}
+
+/*!
+ * Interrupt service routine registered to handle the muxed ANDed interrupts.
+ * This routine is registered only in the case where the UART interrupts are
+ * muxed.
+ *
+ * @param irq the interrupt number
+ * @param dev_id driver private data
+ *
+ * @return The function returns \b IRQ_RETVAL(1) if interrupt was handled,
+ * returns \b IRQ_RETVAL(0) if the interrupt was not handled.
+ * \b IRQ_RETVAL is defined in \b include/linux/interrupt.h.
+ */
+static irqreturn_t mxcuart_int(int irq, void *dev_id)
+{
+ uart_mxc_port *umxc = dev_id;
+ volatile unsigned int sr1, sr2, cr1, cr;
+ unsigned int pass_counter = MXC_ISR_PASS_LIMIT;
+ unsigned int term_cond = 0;
+ int handled = 0;
+
+ sr1 = readl(umxc->port.membase + MXC_UARTUSR1);
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+ cr1 = readl(umxc->port.membase + MXC_UARTUCR1);
+
+ do {
+ /* Clear the bits that triggered the interrupt */
+ writel(sr1, umxc->port.membase + MXC_UARTUSR1);
+ writel(sr2, umxc->port.membase + MXC_UARTUSR2);
+ /*
+ * Read if there is data available
+ */
+ if (sr2 & MXC_UARTUSR2_RDR) {
+ mxcuart_rx_chars(umxc);
+ }
+
+ if ((sr1 & (MXC_UARTUSR1_RTSD | MXC_UARTUSR1_DTRD)) ||
+ (sr2 & (MXC_UARTUSR2_DCDDELT | MXC_UARTUSR2_RIDELT))) {
+ mxcuart_modem_status(umxc, sr1, sr2);
+ }
+
+ /*
+ * Send data if there is data to be sent
+ */
+ if ((cr1 & MXC_UARTUCR1_TRDYEN) && (sr1 & MXC_UARTUSR1_TRDY)) {
+ /* Echo cancellation for IRDA Transmit chars */
+ if (umxc->ir_mode == IRDA && echo_cancel) {
+ /* Disable the receiver */
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ cr &= ~MXC_UARTUCR2_RXEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR2);
+ /* Enable Transmit complete intr to reenable RX */
+ cr = readl(umxc->port.membase + MXC_UARTUCR4);
+ cr |= MXC_UARTUCR4_TCEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR4);
+ }
+ mxcuart_tx_chars(umxc);
+ }
+
+ if (pass_counter-- == 0) {
+ break;
+ }
+
+ sr1 = readl(umxc->port.membase + MXC_UARTUSR1);
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+
+ /* Is the transmit complete to reenable the receiver? */
+ if (umxc->ir_mode == IRDA && echo_cancel) {
+ if (sr2 & MXC_UARTUSR2_TXDC) {
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ cr |= MXC_UARTUCR2_RXEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR2);
+ /* Disable the Transmit complete interrupt bit */
+ cr = readl(umxc->port.membase + MXC_UARTUCR4);
+ cr &= ~MXC_UARTUCR4_TCEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR4);
+ }
+ }
+
+ /*
+ * If there is no data to send or receive and if there is no
+ * change in the modem status signals then quit the routine
+ */
+ term_cond = sr1 & (MXC_UARTUSR1_RTSD | MXC_UARTUSR1_DTRD);
+ term_cond |= sr2 & (MXC_UARTUSR2_RDR | MXC_UARTUSR2_DCDDELT);
+ term_cond |= !(sr2 & MXC_UARTUSR2_TXFE);
+ } while (term_cond > 0);
+
+ handled = 1;
+ return IRQ_RETVAL(handled);
+}
+
+/*!
+ * Interrupt service routine registered to handle the transmit interrupts. This
+ * routine is registered only in the case where the UART interrupts are not
+ * muxed.
+ *
+ * @param irq the interrupt number
+ * @param dev_id driver private data
+ *
+ * @return The function returns \b IRQ_RETVAL(1) if interrupt was handled,
+ * returns \b IRQ_RETVAL(0) if the interrupt was not handled.
+ * \b IRQ_RETVAL is defined in include/linux/interrupt.h.
+ */
+static irqreturn_t mxcuart_tx_int(int irq, void *dev_id)
+{
+ uart_mxc_port *umxc = dev_id;
+ int handled = 0;
+ volatile unsigned int sr2, cr;
+
+ /* Echo cancellation for IRDA Transmit chars */
+ if (umxc->ir_mode == IRDA && echo_cancel) {
+ /* Disable the receiver */
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ cr &= ~MXC_UARTUCR2_RXEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR2);
+ /* Enable Transmit complete to reenable receiver */
+ cr = readl(umxc->port.membase + MXC_UARTUCR4);
+ cr |= MXC_UARTUCR4_TCEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR4);
+ }
+
+ mxcuart_tx_chars(umxc);
+
+ /* Is the transmit complete to reenable the receiver? */
+ if (umxc->ir_mode == IRDA && echo_cancel) {
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+ if (sr2 & MXC_UARTUSR2_TXDC) {
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ cr |= MXC_UARTUCR2_RXEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR2);
+ /* Disable the Transmit complete interrupt bit */
+ cr = readl(umxc->port.membase + MXC_UARTUCR4);
+ cr &= ~MXC_UARTUCR4_TCEN;
+ writel(cr, umxc->port.membase + MXC_UARTUCR4);
+ }
+ }
+
+ handled = 1;
+
+ return IRQ_RETVAL(handled);
+}
+
+/*!
+ * Interrupt service routine registered to handle the receive interrupts. This
+ * routine is registered only in the case where the UART interrupts are not
+ * muxed.
+ *
+ * @param irq the interrupt number
+ * @param dev_id driver private data
+ *
+ * @return The function returns \b IRQ_RETVAL(1) if interrupt was handled,
+ * returns \b IRQ_RETVAL(0) if the interrupt was not handled.
+ * \b IRQ_RETVAL is defined in include/linux/interrupt.h.
+ */
+static irqreturn_t mxcuart_rx_int(int irq, void *dev_id)
+{
+ uart_mxc_port *umxc = dev_id;
+ int handled = 0;
+
+ /* Clear the aging timer bit */
+ writel(MXC_UARTUSR1_AGTIM, umxc->port.membase + MXC_UARTUSR1);
+ mxcuart_rx_chars(umxc);
+ handled = 1;
+
+ return IRQ_RETVAL(handled);
+}
+
+/*!
+ * Interrupt service routine registered to handle the master interrupts. This
+ * routine is registered only in the case where the UART interrupts are not
+ * muxed.
+ *
+ * @param irq the interrupt number
+ * @param dev_id driver private data
+ *
+ * @return The function returns \b IRQ_RETVAL(1) if interrupt was handled,
+ * returns \b IRQ_RETVAL(0) if the interrupt was not handled.
+ * \b IRQ_RETVAL is defined in include/linux/interrupt.h.
+ */
+static irqreturn_t mxcuart_mint_int(int irq, void *dev_id)
+{
+ uart_mxc_port *umxc = dev_id;
+ int handled = 0;
+ volatile unsigned int sr1, sr2;
+
+ sr1 = readl(umxc->port.membase + MXC_UARTUSR1);
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+ /* Clear the modem status interrupt bits */
+ writel(MXC_UARTUSR1_RTSD | MXC_UARTUSR1_DTRD,
+ umxc->port.membase + MXC_UARTUSR1);
+ writel(MXC_UARTUSR2_DCDDELT | MXC_UARTUSR2_RIDELT,
+ umxc->port.membase + MXC_UARTUSR2);
+ mxcuart_modem_status(umxc, sr1, sr2);
+ handled = 1;
+
+ return IRQ_RETVAL(handled);
+}
+
+/*!
+ * This function is called by the core driver to test whether the transmitter
+ * fifo and shift register for the UART port are empty.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ *
+ * @return The function returns TIOCSER_TEMT if it is empty, else returns 0.
+ */
+static unsigned int mxcuart_tx_empty(struct uart_port *port)
+{
+ volatile unsigned int sr2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ sr2 = readl(port->membase + MXC_UARTUSR2);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return sr2 & MXC_UARTUSR2_TXDC ? TIOCSER_TEMT : 0;
+}
+
+/*!
+ * This function is called by the core driver to get the current status of the
+ * modem input signals. The state of the output signals is not collected.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ *
+ * @return The function returns an integer that contains the ORed value of the
+ * status of all the modem input signals or error.
+ */
+static unsigned int mxcuart_get_mctrl(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ unsigned int result = 0;
+ volatile unsigned int sr1, sr2;
+
+ sr1 = readl(umxc->port.membase + MXC_UARTUSR1);
+ sr2 = readl(umxc->port.membase + MXC_UARTUSR2);
+
+ if (sr1 & MXC_UARTUSR1_RTSS) {
+ result |= TIOCM_CTS;
+ }
+ if (umxc->mode == MODE_DTE) {
+ if (!(sr2 & MXC_UARTUSR2_DCDIN)) {
+ result |= TIOCM_CAR;
+ }
+ if (!(sr2 & MXC_UARTUSR2_RIIN)) {
+ result |= TIOCM_RI;
+ }
+ }
+ return result;
+}
+
+/*!
+ * This function is called by the core driver to set the state of the modem
+ * control lines.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param mctrl the state that the modem control lines should be changed to
+ */
+static void mxcuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ volatile unsigned int cr2 = 0, cr3 = 0, uts = 0;
+
+ cr2 = readl(port->membase + MXC_UARTUCR2);
+ cr3 = readl(port->membase + MXC_UARTUCR3);
+ uts = readl(port->membase + MXC_UARTUTS);
+
+ if (mctrl & TIOCM_RTS) {
+ /*
+ * Return to hardware-driven hardware flow control if the
+ * option is enabled
+ */
+ if (umxc->hardware_flow == 1) {
+ cr2 |= MXC_UARTUCR2_CTSC;
+ } else {
+ cr2 |= MXC_UARTUCR2_CTS;
+ cr2 &= ~MXC_UARTUCR2_CTSC;
+ }
+ } else {
+ cr2 &= ~(MXC_UARTUCR2_CTS | MXC_UARTUCR2_CTSC);
+ }
+ writel(cr2, port->membase + MXC_UARTUCR2);
+
+ if (mctrl & TIOCM_DTR) {
+ cr3 |= MXC_UARTUCR3_DSR;
+ } else {
+ cr3 &= ~MXC_UARTUCR3_DSR;
+ }
+ writel(cr3, port->membase + MXC_UARTUCR3);
+
+ if (mctrl & TIOCM_LOOP) {
+ if (umxc->ir_mode == IRDA) {
+ echo_cancel = 0;
+ } else {
+ uts |= MXC_UARTUTS_LOOP;
+ }
+ } else {
+ if (umxc->ir_mode == IRDA) {
+ echo_cancel = 1;
+ } else {
+ uts &= ~MXC_UARTUTS_LOOP;
+ }
+ }
+ writel(uts, port->membase + MXC_UARTUTS);
+}
+
+/*!
+ * This function is called by the core driver to control the transmission of
+ * the break signal. If break_state is non-zero, the break signal is
+ * transmitted, the signal is terminated when another call is made with
+ * break_state set to 0.
+ *
+ * @param port the port structure for the UART passed in by the core
+ * driver
+ * @param break_state the requested state of the break signal
+ */
+static void mxcuart_break_ctl(struct uart_port *port, int break_state)
+{
+ volatile unsigned int cr1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ cr1 = readl(port->membase + MXC_UARTUCR1);
+ if (break_state == -1) {
+ cr1 |= MXC_UARTUCR1_SNDBRK;
+ } else {
+ cr1 &= ~MXC_UARTUCR1_SNDBRK;
+ }
+ writel(cr1, port->membase + MXC_UARTUCR1);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*!
+ * The read DMA callback, this method is called when the DMA buffer has received its
+ * data. This functions copies the data to the tty buffer and updates the tty buffer
+ * pointers. It also queues the DMA buffer back to the DMA system.
+ *
+ * @param arg driver private data
+ * @param error any DMA error
+ * @param cnt amount of data that was transferred
+ */
+static void mxcuart_dmaread_callback(void *arg, int error, unsigned int cnt)
+{
+ uart_mxc_port *umxc = arg;
+ struct tty_struct *tty = umxc->port.state->port.tty;
+ int buff_id, flip_cnt, num_bufs;
+ mxc_dma_requestbuf_t readchnl_request;
+ mxc_uart_rxdmamap *rx_buf_elem = NULL;
+ unsigned int sr1, sr2;
+ char flag;
+
+ num_bufs = umxc->dma_rxbuf_size / RXDMA_BUFF_SIZE;
+ /* Clear the aging timer bit */
+ writel(MXC_UARTUSR1_AGTIM, umxc->port.membase + MXC_UARTUSR1);
+
+ buff_id = umxc->dma_rxbuf_id;
+ flag = TTY_NORMAL;
+
+ umxc->dma_rxbuf_id += 1;
+ if (umxc->dma_rxbuf_id >= num_bufs) {
+ umxc->dma_rxbuf_id = 0;
+ }
+
+ rx_buf_elem = (mxc_uart_rxdmamap *) (umxc->rx_dmamap + buff_id);
+
+ if (error == MXC_DMA_TRANSFER_ERROR) {
+
+ sr1 = __raw_readl(umxc->port.membase + MXC_UARTUSR1);
+ sr2 = __raw_readl(umxc->port.membase + MXC_UARTUSR2);
+
+ if (sr2 & MXC_UARTUSR2_BRCD) {
+ umxc->port.icount.brk++;
+ if (uart_handle_break(&umxc->port)) {
+ goto drop_data;
+ }
+ } else if (sr1 & MXC_UARTUSR1_PARITYERR) {
+ umxc->port.icount.parity++;
+ } else if (sr1 & MXC_UARTUSR1_FRAMERR) {
+ umxc->port.icount.frame++;
+ } else if (sr2 & MXC_UARTUSR2_ORE) {
+ umxc->port.icount.overrun++;
+
+ }
+
+ if (umxc->port.read_status_mask & MXC_UARTURXD_BRK) {
+ if (sr2 & MXC_UARTUSR2_BRCD)
+ flag = TTY_BREAK;
+ } else if (umxc->port.read_status_mask & MXC_UARTURXD_PRERR) {
+ if (sr1 & MXC_UARTUSR1_PARITYERR)
+ flag = TTY_PARITY;
+ } else if (umxc->port.read_status_mask & MXC_UARTURXD_FRMERR) {
+ if (sr1 & MXC_UARTUSR1_FRAMERR)
+ flag = TTY_FRAME;
+ } else if (umxc->port.read_status_mask & MXC_UARTURXD_OVRRUN) {
+ if (sr2 & MXC_UARTUSR2_ORE)
+ flag = TTY_OVERRUN;
+ }
+/* By default clearing all error bits in status reg */
+ __raw_writel((MXC_UARTUSR2_BRCD | MXC_UARTUSR2_ORE),
+ umxc->port.membase + MXC_UARTUSR2);
+ __raw_writel((MXC_UARTUSR1_PARITYERR | MXC_UARTUSR1_FRAMERR),
+ umxc->port.membase + MXC_UARTUSR1);
+ }
+
+ flip_cnt = tty_buffer_request_room(tty, cnt);
+
+ /* Check for space availability in the TTY Flip buffer */
+ if (flip_cnt <= 0) {
+ goto drop_data;
+ }
+ umxc->port.icount.rx += flip_cnt;
+
+ tty_insert_flip_string(tty, rx_buf_elem->rx_buf, flip_cnt);
+
+ if (flag != TTY_NORMAL) {
+ tty_insert_flip_char(tty, 0, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+ umxc->port.state->port.tty->real_raw = 1;
+
+ drop_data:
+ readchnl_request.src_addr = umxc->port.mapbase;
+ readchnl_request.dst_addr = rx_buf_elem->rx_handle;
+ readchnl_request.num_of_bytes = RXDMA_BUFF_SIZE;
+ mxc_dma_config(dma_list[umxc->port.line].rd_channel, &readchnl_request,
+ 1, MXC_DMA_MODE_READ);
+ mxc_dma_enable(dma_list[umxc->port.line].rd_channel);
+}
+
+/*!
+ * Allocates DMA read and write channels, creates DMA read and write buffers and
+ * sets the channel specific parameters.
+ *
+ * @param d_info the structure that holds all the DMA information for a
+ * particular MXC UART
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ *
+ * @return The function returns 0 on success and a non-zero value on failure.
+ */
+static int mxcuart_initdma(dma_info *d_info, uart_mxc_port *umxc)
+{
+ int ret = 0, rxbufs, i, j;
+ mxc_dma_requestbuf_t *readchnl_reqelem;
+ mxc_uart_rxdmamap *rx_buf_elem;
+
+ /* Request for the read and write channels */
+ d_info->rd_channel = mxc_dma_request(umxc->dma_rx_id, "MXC UART Read");
+ if (d_info->rd_channel < 0) {
+ printk(KERN_ERR "MXC UART: Cannot allocate DMA read channel\n");
+ return -1;
+ } else {
+ d_info->wr_channel =
+ mxc_dma_request(umxc->dma_tx_id, "MXC UART Write");
+ if (d_info->wr_channel < 0) {
+ mxc_dma_free(d_info->rd_channel);
+ printk(KERN_ERR
+ "MXC UART: Cannot allocate DMA write channel\n");
+ return -1;
+ }
+ }
+
+ /* Allocate the DMA Transmit Buffer */
+ umxc->tx_buf = kmalloc(TXDMA_BUFF_SIZE, GFP_KERNEL);
+ if (umxc->tx_buf == NULL) {
+ ret = -1;
+ goto err_dma_tx_buff;
+ }
+ rxbufs = umxc->dma_rxbuf_size / RXDMA_BUFF_SIZE;
+ /* Allocate the DMA Virtual Receive Buffer */
+ umxc->rx_dmamap = kmalloc(rxbufs * sizeof(mxc_uart_rxdmamap), GFP_KERNEL);
+ if (umxc->rx_dmamap == NULL) {
+ ret = -1;
+ goto err_dma_rx_buff;
+ }
+
+ /* Allocate the DMA Receive Request structures */
+ readchnl_reqelem = kmalloc(rxbufs * sizeof(mxc_dma_requestbuf_t),
+ GFP_KERNEL);
+ if (readchnl_reqelem == NULL) {
+ ret = -1;
+ goto err_request;
+ }
+
+ for (i = 0; i < rxbufs; i++) {
+ rx_buf_elem = (mxc_uart_rxdmamap *) (umxc->rx_dmamap + i);
+ rx_buf_elem->rx_buf =
+ dma_alloc_coherent(NULL, RXDMA_BUFF_SIZE,
+ &rx_buf_elem->rx_handle, GFP_DMA);
+ if (rx_buf_elem->rx_buf == NULL) {
+ for (j = 0; j < i; j++) {
+ rx_buf_elem =
+ (mxc_uart_rxdmamap *) (umxc->rx_dmamap + j);
+ dma_free_coherent(NULL, RXDMA_BUFF_SIZE,
+ rx_buf_elem->rx_buf,
+ rx_buf_elem->rx_handle);
+ }
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ umxc->dma_rxbuf_id = 0;
+ /* Setup the DMA read request structures */
+ for (i = 0; i < rxbufs; i++) {
+ rx_buf_elem = (mxc_uart_rxdmamap *) (umxc->rx_dmamap + i);
+ (readchnl_reqelem + i)->src_addr = umxc->port.mapbase;
+ (readchnl_reqelem + i)->dst_addr = rx_buf_elem->rx_handle;
+ (readchnl_reqelem + i)->num_of_bytes = RXDMA_BUFF_SIZE;
+ }
+ mxc_dma_config(d_info->rd_channel, readchnl_reqelem, rxbufs,
+ MXC_DMA_MODE_READ);
+ mxc_dma_callback_set(d_info->rd_channel, mxcuart_dmaread_callback,
+ umxc);
+ mxc_dma_callback_set(d_info->wr_channel, mxcuart_dma_writecallback,
+ umxc);
+
+ /* Start the read channel */
+ mxc_dma_enable(d_info->rd_channel);
+ kfree(readchnl_reqelem);
+ tasklet_init(&d_info->dma_tx_tasklet, dma_tx_do_tasklet,
+ (unsigned long)umxc);
+ d_info->dma_txchnl_inuse = 0;
+ return ret;
+ cleanup:
+ kfree(readchnl_reqelem);
+ err_request:
+ kfree(umxc->rx_dmamap);
+ err_dma_rx_buff:
+ kfree(umxc->tx_buf);
+ err_dma_tx_buff:
+ mxc_dma_free(d_info->rd_channel);
+ mxc_dma_free(d_info->wr_channel);
+
+ return ret;
+}
+
+/*!
+ * Stops DMA and frees the DMA resources
+ *
+ * @param d_info the structure that holds all the DMA information for a
+ * particular MXC UART
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ */
+static void mxcuart_freedma(dma_info *d_info, uart_mxc_port *umxc)
+{
+ int i, rxbufs;
+ mxc_uart_rxdmamap *rx_buf_elem;
+
+ rxbufs = umxc->dma_rxbuf_size / RXDMA_BUFF_SIZE;
+
+ for (i = 0; i < rxbufs; i++) {
+ rx_buf_elem = (mxc_uart_rxdmamap *) (umxc->rx_dmamap + i);
+ dma_free_coherent(NULL, RXDMA_BUFF_SIZE,
+ rx_buf_elem->rx_buf, rx_buf_elem->rx_handle);
+ }
+ kfree(umxc->rx_dmamap);
+ kfree(umxc->tx_buf);
+ mxc_dma_free(d_info->rd_channel);
+ mxc_dma_free(d_info->wr_channel);
+}
+
+/*!
+ * This function is called to free the interrupts.
+ *
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ */
+static void mxcuart_free_interrupts(uart_mxc_port *umxc)
+{
+ free_irq(umxc->port.irq, umxc);
+ if (umxc->ints_muxed == 0) {
+ free_irq(umxc->irqs[0], umxc);
+ free_irq(umxc->irqs[1], umxc);
+ }
+}
+
+/*!
+ * Calculate and set the UART port clock value
+ *
+ * @param umxc the MXC UART port structure, this includes the \b uart_port
+ * structure and other members that are specific to MXC UARTs
+ * @param per_clk peripheral clock coming into the MXC UART module
+ * @param req_baud current baudrate requested
+ * @param div returns the reference frequency divider value
+ */
+static void mxcuart_set_ref_freq(uart_mxc_port *umxc, unsigned long per_clk,
+ unsigned int req_baud, int *div)
+{
+ unsigned int d = 1;
+
+ /*
+ * Choose the smallest possible prescaler to maximize
+ * the chance of using integer scaling. Ensure that
+ * the calculation won't overflow. Limit the denom
+ * to 15 bits since a 16-bit denom doesn't work.
+ */
+ if (req_baud < (1 << (31 - (4 + 15))))
+ d = per_clk / (req_baud << (4 + 15)) + 1;
+
+ umxc->port.uartclk = per_clk / d;
+
+ /*
+ * Set the ONEMS register that is used by IR special case bit and
+ * the Escape character detect logic
+ */
+ writel(umxc->port.uartclk / 1000, umxc->port.membase + MXC_UARTONEMS);
+ *div = d;
+}
+
+/*!
+ * This function is called by the core driver to initialize the low-level
+ * driver. The function grabs the interrupt resources and registers its
+ * interrupt service routines. It then initializes the IOMUX registers to
+ * configure the pins for UART signals and finally initializes the various
+ * UART registers and enables the port for reception.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ *
+ * @return The function returns 0 on success and a non-zero value on failure.
+ */
+static int mxcuart_startup(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ int retval;
+ volatile unsigned int cr, cr1 = 0, cr2 = 0, ufcr = 0;
+
+ /*
+ * Some UARTs need separate registrations for the interrupts as
+ * they do not take the muxed interrupt output to the ARM core
+ */
+ if (umxc->ints_muxed == 1) {
+ retval = request_irq(umxc->port.irq, mxcuart_int, 0,
+ "mxcintuart", umxc);
+ if (retval != 0) {
+ return retval;
+ }
+ } else {
+ retval = request_irq(umxc->port.irq, mxcuart_tx_int,
+ 0, "mxcintuart", umxc);
+ if (retval != 0) {
+ return retval;
+ } else {
+ retval = request_irq(umxc->irqs[0], mxcuart_rx_int,
+ 0, "mxcintuart", umxc);
+ if (retval != 0) {
+ free_irq(umxc->port.irq, umxc);
+ return retval;
+ } else {
+ retval =
+ request_irq(umxc->irqs[1], mxcuart_mint_int,
+ 0, "mxcintuart", umxc);
+ if (retval != 0) {
+ free_irq(umxc->port.irq, umxc);
+ free_irq(umxc->irqs[0], umxc);
+ return retval;
+ }
+ }
+ }
+ }
+
+ /* Initialize the DMA if we need SDMA data transfer */
+ if (umxc->dma_enabled == 1) {
+ retval = mxcuart_initdma(dma_list + umxc->port.line, umxc);
+ if (retval != 0) {
+ printk
+ (KERN_ERR
+ "MXC UART: Failed to initialize DMA for UART %d\n",
+ umxc->port.line);
+ mxcuart_free_interrupts(umxc);
+ return retval;
+ }
+ /* Configure the GPR register to receive SDMA events */
+ config_uartdma_event(umxc->port.line);
+ }
+
+ /*
+ * Clear Status Registers 1 and 2
+ */
+ writel(0xFFFF, umxc->port.membase + MXC_UARTUSR1);
+ writel(0xFFFF, umxc->port.membase + MXC_UARTUSR2);
+
+ /* Configure the IOMUX for the UART */
+ gpio_uart_active(umxc->port.line, umxc->ir_mode);
+
+ /*
+ * Set the transceiver invert bits if required
+ */
+ if (umxc->ir_mode == IRDA) {
+ echo_cancel = 1;
+ writel(umxc->ir_rx_inv | MXC_UARTUCR4_IRSC, umxc->port.membase
+ + MXC_UARTUCR4);
+ writel(umxc->rxd_mux | umxc->ir_tx_inv,
+ umxc->port.membase + MXC_UARTUCR3);
+ } else {
+ writel(umxc->rxd_mux, umxc->port.membase + MXC_UARTUCR3);
+ }
+
+ /*
+ * Initialize UCR1,2 and UFCR registers
+ */
+ if (umxc->dma_enabled == 1) {
+ cr2 = (MXC_UARTUCR2_TXEN | MXC_UARTUCR2_RXEN);
+ } else {
+ cr2 =
+ (MXC_UARTUCR2_ATEN | MXC_UARTUCR2_TXEN | MXC_UARTUCR2_RXEN);
+ }
+
+ writel(cr2, umxc->port.membase + MXC_UARTUCR2);
+ /* Wait till we are out of software reset */
+ do {
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ } while (!(cr & MXC_UARTUCR2_SRST));
+
+ if (umxc->mode == MODE_DTE) {
+ ufcr |= ((umxc->tx_threshold << MXC_UARTUFCR_TXTL_OFFSET) |
+ MXC_UARTUFCR_DCEDTE | MXC_UARTUFCR_RFDIV | umxc->
+ rx_threshold);
+ } else {
+ ufcr |= ((umxc->tx_threshold << MXC_UARTUFCR_TXTL_OFFSET) |
+ MXC_UARTUFCR_RFDIV | umxc->rx_threshold);
+ }
+ writel(ufcr, umxc->port.membase + MXC_UARTUFCR);
+
+ /*
+ * Finally enable the UART and the Receive interrupts
+ */
+ if (umxc->ir_mode == IRDA) {
+ cr1 |= MXC_UARTUCR1_IREN;
+ }
+ if (umxc->dma_enabled == 1) {
+ cr1 |= (MXC_UARTUCR1_RXDMAEN | MXC_UARTUCR1_ATDMAEN |
+ MXC_UARTUCR1_UARTEN);
+ } else {
+ cr1 |= (MXC_UARTUCR1_RRDYEN | MXC_UARTUCR1_UARTEN);
+ }
+ writel(cr1, umxc->port.membase + MXC_UARTUCR1);
+
+ return 0;
+}
+
+/*!
+ * This function is called by the core driver for the low-level driver to free
+ * its resources. The function frees all its interrupts and disables the UART.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ */
+static void mxcuart_shutdown(struct uart_port *port)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+
+ /* Disable the IOMUX for the UART */
+ gpio_uart_inactive(umxc->port.line, umxc->ir_mode);
+ mxcuart_free_interrupts(umxc);
+ /* Disable all interrupts, port and break condition */
+ writel(0, umxc->port.membase + MXC_UARTUCR1);
+ writel(0, umxc->port.membase + MXC_UARTUCR3);
+ if (umxc->dma_enabled == 1) {
+ mxcuart_freedma(dma_list + umxc->port.line, umxc);
+ }
+}
+
+/*!
+ * This function is called by the core driver to change the UART parameters,
+ * including baudrate, word length, parity, stop bits. The function also updates
+ * the port structures mask registers to indicate the types of events the user is
+ * interested in receiving.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param termios the desired termios settings
+ * @param old old termios
+ */
+static void mxcuart_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+ volatile unsigned int cr4 = 0, cr2 = 0, ufcr;
+ u_int num, denom, baud;
+ u_int cr2_mask; /* Used to add the changes to CR2 */
+ unsigned long flags, per_clk;
+ int div;
+
+ cr2_mask = ~(MXC_UARTUCR2_IRTS | MXC_UARTUCR2_CTSC | MXC_UARTUCR2_PREN |
+ MXC_UARTUCR2_PROE | MXC_UARTUCR2_STPB | MXC_UARTUCR2_WS);
+
+ per_clk = clk_get_rate(umxc->clk);
+
+ /*
+ * Ask the core to get the baudrate, if requested baudrate is not
+ * between max and min, then either use the baudrate in old termios
+ * setting. If it's still invalid, we try 9600 baud.
+ */
+ baud = uart_get_baud_rate(&umxc->port, termios, old, 0, per_clk / 16);
+ /* Set the Reference frequency divider */
+ mxcuart_set_ref_freq(umxc, per_clk, baud, &div);
+
+ /* Byte size, default is 8-bit mode */
+ switch (termios->c_cflag & CSIZE) {
+ case CS7:
+ cr2 = 0;
+ break;
+ default:
+ cr2 = MXC_UARTUCR2_WS;
+ break;
+ }
+ /* Check to see if we need 2 Stop bits */
+ if (termios->c_cflag & CSTOPB) {
+ cr2 |= MXC_UARTUCR2_STPB;
+ }
+
+ /* Check to see if we need Parity checking */
+ if (termios->c_cflag & PARENB) {
+ cr2 |= MXC_UARTUCR2_PREN;
+ if (termios->c_cflag & PARODD) {
+ cr2 |= MXC_UARTUCR2_PROE;
+ }
+ }
+ spin_lock_irqsave(&umxc->port.lock, flags);
+
+ ufcr = readl(umxc->port.membase + MXC_UARTUFCR);
+ ufcr = (ufcr & (~MXC_UARTUFCR_RFDIV_MASK)) |
+ ((6 - div) << MXC_UARTUFCR_RFDIV_OFFSET);
+ writel(ufcr, umxc->port.membase + MXC_UARTUFCR);
+
+ /*
+ * Update the per-port timeout
+ */
+ uart_update_timeout(&umxc->port, termios->c_cflag, baud);
+
+ umxc->port.read_status_mask = MXC_UARTURXD_OVRRUN;
+ /*
+ * Enable appropriate events to be passed to the TTY layer
+ */
+ if (termios->c_iflag & INPCK) {
+ umxc->port.read_status_mask |= MXC_UARTURXD_FRMERR |
+ MXC_UARTURXD_PRERR;
+ }
+ if (termios->c_iflag & (BRKINT | PARMRK)) {
+ umxc->port.read_status_mask |= MXC_UARTURXD_BRK;
+ }
+
+ /*
+ * Characters to ignore
+ */
+ umxc->port.ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR) {
+ umxc->port.ignore_status_mask |= MXC_UARTURXD_FRMERR |
+ MXC_UARTURXD_PRERR;
+ }
+ if (termios->c_iflag & IGNBRK) {
+ umxc->port.ignore_status_mask |= MXC_UARTURXD_BRK;
+ /*
+ * If we are ignoring parity and break indicators,
+ * ignore overruns too (for real raw support)
+ */
+ if (termios->c_iflag & IGNPAR) {
+ umxc->port.ignore_status_mask |= MXC_UARTURXD_OVRRUN;
+ }
+ }
+
+ /*
+ * Ignore all characters if CREAD is not set, still receive characters
+ * from the port, but throw them away.
+ */
+ if ((termios->c_cflag & CREAD) == 0) {
+ umxc->port.ignore_status_mask |= UART_CREAD_BIT;
+ }
+
+ /* Hardware flow control should controled by userspace */
+ umxc->hardware_flow = (termios->c_cflag & CRTSCTS) ? 1 : 0;
+
+ cr4 = readl(umxc->port.membase + MXC_UARTUCR4);
+ if (UART_ENABLE_MS(port, termios->c_cflag)) {
+ mxcuart_enable_ms(port);
+ if (umxc->hardware_flow == 1) {
+ cr4 = (cr4 & (~MXC_UARTUCR4_CTSTL_MASK)) |
+ (umxc->cts_threshold << MXC_UARTUCR4_CTSTL_OFFSET);
+ cr2 |= MXC_UARTUCR2_CTSC;
+ umxc->port.state->port.tty->hw_stopped = 0;
+ } else {
+ cr2 |= MXC_UARTUCR2_IRTS;
+ }
+ } else {
+ cr2 |= MXC_UARTUCR2_IRTS;
+ }
+
+ /* Add Parity, character length and stop bits information */
+ cr2 |= (readl(umxc->port.membase + MXC_UARTUCR2) & cr2_mask);
+ writel(cr2, umxc->port.membase + MXC_UARTUCR2);
+ /*
+ if (umxc->ir_mode == IRDA) {
+ ret = mxcuart_setir_special(baud);
+ if (ret == 0) {
+ cr4 &= ~MXC_UARTUCR4_IRSC;
+ } else {
+ cr4 |= MXC_UARTUCR4_IRSC;
+ }
+ } */
+ writel(cr4, umxc->port.membase + MXC_UARTUCR4);
+
+ /*
+ * Set baud rate
+ */
+
+ /* Use integer scaling, if possible. Limit the denom to 15 bits. */
+ num = 0;
+ denom = (umxc->port.uartclk + 8 * baud) / (16 * baud) - 1;
+
+ /* Use fractional scaling if needed to limit the max error to 0.5% */
+ if (denom < 100) {
+ u64 n64 = (u64) 16 * 0x8000 * baud + (umxc->port.uartclk / 2);
+ do_div(n64, umxc->port.uartclk);
+ num = (u_int) n64 - 1;
+ denom = 0x7fff;
+ }
+ writel(num, umxc->port.membase + MXC_UARTUBIR);
+ writel(denom, umxc->port.membase + MXC_UARTUBMR);
+
+ spin_unlock_irqrestore(&umxc->port.lock, flags);
+}
+
+/*!
+ * This function is called by the core driver to know the UART type.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ *
+ * @return The function returns a pointer to a string describing the UART port.
+ */
+static const char *mxcuart_type(struct uart_port *port)
+{
+ return port->type == PORT_IMX ? "Freescale i.MX" : NULL;
+}
+
+/*!
+ * This function is called by the core driver to release the memory resources
+ * currently in use by the UART port.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ */
+static void mxcuart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, SZ_4K);
+}
+
+/*!
+ * This function is called by the core driver to request memory resources for
+ * the UART port.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ *
+ * @return The function returns \b -EBUSY on failure, else it returns 0.
+ */
+static int mxcuart_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ struct resource *mmres;
+ void *ret;
+
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mmres)
+ return -ENODEV;
+
+ ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
+ "serial_mxc");
+
+ return ret ? 0 : -EBUSY;
+}
+
+/*!
+ * This function is called by the core driver to perform any autoconfiguration
+ * steps required for the UART port. This function sets the port->type field.
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param flags bit mask of the required configuration
+ */
+static void mxcuart_config_port(struct uart_port *port, int flags)
+{
+ if ((flags & UART_CONFIG_TYPE) && (mxcuart_request_port(port) == 0)) {
+ port->type = PORT_IMX;
+ }
+}
+
+/*!
+ * This function is called by the core driver to verify that the new serial
+ * port information contained within \a ser is suitable for this UART port type.
+ * The function checks to see if the UART port type specified by the user
+ * application while setting the UART port information matches what is stored
+ * in the define \b PORT_MXC found in the header file include/linux/serial_core.h
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param ser the new serial port information
+ *
+ * @return The function returns 0 on success or \b -EINVAL if the port type
+ * specified is not equal to \b PORT_MXC.
+ */
+static int mxcuart_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_IMX) {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+/*!
+ * This function is used to send a high priority XON/XOFF character
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param ch the character to send
+ */
+static void mxcuart_send_xchar(struct uart_port *port, char ch)
+{
+ unsigned long flags;
+
+ port->x_char = ch;
+ if (port->state->port.tty->hw_stopped) {
+ return;
+ }
+
+ if (ch) {
+ spin_lock_irqsave(&port->lock, flags);
+ port->ops->start_tx(port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ }
+}
+
+/*!
+ * This function is used enable/disable the MXC UART clocks
+ *
+ * @param port the port structure for the UART passed in by the core driver
+ * @param state New PM state
+ * @param oldstate Current PM state
+ */
+static void
+mxcuart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+ uart_mxc_port *umxc = (uart_mxc_port *) port;
+
+ if (state)
+ clk_disable(umxc->clk);
+ else
+ clk_enable(umxc->clk);
+}
+
+/*!
+ * This structure contains the pointers to the control functions that are
+ * invoked by the core serial driver to access the UART hardware. The
+ * structure is passed to serial_core.c file during registration.
+ */
+static struct uart_ops mxc_ops = {
+ .tx_empty = mxcuart_tx_empty,
+ .set_mctrl = mxcuart_set_mctrl,
+ .get_mctrl = mxcuart_get_mctrl,
+ .stop_tx = mxcuart_stop_tx,
+ .start_tx = mxcuart_start_tx,
+ .stop_rx = mxcuart_stop_rx,
+ .enable_ms = mxcuart_enable_ms,
+ .break_ctl = mxcuart_break_ctl,
+ .startup = mxcuart_startup,
+ .shutdown = mxcuart_shutdown,
+ .set_termios = mxcuart_set_termios,
+ .type = mxcuart_type,
+ .pm = mxcuart_pm,
+ .release_port = mxcuart_release_port,
+ .request_port = mxcuart_request_port,
+ .config_port = mxcuart_config_port,
+ .verify_port = mxcuart_verify_port,
+ .send_xchar = mxcuart_send_xchar,
+};
+
+#ifdef CONFIG_SERIAL_MXC_CONSOLE
+
+/*
+ * Write out a character once the UART is ready
+ */
+static inline void mxcuart_console_write_char(struct uart_port *port, char ch)
+{
+ volatile unsigned int status;
+
+ do {
+ status = readl(port->membase + MXC_UARTUSR1);
+ } while ((status & MXC_UARTUSR1_TRDY) == 0);
+ writel(ch, port->membase + MXC_UARTUTXD);
+}
+
+/*!
+ * This function is called to write the console messages through the UART port.
+ *
+ * @param co the console structure
+ * @param s the log message to be written to the UART
+ * @param count length of the message
+ */
+static void mxcuart_console_write(struct console *co, const char *s,
+ u_int count)
+{
+ struct uart_port *port = &mxc_ports[co->index]->port;
+ volatile unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3;
+ int i;
+
+ /*
+ * First save the control registers and then disable the interrupts
+ */
+ oldcr1 = readl(port->membase + MXC_UARTUCR1);
+ oldcr2 = readl(port->membase + MXC_UARTUCR2);
+ oldcr3 = readl(port->membase + MXC_UARTUCR3);
+ cr2 =
+ oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN |
+ MXC_UARTUCR2_ESCI);
+ cr3 =
+ oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI |
+ MXC_UARTUCR3_DTRDEN);
+ writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1);
+ writel(cr2, port->membase + MXC_UARTUCR2);
+ writel(cr3, port->membase + MXC_UARTUCR3);
+ /*
+ * Do each character
+ */
+ for (i = 0; i < count; i++) {
+ mxcuart_console_write_char(port, s[i]);
+ if (s[i] == '\n') {
+ mxcuart_console_write_char(port, '\r');
+ }
+ }
+ /*
+ * Finally, wait for the transmitter to become empty
+ */
+ do {
+ status = readl(port->membase + MXC_UARTUSR2);
+ } while (!(status & MXC_UARTUSR2_TXDC));
+
+ /*
+ * Restore the control registers
+ */
+ writel(oldcr1, port->membase + MXC_UARTUCR1);
+ writel(oldcr2, port->membase + MXC_UARTUCR2);
+ writel(oldcr3, port->membase + MXC_UARTUCR3);
+}
+
+/*!
+ * Initializes the UART port to be used to print console message with the
+ * options specified. If no options are specified, then the function
+ * initializes the UART with the default options of baudrate=115200, 8 bit
+ * word size, no parity, no flow control.
+ *
+ * @param co The console structure
+ * @param options Any console options passed in from the command line
+ *
+ * @return The function returns 0 on success or error.
+ */
+static int __init mxcuart_console_setup(struct console *co, char *options)
+{
+ uart_mxc_port *umxc;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ volatile unsigned int cr = 0;
+
+ /*
+ * Check whether an invalid uart number had been specified, and if
+ * so, search for the first available port that does have console
+ * support
+ */
+ if (co->index >= MXC_UART_NR) {
+ co->index = 0;
+ }
+ umxc = mxc_ports[co->index];
+
+ if (umxc == NULL) {
+ return -ENODEV;
+ }
+
+ clk_enable(umxc->clk);
+
+ /* initialize port.lock else oops */
+ spin_lock_init(&umxc->port.lock);
+
+ /*
+ * Initialize the UART registers
+ */
+ writel(MXC_UARTUCR1_UARTEN, umxc->port.membase + MXC_UARTUCR1);
+ /* Enable the transmitter and do a software reset */
+ writel(MXC_UARTUCR2_TXEN, umxc->port.membase + MXC_UARTUCR2);
+ /* Wait till we are out of software reset */
+ do {
+ cr = readl(umxc->port.membase + MXC_UARTUCR2);
+ } while (!(cr & MXC_UARTUCR2_SRST));
+
+ writel(0x0, umxc->port.membase + MXC_UARTUCR3);
+ writel(0x0, umxc->port.membase + MXC_UARTUCR4);
+ /* Set TXTL to 2, RXTL to 1 and RFDIV to 2 */
+ cr = 0x0800 | MXC_UARTUFCR_RFDIV | 0x1;
+ if (umxc->mode == MODE_DTE) {
+ cr |= MXC_UARTUFCR_DCEDTE;
+ }
+ writel(cr, umxc->port.membase + MXC_UARTUFCR);
+ writel(0xFFFF, umxc->port.membase + MXC_UARTUSR1);
+ writel(0xFFFF, umxc->port.membase + MXC_UARTUSR2);
+
+ if (options != NULL) {
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ }
+ gpio_uart_active(umxc->port.line, umxc->ir_mode);
+ return uart_set_options(&umxc->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver mxc_reg;
+
+/*!
+ * This structure contains the pointers to the UART console functions. It is
+ * passed as an argument when registering the console.
+ */
+static struct console mxc_console = {
+ .name = "ttymxc",
+ .write = mxcuart_console_write,
+ .device = uart_console_device,
+ .setup = mxcuart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mxc_reg,
+};
+
+/*!
+ * This function registers the console callback functions with the kernel.
+ */
+static int __init mxcuart_console_init(void)
+{
+ register_console(&mxc_console);
+ return 0;
+}
+
+console_initcall(mxcuart_console_init);
+
+static int __init find_port(struct uart_port *p)
+{
+ int line;
+ struct uart_port *port;
+ for (line = 0; line < MXC_UART_NR; line++) {
+ if (!mxc_ports[line])
+ continue;
+ port = &mxc_ports[line]->port;
+ if (uart_match_port(p, port))
+ return line;
+ }
+ return -ENODEV;
+}
+
+int __init mxc_uart_start_console(struct uart_port *port, char *options)
+{
+ int line;
+ line = find_port(port);
+ if (line < 0)
+ return -ENODEV;
+
+ add_preferred_console("ttymxc", line, options);
+ printk("Switching Console to ttymxc%d at %s 0x%lx (options '%s')\n",
+ line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
+ port->iotype ==
+ UPIO_MEM ? (unsigned long)port->mapbase : (unsigned long)port->
+ iobase, options);
+
+ if (!(mxc_console.flags & CON_ENABLED)) {
+ mxc_console.flags &= ~CON_PRINTBUFFER;
+ register_console(&mxc_console);
+ }
+ return 0;
+}
+
+#define MXC_CONSOLE (&mxc_console)
+#else
+#define MXC_CONSOLE NULL
+#endif /* CONFIG_SERIAL_MXC_CONSOLE */
+
+/*!
+ * This structure contains the information such as the name of the UART driver
+ * that appears in the /dev folder, major and minor numbers etc. This structure
+ * is passed to the serial_core.c file.
+ */
+static struct uart_driver mxc_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttymxc",
+ .dev_name = "ttymxc",
+ .major = SERIAL_MXC_MAJOR,
+ .minor = SERIAL_MXC_MINOR,
+ .nr = MXC_UART_NR,
+ .cons = MXC_CONSOLE,
+};
+
+/*!
+ * This function is called to put the UART in a low power state. Refer to the
+ * document driver-model/driver.txt in the kernel source tree for more
+ * information.
+ *
+ * @param pdev the device structure used to give information on which UART
+ * to suspend
+ * @param state the power state the device is entering
+ *
+ * @return The function returns 0 on success and -1 on failure
+ */
+static int mxcuart_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ uart_mxc_port *umxc = platform_get_drvdata(pdev);
+
+ if (umxc == NULL)
+ return 0; /* skip disabled ports */
+
+ if (umxc && umxc->port.flags & ASYNC_INITIALIZED)
+ uart_suspend_port(&mxc_reg, &umxc->port);
+
+ if (umxc && umxc->port.flags & ASYNC_SUSPENDED)
+ umxc->port.state->port.tty->hw_stopped = 1;
+
+ return 0;
+}
+
+/*!
+ * This function is called to bring the UART back from a low power state. Refer
+ * to the document driver-model/driver.txt in the kernel source tree for more
+ * information.
+ *
+ * @param pdev the device structure used to give information on which UART
+ * to resume
+ *
+ * @return The function returns 0 on success and -1 on failure
+ */
+static int mxcuart_resume(struct platform_device *pdev)
+{
+ uart_mxc_port *umxc = platform_get_drvdata(pdev);
+
+ if (umxc == NULL)
+ return 0; /* skip disabled ports */
+
+ if (umxc && umxc->port.flags & ASYNC_SUSPENDED) {
+ umxc->port.state->port.tty->hw_stopped = 0;
+ uart_resume_port(&mxc_reg, &umxc->port);
+ }
+
+ return 0;
+}
+
+/*!
+ * This function is called during the driver binding process. Based on the UART
+ * that is being probed this function adds the appropriate UART port structure
+ * in the core driver.
+ *
+ * @param pdev the device structure used to store device specific
+ * information that is used by the suspend, resume and remove
+ * functions
+ *
+ * @return The function returns 0 if successful; -1 otherwise.
+ */
+static int mxcuart_probe(struct platform_device *pdev)
+{
+ int id = pdev->id;
+ struct resource *res;
+ void __iomem *base;
+
+ mxc_ports[id] = pdev->dev.platform_data;
+ mxc_ports[id]->port.ops = &mxc_ops;
+
+ /* Do not use UARTs that are disabled during integration */
+ if (mxc_ports[id]->enabled == 1) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ base = ioremap(res->start, res->end - res->start + 1);
+ if (!base)
+ return -ENOMEM;
+
+ mxc_ports[id]->port.membase = base;
+ mxc_ports[id]->port.mapbase = res->start;
+ mxc_ports[id]->port.dev = &pdev->dev;
+ mxc_ports[id]->port.irq = platform_get_irq(pdev, 0);
+ mxc_ports[id]->irqs[0] = platform_get_irq(pdev, 1);
+ mxc_ports[id]->irqs[1] = platform_get_irq(pdev, 2);
+ spin_lock_init(&mxc_ports[id]->port.lock);
+ /* Enable the low latency flag for DMA UART ports */
+ if (mxc_ports[id]->dma_enabled == 1) {
+ mxc_ports[id]->port.flags |= ASYNC_LOW_LATENCY;
+ }
+
+ mxc_ports[id]->clk = clk_get(&pdev->dev, NULL);
+ if (mxc_ports[id]->clk == NULL)
+ return -1;
+
+ uart_add_one_port(&mxc_reg, &mxc_ports[id]->port);
+ platform_set_drvdata(pdev, mxc_ports[id]);
+ }
+ return 0;
+}
+
+/*!
+ * Dissociates the driver from the UART device. Removes the appropriate UART
+ * port structure from the core driver.
+ *
+ * @param pdev the device structure used to give information on which UART
+ * to remove
+ *
+ * @return The function always returns 0.
+ */
+static int mxcuart_remove(struct platform_device *pdev)
+{
+ uart_mxc_port *umxc = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (umxc) {
+ uart_remove_one_port(&mxc_reg, &umxc->port);
+ iounmap(umxc->port.membase);
+ }
+ return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcuart_driver = {
+ .driver = {
+ .name = "mxcintuart",
+ },
+ .probe = mxcuart_probe,
+ .remove = mxcuart_remove,
+ .suspend = mxcuart_suspend,
+ .resume = mxcuart_resume,
+};
+
+/*!
+ * This function is used to initialize the UART driver module. The function
+ * registers the power management callback functions with the kernel and also
+ * registers the UART callback functions with the core serial driver.
+ *
+ * @return The function returns 0 on success and a non-zero value on failure.
+ */
+static int __init mxcuart_init(void)
+{
+ int ret = 0;
+
+ printk(KERN_INFO "Serial: MXC Internal UART driver\n");
+ ret = uart_register_driver(&mxc_reg);
+ if (ret == 0) {
+ /* Register the device driver structure. */
+ ret = platform_driver_register(&mxcuart_driver);
+ if (ret != 0) {
+ uart_unregister_driver(&mxc_reg);
+ }
+ }
+ return ret;
+}
+
+/*!
+ * This function is used to cleanup all resources before the driver exits.
+ */
+static void __exit mxcuart_exit(void)
+{
+ platform_driver_unregister(&mxcuart_driver);
+ uart_unregister_driver(&mxc_reg);
+}
+
+module_init(mxcuart_init);
+module_exit(mxcuart_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MXC serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/mxc_uart_early.c b/drivers/serial/mxc_uart_early.c
new file mode 100644
index 000000000000..f4b6493a9a64
--- /dev/null
+++ b/drivers/serial/mxc_uart_early.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file drivers/serial/mxc_uart_early.c
+ *
+ * @brief Driver for the Freescale Semiconductor MXC serial ports based on
+ * drivers/char/8250_early.c, Copyright 2004 Hewlett-Packard Development Company,
+ * L.P. by Bjorn Helgaasby.
+ *
+ * Early serial console for MXC UARTS.
+ *
+ * This is for use before the serial driver has initialized, in
+ * particular, before the UARTs have been discovered and named.
+ * Instead of specifying the console device as, e.g., "ttymxc0",
+ * we locate the device directly by its MMIO or I/O port address.
+ *
+ * The user can specify the device directly, e.g.,
+ * console=mxcuart,0x43f90000,115200n8
+ * or platform code can call early_uart_console_init() to set
+ * the early UART device.
+ *
+ * After the normal serial driver starts, we try to locate the
+ * matching ttymxc device and start a console there.
+ */
+
+/*
+ * Include Files
+ */
+
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/clk.h>
+#include <mach/mxc_uart.h>
+
+struct mxc_early_uart_device {
+ struct uart_port port;
+ char options[16]; /* e.g., 115200n8 */
+ unsigned int baud;
+ struct clk *clk;
+};
+static struct mxc_early_uart_device mxc_early_device __initdata;
+
+/*
+ * Write out a character once the UART is ready
+ */
+static void __init mxcuart_console_write_char(struct uart_port *port, int ch)
+{
+ unsigned int status;
+
+ do {
+ status = readl(port->membase + MXC_UARTUSR2);
+ } while ((status & MXC_UARTUSR2_TXFE) == 0);
+ writel(ch, port->membase + MXC_UARTUTXD);
+}
+
+/*!
+ * This function is called to write the console messages through the UART port.
+ *
+ * @param co the console structure
+ * @param s the log message to be written to the UART
+ * @param count length of the message
+ */
+void __init early_mxcuart_console_write(struct console *co, const char *s,
+ u_int count)
+{
+ struct uart_port *port = &mxc_early_device.port;
+ volatile unsigned int status, oldcr1, oldcr2, oldcr3, cr2, cr3;
+
+ /*
+ * First save the control registers and then disable the interrupts
+ */
+ oldcr1 = readl(port->membase + MXC_UARTUCR1);
+ oldcr2 = readl(port->membase + MXC_UARTUCR2);
+ oldcr3 = readl(port->membase + MXC_UARTUCR3);
+ cr2 =
+ oldcr2 & ~(MXC_UARTUCR2_ATEN | MXC_UARTUCR2_RTSEN |
+ MXC_UARTUCR2_ESCI);
+ cr3 =
+ oldcr3 & ~(MXC_UARTUCR3_DCD | MXC_UARTUCR3_RI |
+ MXC_UARTUCR3_DTRDEN);
+ writel(MXC_UARTUCR1_UARTEN, port->membase + MXC_UARTUCR1);
+ writel(cr2, port->membase + MXC_UARTUCR2);
+ writel(cr3, port->membase + MXC_UARTUCR3);
+
+ /* Transmit string */
+ uart_console_write(port, s, count, mxcuart_console_write_char);
+
+ /*
+ * Finally, wait for the transmitter to become empty
+ */
+ do {
+ status = readl(port->membase + MXC_UARTUSR2);
+ } while (!(status & MXC_UARTUSR2_TXDC));
+
+ /*
+ * Restore the control registers
+ */
+ writel(oldcr1, port->membase + MXC_UARTUCR1);
+ writel(oldcr2, port->membase + MXC_UARTUCR2);
+ writel(oldcr3, port->membase + MXC_UARTUCR3);
+}
+
+static unsigned int __init probe_baud(struct uart_port *port)
+{
+ /* FIXME Return Default Baud Rate */
+ return 115200;
+}
+
+static int __init mxc_early_uart_setup(struct console *console, char *options)
+{
+ struct mxc_early_uart_device *device = &mxc_early_device;
+ struct uart_port *port = &device->port;
+ int length;
+
+ if (device->port.membase || device->port.iobase)
+ return -ENODEV;
+
+ /* Enable Early MXC UART Clock */
+ clk_enable(device->clk);
+
+ port->uartclk = 5600000;
+ port->iotype = UPIO_MEM;
+ port->membase = ioremap(port->mapbase, SZ_4K);
+
+ if (options) {
+ device->baud = simple_strtoul(options, NULL, 0);
+ length = min(strlen(options), sizeof(device->options));
+ strncpy(device->options, options, length);
+ } else {
+ device->baud = probe_baud(port);
+ snprintf(device->options, sizeof(device->options), "%u",
+ device->baud);
+ }
+ printk(KERN_INFO
+ "MXC_Early serial console at MMIO 0x%x (options '%s')\n",
+ port->mapbase, device->options);
+ return 0;
+}
+
+static struct console mxc_early_uart_console __initdata = {
+ .name = "ttymxc",
+ .write = early_mxcuart_console_write,
+ .setup = mxc_early_uart_setup,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+int __init mxc_early_serial_console_init(unsigned long base, struct clk *clk)
+{
+ mxc_early_device.clk = clk;
+ mxc_early_device.port.mapbase = base;
+
+ register_console(&mxc_early_uart_console);
+ return 0;
+}
+
+int __init mxc_early_uart_console_disable(void)
+{
+ struct mxc_early_uart_device *device = &mxc_early_device;
+ struct uart_port *port = &device->port;
+
+ if (mxc_early_uart_console.index >= 0) {
+ iounmap(port->membase);
+ clk_disable(device->clk);
+ clk_put(device->clk);
+ }
+ return 0;
+}
+late_initcall(mxc_early_uart_console_disable);
diff --git a/drivers/serial/mxc_uart_reg.h b/drivers/serial/mxc_uart_reg.h
new file mode 100644
index 000000000000..dcdcbdb476c1
--- /dev/null
+++ b/drivers/serial/mxc_uart_reg.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MXC_UART_REG_H__
+#define __MXC_UART_REG_H__
+
+/* Address offsets of the UART registers */
+#define MXC_UARTURXD 0x000 /* Receive reg */
+#define MXC_UARTUTXD 0x040 /* Transmitter reg */
+#define MXC_UARTUCR1 0x080 /* Control reg 1 */
+#define MXC_UARTUCR2 0x084 /* Control reg 2 */
+#define MXC_UARTUCR3 0x088 /* Control reg 3 */
+#define MXC_UARTUCR4 0x08C /* Control reg 4 */
+#define MXC_UARTUFCR 0x090 /* FIFO control reg */
+#define MXC_UARTUSR1 0x094 /* Status reg 1 */
+#define MXC_UARTUSR2 0x098 /* Status reg 2 */
+#define MXC_UARTUESC 0x09C /* Escape character reg */
+#define MXC_UARTUTIM 0x0A0 /* Escape timer reg */
+#define MXC_UARTUBIR 0x0A4 /* BRM incremental reg */
+#define MXC_UARTUBMR 0x0A8 /* BRM modulator reg */
+#define MXC_UARTUBRC 0x0AC /* Baud rate count reg */
+#define MXC_UARTONEMS 0x0B0 /* One millisecond reg */
+#define MXC_UARTUTS 0x0B4 /* Test reg */
+
+/* Bit definations of UCR1 */
+#define MXC_UARTUCR1_ADEN 0x8000
+#define MXC_UARTUCR1_ADBR 0x4000
+#define MXC_UARTUCR1_TRDYEN 0x2000
+#define MXC_UARTUCR1_IDEN 0x1000
+#define MXC_UARTUCR1_RRDYEN 0x0200
+#define MXC_UARTUCR1_RXDMAEN 0x0100
+#define MXC_UARTUCR1_IREN 0x0080
+#define MXC_UARTUCR1_TXMPTYEN 0x0040
+#define MXC_UARTUCR1_RTSDEN 0x0020
+#define MXC_UARTUCR1_SNDBRK 0x0010
+#define MXC_UARTUCR1_TXDMAEN 0x0008
+#define MXC_UARTUCR1_ATDMAEN 0x0004
+#define MXC_UARTUCR1_DOZE 0x0002
+#define MXC_UARTUCR1_UARTEN 0x0001
+
+/* Bit definations of UCR2 */
+#define MXC_UARTUCR2_ESCI 0x8000
+#define MXC_UARTUCR2_IRTS 0x4000
+#define MXC_UARTUCR2_CTSC 0x2000
+#define MXC_UARTUCR2_CTS 0x1000
+#define MXC_UARTUCR2_PREN 0x0100
+#define MXC_UARTUCR2_PROE 0x0080
+#define MXC_UARTUCR2_STPB 0x0040
+#define MXC_UARTUCR2_WS 0x0020
+#define MXC_UARTUCR2_RTSEN 0x0010
+#define MXC_UARTUCR2_ATEN 0x0008
+#define MXC_UARTUCR2_TXEN 0x0004
+#define MXC_UARTUCR2_RXEN 0x0002
+#define MXC_UARTUCR2_SRST 0x0001
+
+/* Bit definations of UCR3 */
+#define MXC_UARTUCR3_DTREN 0x2000
+#define MXC_UARTUCR3_PARERREN 0x1000
+#define MXC_UARTUCR3_FRAERREN 0x0800
+#define MXC_UARTUCR3_DSR 0x0400
+#define MXC_UARTUCR3_DCD 0x0200
+#define MXC_UARTUCR3_RI 0x0100
+#define MXC_UARTUCR3_RXDSEN 0x0040
+#define MXC_UARTUCR3_AWAKEN 0x0010
+#define MXC_UARTUCR3_DTRDEN 0x0008
+#define MXC_UARTUCR3_RXDMUXSEL 0x0004
+#define MXC_UARTUCR3_INVT 0x0002
+
+/* Bit definations of UCR4 */
+#define MXC_UARTUCR4_CTSTL_OFFSET 10
+#define MXC_UARTUCR4_CTSTL_MASK (0x3F << 10)
+#define MXC_UARTUCR4_INVR 0x0200
+#define MXC_UARTUCR4_ENIRI 0x0100
+#define MXC_UARTUCR4_REF16 0x0040
+#define MXC_UARTUCR4_IRSC 0x0020
+#define MXC_UARTUCR4_TCEN 0x0008
+#define MXC_UARTUCR4_OREN 0x0002
+#define MXC_UARTUCR4_DREN 0x0001
+
+/* Bit definations of UFCR */
+#define MXC_UARTUFCR_RFDIV 0x0200 /* Ref freq div is set to 2 */
+#define MXC_UARTUFCR_RFDIV_OFFSET 7
+#define MXC_UARTUFCR_RFDIV_MASK (0x7 << 7)
+#define MXC_UARTUFCR_TXTL_OFFSET 10
+#define MXC_UARTUFCR_DCEDTE 0x0040
+
+/* Bit definations of URXD */
+#define MXC_UARTURXD_ERR 0x4000
+#define MXC_UARTURXD_OVRRUN 0x2000
+#define MXC_UARTURXD_FRMERR 0x1000
+#define MXC_UARTURXD_BRK 0x0800
+#define MXC_UARTURXD_PRERR 0x0400
+
+/* Bit definations of USR1 */
+#define MXC_UARTUSR1_PARITYERR 0x8000
+#define MXC_UARTUSR1_RTSS 0x4000
+#define MXC_UARTUSR1_TRDY 0x2000
+#define MXC_UARTUSR1_RTSD 0x1000
+#define MXC_UARTUSR1_FRAMERR 0x0400
+#define MXC_UARTUSR1_RRDY 0x0200
+#define MXC_UARTUSR1_AGTIM 0x0100
+#define MXC_UARTUSR1_DTRD 0x0080
+#define MXC_UARTUSR1_AWAKE 0x0010
+
+/* Bit definations of USR2 */
+#define MXC_UARTUSR2_TXFE 0x4000
+#define MXC_UARTUSR2_IDLE 0x1000
+#define MXC_UARTUSR2_RIDELT 0x0400
+#define MXC_UARTUSR2_RIIN 0x0200
+#define MXC_UARTUSR2_DCDDELT 0x0040
+#define MXC_UARTUSR2_DCDIN 0x0020
+#define MXC_UARTUSR2_TXDC 0x0008
+#define MXC_UARTUSR2_ORE 0x0002
+#define MXC_UARTUSR2_RDR 0x0001
+
+/* Bit definations of UTS */
+#define MXC_UARTUTS_LOOP 0x1000
+
+#endif /* __MXC_UART_REG_H__ */
diff --git a/drivers/serial/mxs-auart.c b/drivers/serial/mxs-auart.c
new file mode 100644
index 000000000000..be79f0e8bf11
--- /dev/null
+++ b/drivers/serial/mxs-auart.c
@@ -0,0 +1,1108 @@
+/*
+ * Freescale STMP37XX/STMP378X Application UART driver
+ *
+ * Author: dmitry pervushin <dimka@embeddedalley.com>
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc.
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
+#include <mach/device.h>
+#include <mach/dmaengine.h>
+
+#include "regs-uartapp.h"
+
+#define MXS_AUART_MAJOR 242
+#define MXS_AUART_RX_THRESHOLD 16
+
+static struct uart_driver auart_driver;
+
+struct mxs_auart_port {
+ struct uart_port port;
+
+ unsigned int flags;
+#define MXS_AUART_PORT_OPEN 0x80000000
+#define MXS_AUART_PORT_DMA_MODE 0x80000000
+ unsigned int ctrl;
+
+ unsigned int irq[3];
+
+ struct clk *clk;
+ struct device *dev;
+ unsigned int dma_rx_chan;
+ unsigned int dma_tx_chan;
+ unsigned int dma_rx_buffer_size;
+ struct list_head rx_done;
+ struct list_head free;
+ struct mxs_dma_desc *tx;
+ struct tasklet_struct rx_task;
+};
+
+static void mxs_auart_stop_tx(struct uart_port *u);
+static void mxs_auart_submit_tx(struct mxs_auart_port *s, int size);
+static void mxs_auart_submit_rx(struct mxs_auart_port *s);
+
+static inline struct mxs_auart_port *to_auart_port(struct uart_port *u)
+{
+ return container_of(u, struct mxs_auart_port, port);
+}
+
+static inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
+{
+ struct circ_buf *xmit = &s->port.state->xmit;
+
+ if (s->flags & MXS_AUART_PORT_DMA_MODE) {
+ int i = 0, size;
+ char *buffer = s->tx->buffer;
+
+ if (mxs_dma_desc_pending(s->tx))
+ return;
+ while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
+ if (i >= PAGE_SIZE)
+ break;
+ if (s->port.x_char) {
+ buffer[i++] = s->port.x_char;
+ s->port.x_char = 0;
+ continue;
+ }
+ size = min_t(u32, PAGE_SIZE - i,
+ CIRC_CNT_TO_END(xmit->head,
+ xmit->tail,
+ UART_XMIT_SIZE));
+ memcpy(buffer + i, xmit->buf + xmit->tail, size);
+ xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+ i += size;
+ }
+ if (i)
+ mxs_auart_submit_tx(s, i);
+ else {
+ if (uart_tx_stopped(&s->port))
+ mxs_auart_stop_tx(&s->port);
+ }
+ return;
+ }
+
+ while (!(__raw_readl(s->port.membase + HW_UARTAPP_STAT) &
+ BM_UARTAPP_STAT_TXFF)) {
+ if (s->port.x_char) {
+ __raw_writel(s->port.x_char,
+ s->port.membase + HW_UARTAPP_DATA);
+ s->port.x_char = 0;
+ continue;
+ }
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
+ __raw_writel(xmit->buf[xmit->tail],
+ s->port.membase + HW_UARTAPP_DATA);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&s->port);
+ } else
+ break;
+ }
+ if (uart_circ_empty(&(s->port.state->xmit)))
+ __raw_writel(BM_UARTAPP_INTR_TXIEN,
+ s->port.membase + HW_UARTAPP_INTR_CLR);
+ else
+ __raw_writel(BM_UARTAPP_INTR_TXIEN,
+ s->port.membase + HW_UARTAPP_INTR_SET);
+
+ if (uart_tx_stopped(&s->port))
+ mxs_auart_stop_tx(&s->port);
+}
+
+static inline unsigned int
+mxs_auart_rx_char(struct mxs_auart_port *s, unsigned int stat, u8 c)
+{
+ int flag;
+
+ flag = TTY_NORMAL;
+ if (stat & BM_UARTAPP_STAT_BERR) {
+ stat &= ~BM_UARTAPP_STAT_BERR;
+ s->port.icount.brk++;
+ if (uart_handle_break(&s->port))
+ return stat;
+ flag = TTY_BREAK;
+ } else if (stat & BM_UARTAPP_STAT_PERR) {
+ stat &= ~BM_UARTAPP_STAT_PERR;
+ s->port.icount.parity++;
+ flag = TTY_PARITY;
+ } else if (stat & BM_UARTAPP_STAT_FERR) {
+ stat &= ~BM_UARTAPP_STAT_FERR;
+ s->port.icount.frame++;
+ flag = TTY_FRAME;
+ }
+
+ if (stat & BM_UARTAPP_STAT_OERR)
+ s->port.icount.overrun++;
+
+ if (uart_handle_sysrq_char(&s->port, c))
+ return stat;
+
+ uart_insert_char(&s->port, stat, BM_UARTAPP_STAT_OERR, c, flag);
+ return stat;
+}
+
+static void mxs_auart_rx_chars(struct mxs_auart_port *s)
+{
+ u8 c;
+ struct tty_struct *tty = s->port.state->port.tty;
+ u32 stat = 0;
+
+ if (s->flags & MXS_AUART_PORT_DMA_MODE) {
+ int i, count;
+ struct list_head *p, *q;
+ LIST_HEAD(list);
+ struct mxs_dma_desc *pdesc;
+ mxs_dma_cooked(s->dma_rx_chan, &list);
+ stat = __raw_readl(s->port.membase + HW_UARTAPP_STAT);
+ list_for_each_safe(p, q, &list) {
+ u8 *buffer;
+ list_del(p);
+ pdesc = list_entry(p, struct mxs_dma_desc, node);
+ count = stat & BM_UARTAPP_STAT_RXCOUNT;
+ buffer = pdesc->buffer;
+ for (i = 0; i < count; i++)
+ stat = mxs_auart_rx_char(s, stat, buffer[i]);
+ list_add(p, &s->free);
+ stat = __raw_readl(s->port.membase + HW_UARTAPP_STAT);
+ }
+ mxs_auart_submit_rx(s);
+ goto out;
+ }
+ for (;;) {
+ stat = __raw_readl(s->port.membase + HW_UARTAPP_STAT);
+ if (stat & BM_UARTAPP_STAT_RXFE)
+ break;
+ c = __raw_readl(s->port.membase + HW_UARTAPP_DATA);
+ stat = mxs_auart_rx_char(s, stat, c);
+ __raw_writel(stat, s->port.membase + HW_UARTAPP_STAT);
+ }
+out:
+ __raw_writel(stat, s->port.membase + HW_UARTAPP_STAT);
+ tty_flip_buffer_push(tty);
+}
+
+/* Allocate and initialize rx and tx DMA chains */
+static int mxs_auart_dma_init(struct mxs_auart_port *s)
+{
+ int ret, i;
+ struct list_head *p, *n;
+ struct mxs_dma_desc *pdesc;
+
+ ret = mxs_dma_request(s->dma_rx_chan, s->dev, dev_name(s->dev));
+ if (ret)
+ goto fail_get_dma_rx;
+ ret = mxs_dma_request(s->dma_tx_chan, s->dev, dev_name(s->dev));
+ if (ret)
+ goto fail_get_dma_tx;
+ ret = -ENOMEM;
+ INIT_LIST_HEAD(&s->rx_done);
+ INIT_LIST_HEAD(&s->free);
+ s->tx = NULL;
+
+
+ for (i = 0; i < 5; i++) {
+ pdesc = mxs_dma_alloc_desc();
+ if (pdesc == NULL || IS_ERR(pdesc))
+ goto fail_alloc_desc;
+
+ if (s->tx == NULL) {
+ pdesc->buffer = dma_alloc_coherent(s->dev, PAGE_SIZE,
+ &pdesc->cmd.address,
+ GFP_DMA);
+ if (pdesc->buffer == NULL)
+ goto fail_alloc_desc;
+ s->tx = pdesc;
+ } else {
+ pdesc->buffer = dma_alloc_coherent(s->dev,
+ s->dma_rx_buffer_size,
+ &pdesc->cmd.address,
+ GFP_DMA);
+ if (pdesc->buffer == NULL)
+ goto fail_alloc_desc;
+ list_add_tail(&pdesc->node, &s->free);
+ }
+ }
+ /*
+ Tell DMA to select UART.
+ Both DMA channels are shared between app UART and IrDA.
+ Target id of 0 means UART, 1 means IrDA
+ */
+ mxs_dma_set_target(s->dma_rx_chan, 0);
+ mxs_dma_set_target(s->dma_tx_chan, 0);
+
+ mxs_dma_enable_irq(s->dma_rx_chan, 1);
+ mxs_dma_enable_irq(s->dma_tx_chan, 1);
+
+ return 0;
+fail_alloc_desc:
+ if (s->tx) {
+ if (s->tx->buffer)
+ dma_free_coherent(s->dev,
+ PAGE_SIZE,
+ s->tx->buffer,
+ s->tx->cmd.address);
+ s->tx->buffer = NULL;
+ mxs_dma_free_desc(s->tx);
+ s->tx = NULL;
+ }
+ list_for_each_safe(p, n, &s->free) {
+ list_del(p);
+ pdesc = list_entry(p, struct mxs_dma_desc, node);
+ if (pdesc->buffer)
+ dma_free_coherent(s->dev,
+ s->dma_rx_buffer_size,
+ pdesc->buffer,
+ pdesc->cmd.address);
+ pdesc->buffer = NULL;
+ mxs_dma_free_desc(pdesc);
+ }
+ mxs_dma_release(s->dma_tx_chan, s->dev);
+fail_get_dma_tx:
+ mxs_dma_release(s->dma_rx_chan, s->dev);
+fail_get_dma_rx:
+ WARN_ON(ret);
+ return ret;
+}
+
+static void mxs_auart_dma_exit(struct mxs_auart_port *s)
+{
+ struct list_head *p, *n;
+ LIST_HEAD(list);
+ struct mxs_dma_desc *pdesc;
+
+ mxs_dma_enable_irq(s->dma_rx_chan, 0);
+ mxs_dma_enable_irq(s->dma_tx_chan, 0);
+
+ mxs_dma_disable(s->dma_tx_chan);
+ mxs_dma_disable(s->dma_rx_chan);
+
+ mxs_dma_get_cooked(s->dma_tx_chan, &list);
+ mxs_dma_get_cooked(s->dma_rx_chan, &s->free);
+
+ mxs_dma_release(s->dma_tx_chan, s->dev);
+ mxs_dma_release(s->dma_rx_chan, s->dev);
+
+ if (s->tx) {
+ if (s->tx->buffer)
+ dma_free_coherent(s->dev,
+ PAGE_SIZE,
+ s->tx->buffer,
+ s->tx->cmd.address);
+ s->tx->buffer = NULL;
+ mxs_dma_free_desc(s->tx);
+ s->tx = NULL;
+ }
+ list_for_each_safe(p, n, &s->free) {
+ list_del(p);
+ pdesc = list_entry(p, struct mxs_dma_desc, node);
+ if (pdesc->buffer)
+ dma_free_coherent(s->dev,
+ s->dma_rx_buffer_size,
+ pdesc->buffer,
+ pdesc->cmd.address);
+ pdesc->buffer = NULL;
+ mxs_dma_free_desc(pdesc);
+ }
+}
+
+static void mxs_auart_submit_rx(struct mxs_auart_port *s)
+{
+ int ret;
+ unsigned int pio_value;
+ struct list_head *p, *n;
+ struct mxs_dma_desc *pdesc;
+
+ pio_value = BM_UARTAPP_CTRL0_RXTO_ENABLE |
+ BF_UARTAPP_CTRL0_RXTIMEOUT(0x80) |
+ BF_UARTAPP_CTRL0_XFER_COUNT(s->dma_rx_buffer_size);
+
+ list_for_each_safe(p, n, &s->free) {
+ list_del(p);
+ pdesc = list_entry(p, struct mxs_dma_desc, node);
+ pdesc->cmd.cmd.bits.bytes = s->dma_rx_buffer_size;
+ pdesc->cmd.cmd.bits.terminate_flush = 1;
+ pdesc->cmd.cmd.bits.pio_words = 1;
+ pdesc->cmd.cmd.bits.wait4end = 1;
+ pdesc->cmd.cmd.bits.dec_sem = 1;
+ pdesc->cmd.cmd.bits.irq = 1;
+ pdesc->cmd.cmd.bits.chain = 1;
+ pdesc->cmd.cmd.bits.command = DMA_WRITE;
+ pdesc->cmd.pio_words[0] = pio_value;
+ ret = mxs_dma_desc_append(s->dma_rx_chan, pdesc);
+ if (ret)
+ pr_info("%s append dma desc, %d\n", __func__, ret);
+ }
+ ret = mxs_dma_enable(s->dma_rx_chan);
+ if (ret)
+ pr_info("%s enable dma desc, %d\n", __func__, ret);
+}
+
+static irqreturn_t mxs_auart_irq_dma_rx(int irq, void *context)
+{
+ struct mxs_auart_port *s = context;
+
+ mxs_dma_ack_irq(s->dma_rx_chan);
+ mxs_auart_rx_chars(s);
+ return IRQ_HANDLED;
+}
+
+static void mxs_auart_submit_tx(struct mxs_auart_port *s, int size)
+{
+ int ret;
+ struct mxs_dma_desc *d = s->tx;
+
+ d->cmd.pio_words[0] = BF_UARTAPP_CTRL1_XFER_COUNT(size);
+ d->cmd.cmd.bits.bytes = size;
+ d->cmd.cmd.bits.pio_words = 1;
+ d->cmd.cmd.bits.wait4end = 1;
+ d->cmd.cmd.bits.dec_sem = 1;
+ d->cmd.cmd.bits.irq = 1;
+ d->cmd.cmd.bits.command = DMA_READ;
+ ret = mxs_dma_desc_append(s->dma_tx_chan, s->tx);
+ if (ret)
+ pr_info("append dma desc, %d\n", ret);
+
+ ret = mxs_dma_enable(s->dma_tx_chan);
+ if (ret)
+ pr_info("enable dma desc, %d\n", ret);
+}
+
+static irqreturn_t mxs_auart_irq_dma_tx(int irq, void *context)
+{
+ struct mxs_auart_port *s = context;
+
+ LIST_HEAD(list);
+ mxs_dma_ack_irq(s->dma_tx_chan);
+ mxs_dma_cooked(s->dma_tx_chan, &list);
+ mxs_auart_tx_chars(s);
+ return IRQ_HANDLED;
+}
+
+static int mxs_auart_request_port(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ if (!request_mem_region((u32)u->mapbase, SZ_4K, dev_name(s->dev)))
+ return -EBUSY;
+ return 0;
+
+}
+
+static int mxs_auart_verify_port(struct uart_port *u,
+ struct serial_struct *ser)
+{
+ if (u->type != PORT_UNKNOWN && u->type != PORT_IMX)
+ return -EINVAL;
+ return 0;
+}
+
+static void mxs_auart_config_port(struct uart_port *u, int flags)
+{
+}
+
+static const char *mxs_auart_type(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ return dev_name(s->dev);
+}
+
+static void mxs_auart_release_port(struct uart_port *u)
+{
+ release_mem_region(u->mapbase, SZ_4K);
+}
+
+static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ u32 ctrl = __raw_readl(u->membase + HW_UARTAPP_CTRL2);
+
+ ctrl &= ~BM_UARTAPP_CTRL2_RTS;
+ if (mctrl & TIOCM_RTS)
+ ctrl |= BM_UARTAPP_CTRL2_RTS;
+ s->ctrl = mctrl;
+ __raw_writel(ctrl, u->membase + HW_UARTAPP_CTRL2);
+}
+
+static u32 mxs_auart_get_mctrl(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+ u32 stat = __raw_readl(u->membase + HW_UARTAPP_STAT);
+ int ctrl2 = __raw_readl(u->membase + HW_UARTAPP_CTRL2);
+ u32 mctrl = s->ctrl;
+
+ mctrl &= ~TIOCM_CTS;
+ if (stat & BM_UARTAPP_STAT_CTS)
+ mctrl |= TIOCM_CTS;
+
+ if (ctrl2 & BM_UARTAPP_CTRL2_RTS)
+ mctrl |= TIOCM_RTS;
+
+ return mctrl;
+}
+
+static void mxs_auart_settermios(struct uart_port *u,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ u32 bm, ctrl, ctrl2, div;
+ unsigned int cflag, baud;
+
+ if (termios == NULL) {
+ printk(KERN_ERR "Empty ktermios setting:!\n");
+ return;
+ }
+
+ cflag = termios->c_cflag;
+
+ ctrl = BM_UARTAPP_LINECTRL_FEN;
+ ctrl2 = __raw_readl(u->membase + HW_UARTAPP_CTRL2);
+
+ /* byte size */
+ switch (cflag & CSIZE) {
+ case CS5:
+ bm = 0;
+ break;
+ case CS6:
+ bm = 1;
+ break;
+ case CS7:
+ bm = 2;
+ break;
+ case CS8:
+ bm = 3;
+ break;
+ default:
+ return;
+ }
+
+ ctrl |= BF_UARTAPP_LINECTRL_WLEN(bm);
+
+ /* parity */
+ if (cflag & PARENB) {
+ ctrl |= BM_UARTAPP_LINECTRL_PEN;
+ if ((cflag & PARODD) == 0)
+ ctrl |= BM_UARTAPP_LINECTRL_EPS;
+ }
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ ctrl |= BM_UARTAPP_LINECTRL_STP2;
+
+ /* figure out the hardware flow control settings */
+ if (cflag & CRTSCTS)
+ ctrl2 |= BM_UARTAPP_CTRL2_CTSEN /* | BM_UARTAPP_CTRL2_RTSEN */ ;
+ else
+ ctrl2 &= ~BM_UARTAPP_CTRL2_CTSEN;
+
+ /* set baud rate */
+ baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
+ div = u->uartclk * 32 / baud;
+ ctrl |= BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
+ ctrl |= BF_UARTAPP_LINECTRL_BAUD_DIVINT(div >> 6);
+
+ if ((cflag & CREAD) != 0)
+ ctrl2 |= BM_UARTAPP_CTRL2_RXE;
+
+ __raw_writel(ctrl, u->membase + HW_UARTAPP_LINECTRL);
+ __raw_writel(ctrl2, u->membase + HW_UARTAPP_CTRL2);
+}
+
+static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
+{
+ u32 istatus, istat;
+ struct mxs_auart_port *s = context;
+ u32 stat = __raw_readl(s->port.membase + HW_UARTAPP_STAT);
+
+ istatus = istat = __raw_readl(s->port.membase + HW_UARTAPP_INTR);
+
+ if (istat & BM_UARTAPP_INTR_CTSMIS) {
+ uart_handle_cts_change(&s->port, stat & BM_UARTAPP_STAT_CTS);
+ __raw_writel(BM_UARTAPP_INTR_CTSMIS,
+ s->port.membase + HW_UARTAPP_INTR_CLR);
+ istat &= ~BM_UARTAPP_INTR_CTSMIS;
+ }
+ if (istat & (BM_UARTAPP_INTR_RTIS | BM_UARTAPP_INTR_RXIS)) {
+ mxs_auart_rx_chars(s);
+ istat &= ~(BM_UARTAPP_INTR_RTIS | BM_UARTAPP_INTR_RXIS);
+ }
+
+ if (istat & BM_UARTAPP_INTR_TXIS) {
+ mxs_auart_tx_chars(s);
+ istat &= ~BM_UARTAPP_INTR_TXIS;
+ }
+ /* modem status interrupt bits are undefined
+ after reset,and the hardware do not support
+ DSRMIS,DCDMIS and RIMIS bit,so we should ingore
+ them when they are pending. */
+ if (istat & (BM_UARTAPP_INTR_ABDIS
+ | BM_UARTAPP_INTR_OEIS
+ | BM_UARTAPP_INTR_BEIS
+ | BM_UARTAPP_INTR_PEIS
+ | BM_UARTAPP_INTR_FEIS
+ | BM_UARTAPP_INTR_RTIS
+ | BM_UARTAPP_INTR_TXIS
+ | BM_UARTAPP_INTR_RXIS
+ | BM_UARTAPP_INTR_CTSMIS)) {
+ dev_info(s->dev, "Unhandled status %x\n", istat);
+ }
+ __raw_writel(istatus & (BM_UARTAPP_INTR_ABDIS
+ | BM_UARTAPP_INTR_OEIS
+ | BM_UARTAPP_INTR_BEIS
+ | BM_UARTAPP_INTR_PEIS
+ | BM_UARTAPP_INTR_FEIS
+ | BM_UARTAPP_INTR_RTIS
+ | BM_UARTAPP_INTR_TXIS
+ | BM_UARTAPP_INTR_RXIS
+ | BM_UARTAPP_INTR_DSRMIS
+ | BM_UARTAPP_INTR_DCDMIS
+ | BM_UARTAPP_INTR_CTSMIS
+ | BM_UARTAPP_INTR_RIMIS),
+ s->port.membase + HW_UARTAPP_INTR_CLR);
+
+ return IRQ_HANDLED;
+}
+
+static int mxs_auart_free_irqs(struct mxs_auart_port *s)
+{
+ int irqn = 0;
+
+ for (irqn = 0; irqn < ARRAY_SIZE(s->irq); irqn++)
+ free_irq(s->irq[irqn], s);
+ return 0;
+}
+
+static int mxs_auart_request_irqs(struct mxs_auart_port *s)
+{
+ int err = 0;
+
+ /*
+ * order counts. resources should be listed in the same order
+ */
+ irq_handler_t handlers[] = {
+ mxs_auart_irq_handle,
+ mxs_auart_irq_dma_rx,
+ mxs_auart_irq_dma_tx,
+ };
+ char *handlers_names[] = {
+ "auart internal",
+ "auart dma rx",
+ "auart dma tx",
+ };
+ int irqn;
+
+ for (irqn = 0; irqn < ARRAY_SIZE(handlers); irqn++) {
+ err = request_irq(s->irq[irqn], handlers[irqn],
+ 0, handlers_names[irqn], s);
+ if (err)
+ goto out;
+ }
+ return 0;
+out:
+ mxs_auart_free_irqs(s);
+ return err;
+}
+
+static inline void mxs_auart_reset(struct uart_port *u)
+{
+ int i;
+ unsigned int reg;
+
+ __raw_writel(BM_UARTAPP_CTRL0_SFTRST,
+ u->membase + HW_UARTAPP_CTRL0_CLR);
+
+ for (i = 0; i < 10000; i++) {
+ reg = __raw_readl(u->membase + HW_UARTAPP_CTRL0);
+ if (!(reg & BM_UARTAPP_CTRL0_SFTRST))
+ break;
+ udelay(3);
+ }
+
+ __raw_writel(BM_UARTAPP_CTRL0_CLKGATE,
+ u->membase + HW_UARTAPP_CTRL0_CLR);
+}
+
+static int mxs_auart_startup(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ mxs_auart_reset(u);
+
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN,
+ s->port.membase + HW_UARTAPP_CTRL2_SET);
+
+ /* Enable the Application UART DMA bits. */
+ if (s->flags & MXS_AUART_PORT_DMA_MODE) {
+ int ret;
+ ret = mxs_auart_dma_init(s);
+ if (ret) {
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN,
+ s->port.membase + HW_UARTAPP_CTRL2_CLR);
+ return ret;
+ }
+ __raw_writel(BM_UARTAPP_CTRL2_TXDMAE | BM_UARTAPP_CTRL2_RXDMAE
+ | BM_UARTAPP_CTRL2_DMAONERR,
+ s->port.membase + HW_UARTAPP_CTRL2_SET);
+ /* clear any pending interrupts */
+ __raw_writel(0, s->port.membase + HW_UARTAPP_INTR);
+
+ /* reset all dma channels */
+ mxs_dma_reset(s->dma_tx_chan);
+ mxs_dma_reset(s->dma_rx_chan);
+ } else
+ __raw_writel(BM_UARTAPP_INTR_RXIEN | BM_UARTAPP_INTR_RTIEN,
+ s->port.membase + HW_UARTAPP_INTR);
+
+ __raw_writel(BM_UARTAPP_INTR_CTSMIEN,
+ s->port.membase + HW_UARTAPP_INTR_SET);
+
+ /*
+ * Enable fifo so all four bytes of a DMA word are written to
+ * output (otherwise, only the LSB is written, ie. 1 in 4 bytes)
+ */
+ __raw_writel(BM_UARTAPP_LINECTRL_FEN,
+ s->port.membase + HW_UARTAPP_LINECTRL_SET);
+
+ if (s->flags & MXS_AUART_PORT_DMA_MODE)
+ mxs_auart_submit_rx(s);
+ return mxs_auart_request_irqs(s);
+}
+
+static void mxs_auart_shutdown(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ __raw_writel(BM_UARTAPP_CTRL0_SFTRST,
+ s->port.membase + HW_UARTAPP_CTRL0_SET);
+
+ if (s->flags & MXS_AUART_PORT_DMA_MODE)
+ mxs_auart_dma_exit(s);
+ else
+ __raw_writel(BM_UARTAPP_INTR_RXIEN | BM_UARTAPP_INTR_RTIEN |
+ BM_UARTAPP_INTR_CTSMIEN,
+ s->port.membase + HW_UARTAPP_INTR_CLR);
+ mxs_auart_free_irqs(s);
+}
+
+static unsigned int mxs_auart_tx_empty(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ if (s->flags & MXS_AUART_PORT_DMA_MODE)
+ return mxs_dma_desc_pending(s->tx) ? 0 : TIOCSER_TEMT;
+
+ if (__raw_readl(u->membase + HW_UARTAPP_STAT) &
+ BM_UARTAPP_STAT_TXFE)
+ return TIOCSER_TEMT;
+ else
+ return 0;
+}
+
+static void mxs_auart_start_tx(struct uart_port *u)
+{
+ struct mxs_auart_port *s = to_auart_port(u);
+
+ /* enable transmitter */
+ __raw_writel(BM_UARTAPP_CTRL2_TXE, u->membase + HW_UARTAPP_CTRL2_SET);
+
+ mxs_auart_tx_chars(s);
+}
+
+static void mxs_auart_stop_tx(struct uart_port *u)
+{
+ __raw_writel(BM_UARTAPP_CTRL2_TXE, u->membase + HW_UARTAPP_CTRL2_CLR);
+}
+
+static void mxs_auart_stop_rx(struct uart_port *u)
+{
+ __raw_writel(BM_UARTAPP_CTRL2_RXE, u->membase + HW_UARTAPP_CTRL2_CLR);
+}
+
+static void mxs_auart_break_ctl(struct uart_port *u, int ctl)
+{
+ if (ctl)
+ __raw_writel(BM_UARTAPP_LINECTRL_BRK,
+ u->membase + HW_UARTAPP_LINECTRL_SET);
+ else
+ __raw_writel(BM_UARTAPP_LINECTRL_BRK,
+ u->membase + HW_UARTAPP_LINECTRL_CLR);
+}
+
+static void mxs_auart_enable_ms(struct uart_port *port)
+{
+ /* just empty */
+}
+
+static struct uart_ops mxs_auart_ops = {
+ .tx_empty = mxs_auart_tx_empty,
+ .start_tx = mxs_auart_start_tx,
+ .stop_tx = mxs_auart_stop_tx,
+ .stop_rx = mxs_auart_stop_rx,
+ .enable_ms = mxs_auart_enable_ms,
+ .break_ctl = mxs_auart_break_ctl,
+ .set_mctrl = mxs_auart_set_mctrl,
+ .get_mctrl = mxs_auart_get_mctrl,
+ .startup = mxs_auart_startup,
+ .shutdown = mxs_auart_shutdown,
+ .set_termios = mxs_auart_settermios,
+ .type = mxs_auart_type,
+ .release_port = mxs_auart_release_port,
+ .request_port = mxs_auart_request_port,
+ .config_port = mxs_auart_config_port,
+ .verify_port = mxs_auart_verify_port,
+};
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+static struct mxs_auart_port auart_port[CONFIG_MXS_AUART_PORTS] = {};
+
+static void
+auart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port;
+ unsigned int status, old_cr;
+ int i;
+
+ if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0)
+ return;
+
+ port = &auart_port[co->index].port;
+
+ /* First save the CR then disable the interrupts */
+ old_cr = __raw_readl(port->membase + HW_UARTAPP_CTRL2);
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN | BM_UARTAPP_CTRL2_TXE,
+ port->membase + HW_UARTAPP_CTRL2_SET);
+
+ /* Now, do each character */
+ for (i = 0; i < count; i++) {
+ do {
+ status = __raw_readl(port->membase + HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_TXFF);
+
+ __raw_writel(s[i], port->membase + HW_UARTAPP_DATA);
+ if (s[i] == '\n') {
+ do {
+ status = __raw_readl(port->membase +
+ HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_TXFF);
+ __raw_writel('\r', port->membase + HW_UARTAPP_DATA);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = __raw_readl(port->membase + HW_UARTAPP_STAT);
+ } while (status & BM_UARTAPP_STAT_BUSY);
+ __raw_writel(old_cr, port->membase + HW_UARTAPP_CTRL2);
+}
+
+static void __init
+auart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (__raw_readl(port->membase + HW_UARTAPP_CTRL2)
+ & BM_UARTAPP_CTRL2_UARTEN) {
+ unsigned int lcr_h, quot;
+ lcr_h = __raw_readl(port->membase + HW_UARTAPP_LINECTRL);
+
+ *parity = 'n';
+ if (lcr_h & BM_UARTAPP_LINECTRL_PEN) {
+ if (lcr_h & BM_UARTAPP_LINECTRL_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((lcr_h & BM_UARTAPP_LINECTRL_WLEN)
+ == BF_UARTAPP_LINECTRL_WLEN(2))
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL)
+ & BM_UARTAPP_LINECTRL_BAUD_DIVINT))
+ >> (BP_UARTAPP_LINECTRL_BAUD_DIVINT - 6))
+ | (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL)
+ & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC))
+ >> BP_UARTAPP_LINECTRL_BAUD_DIVFRAC);
+ if (quot == 0)
+ quot = 1;
+ *baud = (port->uartclk << 2) / quot;
+ }
+}
+
+static int __init auart_console_setup(struct console *co, char *options)
+{
+ struct mxs_auart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ /*
+ * 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 > CONFIG_MXS_AUART_PORTS || co->index < 0)
+ return -EINVAL;
+
+ port = &auart_port[co->index].port;
+
+ if (port->port.membase == 0) {
+ if (cpu_is_mx23()) {
+ if (co->index == 1) {
+ port->port.membase = IO_ADDRESS(0x8006C000);
+ port->port.mapbase = 0x8006C000;
+ } else {
+ port->port.membase = IO_ADDRESS(0x8006E000);
+ port->port.mapbase = 0x8006E000;
+ }
+ }
+
+ port->port.fifosize = 16;
+ port->port.ops = &mxs_auart_ops;
+ port->port.flags = ASYNC_BOOT_AUTOCONF;
+ port->port.line = 0;
+ }
+ mxs_auart_reset(port);
+
+ __raw_writel(BM_UARTAPP_CTRL2_UARTEN,
+ port->port.membase + HW_UARTAPP_CTRL2_SET);
+
+ if (port->clk == NULL || IS_ERR(port->clk)) {
+ port->clk = clk_get(NULL, "uart");
+ if (port->clk == NULL || IS_ERR(port->clk))
+ return -ENODEV;
+ port->port.uartclk = clk_get_rate(port->clk);
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ auart_console_get_options(port, &baud, &parity, &bits);
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console auart_console = {
+ .name = "ttySP",
+ .write = auart_console_write,
+ .device = uart_console_device,
+ .setup = auart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &auart_driver,
+};
+
+#ifdef CONFIG_MXS_EARLY_CONSOLE
+static int __init auart_console_init(void)
+{
+ register_console(&auart_console);
+ return 0;
+}
+
+console_initcall(auart_console_init);
+#endif
+
+#endif
+static struct uart_driver auart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "auart",
+ .dev_name = "ttySP",
+ .major = MXS_AUART_MAJOR,
+ .minor = 0,
+ .nr = CONFIG_MXS_AUART_PORTS,
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+ .cons = &auart_console,
+#endif
+};
+
+static int __devinit mxs_auart_probe(struct platform_device *pdev)
+{
+ struct mxs_auart_plat_data *plat;
+ struct mxs_auart_port *s;
+ u32 version;
+ int i, ret = 0;
+ struct resource *r;
+
+ s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
+ if (!s) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ plat = pdev->dev.platform_data;
+ if (plat == NULL) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ if (plat && plat->clk)
+ s->clk = clk_get(NULL, plat->clk);
+ else
+ s->clk = clk_get(NULL, "uart");
+ if (IS_ERR(s->clk)) {
+ ret = PTR_ERR(s->clk);
+ goto out_free;
+ }
+
+ clk_enable(s->clk);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ ret = -ENXIO;
+ goto out_free_clk;
+ }
+ s->port.mapbase = r->start;
+ s->port.membase = (void __iomem *)IO_ADDRESS(r->start);
+ s->port.ops = &mxs_auart_ops;
+ s->port.iotype = UPIO_MEM;
+ s->port.line = pdev->id < 0 ? 0 : pdev->id;
+ s->port.fifosize = plat->fifo_size;
+ s->port.timeout = plat->timeout ? plat->timeout : (HZ / 10);
+ s->port.uartclk = clk_get_rate(s->clk);
+ s->port.type = PORT_IMX;
+ s->port.dev = s->dev = get_device(&pdev->dev);
+
+ s->flags = plat->dma_mode ? MXS_AUART_PORT_DMA_MODE : 0;
+ s->ctrl = 0;
+ s->dma_rx_buffer_size = plat->dma_rx_buffer_size;
+
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+ s->irq[i] = platform_get_irq(pdev, i);
+ if (s->irq[i] < 0) {
+ ret = s->irq[i];
+ goto out_free_clk;
+ }
+ }
+ s->port.irq = s->irq[0];
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!r) {
+ ret = -ENXIO;
+ goto out_free_clk;
+ }
+ s->dma_rx_chan = r->start;
+
+ r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!r) {
+ ret = -ENXIO;
+ goto out_free_clk;
+ }
+ s->dma_tx_chan = r->start;
+
+ platform_set_drvdata(pdev, s);
+
+ device_init_wakeup(&pdev->dev, 1);
+
+#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
+ memcpy(&auart_port[pdev->id], s, sizeof(struct mxs_auart_port));
+#endif
+
+ ret = uart_add_one_port(&auart_driver, &s->port);
+ if (ret)
+ goto out_free_clk;
+
+ version = __raw_readl(s->port.membase + HW_UARTAPP_VERSION);
+ printk(KERN_INFO "Found APPUART %d.%d.%d\n",
+ (version >> 24) & 0xFF,
+ (version >> 16) & 0xFF, version & 0xFFFF);
+ return 0;
+
+out_free_clk:
+ if (!IS_ERR(s->clk))
+ clk_put(s->clk);
+out_free:
+ kfree(s);
+out:
+ return ret;
+}
+
+static int __devexit mxs_auart_remove(struct platform_device *pdev)
+{
+ struct mxs_auart_port *s;
+
+ s = platform_get_drvdata(pdev);
+ if (s) {
+ put_device(s->dev);
+ clk_disable(s->clk);
+ clk_put(s->clk);
+ uart_remove_one_port(&auart_driver, &s->port);
+ kfree(s);
+ }
+ return 0;
+}
+
+static struct platform_driver mxs_auart_driver = {
+ .probe = mxs_auart_probe,
+ .remove = __devexit_p(mxs_auart_remove),
+ .driver = {
+ .name = "mxs-auart",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mxs_auart_init(void)
+{
+ int r;
+
+ r = uart_register_driver(&auart_driver);
+ if (r)
+ goto out;
+ r = platform_driver_register(&mxs_auart_driver);
+ if (r)
+ goto out_err;
+ return 0;
+out_err:
+ uart_unregister_driver(&auart_driver);
+out:
+ return r;
+}
+
+static void __exit mxs_auart_exit(void)
+{
+ platform_driver_unregister(&mxs_auart_driver);
+ uart_unregister_driver(&auart_driver);
+}
+
+module_init(mxs_auart_init)
+module_exit(mxs_auart_exit)
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Freescale MXS application uart driver");
diff --git a/drivers/serial/mxs-duart.c b/drivers/serial/mxs-duart.c
new file mode 100644
index 000000000000..64e5057344e1
--- /dev/null
+++ b/drivers/serial/mxs-duart.c
@@ -0,0 +1,803 @@
+/*
+ * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#if defined(CONFIG_SERIAL_MXS_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/device.h>
+#include "regs-duart.h"
+
+/* treated as variable unless submitted to open-source */
+#define PORT_DUART 100
+#define SERIAL_DUART_MAJOR 204
+#define SERIAL_DUART_MINOR 16
+#define SERIAL_RX_LIMIT 256
+#define ISR_PASS_LIMIT 256
+
+#define DUART_DEVID "DebugUART"
+
+static int force_cd = 1;
+static struct uart_driver duart_drv;
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct duart_port {
+ struct uart_port port;
+ struct clk *clk;
+ unsigned int im; /* interrupt mask */
+ unsigned int old_status;
+ int suspended;
+};
+
+static void duart_stop_tx(struct uart_port *port)
+{
+ struct duart_port *dp = container_of(port, struct duart_port, port);
+
+ dp->im &= ~BM_UARTDBGIMSC_TXIM;
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+}
+
+static void duart_start_tx(struct uart_port *port)
+{
+ struct duart_port *dp = container_of(port, struct duart_port, port);
+
+ dp->im |= BM_UARTDBGIMSC_TXIM;
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+}
+
+static void duart_stop_rx(struct uart_port *port)
+{
+ struct duart_port *dp = container_of(port, struct duart_port, port);
+
+ dp->im &= ~(BM_UARTDBGIMSC_OEIM | BM_UARTDBGIMSC_BEIM |
+ BM_UARTDBGIMSC_PEIM | BM_UARTDBGIMSC_FEIM |
+ BM_UARTDBGIMSC_RTIM | BM_UARTDBGIMSC_RXIM);
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+}
+
+static void duart_enable_ms(struct uart_port *port)
+{
+ struct duart_port *dp = container_of(port, struct duart_port, port);
+
+ dp->im |= BM_UARTDBGIMSC_RIMIM | BM_UARTDBGIMSC_CTSMIM |
+ BM_UARTDBGIMSC_DCDMIM | BM_UARTDBGIMSC_DSRMIM;
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+}
+
+static void duart_rx_chars(struct duart_port *dp)
+{
+ struct tty_struct *tty = dp->port.state->port.tty;
+ unsigned int status, ch, flag, rsr, max_count = SERIAL_RX_LIMIT;
+
+ status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
+ while ((status & BM_UARTDBGFR_RXFE) == 0 && max_count--) {
+ ch = __raw_readl(dp->port.membase + HW_UARTDBGDR);
+ flag = TTY_NORMAL;
+ dp->port.icount.rx++;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ rsr = __raw_readl(dp->port.membase + HW_UARTDBGRSR_ECR);
+ if (unlikely(rsr & (BM_UARTDBGRSR_ECR_OE |
+ BM_UARTDBGRSR_ECR_BE |
+ BM_UARTDBGRSR_ECR_PE |
+ BM_UARTDBGRSR_ECR_FE))) {
+ if (rsr & BM_UARTDBGRSR_ECR_BE) {
+ rsr &= ~(BM_UARTDBGRSR_ECR_FE |
+ BM_UARTDBGRSR_ECR_PE);
+ dp->port.icount.brk++;
+ if (uart_handle_break(&dp->port))
+ goto ignore_char;
+ } else if (rsr & BM_UARTDBGRSR_ECR_PE)
+ dp->port.icount.parity++;
+ else if (rsr & BM_UARTDBGRSR_ECR_FE)
+ dp->port.icount.frame++;
+ if (rsr & BM_UARTDBGRSR_ECR_OE)
+ dp->port.icount.overrun++;
+
+ rsr &= dp->port.read_status_mask;
+
+ if (rsr & BM_UARTDBGRSR_ECR_BE)
+ flag = TTY_BREAK;
+ else if (rsr & BM_UARTDBGRSR_ECR_PE)
+ flag = TTY_PARITY;
+ else if (rsr & BM_UARTDBGRSR_ECR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(&dp->port, ch))
+ goto ignore_char;
+
+ uart_insert_char(&dp->port, rsr, BM_UARTDBGRSR_ECR_OE, ch,
+ flag);
+
+ignore_char:
+ status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
+ }
+ tty_flip_buffer_push(tty);
+ return;
+}
+
+static void duart_tx_chars(struct duart_port *dp)
+{
+ int count;
+ struct circ_buf *xmit = &dp->port.state->xmit;
+
+ if (dp->port.x_char) {
+ __raw_writel(dp->port.x_char, dp->port.membase + HW_UARTDBGDR);
+ dp->port.icount.tx++;
+ dp->port.x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&dp->port)) {
+ duart_stop_tx(&dp->port);
+ return;
+ }
+
+ count = dp->port.fifosize >> 1;
+ do {
+ __raw_writel(xmit->buf[xmit->tail],
+ dp->port.membase + HW_UARTDBGDR);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ dp->port.icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&dp->port);
+
+ if (uart_circ_empty(xmit))
+ duart_stop_tx(&dp->port);
+}
+
+static void duart_modem_status(struct duart_port *dp)
+{
+ unsigned int status, delta;
+ status = __raw_readl(dp->port.membase + HW_UARTDBGFR) &
+ (BM_UARTDBGFR_DCD | BM_UARTDBGFR_DSR | BM_UARTDBGFR_CTS);
+
+ delta = status ^ dp->old_status;
+ dp->old_status = status;
+
+ if (!delta)
+ return;
+
+ if (delta & BM_UARTDBGFR_DCD)
+ uart_handle_dcd_change(&dp->port, status & BM_UARTDBGFR_DCD);
+
+ if (delta & BM_UARTDBGFR_DSR)
+ dp->port.icount.dsr++;
+
+ if (delta & BM_UARTDBGFR_CTS)
+ uart_handle_cts_change(&dp->port, status & BM_UARTDBGFR_CTS);
+
+ wake_up_interruptible(&dp->port.state->port.delta_msr_wait);
+}
+
+static irqreturn_t duart_int(int irq, void *dev_id)
+{
+ int handled = 0;
+ struct duart_port *dp = dev_id;
+ unsigned int status, pass_counter = ISR_PASS_LIMIT;
+
+ spin_lock(&dp->port.lock);
+
+ status = __raw_readl(dp->port.membase + HW_UARTDBGMIS);
+ while (status) {
+ handled = 1;
+
+ __raw_writel(status & ~(BM_UARTDBGMIS_TXMIS |
+ BM_UARTDBGMIS_RTMIS |
+ BM_UARTDBGMIS_RXMIS),
+ dp->port.membase + HW_UARTDBGICR);
+
+ if (status & (BM_UARTDBGMIS_RTMIS | BM_UARTDBGMIS_RXMIS))
+ duart_rx_chars(dp);
+ if (status & (BM_UARTDBGMIS_DSRMMIS |
+ BM_UARTDBGMIS_DCDMMIS |
+ BM_UARTDBGMIS_CTSMMIS | BM_UARTDBGMIS_RIMMIS))
+ duart_modem_status(dp);
+ if (status & BM_UARTDBGMIS_TXMIS)
+ duart_tx_chars(dp);
+
+ if (pass_counter-- == 0)
+ break;
+
+ status = __raw_readl(dp->port.membase + HW_UARTDBGMIS);
+ };
+
+ spin_unlock(&dp->port.lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int duart_tx_empty(struct uart_port *port)
+{
+ struct duart_port *dp = (struct duart_port *)port;
+ unsigned int status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
+ return status & (BM_UARTDBGFR_BUSY | BM_UARTDBGFR_TXFF) ?
+ 0 : TIOCSER_TEMT;
+}
+
+static unsigned int duart_get_mctrl(struct uart_port *port)
+{
+ unsigned int result = 0;
+ struct duart_port *dp = (struct duart_port *)port;
+ unsigned int status = __raw_readl(dp->port.membase + HW_UARTDBGFR);
+
+#define TEST_AND_SET_BIT(uartbit, tiocmbit) do { \
+ if (status & uartbit) \
+ result |= tiocmbit; \
+ } while (0)
+
+ TEST_AND_SET_BIT(BM_UARTDBGFR_DCD, TIOCM_CAR);
+ TEST_AND_SET_BIT(BM_UARTDBGFR_DSR, TIOCM_DSR);
+ TEST_AND_SET_BIT(BM_UARTDBGFR_CTS, TIOCM_CTS);
+ TEST_AND_SET_BIT(BM_UARTDBGFR_RI, TIOCM_RNG);
+#undef TEST_AND_SET_BIT
+ if (force_cd)
+ result |= TIOCM_CAR;
+ return result;
+}
+
+static void duart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ unsigned int cr;
+ struct duart_port *dp = (struct duart_port *)port;
+
+ cr = __raw_readl(dp->port.membase + HW_UARTDBGCR);
+
+#define TEST_AND_SET_BIT(tiocmbit, uartbit) do { \
+ if (mctrl & tiocmbit) \
+ cr |= uartbit; \
+ else \
+ cr &= ~uartbit; \
+ } while (0)
+
+ TEST_AND_SET_BIT(TIOCM_RTS, BM_UARTDBGCR_RTS);
+ TEST_AND_SET_BIT(TIOCM_DTR, BM_UARTDBGCR_DTR);
+ TEST_AND_SET_BIT(TIOCM_OUT1, BM_UARTDBGCR_OUT1);
+ TEST_AND_SET_BIT(TIOCM_OUT2, BM_UARTDBGCR_OUT2);
+ TEST_AND_SET_BIT(TIOCM_LOOP, BM_UARTDBGCR_LBE);
+#undef TEST_AND_SET_BIT
+
+ __raw_writel(cr, dp->port.membase + HW_UARTDBGCR);
+}
+
+static void duart_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+ unsigned int lcr_h;
+ struct duart_port *dp = (struct duart_port *)port;
+
+ spin_lock_irqsave(&dp->port.lock, flags);
+ lcr_h = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
+ if (break_state == -1)
+ lcr_h |= BM_UARTDBGLCR_H_BRK;
+ else
+ lcr_h &= ~BM_UARTDBGLCR_H_BRK;
+ __raw_writel(lcr_h, dp->port.membase + HW_UARTDBGLCR_H);
+ spin_unlock_irqrestore(&dp->port.lock, flags);
+}
+
+static int duart_startup(struct uart_port *port)
+{
+ u32 cr, lcr;
+ int retval;
+ struct duart_port *dp = (struct duart_port *)port;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(dp->port.irq, duart_int, 0, DUART_DEVID, dp);
+ if (retval)
+ return retval;
+
+ /* wake up the UART */
+ __raw_writel(0, dp->port.membase + HW_UARTDBGDR);
+
+ __raw_writel(BF_UARTDBGIFLS_TXIFLSEL(BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF)
+ |
+ BF_UARTDBGIFLS_RXIFLSEL(BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF),
+ dp->port.membase + HW_UARTDBGIFLS);
+
+ /*
+ * Provoke TX FIFO interrupt into asserting.
+ */
+ cr = BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_RXE | BM_UARTDBGCR_TXE;
+ __raw_writel(cr, dp->port.membase + HW_UARTDBGCR);
+
+ lcr = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
+ lcr |= BM_UARTDBGLCR_H_FEN;
+ __raw_writel(lcr, dp->port.membase + HW_UARTDBGLCR_H);
+
+ /*
+ * initialise the old status of the modem signals
+ */
+ dp->old_status = __raw_readl(dp->port.membase + HW_UARTDBGFR) &
+ (BM_UARTDBGFR_DCD | BM_UARTDBGFR_DSR | BM_UARTDBGFR_CTS);
+ /*
+ * Finally, enable interrupts
+ */
+ dp->im = BM_UARTDBGIMSC_RXIM | BM_UARTDBGIMSC_RTIM;
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+
+ return 0;
+}
+
+static void duart_shutdown(struct uart_port *port)
+{
+ unsigned long flags;
+ unsigned int val;
+ struct duart_port *dp = (struct duart_port *)port;
+
+ /*
+ * disable all interrupts
+ */
+ spin_lock_irqsave(&dp->port.lock, flags);
+ dp->im = 0;
+ __raw_writel(dp->im, dp->port.membase + HW_UARTDBGIMSC);
+ __raw_writel(0xffff, dp->port.membase + HW_UARTDBGICR);
+ spin_unlock_irqrestore(&dp->port.lock, flags);
+
+ free_irq(dp->port.irq, dp);
+
+ /*
+ * disable the port
+ */
+ __raw_writel(BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_TXE,
+ dp->port.membase + HW_UARTDBGCR);
+ /*
+ * disable break condition and fifos
+ */
+ val = __raw_readl(dp->port.membase + HW_UARTDBGLCR_H);
+ val &= ~(BM_UARTDBGLCR_H_BRK | BM_UARTDBGLCR_H_FEN);
+ __raw_writel(val, dp->port.membase + HW_UARTDBGLCR_H);
+}
+
+static void
+duart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int lcr_h, old_cr;
+ unsigned long flags;
+ unsigned int baud, quot;
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
+ quot = (port->uartclk << 2) / baud;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr_h = BF_UARTDBGLCR_H_WLEN(0);
+ break;
+ case CS6:
+ lcr_h = BF_UARTDBGLCR_H_WLEN(1);
+ break;
+ case CS7:
+ lcr_h = BF_UARTDBGLCR_H_WLEN(2);
+ break;
+ default: /* CS8 */
+ lcr_h = BF_UARTDBGLCR_H_WLEN(3);
+ break;
+ }
+ if (termios->c_cflag & CSTOPB)
+ lcr_h |= BM_UARTDBGLCR_H_STP2;
+ if (termios->c_cflag & PARENB) {
+ lcr_h |= BM_UARTDBGLCR_H_PEN;
+ if (!(termios->c_cflag & PARODD))
+ lcr_h |= BM_UARTDBGLCR_H_EPS;
+ }
+ lcr_h |= BM_UARTDBGLCR_H_FEN;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /*
+ * Update the per-port timeout.
+ */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ port->read_status_mask = BM_UARTDBGRSR_ECR_OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= BM_UARTDBGRSR_ECR_FE |
+ BM_UARTDBGRSR_ECR_PE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= BM_UARTDBGRSR_ECR_BE;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= BM_UARTDBGRSR_ECR_FE |
+ BM_UARTDBGRSR_ECR_PE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= BM_UARTDBGRSR_ECR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= BM_UARTDBGRSR_ECR_OE;
+ }
+
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ duart_enable_ms(port);
+
+ /* first, disable everything */
+ old_cr = __raw_readl(port->membase + HW_UARTDBGCR);
+ __raw_writel(0, port->membase + HW_UARTDBGCR);
+
+ /* Set baud rate */
+ __raw_writel(quot & 0x3f, port->membase + HW_UARTDBGFBRD);
+ __raw_writel(quot >> 6, port->membase + HW_UARTDBGIBRD);
+ /*
+ * ----------v----------v----------v----------v-----
+ * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+ * ----------^----------^----------^----------^-----
+ */
+ __raw_writel(lcr_h, port->membase + HW_UARTDBGLCR_H);
+ __raw_writel(old_cr, port->membase + HW_UARTDBGCR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *duart_type(struct uart_port *port)
+{
+ return port->type == PORT_DUART ? DUART_DEVID : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void duart_release_port(struct uart_port *port)
+{
+ release_mem_region(port->mapbase, PAGE_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int duart_request_port(struct uart_port *port)
+{
+ return request_mem_region(port->mapbase, PAGE_SIZE, DUART_DEVID)
+ != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void duart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_DUART;
+ duart_request_port(port);
+ }
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int duart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_DUART)
+ ret = -EINVAL;
+ if (ser->irq < 0 || ser->irq >= NR_IRQS)
+ ret = -EINVAL;
+ if (ser->baud_base < 9600)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops duart_pops = {
+ .tx_empty = duart_tx_empty,
+ .set_mctrl = duart_set_mctrl,
+ .get_mctrl = duart_get_mctrl,
+ .stop_tx = duart_stop_tx,
+ .start_tx = duart_start_tx,
+ .stop_rx = duart_stop_rx,
+ .enable_ms = duart_enable_ms,
+ .break_ctl = duart_break_ctl,
+ .startup = duart_startup,
+ .shutdown = duart_shutdown,
+ .set_termios = duart_set_termios,
+ .type = duart_type,
+ .release_port = duart_release_port,
+ .request_port = duart_request_port,
+ .config_port = duart_config_port,
+ .verify_port = duart_verify_port,
+};
+
+static struct duart_port duart_port = {
+ .port = {
+ .iotype = SERIAL_IO_MEM,
+#ifdef CONFIG_MXS_EARLY_CONSOLE
+ .membase = MXS_DEBUG_CONSOLE_VIRT,
+ .mapbase = MXS_DEBUG_CONSOLE_PHYS,
+#endif
+ .fifosize = 16,
+ .ops = &duart_pops,
+ .flags = ASYNC_BOOT_AUTOCONF,
+ .line = 0,
+ },
+};
+
+#ifdef CONFIG_SERIAL_MXS_DUART_CONSOLE
+
+static void
+duart_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_port *port = &duart_port.port;
+ unsigned int status, old_cr;
+ int i;
+ /*
+ * First save the CR then disable the interrupts
+ */
+ old_cr = __raw_readl(port->membase + HW_UARTDBGCR);
+ __raw_writel(BM_UARTDBGCR_UARTEN | BM_UARTDBGCR_TXE,
+ port->membase + HW_UARTDBGCR);
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = __raw_readl(port->membase + HW_UARTDBGFR);
+ } while (status & BM_UARTDBGFR_TXFF);
+
+ __raw_writel(s[i], port->membase + HW_UARTDBGDR);
+ if (s[i] == '\n') {
+ do {
+ status = __raw_readl(port->membase +
+ HW_UARTDBGFR);
+ } while (status & BM_UARTDBGFR_TXFF);
+ __raw_writel('\r', port->membase + HW_UARTDBGDR);
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = __raw_readl(port->membase + HW_UARTDBGFR);
+ } while (status & BM_UARTDBGFR_BUSY);
+ __raw_writel(old_cr, port->membase + HW_UARTDBGCR);
+}
+
+static void __init
+duart_console_get_options(struct uart_port *port, int *baud,
+ int *parity, int *bits)
+{
+ if (__raw_readl(port->membase + HW_UARTDBGCR) & BM_UARTDBGCR_UARTEN) {
+ unsigned int lcr_h, quot;
+ lcr_h = __raw_readl(port->membase + HW_UARTDBGLCR_H);
+
+ *parity = 'n';
+ if (lcr_h & BM_UARTDBGLCR_H_PEN) {
+ if (lcr_h & BM_UARTDBGLCR_H_EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+
+ if ((lcr_h & BM_UARTDBGLCR_H_WLEN) == BF_UARTDBGLCR_H_WLEN(2))
+ *bits = 7;
+ else
+ *bits = 8;
+
+ quot = (__raw_readl(port->membase + HW_UARTDBGFBRD) & 0x3F) |
+ __raw_readl(port->membase + HW_UARTDBGIBRD) << 6;
+ if (quot == 0)
+ quot = 1;
+ *baud = (port->uartclk << 2) / quot;
+ }
+}
+
+static int __init duart_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ /*
+ * 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)
+ return -EINVAL;
+
+ port = &duart_port.port;
+
+ if (duart_port.clk == NULL || IS_ERR(duart_port.clk)) {
+ duart_port.clk = clk_get(NULL, "uart");
+ if (duart_port.clk == NULL || IS_ERR(duart_port.clk))
+ return -ENODEV;
+ duart_port.port.uartclk = clk_get_rate(duart_port.clk);
+ }
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ duart_console_get_options(port, &baud, &parity, &bits);
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console duart_console = {
+ .name = "ttyAM",
+ .write = duart_console_write,
+ .device = uart_console_device,
+ .setup = duart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &duart_drv,
+};
+
+#ifdef CONFIG_MXS_EARLY_CONSOLE
+static int __init duart_console_init(void)
+{
+ register_console(&duart_console);
+ return 0;
+}
+
+console_initcall(duart_console_init);
+#endif
+
+#endif
+
+static struct uart_driver duart_drv = {
+ .owner = THIS_MODULE,
+ .driver_name = "ttyAM",
+ .dev_name = "ttyAM",
+ .major = SERIAL_DUART_MAJOR,
+ .minor = SERIAL_DUART_MINOR,
+ .nr = 1,
+#ifdef CONFIG_SERIAL_MXS_DUART_CONSOLE
+ .cons = &duart_console,
+#endif
+};
+
+static int __devinit duart_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+ /*
+ * Will use mapbase and membase here if !CONFIG_MXS_EARLY_CONSOLE,
+ * or use the overridden values later if CONFIG_MXS_EARLY_CONSOLE
+ */
+ duart_port.port.mapbase = res->start;
+ duart_port.port.membase =
+ (unsigned char __iomem *)IO_ADDRESS(res->start);
+
+ duart_port.port.irq = platform_get_irq(pdev, 0);
+ if (duart_port.port.irq < 0)
+ return -EINVAL;
+ device_init_wakeup(&pdev->dev, 1);
+
+ duart_port.clk = clk_get(NULL, "uart");
+ if (duart_port.clk == NULL || IS_ERR(duart_port.clk))
+ return -ENODEV;
+ duart_port.suspended = 0;
+ duart_port.port.dev = &pdev->dev;
+ duart_port.port.uartclk = clk_get_rate(duart_port.clk);
+ uart_add_one_port(&duart_drv, &duart_port.port);
+ return 0;
+}
+
+static int __devexit duart_remove(struct platform_device *pdev)
+{
+ clk_put(duart_port.clk);
+ uart_remove_one_port(&duart_drv, &duart_port.port);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int duart_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret = 0;
+ if (!duart_port.suspended) {
+ ret = uart_suspend_port(&duart_drv, &duart_port.port);
+ if (!ret)
+ duart_port.suspended = 1;
+ }
+ return ret;
+}
+
+static int duart_resume(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret = 0;
+ if (duart_port.suspended) {
+ ret = uart_resume_port(&duart_drv, &duart_port.port);
+ if (!ret)
+ duart_port.suspended = 0;
+ }
+ return ret;
+}
+#else
+#define duart_suspend NULL
+#define duart_resume NULL
+#endif
+
+static struct platform_driver duart_driver = {
+ .probe = duart_probe,
+ .remove = __devexit_p(duart_remove),
+ .suspend = duart_suspend,
+ .resume = duart_resume,
+ .driver = {
+ .name = "mxs-duart",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init duart_init(void)
+{
+ int ret;
+ ret = uart_register_driver(&duart_drv);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&duart_driver);
+ if (ret)
+ uart_unregister_driver(&duart_drv);
+
+ return ret;
+}
+
+static void __exit duart_exit(void)
+{
+ platform_driver_unregister(&duart_driver);
+ uart_unregister_driver(&duart_drv);
+}
+
+module_init(duart_init);
+module_exit(duart_exit);
+module_param(force_cd, int, 0644);
+MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd/Freescale Inc");
+MODULE_DESCRIPTION("i.MXS debug uart");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/regs-duart.h b/drivers/serial/regs-duart.h
new file mode 100644
index 000000000000..0b5932c79a55
--- /dev/null
+++ b/drivers/serial/regs-duart.h
@@ -0,0 +1,301 @@
+/*
+ * Freescale UARTDBG Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.21
+ * Template revision: 26195
+ */
+
+#ifndef __ARCH_ARM___UARTDBG_H
+#define __ARCH_ARM___UARTDBG_H
+
+
+#define HW_UARTDBGDR (0x00000000)
+
+#define BP_UARTDBGDR_UNAVAILABLE 16
+#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDR_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
+#define BP_UARTDBGDR_RESERVED 12
+#define BM_UARTDBGDR_RESERVED 0x0000F000
+#define BF_UARTDBGDR_RESERVED(v) \
+ (((v) << 12) & BM_UARTDBGDR_RESERVED)
+#define BM_UARTDBGDR_OE 0x00000800
+#define BM_UARTDBGDR_BE 0x00000400
+#define BM_UARTDBGDR_PE 0x00000200
+#define BM_UARTDBGDR_FE 0x00000100
+#define BP_UARTDBGDR_DATA 0
+#define BM_UARTDBGDR_DATA 0x000000FF
+#define BF_UARTDBGDR_DATA(v) \
+ (((v) << 0) & BM_UARTDBGDR_DATA)
+
+#define HW_UARTDBGRSR_ECR (0x00000004)
+
+#define BP_UARTDBGRSR_ECR_UNAVAILABLE 8
+#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
+ (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
+#define BP_UARTDBGRSR_ECR_EC 4
+#define BM_UARTDBGRSR_ECR_EC 0x000000F0
+#define BF_UARTDBGRSR_ECR_EC(v) \
+ (((v) << 4) & BM_UARTDBGRSR_ECR_EC)
+#define BM_UARTDBGRSR_ECR_OE 0x00000008
+#define BM_UARTDBGRSR_ECR_BE 0x00000004
+#define BM_UARTDBGRSR_ECR_PE 0x00000002
+#define BM_UARTDBGRSR_ECR_FE 0x00000001
+
+#define HW_UARTDBGFR (0x00000018)
+
+#define BP_UARTDBGFR_UNAVAILABLE 16
+#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGFR_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
+#define BP_UARTDBGFR_RESERVED 9
+#define BM_UARTDBGFR_RESERVED 0x0000FE00
+#define BF_UARTDBGFR_RESERVED(v) \
+ (((v) << 9) & BM_UARTDBGFR_RESERVED)
+#define BM_UARTDBGFR_RI 0x00000100
+#define BM_UARTDBGFR_TXFE 0x00000080
+#define BM_UARTDBGFR_RXFF 0x00000040
+#define BM_UARTDBGFR_TXFF 0x00000020
+#define BM_UARTDBGFR_RXFE 0x00000010
+#define BM_UARTDBGFR_BUSY 0x00000008
+#define BM_UARTDBGFR_DCD 0x00000004
+#define BM_UARTDBGFR_DSR 0x00000002
+#define BM_UARTDBGFR_CTS 0x00000001
+
+#define HW_UARTDBGILPR (0x00000020)
+
+#define BP_UARTDBGILPR_UNAVAILABLE 8
+#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGILPR_UNAVAILABLE(v) \
+ (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
+#define BP_UARTDBGILPR_ILPDVSR 0
+#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
+#define BF_UARTDBGILPR_ILPDVSR(v) \
+ (((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
+
+#define HW_UARTDBGIBRD (0x00000024)
+
+#define BP_UARTDBGIBRD_UNAVAILABLE 16
+#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
+#define BP_UARTDBGIBRD_BAUD_DIVINT 0
+#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
+#define BF_UARTDBGIBRD_BAUD_DIVINT(v) \
+ (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
+
+#define HW_UARTDBGFBRD (0x00000028)
+
+#define BP_UARTDBGFBRD_UNAVAILABLE 8
+#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
+#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
+ (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
+#define BP_UARTDBGFBRD_RESERVED 6
+#define BM_UARTDBGFBRD_RESERVED 0x000000C0
+#define BF_UARTDBGFBRD_RESERVED(v) \
+ (((v) << 6) & BM_UARTDBGFBRD_RESERVED)
+#define BP_UARTDBGFBRD_BAUD_DIVFRAC 0
+#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
+#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v) \
+ (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
+
+#define HW_UARTDBGLCR_H (0x0000002c)
+
+#define BP_UARTDBGLCR_H_UNAVAILABLE 16
+#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
+#define BP_UARTDBGLCR_H_RESERVED 8
+#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
+#define BF_UARTDBGLCR_H_RESERVED(v) \
+ (((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
+#define BM_UARTDBGLCR_H_SPS 0x00000080
+#define BP_UARTDBGLCR_H_WLEN 5
+#define BM_UARTDBGLCR_H_WLEN 0x00000060
+#define BF_UARTDBGLCR_H_WLEN(v) \
+ (((v) << 5) & BM_UARTDBGLCR_H_WLEN)
+#define BM_UARTDBGLCR_H_FEN 0x00000010
+#define BM_UARTDBGLCR_H_STP2 0x00000008
+#define BM_UARTDBGLCR_H_EPS 0x00000004
+#define BM_UARTDBGLCR_H_PEN 0x00000002
+#define BM_UARTDBGLCR_H_BRK 0x00000001
+
+#define HW_UARTDBGCR (0x00000030)
+
+#define BP_UARTDBGCR_UNAVAILABLE 16
+#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGCR_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
+#define BM_UARTDBGCR_CTSEN 0x00008000
+#define BM_UARTDBGCR_RTSEN 0x00004000
+#define BM_UARTDBGCR_OUT2 0x00002000
+#define BM_UARTDBGCR_OUT1 0x00001000
+#define BM_UARTDBGCR_RTS 0x00000800
+#define BM_UARTDBGCR_DTR 0x00000400
+#define BM_UARTDBGCR_RXE 0x00000200
+#define BM_UARTDBGCR_TXE 0x00000100
+#define BM_UARTDBGCR_LBE 0x00000080
+#define BP_UARTDBGCR_RESERVED 3
+#define BM_UARTDBGCR_RESERVED 0x00000078
+#define BF_UARTDBGCR_RESERVED(v) \
+ (((v) << 3) & BM_UARTDBGCR_RESERVED)
+#define BM_UARTDBGCR_SIRLP 0x00000004
+#define BM_UARTDBGCR_SIREN 0x00000002
+#define BM_UARTDBGCR_UARTEN 0x00000001
+
+#define HW_UARTDBGIFLS (0x00000034)
+
+#define BP_UARTDBGIFLS_UNAVAILABLE 16
+#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
+#define BP_UARTDBGIFLS_RESERVED 6
+#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
+#define BF_UARTDBGIFLS_RESERVED(v) \
+ (((v) << 6) & BM_UARTDBGIFLS_RESERVED)
+#define BP_UARTDBGIFLS_RXIFLSEL 3
+#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
+#define BF_UARTDBGIFLS_RXIFLSEL(v) \
+ (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_EIGHT 0x0
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER 0x1
+#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF 0x2
+#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS 0x4
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5 0x5
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6 0x6
+#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7 0x7
+#define BP_UARTDBGIFLS_TXIFLSEL 0
+#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
+#define BF_UARTDBGIFLS_TXIFLSEL(v) \
+ (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_EIGHT 0x0
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER 0x1
+#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF 0x2
+#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS 0x4
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5 0x5
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6 0x6
+#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7 0x7
+
+#define HW_UARTDBGIMSC (0x00000038)
+
+#define BP_UARTDBGIMSC_UNAVAILABLE 16
+#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
+#define BP_UARTDBGIMSC_RESERVED 11
+#define BM_UARTDBGIMSC_RESERVED 0x0000F800
+#define BF_UARTDBGIMSC_RESERVED(v) \
+ (((v) << 11) & BM_UARTDBGIMSC_RESERVED)
+#define BM_UARTDBGIMSC_OEIM 0x00000400
+#define BM_UARTDBGIMSC_BEIM 0x00000200
+#define BM_UARTDBGIMSC_PEIM 0x00000100
+#define BM_UARTDBGIMSC_FEIM 0x00000080
+#define BM_UARTDBGIMSC_RTIM 0x00000040
+#define BM_UARTDBGIMSC_TXIM 0x00000020
+#define BM_UARTDBGIMSC_RXIM 0x00000010
+#define BM_UARTDBGIMSC_DSRMIM 0x00000008
+#define BM_UARTDBGIMSC_DCDMIM 0x00000004
+#define BM_UARTDBGIMSC_CTSMIM 0x00000002
+#define BM_UARTDBGIMSC_RIMIM 0x00000001
+
+#define HW_UARTDBGRIS (0x0000003c)
+
+#define BP_UARTDBGRIS_UNAVAILABLE 16
+#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGRIS_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
+#define BP_UARTDBGRIS_RESERVED 11
+#define BM_UARTDBGRIS_RESERVED 0x0000F800
+#define BF_UARTDBGRIS_RESERVED(v) \
+ (((v) << 11) & BM_UARTDBGRIS_RESERVED)
+#define BM_UARTDBGRIS_OERIS 0x00000400
+#define BM_UARTDBGRIS_BERIS 0x00000200
+#define BM_UARTDBGRIS_PERIS 0x00000100
+#define BM_UARTDBGRIS_FERIS 0x00000080
+#define BM_UARTDBGRIS_RTRIS 0x00000040
+#define BM_UARTDBGRIS_TXRIS 0x00000020
+#define BM_UARTDBGRIS_RXRIS 0x00000010
+#define BM_UARTDBGRIS_DSRRMIS 0x00000008
+#define BM_UARTDBGRIS_DCDRMIS 0x00000004
+#define BM_UARTDBGRIS_CTSRMIS 0x00000002
+#define BM_UARTDBGRIS_RIRMIS 0x00000001
+
+#define HW_UARTDBGMIS (0x00000040)
+
+#define BP_UARTDBGMIS_UNAVAILABLE 16
+#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGMIS_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
+#define BP_UARTDBGMIS_RESERVED 11
+#define BM_UARTDBGMIS_RESERVED 0x0000F800
+#define BF_UARTDBGMIS_RESERVED(v) \
+ (((v) << 11) & BM_UARTDBGMIS_RESERVED)
+#define BM_UARTDBGMIS_OEMIS 0x00000400
+#define BM_UARTDBGMIS_BEMIS 0x00000200
+#define BM_UARTDBGMIS_PEMIS 0x00000100
+#define BM_UARTDBGMIS_FEMIS 0x00000080
+#define BM_UARTDBGMIS_RTMIS 0x00000040
+#define BM_UARTDBGMIS_TXMIS 0x00000020
+#define BM_UARTDBGMIS_RXMIS 0x00000010
+#define BM_UARTDBGMIS_DSRMMIS 0x00000008
+#define BM_UARTDBGMIS_DCDMMIS 0x00000004
+#define BM_UARTDBGMIS_CTSMMIS 0x00000002
+#define BM_UARTDBGMIS_RIMMIS 0x00000001
+
+#define HW_UARTDBGICR (0x00000044)
+
+#define BP_UARTDBGICR_UNAVAILABLE 16
+#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGICR_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
+#define BP_UARTDBGICR_RESERVED 11
+#define BM_UARTDBGICR_RESERVED 0x0000F800
+#define BF_UARTDBGICR_RESERVED(v) \
+ (((v) << 11) & BM_UARTDBGICR_RESERVED)
+#define BM_UARTDBGICR_OEIC 0x00000400
+#define BM_UARTDBGICR_BEIC 0x00000200
+#define BM_UARTDBGICR_PEIC 0x00000100
+#define BM_UARTDBGICR_FEIC 0x00000080
+#define BM_UARTDBGICR_RTIC 0x00000040
+#define BM_UARTDBGICR_TXIC 0x00000020
+#define BM_UARTDBGICR_RXIC 0x00000010
+#define BM_UARTDBGICR_DSRMIC 0x00000008
+#define BM_UARTDBGICR_DCDMIC 0x00000004
+#define BM_UARTDBGICR_CTSMIC 0x00000002
+#define BM_UARTDBGICR_RIMIC 0x00000001
+
+#define HW_UARTDBGDMACR (0x00000048)
+
+#define BP_UARTDBGDMACR_UNAVAILABLE 16
+#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
+#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
+ (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
+#define BP_UARTDBGDMACR_RESERVED 3
+#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
+#define BF_UARTDBGDMACR_RESERVED(v) \
+ (((v) << 3) & BM_UARTDBGDMACR_RESERVED)
+#define BM_UARTDBGDMACR_DMAONERR 0x00000004
+#define BM_UARTDBGDMACR_TXDMAE 0x00000002
+#define BM_UARTDBGDMACR_RXDMAE 0x00000001
+#endif /* __ARCH_ARM___UARTDBG_H */
diff --git a/drivers/serial/regs-uartapp.h b/drivers/serial/regs-uartapp.h
new file mode 100644
index 000000000000..aad9a7866556
--- /dev/null
+++ b/drivers/serial/regs-uartapp.h
@@ -0,0 +1,307 @@
+/*
+ * Freescale UARTAPP Register Definitions
+ *
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.42
+ * Template revision: 26195
+ */
+
+#ifndef __ARCH_ARM___UARTAPP_H
+#define __ARCH_ARM___UARTAPP_H
+
+
+#define HW_UARTAPP_CTRL0 (0x00000000)
+#define HW_UARTAPP_CTRL0_SET (0x00000004)
+#define HW_UARTAPP_CTRL0_CLR (0x00000008)
+#define HW_UARTAPP_CTRL0_TOG (0x0000000c)
+
+#define BM_UARTAPP_CTRL0_SFTRST 0x80000000
+#define BM_UARTAPP_CTRL0_CLKGATE 0x40000000
+#define BM_UARTAPP_CTRL0_RUN 0x20000000
+#define BM_UARTAPP_CTRL0_RX_SOURCE 0x10000000
+#define BM_UARTAPP_CTRL0_RXTO_ENABLE 0x08000000
+#define BP_UARTAPP_CTRL0_RXTIMEOUT 16
+#define BM_UARTAPP_CTRL0_RXTIMEOUT 0x07FF0000
+#define BF_UARTAPP_CTRL0_RXTIMEOUT(v) \
+ (((v) << 16) & BM_UARTAPP_CTRL0_RXTIMEOUT)
+#define BP_UARTAPP_CTRL0_XFER_COUNT 0
+#define BM_UARTAPP_CTRL0_XFER_COUNT 0x0000FFFF
+#define BF_UARTAPP_CTRL0_XFER_COUNT(v) \
+ (((v) << 0) & BM_UARTAPP_CTRL0_XFER_COUNT)
+
+#define HW_UARTAPP_CTRL1 (0x00000010)
+#define HW_UARTAPP_CTRL1_SET (0x00000014)
+#define HW_UARTAPP_CTRL1_CLR (0x00000018)
+#define HW_UARTAPP_CTRL1_TOG (0x0000001c)
+
+#define BP_UARTAPP_CTRL1_RSVD2 29
+#define BM_UARTAPP_CTRL1_RSVD2 0xE0000000
+#define BF_UARTAPP_CTRL1_RSVD2(v) \
+ (((v) << 29) & BM_UARTAPP_CTRL1_RSVD2)
+#define BM_UARTAPP_CTRL1_RUN 0x10000000
+#define BP_UARTAPP_CTRL1_RSVD1 16
+#define BM_UARTAPP_CTRL1_RSVD1 0x0FFF0000
+#define BF_UARTAPP_CTRL1_RSVD1(v) \
+ (((v) << 16) & BM_UARTAPP_CTRL1_RSVD1)
+#define BP_UARTAPP_CTRL1_XFER_COUNT 0
+#define BM_UARTAPP_CTRL1_XFER_COUNT 0x0000FFFF
+#define BF_UARTAPP_CTRL1_XFER_COUNT(v) \
+ (((v) << 0) & BM_UARTAPP_CTRL1_XFER_COUNT)
+
+#define HW_UARTAPP_CTRL2 (0x00000020)
+#define HW_UARTAPP_CTRL2_SET (0x00000024)
+#define HW_UARTAPP_CTRL2_CLR (0x00000028)
+#define HW_UARTAPP_CTRL2_TOG (0x0000002c)
+
+#define BM_UARTAPP_CTRL2_INVERT_RTS 0x80000000
+#define BM_UARTAPP_CTRL2_INVERT_CTS 0x40000000
+#define BM_UARTAPP_CTRL2_INVERT_TX 0x20000000
+#define BM_UARTAPP_CTRL2_INVERT_RX 0x10000000
+#define BM_UARTAPP_CTRL2_RTS_SEMAPHORE 0x08000000
+#define BM_UARTAPP_CTRL2_DMAONERR 0x04000000
+#define BM_UARTAPP_CTRL2_TXDMAE 0x02000000
+#define BM_UARTAPP_CTRL2_RXDMAE 0x01000000
+#define BM_UARTAPP_CTRL2_RSVD2 0x00800000
+#define BP_UARTAPP_CTRL2_RXIFLSEL 20
+#define BM_UARTAPP_CTRL2_RXIFLSEL 0x00700000
+#define BF_UARTAPP_CTRL2_RXIFLSEL(v) \
+ (((v) << 20) & BM_UARTAPP_CTRL2_RXIFLSEL)
+#define BV_UARTAPP_CTRL2_RXIFLSEL__NOT_EMPTY 0x0
+#define BV_UARTAPP_CTRL2_RXIFLSEL__ONE_QUARTER 0x1
+#define BV_UARTAPP_CTRL2_RXIFLSEL__ONE_HALF 0x2
+#define BV_UARTAPP_CTRL2_RXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTAPP_CTRL2_RXIFLSEL__SEVEN_EIGHTHS 0x4
+#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID5 0x5
+#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID6 0x6
+#define BV_UARTAPP_CTRL2_RXIFLSEL__INVALID7 0x7
+#define BM_UARTAPP_CTRL2_RSVD3 0x00080000
+#define BP_UARTAPP_CTRL2_TXIFLSEL 16
+#define BM_UARTAPP_CTRL2_TXIFLSEL 0x00070000
+#define BF_UARTAPP_CTRL2_TXIFLSEL(v) \
+ (((v) << 16) & BM_UARTAPP_CTRL2_TXIFLSEL)
+#define BV_UARTAPP_CTRL2_TXIFLSEL__EMPTY 0x0
+#define BV_UARTAPP_CTRL2_TXIFLSEL__ONE_QUARTER 0x1
+#define BV_UARTAPP_CTRL2_TXIFLSEL__ONE_HALF 0x2
+#define BV_UARTAPP_CTRL2_TXIFLSEL__THREE_QUARTERS 0x3
+#define BV_UARTAPP_CTRL2_TXIFLSEL__SEVEN_EIGHTHS 0x4
+#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID5 0x5
+#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID6 0x6
+#define BV_UARTAPP_CTRL2_TXIFLSEL__INVALID7 0x7
+#define BM_UARTAPP_CTRL2_CTSEN 0x00008000
+#define BM_UARTAPP_CTRL2_RTSEN 0x00004000
+#define BM_UARTAPP_CTRL2_OUT2 0x00002000
+#define BM_UARTAPP_CTRL2_OUT1 0x00001000
+#define BM_UARTAPP_CTRL2_RTS 0x00000800
+#define BM_UARTAPP_CTRL2_DTR 0x00000400
+#define BM_UARTAPP_CTRL2_RXE 0x00000200
+#define BM_UARTAPP_CTRL2_TXE 0x00000100
+#define BM_UARTAPP_CTRL2_LBE 0x00000080
+#define BM_UARTAPP_CTRL2_USE_LCR2 0x00000040
+#define BP_UARTAPP_CTRL2_RSVD4 3
+#define BM_UARTAPP_CTRL2_RSVD4 0x00000038
+#define BF_UARTAPP_CTRL2_RSVD4(v) \
+ (((v) << 3) & BM_UARTAPP_CTRL2_RSVD4)
+#define BM_UARTAPP_CTRL2_SIRLP 0x00000004
+#define BM_UARTAPP_CTRL2_SIREN 0x00000002
+#define BM_UARTAPP_CTRL2_UARTEN 0x00000001
+
+#define HW_UARTAPP_LINECTRL (0x00000030)
+#define HW_UARTAPP_LINECTRL_SET (0x00000034)
+#define HW_UARTAPP_LINECTRL_CLR (0x00000038)
+#define HW_UARTAPP_LINECTRL_TOG (0x0000003c)
+
+#define BP_UARTAPP_LINECTRL_BAUD_DIVINT 16
+#define BM_UARTAPP_LINECTRL_BAUD_DIVINT 0xFFFF0000
+#define BF_UARTAPP_LINECTRL_BAUD_DIVINT(v) \
+ (((v) << 16) & BM_UARTAPP_LINECTRL_BAUD_DIVINT)
+#define BP_UARTAPP_LINECTRL_RSVD 14
+#define BM_UARTAPP_LINECTRL_RSVD 0x0000C000
+#define BF_UARTAPP_LINECTRL_RSVD(v) \
+ (((v) << 14) & BM_UARTAPP_LINECTRL_RSVD)
+#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC 8
+#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC 0x00003F00
+#define BF_UARTAPP_LINECTRL_BAUD_DIVFRAC(v) \
+ (((v) << 8) & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC)
+#define BM_UARTAPP_LINECTRL_SPS 0x00000080
+#define BP_UARTAPP_LINECTRL_WLEN 5
+#define BM_UARTAPP_LINECTRL_WLEN 0x00000060
+#define BF_UARTAPP_LINECTRL_WLEN(v) \
+ (((v) << 5) & BM_UARTAPP_LINECTRL_WLEN)
+#define BM_UARTAPP_LINECTRL_FEN 0x00000010
+#define BM_UARTAPP_LINECTRL_STP2 0x00000008
+#define BM_UARTAPP_LINECTRL_EPS 0x00000004
+#define BM_UARTAPP_LINECTRL_PEN 0x00000002
+#define BM_UARTAPP_LINECTRL_BRK 0x00000001
+
+#define HW_UARTAPP_LINECTRL2 (0x00000040)
+#define HW_UARTAPP_LINECTRL2_SET (0x00000044)
+#define HW_UARTAPP_LINECTRL2_CLR (0x00000048)
+#define HW_UARTAPP_LINECTRL2_TOG (0x0000004c)
+
+#define BP_UARTAPP_LINECTRL2_BAUD_DIVINT 16
+#define BM_UARTAPP_LINECTRL2_BAUD_DIVINT 0xFFFF0000
+#define BF_UARTAPP_LINECTRL2_BAUD_DIVINT(v) \
+ (((v) << 16) & BM_UARTAPP_LINECTRL2_BAUD_DIVINT)
+#define BP_UARTAPP_LINECTRL2_RSVD 14
+#define BM_UARTAPP_LINECTRL2_RSVD 0x0000C000
+#define BF_UARTAPP_LINECTRL2_RSVD(v) \
+ (((v) << 14) & BM_UARTAPP_LINECTRL2_RSVD)
+#define BP_UARTAPP_LINECTRL2_BAUD_DIVFRAC 8
+#define BM_UARTAPP_LINECTRL2_BAUD_DIVFRAC 0x00003F00
+#define BF_UARTAPP_LINECTRL2_BAUD_DIVFRAC(v) \
+ (((v) << 8) & BM_UARTAPP_LINECTRL2_BAUD_DIVFRAC)
+#define BM_UARTAPP_LINECTRL2_SPS 0x00000080
+#define BP_UARTAPP_LINECTRL2_WLEN 5
+#define BM_UARTAPP_LINECTRL2_WLEN 0x00000060
+#define BF_UARTAPP_LINECTRL2_WLEN(v) \
+ (((v) << 5) & BM_UARTAPP_LINECTRL2_WLEN)
+#define BM_UARTAPP_LINECTRL2_FEN 0x00000010
+#define BM_UARTAPP_LINECTRL2_STP2 0x00000008
+#define BM_UARTAPP_LINECTRL2_EPS 0x00000004
+#define BM_UARTAPP_LINECTRL2_PEN 0x00000002
+#define BM_UARTAPP_LINECTRL2_RSVD1 0x00000001
+
+#define HW_UARTAPP_INTR (0x00000050)
+#define HW_UARTAPP_INTR_SET (0x00000054)
+#define HW_UARTAPP_INTR_CLR (0x00000058)
+#define HW_UARTAPP_INTR_TOG (0x0000005c)
+
+#define BP_UARTAPP_INTR_RSVD1 28
+#define BM_UARTAPP_INTR_RSVD1 0xF0000000
+#define BF_UARTAPP_INTR_RSVD1(v) \
+ (((v) << 28) & BM_UARTAPP_INTR_RSVD1)
+#define BM_UARTAPP_INTR_ABDIEN 0x08000000
+#define BM_UARTAPP_INTR_OEIEN 0x04000000
+#define BM_UARTAPP_INTR_BEIEN 0x02000000
+#define BM_UARTAPP_INTR_PEIEN 0x01000000
+#define BM_UARTAPP_INTR_FEIEN 0x00800000
+#define BM_UARTAPP_INTR_RTIEN 0x00400000
+#define BM_UARTAPP_INTR_TXIEN 0x00200000
+#define BM_UARTAPP_INTR_RXIEN 0x00100000
+#define BM_UARTAPP_INTR_DSRMIEN 0x00080000
+#define BM_UARTAPP_INTR_DCDMIEN 0x00040000
+#define BM_UARTAPP_INTR_CTSMIEN 0x00020000
+#define BM_UARTAPP_INTR_RIMIEN 0x00010000
+#define BP_UARTAPP_INTR_RSVD2 12
+#define BM_UARTAPP_INTR_RSVD2 0x0000F000
+#define BF_UARTAPP_INTR_RSVD2(v) \
+ (((v) << 12) & BM_UARTAPP_INTR_RSVD2)
+#define BM_UARTAPP_INTR_ABDIS 0x00000800
+#define BM_UARTAPP_INTR_OEIS 0x00000400
+#define BM_UARTAPP_INTR_BEIS 0x00000200
+#define BM_UARTAPP_INTR_PEIS 0x00000100
+#define BM_UARTAPP_INTR_FEIS 0x00000080
+#define BM_UARTAPP_INTR_RTIS 0x00000040
+#define BM_UARTAPP_INTR_TXIS 0x00000020
+#define BM_UARTAPP_INTR_RXIS 0x00000010
+#define BM_UARTAPP_INTR_DSRMIS 0x00000008
+#define BM_UARTAPP_INTR_DCDMIS 0x00000004
+#define BM_UARTAPP_INTR_CTSMIS 0x00000002
+#define BM_UARTAPP_INTR_RIMIS 0x00000001
+
+#define HW_UARTAPP_DATA (0x00000060)
+
+#define BP_UARTAPP_DATA_DATA 0
+#define BM_UARTAPP_DATA_DATA 0xFFFFFFFF
+#define BF_UARTAPP_DATA_DATA(v) (v)
+
+#define HW_UARTAPP_STAT (0x00000070)
+
+#define BM_UARTAPP_STAT_PRESENT 0x80000000
+#define BV_UARTAPP_STAT_PRESENT__UNAVAILABLE 0x0
+#define BV_UARTAPP_STAT_PRESENT__AVAILABLE 0x1
+#define BM_UARTAPP_STAT_HISPEED 0x40000000
+#define BV_UARTAPP_STAT_HISPEED__UNAVAILABLE 0x0
+#define BV_UARTAPP_STAT_HISPEED__AVAILABLE 0x1
+#define BM_UARTAPP_STAT_BUSY 0x20000000
+#define BM_UARTAPP_STAT_CTS 0x10000000
+#define BM_UARTAPP_STAT_TXFE 0x08000000
+#define BM_UARTAPP_STAT_RXFF 0x04000000
+#define BM_UARTAPP_STAT_TXFF 0x02000000
+#define BM_UARTAPP_STAT_RXFE 0x01000000
+#define BP_UARTAPP_STAT_RXBYTE_INVALID 20
+#define BM_UARTAPP_STAT_RXBYTE_INVALID 0x00F00000
+#define BF_UARTAPP_STAT_RXBYTE_INVALID(v) \
+ (((v) << 20) & BM_UARTAPP_STAT_RXBYTE_INVALID)
+#define BM_UARTAPP_STAT_OERR 0x00080000
+#define BM_UARTAPP_STAT_BERR 0x00040000
+#define BM_UARTAPP_STAT_PERR 0x00020000
+#define BM_UARTAPP_STAT_FERR 0x00010000
+#define BP_UARTAPP_STAT_RXCOUNT 0
+#define BM_UARTAPP_STAT_RXCOUNT 0x0000FFFF
+#define BF_UARTAPP_STAT_RXCOUNT(v) \
+ (((v) << 0) & BM_UARTAPP_STAT_RXCOUNT)
+
+#define HW_UARTAPP_DEBUG (0x00000080)
+
+#define BP_UARTAPP_DEBUG_RXIBAUD_DIV 16
+#define BM_UARTAPP_DEBUG_RXIBAUD_DIV 0xFFFF0000
+#define BF_UARTAPP_DEBUG_RXIBAUD_DIV(v) \
+ (((v) << 16) & BM_UARTAPP_DEBUG_RXIBAUD_DIV)
+#define BP_UARTAPP_DEBUG_RXFBAUD_DIV 10
+#define BM_UARTAPP_DEBUG_RXFBAUD_DIV 0x0000FC00
+#define BF_UARTAPP_DEBUG_RXFBAUD_DIV(v) \
+ (((v) << 10) & BM_UARTAPP_DEBUG_RXFBAUD_DIV)
+#define BP_UARTAPP_DEBUG_RSVD1 6
+#define BM_UARTAPP_DEBUG_RSVD1 0x000003C0
+#define BF_UARTAPP_DEBUG_RSVD1(v) \
+ (((v) << 6) & BM_UARTAPP_DEBUG_RSVD1)
+#define BM_UARTAPP_DEBUG_TXDMARUN 0x00000020
+#define BM_UARTAPP_DEBUG_RXDMARUN 0x00000010
+#define BM_UARTAPP_DEBUG_TXCMDEND 0x00000008
+#define BM_UARTAPP_DEBUG_RXCMDEND 0x00000004
+#define BM_UARTAPP_DEBUG_TXDMARQ 0x00000002
+#define BM_UARTAPP_DEBUG_RXDMARQ 0x00000001
+
+#define HW_UARTAPP_VERSION (0x00000090)
+
+#define BP_UARTAPP_VERSION_MAJOR 24
+#define BM_UARTAPP_VERSION_MAJOR 0xFF000000
+#define BF_UARTAPP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_UARTAPP_VERSION_MAJOR)
+#define BP_UARTAPP_VERSION_MINOR 16
+#define BM_UARTAPP_VERSION_MINOR 0x00FF0000
+#define BF_UARTAPP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_UARTAPP_VERSION_MINOR)
+#define BP_UARTAPP_VERSION_STEP 0
+#define BM_UARTAPP_VERSION_STEP 0x0000FFFF
+#define BF_UARTAPP_VERSION_STEP(v) \
+ (((v) << 0) & BM_UARTAPP_VERSION_STEP)
+
+#define HW_UARTAPP_AUTOBAUD (0x000000a0)
+
+#define BP_UARTAPP_AUTOBAUD_REFCHAR1 24
+#define BM_UARTAPP_AUTOBAUD_REFCHAR1 0xFF000000
+#define BF_UARTAPP_AUTOBAUD_REFCHAR1(v) \
+ (((v) << 24) & BM_UARTAPP_AUTOBAUD_REFCHAR1)
+#define BP_UARTAPP_AUTOBAUD_REFCHAR0 16
+#define BM_UARTAPP_AUTOBAUD_REFCHAR0 0x00FF0000
+#define BF_UARTAPP_AUTOBAUD_REFCHAR0(v) \
+ (((v) << 16) & BM_UARTAPP_AUTOBAUD_REFCHAR0)
+#define BP_UARTAPP_AUTOBAUD_RSVD1 5
+#define BM_UARTAPP_AUTOBAUD_RSVD1 0x0000FFE0
+#define BF_UARTAPP_AUTOBAUD_RSVD1(v) \
+ (((v) << 5) & BM_UARTAPP_AUTOBAUD_RSVD1)
+#define BM_UARTAPP_AUTOBAUD_UPDATE_TX 0x00000010
+#define BM_UARTAPP_AUTOBAUD_TWO_REF_CHARS 0x00000008
+#define BM_UARTAPP_AUTOBAUD_START_WITH_RUNBIT 0x00000004
+#define BM_UARTAPP_AUTOBAUD_START_BAUD_DETECT 0x00000002
+#define BM_UARTAPP_AUTOBAUD_BAUD_DETECT_ENABLE 0x00000001
+#endif /* __ARCH_ARM___UARTAPP_H */
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 7f2830709512..4087aff757bb 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2092,7 +2092,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
*/
if (uart_console(uport)) {
uart_change_pm(state, 0);
- uport->ops->set_termios(uport, &termios, NULL);
+ uport->ops->set_termios(uport, port->tty->termios, NULL);
console_start(uport->cons);
}