Subject: [@num@/@total@] i.MX2 family: Adding the common serial driver
From: Juergen Beisert <j.beisert@pengutronix.de>

This patch adds common UART driver for the whole i.MX/MXC family.of processors.

TODO:
 - should it be a full blown driver for all possible architectures?
   Or better one main part with several adpations to i.MX1/i.MX2/i.MX3?
 - get a sign from freescale for the patch

Signed-off-by: Juergen Beisert <j.beisert@pengutronix.de>

---

 drivers/serial/Kconfig              |   24
 drivers/serial/Makefile             |    1
 drivers/serial/mxc_uart.c           | 1577 ++++++++++++++++++++++++++++++++++++
 include/asm-arm/arch-mxc/mxc_uart.h |  253 +++++
 include/linux/serial_core.h         |    2
 5 files changed, 1857 insertions(+)

Index: drivers/serial/mxc_uart.c
===================================================================
--- /dev/null
+++ drivers/serial/mxc_uart.c
@@ -0,0 +1,1577 @@
+/*
+ * Copyright 2004-2007 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
+ */
+#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 <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/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
+
+/* 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;
+
+/* Used to indicate if we want echo cancellation in the Irda mode */
+static int echo_cancel;
+/* Stores the port number of the UART used as a console. */
+static int console_index = 0;
+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];
+
+/* Called by the core driver to stop UART transmission */
+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.
+ */
+static void dma_tx_do_tasklet(unsigned long arg)
+{
+	uart_mxc_port *umxc = (uart_mxc_port *) arg;
+	struct circ_buf *xmit = &umxc->port.info->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.
+ */
+static void mxcuart_dma_writecallback(void *arg, int error, unsigned int count)
+{
+	uart_mxc_port *umxc = arg;
+	struct circ_buf *xmit = &umxc->port.info->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);
+	}
+}
+
+/* Called by the core driver to start transmitting characters */
+static void mxcuart_start_tx(struct uart_port *port)
+{
+	uart_mxc_port *umxc = (uart_mxc_port *) port;
+	struct circ_buf *xmit = &umxc->port.info->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);
+}
+
+/* Called by the core driver to stop receiving characters */
+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);
+}
+
+/* Called by the core driver to enable the modem status interrupts */
+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);
+}
+
+/*
+ * 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.
+ */
+static void mxcuart_rx_chars(uart_mxc_port * umxc)
+{
+	struct tty_struct *tty = umxc->port.info->tty;
+	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_PARITY;
+			} else if (status & MXC_UARTURXD_PRERR) {
+				flag = TTY_FRAME;
+			}
+		}
+
+		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(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.
+ */
+static void mxcuart_tx_chars(uart_mxc_port * umxc)
+{
+	struct circ_buf *xmit = &umxc->port.info->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.
+ */
+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.info->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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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);
+}
+
+/*
+ * Called by the core driver to test whether the transmitter
+ * fifo and shift register for the UART port are empty.
+ */
+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;
+}
+
+/* Called to get the current status of the modem input signals */
+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;
+}
+
+/* Called by the core driver to set the state of the modem control lines */
+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);
+}
+
+/* Called by the core driver to control the transmission 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);
+}
+
+/* DMA callback, this method is called when the DMA buffer has received its data */
+static void mxcuart_dmaread_callback(void *arg, int error, unsigned int cnt)
+{
+	uart_mxc_port *umxc = arg;
+	struct tty_struct *tty = umxc->port.info->tty;
+	int buff_id, flip_cnt, num_bufs;
+	mxc_dma_requestbuf_t readchnl_request;
+	mxc_uart_rxdmamap *rx_buf_elem = NULL;
+
+	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;
+
+	if ((umxc->dma_rxbuf_id += 1) >= num_bufs) {
+		umxc->dma_rxbuf_id = 0;
+	}
+
+	rx_buf_elem = (mxc_uart_rxdmamap *) (umxc->rx_dmamap + buff_id);
+
+	if (error == MXC_DMA_TRANSFER_ERROR) {
+		goto drop_data;
+	}
+
+	flip_cnt = tty_buffer_request_room(tty, cnt);
+	/* Check for space availability in the TTY Flip buffer */
+	if (flip_cnt <= 0) {
+		goto drop_data;
+	}
+
+	tty_insert_flip_string(tty, rx_buf_elem->rx_buf, flip_cnt);
+	tty_flip_buffer_push(tty);
+
+	umxc->port.info->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 */
+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 */
+	if ((umxc->tx_buf = kmalloc(TXDMA_BUFF_SIZE, GFP_KERNEL)) == NULL) {
+		ret = -1;
+		goto err_dma_tx_buff;
+	}
+	rxbufs = umxc->dma_rxbuf_size / RXDMA_BUFF_SIZE;
+	/* Allocate the DMA Virtual Receive Buffer */
+	if ((umxc->rx_dmamap = kmalloc(rxbufs * sizeof(mxc_uart_rxdmamap),
+				       GFP_KERNEL)) == NULL) {
+		ret = -1;
+		goto err_dma_rx_buff;
+	}
+
+	/* Allocate the DMA Receive Request structures */
+	if ((readchnl_reqelem =
+	     kmalloc(rxbufs * sizeof(mxc_dma_requestbuf_t),
+		     GFP_KERNEL)) == 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 */
+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);
+}
+
+/* Free the interrupts */
+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 the maximum baud rate supported */
+static void mxcuart_get_maxbaud(unsigned long per_clk, unsigned long *max_baud)
+{
+	unsigned long baud;
+
+	baud = per_clk / 16;
+	if (baud > MAX_UART_BAUDRATE) {
+		baud = MAX_UART_BAUDRATE;
+	}
+	*max_baud = baud;
+}
+
+/* Calculate and set the UART port clock value */
+static void mxcuart_set_ref_freq(uart_mxc_port * umxc, unsigned long per_clk,
+				unsigned int req_baud, int *div)
+{
+	int d = 1;
+
+	d = per_clk / ((req_baud * 16) + 1000);
+	if (d > 6) {
+		d = 6;
+	}
+
+	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;
+}
+
+/*
+ * 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.
+ */
+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(MXC_IRDA_RX_INV | MXC_UARTUCR4_IRSC, umxc->port.membase
+		       + MXC_UARTUCR4);
+		writel(umxc->rxd_mux | MXC_IRDA_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;
+}
+
+/* Called by the core driver for the low-level driver to free its resources */
+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);
+	}
+}
+
+/* Called by the core driver to change the UART parameters */
+static void mxcuart_set_termios(struct uart_port *port,
+				struct termios *termios, struct termios *old)
+{
+	uart_mxc_port *umxc = (uart_mxc_port *) port;
+	volatile unsigned int cr4 = 0, cr2 = 0, sr1, ufcr;
+	u_int num, denom, baud;
+	u_int cr2_mask;		/* Used to add the changes to CR2 */
+	unsigned long flags, max_baud, 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);
+
+	mxcuart_get_maxbaud(per_clk, &max_baud);
+	/*
+	 * 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, max_baud);
+	/* 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;
+	}
+
+	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;
+		} else {
+			cr2 |= MXC_UARTUCR2_IRTS;
+			sr1 = readl(umxc->port.membase + MXC_UARTUSR1);
+			/* RTS not active, do not transmit */
+			if ((sr1 & MXC_UARTUSR1_RTSS) == 0) {
+				umxc->port.info->tty->hw_stopped = 1;
+			}
+		}
+	} 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 */
+	num = (baud / 100) - 1;
+	denom = (umxc->port.uartclk / 1600) - 1;
+	if ((denom < 65536) && (umxc->port.uartclk > 1600)) {
+		writel(num, umxc->port.membase + MXC_UARTUBIR);
+		writel(denom, umxc->port.membase + MXC_UARTUBMR);
+	}
+	spin_unlock_irqrestore(&umxc->port.lock, flags);
+}
+
+/*
+ * Called by the core driver to know the UART type.
+ */
+static const char *mxcuart_type(struct uart_port *port)
+{
+	return port->type == PORT_MXC ? "Freescale MXC" : NULL;
+}
+
+/* Called by the core driver to release the memory resources */
+static void mxcuart_release_port(struct uart_port *port)
+{
+}
+
+/* Called by the core driver to request memory resources */
+static int mxcuart_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* Called by the core driver to perform any autoconfiguration */
+static void mxcuart_config_port(struct uart_port *port, int flags)
+{
+	if ((flags & UART_CONFIG_TYPE) && (mxcuart_request_port(port) == 0)) {
+		port->type = PORT_MXC;
+	}
+}
+
+/* Called by the core driver to verify given settings for this port */
+static int mxcuart_verify_port(struct uart_port *port,
+			       struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_MXC) {
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+/* Send a high priority XON/XOFF character */
+static void mxcuart_send_xchar(struct uart_port *port, char ch)
+{
+	unsigned long flags;
+
+	port->x_char = ch;
+	if (port->info->tty->hw_stopped) {
+		return;
+	}
+
+	if (ch) {
+		spin_lock_irqsave(&port->lock, flags);
+		port->ops->start_tx(port);
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+/* Enable/disable the MXC UART clocks */
+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)
+{
+	unsigned int status;
+
+	do {
+		status = readl(port->membase + MXC_UARTUSR1);
+	} while ((status & MXC_UARTUSR1_TRDY) == 0);
+	writel(ch, port->membase + MXC_UARTUTXD);
+}
+
+/* Write the console messages through the UART port */
+static void mxcuart_console_write(struct console *co, const char *s,
+				u_int count)
+{
+	struct uart_port *port = &mxc_ports[co->index]->port;
+	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 */
+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';
+	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;
+	}
+	console_index = co->index;
+	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);
+	}
+	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,
+};
+
+static int __init mxcuart_console_init(void)
+{
+	register_console(&mxc_console);
+	return 0;
+}
+
+console_initcall(mxcuart_console_init);
+
+#define MXC_CONSOLE     &mxc_console
+#else
+#define MXC_CONSOLE     NULL
+#endif /* CONFIG_SERIAL_MXC_CONSOLE */
+
+/* Data to pass to the serial_core.c */
+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,
+};
+
+/* Put the UART in a low power state */
+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 */
+	}
+	uart_suspend_port(&mxc_reg, &umxc->port);
+	if (umxc->port.info && umxc->port.info->flags & UIF_INITIALIZED) {
+		umxc->port.info->tty->hw_stopped = 1;
+	}
+
+	if (device_may_wakeup(&pdev->dev)) {
+		/* UART RTS signal is used as wakeup source */
+		writel(MXC_UARTUCR1_RTSDEN, umxc->port.membase + MXC_UARTUCR1);
+		gpio_uart_active(umxc->port.line, umxc->ir_mode);
+	}
+
+	return 0;
+}
+
+/* Bring the UART back from a low power state */
+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->port.info && umxc->port.info->flags & UIF_INITIALIZED) {
+		umxc->port.info->tty->hw_stopped = 0;
+	}
+	if (device_may_wakeup(&pdev->dev)) {
+		writel(0, umxc->port.membase + MXC_UARTUCR1);
+		gpio_uart_inactive(umxc->port.line, umxc->ir_mode);
+	}
+	uart_resume_port(&mxc_reg, &umxc->port);
+
+	return 0;
+}
+
+/* Platform device/driver probe */
+static int mxcuart_probe(struct platform_device *pdev)
+{
+	int id = pdev->id;
+	int err;
+
+	err = request_mem_region(pdev->resource[0].start,
+				pdev->resource[0].end - pdev->resource[0].start + 1,
+				"serial_mxc");
+	if (err == 0) {
+		printk(KERN_ERR "Cannot claim UART area!\n");
+		return err;
+	}
+
+	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) {
+		mxc_ports[id]->port.dev = &pdev->dev;
+		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 |= UPF_LOW_LATENCY;
+		}
+
+		mxc_ports[id]->clk = clk_get(&pdev->dev, "uart_clk");
+		clk_enable(mxc_ports[id]->clk);
+		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]);
+		pdev->dev.power.can_wakeup = 1;
+	}
+	return 0;
+}
+
+/* Platform device/driver remove */
+static int mxcuart_remove(struct platform_device *pdev)
+{
+	uart_mxc_port *umxc = platform_get_drvdata(pdev);
+
+	release_region(pdev->resource[0].start,
+		       pdev->resource[0].end - pdev->resource[0].start + 1);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (umxc) {
+		uart_remove_one_port(&mxc_reg, &umxc->port);
+	}
+	return 0;
+}
+
+static struct platform_driver mxcuart_driver = {
+	.driver = {
+		   .name = "mxcintuart",
+		   },
+	.probe = mxcuart_probe,
+	.remove = mxcuart_remove,
+	.suspend = mxcuart_suspend,
+	.resume = mxcuart_resume,
+};
+
+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;
+}
+
+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");
Index: drivers/serial/Kconfig
===================================================================
--- drivers/serial/Kconfig.orig
+++ drivers/serial/Kconfig
@@ -280,6 +280,30 @@ config SERIAL_8250_RM9K
 
 comment "Non-8250 serial port support"
 
