Skip to contentSkip to conversation

Fix up the imx uart driver so it now compiles with new kernels.

PATCH New Greg Gallagher 1 participant 1 message Jan 9, 2018 Arm i.MX and Layerscape

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Fix up the imx uart driver so it now compiles with new kernels.

From: Wolfgang Netbal <[email protected]>

This patch is based on one that was submitted by Michael Welling back in Feb
2016 but a formal patch was never submitted. The original thread that this
patch was derived from is located here https://xenomai.org/pipermail/xenomai/2016-February/035924.html

Fixed up kernel style errors and I added a couple small changes and tested on a imx7d board. One quick note, the IMX7D define may not really be needed since most imx7 uarts look to be compatible with imx6.

---
 kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
 1 file changed, 229 insertions(+), 108 deletions(-)
kernel/drivers/serial/rt_imx_uart.c +229 -108
index 092cecc..2c93789 100644
@@ -36,8 +36,10 @@
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/div64.h>
-#include <mach/hardware.h>
-#include <mach/imx-uart.h>
+#include <linux/platform_data/serial-imx.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <rtdm/serial.h>
 #include <rtdm/driver.h>
@@ -65,7 +67,10 @@ MODULE_LICENSE("GPL");
 #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 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)
@@ -143,7 +148,7 @@ MODULE_LICENSE("GPL");
 #define USR1_DTRD	(1<<7)	/* DTR Delta */
 #define USR1_RXDS	(1<<6)	/* Receiver idle interrupt flag */
 #define USR1_AIRINT	(1<<5)	/* Async IR wake interrupt flag */
-#define USR1_AWAKE	(1<<4)	/* Aysnc wake interrupt flag */
+#define USR1_AWAKE	(1<<4)	/* Async wake interrupt flag */
 #define USR2_ADET	(1<<15) /* Auto baud rate detect complete */
 #define USR2_TXFE	(1<<14) /* Transmit buffer FIFO empty */
 #define USR2_DTRF	(1<<13) /* DTR edge interrupt flag */
@@ -189,9 +194,25 @@ MODULE_LICENSE("GPL");
 #define RT_IMX_UART_MAX		5
 
 static int tx_fifo[RT_IMX_UART_MAX];
-compat_module_param_array(tx_fifo, int, RT_IMX_UART_MAX, 0400);
+module_param_array(tx_fifo, int, NULL, 0400);
 MODULE_PARM_DESC(tx_fifo, "Transmitter FIFO size");
 
