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

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

Changes since last review:
 - DMA support removed, because currently it seems broken on the i.MX27
   (note by Russell King)
 - ran checkpatch.pl on it

TODO:

 - should it be a full blown driver for all possible architectures?
   Or better one main part with several adaptions 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   | 1185 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/serial_core.h |    4 
 4 files changed, 1214 insertions(+)

Index: drivers/serial/mxc_uart.c
===================================================================
--- /dev/null
+++ drivers/serial/mxc_uart.c
@@ -0,0 +1,1185 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * 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.
+ */
+
+#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/clk.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/imx_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
+
+/* Used to indicate if we want echo cancellation in the Irda mode */
+static int echo_cancel;
+
+static struct uart_mxc_port *mxc_ports[MXC_UART_NR];
+
+/* Called by the core driver to stop UART transmission */
+static void mxcuart_stop_tx(struct uart_port *port)
+{
+	unsigned int cr1;
+
+	cr1 = readl(port->membase + MXC_UARTUCR1);
+
+	/* Disable Transmitter rdy interrupt */
+	cr1 &= ~MXC_UARTUCR1_TRDYEN;
+
+	writel(cr1, port->membase + MXC_UARTUCR1);
+}
+
+/* Called by the core driver to start transmitting characters */
+static void mxcuart_start_tx(struct uart_port *port)
+{
+	unsigned int cr1;
+
+	cr1 = readl(port->membase + MXC_UARTUCR1);
+	/* Enable Transmitter rdy interrupt */
+	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)
+{
+	unsigned int cr1;
+
+	cr1 = readl(port->membase + MXC_UARTUCR1);
+	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)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+	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->flags & MXC_UART_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(struct uart_mxc_port *umxc)
+{
+	struct tty_struct *tty = umxc->port.info->tty;
+	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(struct 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(struct uart_mxc_port *umxc, unsigned int sr1,
+				unsigned int sr2)
+{
+	if (umxc->flags & MXC_UART_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)
+{
+	struct uart_mxc_port *umxc = dev_id;
+	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->flags & MXC_UART_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->flags & MXC_UART_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)
+{
+	struct uart_mxc_port *umxc = dev_id;
+	int handled = 0;
+	unsigned int sr2, cr;
+
+	/* Echo cancellation for IRDA Transmit chars */
+	if ((umxc->flags & MXC_UART_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->flags & MXC_UART_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)
+{
+	struct 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)
+{
+	struct uart_mxc_port *umxc = dev_id;
+	int handled = 0;
+	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)
+{
+	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)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+	unsigned int result = 0;
+	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->flags & MXC_UART_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)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+	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->flags & MXC_UART_MODE_IRDA)
+			echo_cancel = 0;
+		else
+			uts |= MXC_UARTUTS_LOOP;
+	} else {
+		if (umxc->flags & MXC_UART_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)
+{
+	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);
+}
+
+/* Free the interrupts */
+static void mxcuart_free_interrupts(struct 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;
+	*max_baud = baud;
+}
+
+/* Calculate and set the UART port clock value */
+static void mxcuart_set_ref_freq(struct 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)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+	int retval;
+	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;
+				}
+			}
+		}
+	}
+
+	/*
+	 * 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 */
+	umxc->init(NULL); /* FIXME */
+
+	/*
+	 * Set the transceiver invert bits if required
+	 */
+	if (umxc->flags & MXC_UART_MODE_IRDA) {
+		echo_cancel = 1;
+		writel(((umxc->flags & MXC_UART_MODE_IRDA_RX_INV) ?
+				MXC_UARTUCR4_INVR : 0) | MXC_UARTUCR4_IRSC,
+				umxc->port.membase + MXC_UARTUCR4);
+		writel(umxc->rxd_mux |
+			((umxc->flags & MXC_UART_MODE_IRDA_TX_INV) ?
+				MXC_UARTUCR3_INVT : 0),
+				umxc->port.membase + MXC_UARTUCR3);
+	} else {
+		writel(umxc->rxd_mux, umxc->port.membase + MXC_UARTUCR3);
+	}
+
+	/*
+	 * Initialize UCR1,2 and UFCR registers
+	 */
+	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->flags & MXC_UART_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->flags & MXC_UART_MODE_IRDA)
+		cr1 |= MXC_UARTUCR1_IREN;
+
+	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)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+
+	/* Disable the IOMUX for the UART */
+	umxc->exit(NULL); /* FIXME */
+
+	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);
+}
+
+/* Called by the core driver to change the UART parameters */
+static void mxcuart_set_termios(struct uart_port *port,
+				struct ktermios *termios, struct ktermios *old)
+{
+	struct uart_mxc_port *umxc = (struct uart_mxc_port *) port;
+	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)
+{
+	struct uart_mxc_port *umxc = (struct 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)
+{
+	struct 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;
+
+	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->flags & MXC_UART_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)
+{
+	struct 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);
+		umxc->init(NULL); /* FIXME */
+	}
+
+	return 0;
+}
+
+/* Bring the UART back from a low power state */
+static int mxcuart_resume(struct platform_device *pdev)
+{
+	struct 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);
+		umxc->exit(NULL); /* FIXME */
+	}
+	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 = 0;
+	struct resource *r;
+
+	r = request_mem_region(pdev->resource[0].start,
+			pdev->resource[0].end - pdev->resource[0].start + 1,
+			"serial_mxc");
+	if (!r) {
+		printk(KERN_ERR "Cannot claim UART area!\n");
+		return -EBUSY;
+	}
+
+	mxc_ports[id] = pdev->dev.platform_data;
+	mxc_ports[id]->port.ops = &mxc_ops;
+
+	mxc_ports[id]->port.dev = &pdev->dev;
+	spin_lock_init(&mxc_ports[id]->port.lock);
+
+	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 err;
+}
+
+/* Platform device/driver remove */
+static int mxcuart_remove(struct platform_device *pdev)
+{
+	struct 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
@@ -67,3 +67,4 @@ obj-$(CONFIG_SERIAL_NETX) += netx-serial
 obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
 obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
 obj-$(CONFIG_SERIAL_QE) += ucc_uart.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
@@ -2,6 +2,7 @@
  *  linux/drivers/char/serial_core.h
  *
  *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *  Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  *
  * 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
@@ -156,6 +157,9 @@
 #define PORT_MN10300		80
 #define PORT_MN10300_CTS	81
 
+/* Freescale Semiconductor MXC fmaily */
+#define PORT_MXC        82
+
 #ifdef __KERNEL__
 
 #include <linux/compiler.h>
