Merge branch 'sh-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / tty / serial / imx.c
index a544731..827db76 100644 (file)
 #include <linux/delay.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <mach/hardware.h>
 #include <mach/imx-uart.h>
 
 /* Register definitions */
@@ -66,8 +67,9 @@
 #define UBIR  0xa4 /* BRM Incremental Register */
 #define UBMR  0xa8 /* BRM Modulator Register */
 #define UBRC  0xac /* Baud Rate Count Register */
-#define MX2_ONEMS 0xb0 /* One Millisecond register */
-#define UTS (cpu_is_mx1() ? 0xd0 : 0xb4) /* UART Test Register */
+#define IMX21_ONEMS 0xb0 /* One Millisecond register */
+#define IMX1_UTS 0xd0 /* UART Test Register on i.mx1 */
+#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
 
 /* UART Control Register Bit Fields.*/
 #define  URXD_CHARRDY    (1<<15)
@@ -87,7 +89,7 @@
 #define  UCR1_RTSDEN     (1<<5)         /* RTS delta interrupt enable */
 #define  UCR1_SNDBRK     (1<<4)         /* Send break */
 #define  UCR1_TDMAEN     (1<<3)         /* Transmitter ready DMA enable */
-#define  MX1_UCR1_UARTCLKEN  (1<<2)     /* UART clock enabled, mx1 only */
+#define  IMX1_UCR1_UARTCLKEN  (1<<2)  /* UART clock enabled, i.mx1 only */
 #define  UCR1_DOZE       (1<<1)         /* Doze */
 #define  UCR1_UARTEN     (1<<0)         /* UART enabled */
 #define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
 #define  UCR3_RXDSEN    (1<<6)  /* Receive status interrupt enable */
 #define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
 #define  UCR3_AWAKEN    (1<<4)  /* Async wake interrupt enable */
-#define  MX1_UCR3_REF25         (1<<3)  /* Ref freq 25 MHz, only on mx1 */
-#define  MX1_UCR3_REF30         (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
-#define  MX2_UCR3_RXDMUXSEL     (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
+#define  IMX21_UCR3_RXDMUXSEL   (1<<2)  /* RXD Muxed Input Select */
 #define  UCR3_INVT      (1<<1)  /* Inverted Infrared transmission */
 #define  UCR3_BPEN      (1<<0)  /* Preset registers enable */
 #define  UCR4_CTSTL_SHF  10      /* CTS trigger level shift */
 
 #define UART_NR 8
 