+/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */
+enum imx_uart_type {
+	IMX1_UART,
+	IMX21_UART,
+	IMX53_UART,
+	IMX6Q_UART,
+	IMX7D_UART,
+};
+
+/* device type dependent stuff */
+struct imx_uart_data {
+	unsigned int uts_reg;
+	enum imx_uart_type devtype;
+};
+
+
 struct rt_imx_uart_port {
 	unsigned char __iomem *membase;	/* read/write[bwl] */
 	resource_size_t mapbase;	/* for ioremap */
@@ -200,11 +221,79 @@ struct rt_imx_uart_port {
 	unsigned int have_rtscts;
 	unsigned int use_dcedte;
 	unsigned int use_hwflow;
-	struct clk *clk;		/* clock id for UART clock */
+	struct clk *clk_ipg;		/* clock id for UART clock */
+	struct clk *clk_per;		/* clock id for UART clock */
+	const struct imx_uart_data *devdata;
 	unsigned int uartclk;		/* base uart clock */
 	struct rtdm_device rtdm_dev;	/* RTDM device structure */
 };
 
+
+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,
+	},
+	[IMX53_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX53_UART,
+	},
+	[IMX6Q_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX6Q_UART,
+	},
+	[IMX7D_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX7D_UART,
+	},
+};
+
+static const struct platform_device_id rt_imx_uart_id_table[] = {
+	{
+		.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],
+	}, {
+		.name = "imx53-uart",
+		.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART],
+	}, {
+		.name = "imx6q-uart",
+		.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
+	}, {
+		.name = "imx-uart",
+		.driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX7D_UART],
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(platform, rt_imx_uart_id_table);
+
+static const struct of_device_id rt_imx_uart_dt_ids[] = {
+	{
+		.compatible = "fsl,imx7d-uart",
+		.data = &imx_uart_devdata[IMX7D_UART], },
+	{
+		.compatible = "fsl,imx6q-uart",
+		.data = &imx_uart_devdata[IMX6Q_UART], },
+	{
+		.compatible = "fsl,imx53-uart",
+		.data = &imx_uart_devdata[IMX53_UART], },
+	{
+		.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, rt_imx_uart_dt_ids);
+
 struct rt_imx_uart_ctx {
 	struct rtser_config config;	/* current device configuration */
 
@@ -217,6 +306,7 @@ struct rt_imx_uart_ctx {
 	int in_nwait;			/* bytes the user waits for */
 	rtdm_event_t in_event;		/* raised to unblock reader */
 	char in_buf[IN_BUFFER_SIZE];	/* RX ring buffer */
+
 	volatile unsigned long in_lock;	/* single-reader lock */
 	uint64_t *in_history;		/* RX timestamp buffer */
 
@@ -344,6 +434,7 @@ static int rt_imx_uart_rx_chars(struct rt_imx_uart_ctx *ctx,
 static void rt_imx_uart_tx_chars(struct rt_imx_uart_ctx *ctx)
 {
 	int ch, count;
+	unsigned int uts_reg = ctx->port->devdata->uts_reg;
 
 	for (count = ctx->port->tx_fifo;
 	     (count > 0) && (ctx->out_npend > 0);
@@ -352,7 +443,7 @@ static void rt_imx_uart_tx_chars(struct rt_imx_uart_ctx *ctx)
 		writel(ch, ctx->port->membase + URTX0);
 		ctx->out_head &= (OUT_BUFFER_SIZE - 1);
 
-		if (readl(ctx->port->membase + UTS) & UTS_TXFULL)
+		if (readl(ctx->port->membase + uts_reg) & UTS_TXFULL)
 			break;
 	}
 }
@@ -458,7 +549,7 @@ static int rt_imx_uart_int(rtdm_irq_t *irq_context)
 	rtdm_lock_put(&ctx->lock);
 
 	if (ret != RTDM_IRQ_HANDLED)
-		printk(KERN_WARNING "%s: unhandled interrupt\n", __func__);
+		pr_warn("%s: unhandled interrupt\n", __func__);
 	return ret;
 }
 
@@ -493,9 +584,10 @@ static unsigned int rt_imx_uart_get_msr(struct rt_imx_uart_ctx *ctx)
 static void rt_imx_uart_set_mcr(struct rt_imx_uart_ctx *ctx,
 				unsigned int mcr)
 {
+	unsigned int uts_reg = ctx->port->devdata->uts_reg;
 	unsigned long ucr2 = readl(ctx->port->membase + UCR2);
 	unsigned long ucr3 = readl(ctx->port->membase + UCR3);
-	unsigned long uts = readl(ctx->port->membase + UTS);
+	unsigned long uts = readl(ctx->port->membase + uts_reg);
 
 	if (mcr & RTSER_MCR_RTS) {
 		/*
@@ -523,7 +615,7 @@ static void rt_imx_uart_set_mcr(struct rt_imx_uart_ctx *ctx,
 		uts |= UTS_LOOP;
 	else
 		uts &= ~UTS_LOOP;
-	writel(uts, ctx->port->membase + UTS);
+	writel(uts, ctx->port->membase + uts_reg);
 }
 
 static void rt_imx_uart_break_ctl(struct rt_imx_uart_ctx *ctx,
@@ -557,7 +649,8 @@ static int rt_imx_uart_set_config(struct rt_imx_uart_ctx *ctx,
 		ctx->config.stop_bits = config->stop_bits & STOP_BITS_MASK;
 
 	/* Timeout manipulation is not atomic. The user is supposed to take
-	   care not to use and change timeouts at the same time. */
+	 * care not to use and change timeouts at the same time.
+	 */
 	if (config->config_mask & RTSER_SET_TIMEOUT_RX)
 		ctx->config.rx_timeout = config->rx_timeout;
 	if (config->config_mask & RTSER_SET_TIMEOUT_TX)
@@ -723,7 +816,7 @@ static int rt_imx_uart_setup_ufcr(struct rt_imx_uart_port *port)
 	 * RFDIV is set such way to satisfy requested uartclk value
 	 */
 	val = TXTL << 10 | RXTL;
-	ufcr_rfdiv = (clk_get_rate(port->clk) + port->uartclk / 2) /
+	ufcr_rfdiv = (clk_get_rate(port->clk_per) + port->uartclk / 2) /
 		port->uartclk;
 
 	if (!ufcr_rfdiv)
@@ -852,8 +945,7 @@ void rt_imx_uart_close(struct rtdm_fd *fd)
 	rtdm_irq_free(&ctx->irq_handle);
 	rt_imx_uart_cleanup_ctx(ctx);
 
-	if (in_history)
-		kfree(in_history);
+	kfree(in_history);
 }
 
 static int rt_imx_uart_ioctl(struct rtdm_fd *fd,
@@ -897,7 +989,7 @@ static int rt_imx_uart_ioctl(struct rtdm_fd *fd,
 		}
 
 		if ((config->config_mask & RTSER_SET_BAUD) &&
-		    (config->baud_rate > clk_get_rate(ctx->port->clk) / 16 ||
+		    (config->baud_rate > clk_get_rate(ctx->port->clk_per) / 16 ||
 		     config->baud_rate <= 0))
 			/* invalid baudrate for this port */
 			return -EINVAL;
@@ -910,7 +1002,8 @@ static int rt_imx_uart_ioctl(struct rtdm_fd *fd,
 			if (rtdm_in_rt_context())
 				return -ENOSYS;
 
-			if (config->timestamp_history & RTSER_RX_TIMESTAMP_HISTORY)
+			if (config->timestamp_history &
+						RTSER_RX_TIMESTAMP_HISTORY)
 				hist_buf = kmalloc(IN_BUFFER_SIZE *
 						   sizeof(nanosecs_abs_t),
 						   GFP_KERNEL);
@@ -918,9 +1011,7 @@ static int rt_imx_uart_ioctl(struct rtdm_fd *fd,
 
 		rt_imx_uart_set_config(ctx, config, &hist_buf);
 
-		if (hist_buf)
-			kfree(hist_buf);
-
+		kfree(hist_buf);
 		break;
 	}
 
@@ -994,7 +1085,8 @@ static int rt_imx_uart_ioctl(struct rtdm_fd *fd,
 
 		while (!ctx->ioc_events) {
 			/* Only enable error interrupt
-			   when the user waits for it. */
+			 * when the user waits for it.
+			 */
 			if (ctx->config.event_mask & RTSER_EVENT_ERRPEND) {
 				ctx->ier_status |= IER_STAT;
 #ifdef FIXME
@@ -1144,7 +1236,8 @@ ssize_t rt_imx_uart_read(struct rtdm_fd *fd, void *buf, size_t nbyte)
 			/* Do we have to wrap around the buffer end? */
 			if (in_pos + subblock > IN_BUFFER_SIZE) {
 				/* Treat the block between head and buffer end
-				   separately. */
+				 * separately.
+				 */
 				subblock = IN_BUFFER_SIZE - in_pos;
 
 				if (rtdm_fd_is_user(fd)) {
@@ -1196,8 +1289,9 @@ ssize_t rt_imx_uart_read(struct rtdm_fd *fd, void *buf, size_t nbyte)
 
 		if (nonblocking)
 			/* ret was set to EAGAIN in case of a real
-			   non-blocking call or contains the error
-			   returned by rtdm_event_wait[_until] */
+			 * non-blocking call or contains the error
+			 * returned by rtdm_event_wait[_until]
+			 */
 			break;
 
 		ctx->in_nwait = nbyte;
@@ -1210,7 +1304,8 @@ ssize_t rt_imx_uart_read(struct rtdm_fd *fd, void *buf, size_t nbyte)
 		if (ret < 0) {
 			if (ret == -EIDRM) {
 				/* Device has been closed -
-				   return immediately. */
+				 * return immediately.
+				 */
 				return -EBADF;
 			}
 
@@ -1219,7 +1314,8 @@ ssize_t rt_imx_uart_read(struct rtdm_fd *fd, void *buf, size_t nbyte)
 			nonblocking = 1;
 			if (ctx->in_npend > 0) {
 				/* Final turn: collect pending bytes
-				   before exit. */
+				 * before exit.
+				 */
 				continue;
 			}
 
@@ -1287,7 +1383,8 @@ static ssize_t rt_imx_uart_write(struct rtdm_fd *fd, const void *buf,
 			/* Do we have to wrap around the buffer end? */
 			if (out_pos + subblock > OUT_BUFFER_SIZE) {
 				/* Treat the block between head and buffer
-				   end separately. */
+				 * end separately.
+				 */
 				subblock = OUT_BUFFER_SIZE - out_pos;
 
 				if (rtdm_fd_is_user(fd)) {
@@ -1344,7 +1441,8 @@ static ssize_t rt_imx_uart_write(struct rtdm_fd *fd, const void *buf,
 		if (ret < 0) {
 			if (ret == -EIDRM) {
 				/* Device has been closed -
-				   return immediately. */
+				 * return immediately.
+				 */
 				return -EBADF;
 			}
 			if (ret == -EWOULDBLOCK) {
@@ -1382,42 +1480,96 @@ static struct rtdm_driver imx_uart_driver = {
 	},
 };
 
+
+#ifdef CONFIG_OF
+
+/*
+ * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
+ * could successfully get all information from dt or a negative errno.
+ */
+static int rt_imx_uart_probe_dt(struct rt_imx_uart_port *port,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(rt_imx_uart_dt_ids, &pdev->dev);
+	int ret;
+
+	if (!np)
+		/* no device tree device */
+		return 1;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+
+	pdev->id = ret;
+
+	if (of_get_property(np, "fsl,uart-has-rtscts", NULL))
+		port->have_rtscts = 1;
+	if (of_get_property(np, "fsl,irda-mode", NULL))
+		dev_warn(&pdev->dev, "IRDA not yet supported\n");
+
+	if (of_get_property(np, "fsl,dte-mode", NULL))
+		port->use_dcedte = 1;
+
+	port->devdata = of_id->data;
+
+	return 0;
+}
+#else
+static inline int rt_imx_uart_probe_dt(struct rt_imx_uart_port *port,
+				       struct platform_device *pdev)
+{
+	return 1;
+}
+#endif
+
+static void rt_imx_uart_probe_pdata(struct rt_imx_uart_port *port,
+				    struct platform_device *pdev)
+{
+	struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	port->devdata = (struct imx_uart_data  *) pdev->id_entry->driver_data;
+
+	if (!pdata)
+		return;
+
+	if (pdata->flags & IMXUART_HAVE_RTSCTS)
+		port->have_rtscts = 1;
+}
+
 static int rt_imx_uart_probe(struct platform_device *pdev)
 {
-	struct imxuart_platform_data *pdata;
 	struct rtdm_device *dev;
 	struct rt_imx_uart_port *port;
 	struct resource *res;
-	int err;
+	int ret;
 
-	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
 	if (!port)
 		return -ENOMEM;
 
+	ret = rt_imx_uart_probe_dt(port, pdev);
+	if (ret > 0)
+		rt_imx_uart_probe_pdata(port, pdev);
+	else if (ret < 0)
+		return ret;
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res) {
-		err = -ENODEV;
-		goto kfree_out;
-	}
-	port->mapbase = res->start;
+	if (!res)
+		return -ENODEV;
 
 	port->irq = platform_get_irq(pdev, 0);
-	if (port->irq <= 0) {
-		err = -ENODEV;
-		goto kfree_out;
-	}
 
-	if (!request_mem_region(port->mapbase, PAGE_SIZE, DRIVER_NAME)) {
-		err = -EBUSY;
-		goto kfree_out;
-	}
-
-	port->membase = ioremap(port->mapbase, PAGE_SIZE);
-	if (!port->membase) {
-		err = -ENOMEM;
-		goto release_mem_region_out;
-	}
+	if (port->irq <= 0)
+		return -ENODEV;
 
+	port->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(port->membase))
+		return PTR_ERR(port->membase);
 
 	dev = &port->rtdm_dev;
 	dev->driver = &imx_uart_driver;
@@ -1429,54 +1581,29 @@ static int rt_imx_uart_probe(struct platform_device *pdev)
 	else
 		port->tx_fifo = tx_fifo[pdev->id];
 
-	port->clk = clk_get(&pdev->dev, "uart");
-	if (IS_ERR(port->clk)) {
-		err = PTR_ERR(port->clk);
-		goto iounmap_out;
-	}
-	clk_enable(port->clk);
-	port->uartclk = clk_get_rate(port->clk);
+	port->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
+	if (IS_ERR(port->clk_ipg))
+		return PTR_ERR(port->clk_ipg);
 
-	port->use_hwflow = 1;
+	port->clk_per = devm_clk_get(&pdev->dev, "per");
+	if (IS_ERR(port->clk_per))
+		return PTR_ERR(port->clk_per);
 
-	pdata = pdev->dev.platform_data;
-	if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
-		port->have_rtscts = 1;
-	if (pdata && (pdata->flags & IMXUART_USE_DCEDTE))
-		port->use_dcedte = 1;
-	if (pdata && pdata->init) {
-		err = pdata->init(pdev);
-		if (err)
-			goto clk_disable_out;
-	}
+	clk_enable(port->clk_ipg);
+	clk_enable(port->clk_per);
+	port->uartclk = clk_get_rate(port->clk_per);
 
-	err = rtdm_dev_register(dev);
-	if (err)
-		goto pdata_exit_out;
+	port->use_hwflow = 1;
 
-	platform_set_drvdata(pdev, port);
+	ret = rtdm_dev_register(dev);
+	if (ret)
+		return ret;
 
-	printk(KERN_INFO
-	       "%s on IMX UART%d: membase=0x%p mapbase=%#x irq=%d uartclk=%d\n",
-	       dev->name, pdev->id, port->membase, (u32)port->mapbase,
-	       port->irq, port->uartclk);
+	platform_set_drvdata(pdev, port);
 
+	pr_info("%s on IMX UART%d: membase=0x%p irq=%d uartclk=%d\n",
+	       dev->name, pdev->id, port->membase, port->irq, port->uartclk);
 	return 0;
-
-pdata_exit_out:
-	if (pdata && pdata->exit)
-		pdata->exit(pdev);
-clk_disable_out:
-	clk_put(port->clk);
-	clk_disable(port->clk);
-iounmap_out:
-	iounmap(port->membase);
-release_mem_region_out:
-	release_mem_region(port->mapbase, SZ_4K);
-kfree_out:
-	kfree(port);
-
-	return err;
 }
 
 static int rt_imx_uart_remove(struct platform_device *pdev)
@@ -1490,26 +1617,9 @@ static int rt_imx_uart_remove(struct platform_device *pdev)
 
 	rtdm_dev_unregister(dev);
 
-	if (port->clk) {
-		clk_put(port->clk);
-		clk_disable(port->clk);
-	}
-
-	if (pdata && pdata->exit)
-		pdata->exit(pdev);
-
-	iounmap(port->membase);
-	release_mem_region(port->mapbase, PAGE_SIZE);
-	kfree(port);
-
 	return 0;
 }
 
-static const struct platform_device_id rt_imx_uart_id_table[] = {
-	{"imx-uart",},
-	{},
-};
-
 static struct platform_driver rt_imx_uart_driver = {
 	.probe = rt_imx_uart_probe,
 	.remove	= rt_imx_uart_remove,
@@ -1517,15 +1627,26 @@ static struct platform_driver rt_imx_uart_driver = {
 	.driver = {
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
+		.of_match_table = rt_imx_uart_dt_ids,
 	},
+	.prevent_deferred_probe = true,
 };
 
+
 static int __init rt_imx_uart_init(void)
 {
+	int ret;
+
 	if (!realtime_core_enabled())
 		return 0;
 
-	return platform_driver_register(&rt_imx_uart_driver);
+	ret = platform_driver_register(&rt_imx_uart_driver);
+	if (ret) {
+		pr_err("%s; Could not register  driver (err=%d)\n",
+			__func__, ret);
+	}
+
+	return ret;
 }
 
 static void __exit rt_imx_uart_exit(void)
Signature · 1 line
2.7.4