mxc: add MX3 support for i.MX internal UART driver
authorSascha Hauer <s.hauer@pengutronix.de>
Sat, 5 Jul 2008 08:02:48 +0000 (10:02 +0200)
committerRobert Schwebel <r.schwebel@pengutronix.de>
Sat, 5 Jul 2008 08:02:48 +0000 (10:02 +0200)
This patch adds MX3 support for the i.MX internal uart driver.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/devices.c [new file with mode: 0644]
drivers/serial/Kconfig
drivers/serial/imx.c
include/asm-arm/arch-mxc/imx-uart.h [new file with mode: 0644]

index febb37f..a788cb0 100644 (file)
@@ -4,5 +4,5 @@
 
 # Object file lists.
 
-obj-y                  := mm.o time.o clock.o
+obj-y                  := mm.o time.o clock.o devices.o
 obj-$(CONFIG_MACH_MX31ADS)     += mx31ads.o
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
new file mode 100644 (file)
index 0000000..1bc6d23
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Sascha Hauer, 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/platform_device.h>
+#include <linux/serial.h>
+#include <asm/hardware.h>
+#include <asm/arch/imx-uart.h>
+
+static struct resource uart0[] = {
+       {
+               .start = UART1_BASE_ADDR,
+               .end = UART1_BASE_ADDR + 0x0B5,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MXC_INT_UART1,
+               .end = MXC_INT_UART1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mxc_uart_device0 = {
+       .name = "imx-uart",
+       .id = 0,
+       .resource = uart0,
+       .num_resources = ARRAY_SIZE(uart0),
+};
+
+static struct resource uart1[] = {
+       {
+               .start = UART2_BASE_ADDR,
+               .end = UART2_BASE_ADDR + 0x0B5,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MXC_INT_UART2,
+               .end = MXC_INT_UART2,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mxc_uart_device1 = {
+       .name = "imx-uart",
+       .id = 1,
+       .resource = uart1,
+       .num_resources = ARRAY_SIZE(uart1),
+};
+
+static struct resource uart2[] = {
+       {
+               .start = UART3_BASE_ADDR,
+               .end = UART3_BASE_ADDR + 0x0B5,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MXC_INT_UART3,
+               .end = MXC_INT_UART3,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mxc_uart_device2 = {
+       .name = "imx-uart",
+       .id = 2,
+       .resource = uart2,
+       .num_resources = ARRAY_SIZE(uart2),
+};
+
+static struct resource uart3[] = {
+       {
+               .start = UART4_BASE_ADDR,
+               .end = UART4_BASE_ADDR + 0x0B5,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MXC_INT_UART4,
+               .end = MXC_INT_UART4,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mxc_uart_device3 = {
+       .name = "imx-uart",
+       .id = 3,
+       .resource = uart3,
+       .num_resources = ARRAY_SIZE(uart3),
+};
+
+static struct resource uart4[] = {
+       {
+               .start = UART5_BASE_ADDR,
+               .end = UART5_BASE_ADDR + 0x0B5,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = MXC_INT_UART5,
+               .end = MXC_INT_UART5,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device mxc_uart_device4 = {
+       .name = "imx-uart",
+       .id = 4,
+       .resource = uart4,
+       .num_resources = ARRAY_SIZE(uart4),
+};
+
+/*
+ * Register only those UARTs that physically exist
+ */
+int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata)
+{
+       switch (uart_no) {
+       case 0:
+               mxc_uart_device0.dev.platform_data = pdata;
+               platform_device_register(&mxc_uart_device0);
+               break;
+       case 1:
+               mxc_uart_device1.dev.platform_data = pdata;
+               platform_device_register(&mxc_uart_device1);
+               break;
+       case 2:
+               mxc_uart_device2.dev.platform_data = pdata;
+               platform_device_register(&mxc_uart_device2);
+               break;
+       case 3:
+               mxc_uart_device3.dev.platform_data = pdata;
+               platform_device_register(&mxc_uart_device3);
+               break;
+       case 4:
+               mxc_uart_device4.dev.platform_data = pdata;
+               platform_device_register(&mxc_uart_device4);
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
index 9bc4276..0843c54 100644 (file)
@@ -753,7 +753,7 @@ config BFIN_UART3_CTSRTS
 
 config SERIAL_IMX
        bool "IMX serial port support"
-       depends on ARM && ARCH_IMX
+       depends on ARM && (ARCH_IMX || ARCH_MXC)
        select SERIAL_CORE
        help
          If you have a machine based on a Motorola IMX CPU you
index 9e2162e..549440b 100644 (file)
 #define UBIR  0xa4 /* BRM Incremental Register */
 #define UBMR  0xa8 /* BRM Modulator Register */
 #define UBRC  0xac /* Baud Rate Count Register */
+#ifdef CONFIG_ARCH_MX3
+#define ONEMS 0xb0 /* One Millisecond register */
+#define UTS   0xb4 /* UART Test Register */
+#endif
+#ifdef CONFIG_ARCH_IMX
 #define BIPR1 0xb0 /* Incremental Preset Register 1 */
 #define BIPR2 0xb4 /* Incremental Preset Register 2 */
 #define BIPR3 0xb8 /* Incremental Preset Register 3 */
@@ -71,6 +76,7 @@
 #define BMPR3 0xc8 /* BRM Modulator Register 3 */
 #define BMPR4 0xcc /* BRM Modulator Register 4 */
 #define UTS   0xd0 /* UART Test Register */
+#endif
 
 /* UART Control Register Bit Fields.*/
 #define  URXD_CHARRDY    (1<<15)
 #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 */
+#ifdef CONFIG_ARCH_IMX
 #define  UCR1_UARTCLKEN  (1<<2)         /* UART clock enabled */
+#endif
+#ifdef CONFIG_ARCH_MX3
+#define  UCR1_UARTCLKEN  (0)    /* not present on mx2/mx3 */
+#endif
 #define  UCR1_DOZE       (1<<1)         /* Doze */
 #define  UCR1_UARTEN     (1<<0)         /* UART enabled */
 #define  UCR2_ESCI              (1<<15) /* Escape seq interrupt enable */
 #define  UTS_SOFTRST    (1<<0)  /* Software reset */
 
 /* We've been assigned a range on the "Low-density serial ports" major */
+#ifdef CONFIG_ARCH_IMX
 #define SERIAL_IMX_MAJOR       204
 #define MINOR_START            41
+#define DEV_NAME               "ttySMX"
+#define MAX_INTERNAL_IRQ       IMX_IRQS
+#endif
+
+#ifdef CONFIG_ARCH_MX3
+#define SERIAL_IMX_MAJOR        207
+#define MINOR_START            16
+#define DEV_NAME               "ttymxc"
+#define MAX_INTERNAL_IRQ       MXC_MAX_INT_LINES
+#endif
 
 /*
  * This determines how often we check the modem status signals
@@ -409,6 +431,26 @@ out:
        return IRQ_HANDLED;
 }
 
+static irqreturn_t imx_int(int irq, void *dev_id)
+{
+       struct imx_port *sport = dev_id;
+       unsigned int sts;
+
+       sts = readl(sport->port.membase + USR1);
+
+       if (sts & USR1_RRDY)
+               imx_rxint(irq, dev_id);
+
+       if (sts & USR1_TRDY &&
+                       readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+               imx_txint(irq, dev_id);
+
+       if (sts & USR1_RTSS)
+               imx_rtsint(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
 /*
  * Return TIOCSER_TEMT when transmitter is not busy.
  */
@@ -514,21 +556,34 @@ static int imx_startup(struct uart_port *port)
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
        /*
-        * Allocate the IRQ
+        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
+        * chips only have one interrupt.
         */
-       retval = request_irq(sport->rxirq, imx_rxint, 0,
-                            DRIVER_NAME, sport);
-       if (retval) goto error_out1;
-
-       retval = request_irq(sport->txirq, imx_txint, 0,
-                            DRIVER_NAME, sport);
-       if (retval) goto error_out2;
-
-       retval = request_irq(sport->rtsirq, imx_rtsint,
-                            (sport->rtsirq < IMX_IRQS) ? 0 :
+       if (sport->txirq > 0) {
+               retval = request_irq(sport->rxirq, imx_rxint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out1;
+
+               retval = request_irq(sport->txirq, imx_txint, 0,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out2;
+
+               retval = request_irq(sport->rtsirq, imx_rtsint,
+                            (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                            DRIVER_NAME, sport);
-       if (retval) goto error_out3;
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out3;
+       } else {
+               retval = request_irq(sport->port.irq, imx_int, 0,
+                               DRIVER_NAME, sport);
+               if (retval) {
+                       free_irq(sport->port.irq, sport);
+                       goto error_out1;
+               }
+       }
 
        /*
         * Finally, clear and enable interrupts
@@ -553,9 +608,11 @@ static int imx_startup(struct uart_port *port)
        return 0;
 
 error_out3:
-       free_irq(sport->txirq, sport);
+       if (sport->txirq)
+               free_irq(sport->txirq, sport);
 error_out2:
-       free_irq(sport->rxirq, sport);
+       if (sport->rxirq)
+               free_irq(sport->rxirq, sport);
 error_out1:
        return retval;
 }
@@ -573,9 +630,12 @@ static void imx_shutdown(struct uart_port *port)
        /*
         * Free the interrupts
         */
-       free_irq(sport->rtsirq, sport);
-       free_irq(sport->txirq, sport);
-       free_irq(sport->rxirq, sport);
+       if (sport->txirq > 0) {
+               free_irq(sport->rtsirq, sport);
+               free_irq(sport->txirq, sport);
+               free_irq(sport->rxirq, sport);
+       } else
+               free_irq(sport->port.irq, sport);
 
        /*
         * Disable all interrupts, port and break condition.
@@ -973,7 +1033,7 @@ imx_console_setup(struct console *co, char *options)
 
 static struct uart_driver imx_reg;
 static struct console imx_console = {
-       .name           = "ttySMX",
+       .name           = DEV_NAME,
        .write          = imx_console_write,
        .device         = uart_console_device,
        .setup          = imx_console_setup,
@@ -990,7 +1050,7 @@ static struct console imx_console = {
 static struct uart_driver imx_reg = {
        .owner          = THIS_MODULE,
        .driver_name    = DRIVER_NAME,
-       .dev_name       = "ttySMX",
+       .dev_name       = DEV_NAME,
        .major          = SERIAL_IMX_MAJOR,
        .minor          = MINOR_START,
        .nr             = ARRAY_SIZE(imx_ports),
diff --git a/include/asm-arm/arch-mxc/imx-uart.h b/include/asm-arm/arch-mxc/imx-uart.h
new file mode 100644 (file)
index 0000000..83fb72c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 by Sascha Hauer <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.
+ */
+
+#ifndef ASMARM_ARCH_UART_H
+#define ASMARM_ARCH_UART_H
+
+#define IMXUART_HAVE_RTSCTS (1<<0)
+
+struct imxuart_platform_data {
+       int (*init)(struct platform_device *pdev);
+       int (*exit)(struct platform_device *pdev);
+       unsigned int flags;
+};
+
+int __init imx_init_uart(int uart_no, struct imxuart_platform_data *pdata);
+
+#endif