+/* i.mx21 type uart runs on all i.mx except i.mx1 */
+enum imx_uart_type {
+       IMX1_UART,
+       IMX21_UART,
+};
+
+/* device type dependent stuff */
+struct imx_uart_data {
+       unsigned uts_reg;
+       enum imx_uart_type devtype;
+};
+
 struct imx_port {
        struct uart_port        port;
        struct timer_list       timer;
@@ -192,6 +204,7 @@ struct imx_port {
        unsigned int            irda_inv_tx:1;
        unsigned short          trcv_delay; /* transceiver delay */
        struct clk              *clk;
+       struct imx_uart_data    *devdata;
 };
 
 #ifdef CONFIG_IRDA
@@ -200,6 +213,52 @@ struct imx_port {
 #define USE_IRDA(sport)        (0)
 #endif
 
+static struct imx_uart_data imx_uart_devdata[] = {
+       [IMX1_UART] = {
+               .uts_reg = IMX1_UTS,
+               .devtype = IMX1_UART,
+       },
+       [IMX21_UART] = {
+               .uts_reg = IMX21_UTS,
+               .devtype = IMX21_UART,
+       },
+};
+
+static struct platform_device_id imx_uart_devtype[] = {
+       {
+               .name = "imx1-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART],
+       }, {
+               .name = "imx21-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
+
+static struct of_device_id imx_uart_dt_ids[] = {
+       { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
+       { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
+
+static inline unsigned uts_reg(struct imx_port *sport)
+{
+       return sport->devdata->uts_reg;
+}
+
+static inline int is_imx1_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX1_UART;
+}
+
+static inline int is_imx21_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX21_UART;
+}
+
 /*
  * Handle any change of modem status signal since we were last called.
  */
@@ -326,7 +385,8 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
        struct circ_buf *xmit = &sport->port.state->xmit;
 
        while (!uart_circ_empty(xmit) &&
-                       !(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+                       !(readl(sport->port.membase + uts_reg(sport))
+                               & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
                 * out the port here */
                writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
@@ -373,7 +433,7 @@ static void imx_start_tx(struct uart_port *port)
                writel(temp, sport->port.membase + UCR4);
        }
 
-       if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+       if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
                imx_transmit_buffer(sport);
 }
 
@@ -689,9 +749,9 @@ static int imx_startup(struct uart_port *port)
                }
        }
 
-       if (!cpu_is_mx1()) {
+       if (is_imx21_uart(sport)) {
                temp = readl(sport->port.membase + UCR3);
-               temp |= MX2_UCR3_RXDMUXSEL;
+               temp |= IMX21_UCR3_RXDMUXSEL;
                writel(temp, sport->port.membase + UCR3);
        }
 
@@ -923,9 +983,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        writel(num, sport->port.membase + UBIR);
        writel(denom, sport->port.membase + UBMR);
 
-       if (!cpu_is_mx1())
+       if (is_imx21_uart(sport))
                writel(sport->port.uartclk / div / 1000,
-                               sport->port.membase + MX2_ONEMS);
+                               sport->port.membase + IMX21_ONEMS);
 
        writel(old_ucr1, sport->port.membase + UCR1);
 
@@ -954,7 +1014,7 @@ static void imx_release_port(struct uart_port *port)
        struct resource *mmres;
 
        mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mmres->start, mmres->end - mmres->start + 1);
+       release_mem_region(mmres->start, resource_size(mmres));
 }
 
 /*
@@ -970,8 +1030,7 @@ static int imx_request_port(struct uart_port *port)
        if (!mmres)
                return -ENODEV;
 
-       ret = request_mem_region(mmres->start, mmres->end - mmres->start + 1,
-                       "imx-uart");
+       ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart");
 
        return  ret ? 0 : -EBUSY;
 }
@@ -1042,7 +1101,7 @@ static void imx_console_putchar(struct uart_port *port, int ch)
 {
        struct imx_port *sport = (struct imx_port *)port;
 
-       while (readl(sport->port.membase + UTS) & UTS_TXFULL)
+       while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)
                barrier();
 
        writel(ch, sport->port.membase + URTX0);
@@ -1063,8 +1122,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
        ucr1 = old_ucr1 = readl(sport->port.membase + UCR1);
        old_ucr2 = readl(sport->port.membase + UCR2);
 
-       if (cpu_is_mx1())
-               ucr1 |= MX1_UCR1_UARTCLKEN;
+       if (is_imx1_uart(sport))
+               ucr1 |= IMX1_UCR1_UARTCLKEN;
        ucr1 |= UCR1_UARTEN;
        ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
 
@@ -1223,6 +1282,63 @@ static int serial_imx_resume(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(imx_uart_dt_ids, &pdev->dev);
+       int ret;
+
+       if (!np)
+               return -ENODEV;
+
+       ret = of_alias_get_id(np, "serial");
+       if (ret < 0) {
+               pr_err("%s: failed to get alias id, errno %d\n",
+                       __func__, ret);
+               return -ENODEV;
+       } else {
+               sport->port.line = ret;
+       }
+
+       if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+               sport->have_rtscts = 1;
+
+       if (of_get_property(np, "fsl,irda-mode", NULL))
+               sport->use_irda = 1;
+
+       sport->devdata = of_id->data;
+
+       return 0;
+}
+#else
+static inline int serial_imx_probe_dt(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       return -ENODEV;
+}
+#endif
+
+static void serial_imx_probe_pdata(struct imx_port *sport,
+               struct platform_device *pdev)
+{
+       struct imxuart_platform_data *pdata = pdev->dev.platform_data;
+
+       sport->port.line = pdev->id;
+       sport->devdata = (struct imx_uart_data  *) pdev->id_entry->driver_data;
+
+       if (!pdata)
+               return;
+
+       if (pdata->flags & IMXUART_HAVE_RTSCTS)
+               sport->have_rtscts = 1;
+
+       if (pdata->flags & IMXUART_IRDA)
+               sport->use_irda = 1;
+}
+
 static int serial_imx_probe(struct platform_device *pdev)
 {
        struct imx_port *sport;
@@ -1235,6 +1351,10 @@ static int serial_imx_probe(struct platform_device *pdev)
        if (!sport)
                return -ENOMEM;
 
+       ret = serial_imx_probe_dt(sport, pdev);
+       if (ret == -ENODEV)
+               serial_imx_probe_pdata(sport, pdev);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                ret = -ENODEV;
@@ -1259,7 +1379,6 @@ static int serial_imx_probe(struct platform_device *pdev)
        sport->port.fifosize = 32;
        sport->port.ops = &imx_pops;
        sport->port.flags = UPF_BOOT_AUTOCONF;
-       sport->port.line = pdev->id;
        init_timer(&sport->timer);
        sport->timer.function = imx_timeout;
        sport->timer.data     = (unsigned long)sport;
@@ -1273,17 +1392,9 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        sport->port.uartclk = clk_get_rate(sport->clk);
 
-       imx_ports[pdev->id] = sport;
+       imx_ports[sport->port.line] = sport;
 
        pdata = pdev->dev.platform_data;
-       if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-               sport->have_rtscts = 1;
-
-#ifdef CONFIG_IRDA
-       if (pdata && (pdata->flags & IMXUART_IRDA))
-               sport->use_irda = 1;
-#endif
-
        if (pdata && pdata->init) {
                ret = pdata->init(pdev);
                if (ret)
@@ -1341,9 +1452,11 @@ static struct platform_driver serial_imx_driver = {
 
        .suspend        = serial_imx_suspend,
        .resume         = serial_imx_resume,
+       .id_table       = imx_uart_devtype,
        .driver         = {
                .name   = "imx-uart",
                .owner  = THIS_MODULE,
+               .of_match_table = imx_uart_dt_ids,
        },
 };