+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_AMBA_PL010
 	tristate "ARM AMBA PL010 serial port support"
 	depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
Index: drivers/serial/Makefile
===================================================================
--- drivers/serial/Makefile.orig
+++ drivers/serial/Makefile
@@ -64,3 +64,4 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlit
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+obj-$(CONFIG_SERIAL_MXC) += mxc_uart.o
Index: include/linux/serial_core.h
===================================================================
--- include/linux/serial_core.h.orig
+++ include/linux/serial_core.h
@@ -149,6 +149,8 @@
 /* Freescale ColdFire */
 #define PORT_MCF	78
 
+/* Freescale Semiconductor MXC fmaily */
+#define PORT_MXC        79
 
 #ifdef __KERNEL__
 
Index: include/asm-arm/arch-mxc/mxc_uart.h
===================================================================
--- /dev/null
+++ include/asm-arm/arch-mxc/mxc_uart.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2004-2007 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 __ASM_ARCH_MXC_UART_H__
+#define __ASM_ARCH_MXC_UART_H__
+
+#ifdef __KERNEL__
+
+#include <linux/serial_core.h>
+#include <asm/arch/dma.h>
+
+/*
+ * The modes of the UART ports
+ */
+#define MODE_DTE                0
+#define MODE_DCE                1
+/*
+ * Is the UART configured to be a IR port
+ */
+#define IRDA                    0
+#define NO_IRDA                 1
+
+/*
+ * This structure is used to store the the physical and virtual
+ * addresses of the UART DMA receive buffer.
+ */
+typedef struct {
+	char *rx_buf;	/* DMA Receive buffer virtual address */
+	dma_addr_t rx_handle;	/* DMA Receive buffer physical address */
+} mxc_uart_rxdmamap;
+
+/*
+ * This structure is a way for the low level driver to define their own
+ * uart_port structure. This structure includes the core uart_port
+ * structure that is provided by Linux as an element and has other
+ * elements that are specifically required by this low-level driver.
+ */
+typedef struct {
+	/*
+	 * The port structure holds all the information about the UART
+	 * port like base address, and so on.
+	 */
+	struct uart_port port;
+	/*
+	 * Flag to determine if the interrupts are muxed.
+	 */
+	int ints_muxed;
+	/*
+	 * Array that holds the receive and master interrupt numbers
+	 * when the interrupts are not muxed.
+	 */
+	int irqs[2];
+	/*
+	 * Flag to determine the DTE/DCE mode.
+	 */
+	int mode;
+	/*
+	 * Flag to hold the IR mode of the port.
+	 */
+	int ir_mode;
+	/*
+	 * Flag to enable/disable the UART port.
+	 */
+	int enabled;
+	/*
+	 * Flag to indicate if we wish to use hardware-driven hardware
+	 * flow control.
+	 */
+	int hardware_flow;
+	/*
+	 * Holds the threshold value at which the CTS line is deasserted in
+	 * case we use hardware-driven hardware flow control.
+	 */
+	unsigned int cts_threshold;
+	/*
+	 * Flag to enable/disable DMA data transfer.
+	 */
+	int dma_enabled;
+	/*
+	 * Holds the DMA receive buffer size.
+	 */
+	int dma_rxbuf_size;
+	/*
+	 * DMA Receive buffers information
+	 */
+	mxc_uart_rxdmamap *rx_dmamap;
+	/*
+	 * DMA RX buffer id
+	 */
+	int dma_rxbuf_id;
+	/*
+	 * DMA Transmit buffer virtual address
+	 */
+	char *tx_buf;
+	/*
+	 * DMA Transmit buffer physical address
+	 */
+	dma_addr_t tx_handle;
+	/*
+	 * Holds the RxFIFO threshold value.
+	 */
+	unsigned int rx_threshold;
+	/*
+	 * Holds the TxFIFO threshold value.
+	 */
+	unsigned int tx_threshold;
+	/*
+	 * Information whether this is a shared UART
+	 */
+	unsigned int shared;
+	/*
+	 * Clock id for UART clock
+	 */
+	struct clk *clk;
+	/*
+	 * Information whether RXDMUXSEL must be set or not for IR port
+	 */
+	int rxd_mux;
+	/*
+	 * DMA ID for transmit
+	 */
+	mxc_dma_device_t dma_tx_id;
+	/*
+	 * DMA ID for receive
+	 */
+	mxc_dma_device_t dma_rx_id;
+} uart_mxc_port;
+
+/* 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 /* __KERNEL__ */
+
+#endif /* __ASM_ARCH_MXC_UART_H__ */
