Subject: imx uart: do not assume 16 MHz reference frequency
From: Sascha Hauer <s.hauer@pengutronix.de>

We assumed a 16MHz reference frequency for the UART. While this
is true for i.MX1 most of the time it is not true for MX27/MX31.
This calculation has been taken from the freescale bsp code.
Also, add handling for the ONEMS register which is present on
newer versions of the chip.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 drivers/serial/imx.c |   32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

Index: linux-2.6.26-rc6/drivers/serial/imx.c
===================================================================
--- linux-2.6.26-rc6.orig/drivers/serial/imx.c
+++ linux-2.6.26-rc6/drivers/serial/imx.c
@@ -589,6 +589,7 @@ imx_set_termios(struct uart_port *port, 
 	unsigned long flags;
 	unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
 	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+	unsigned int div, num, denom, ufcr;
 
 	/*
 	 * If we don't support modem control lines, don't allow
@@ -684,14 +685,25 @@ imx_set_termios(struct uart_port *port, 
 			sport->port.membase + UCR2);
 	old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
 
-	/* set the baud rate. We assume uartclk = 16 MHz
-	 *
-	 * baud * 16   UBIR - 1
-	 * --------- = --------
-	 *  uartclk    UBMR - 1
-	 */
-	writel((baud / 100) - 1, sport->port.membase + UBIR);
-	writel(10000 - 1, sport->port.membase + UBMR);
+	div = sport->port.uartclk / ((baud * 16) + 1000);
+	if (div > 6)
+		div = 6;
+
+	num = (baud / 100) - 1;
+	denom = (sport->port.uartclk / div / 1600) - 1;
+	if ((denom < 65536) && (sport->port.uartclk > 1600)) {
+		writel(num, sport->port.membase + UBIR);
+		writel(denom, sport->port.membase + UBMR);
+	}
+
+	ufcr = readl(sport->port.membase + UFCR);
+	ufcr = (ufcr & (~UFCR_RFDIV)) |
+	    ((6 - div) << 7);
+	writel(ufcr, sport->port.membase + UFCR);
+
+#ifdef ONEMS
+	writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
+#endif
 
 	writel(old_ucr1, sport->port.membase + UCR1);
 
@@ -812,7 +824,6 @@ static struct imx_port imx_ports[] = {
 		.membase	= (void *)IMX_UART1_BASE,
 		.mapbase	= 0x00206000,
 		.irq		= UART1_MINT_RX,
-		.uartclk	= 16000000,
 		.fifosize	= 32,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.ops		= &imx_pops,
@@ -828,7 +839,6 @@ static struct imx_port imx_ports[] = {
 		.membase	= (void *)IMX_UART2_BASE,
 		.mapbase	= 0x00207000,
 		.irq		= UART2_MINT_RX,
-		.uartclk	= 16000000,
 		.fifosize	= 32,
 		.flags		= UPF_BOOT_AUTOCONF,
 		.ops		= &imx_pops,
@@ -858,6 +868,8 @@ static void __init imx_init_ports(void)
 		init_timer(&imx_ports[i].timer);
 		imx_ports[i].timer.function = imx_timeout;
 		imx_ports[i].timer.data     = (unsigned long)&imx_ports[i];
+
+		imx_ports[i].port.uartclk = imx_get_perclk1();
 	}
 }
 
