* [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
@ 2018-01-08 21:09 Greg Gallagher
2018-01-08 21:16 ` Michael Welling
0 siblings, 1 reply; 12+ messages in thread
From: Greg Gallagher @ 2018-01-08 21:09 UTC (permalink / raw)
To: xenomai
From: Michael Welling <mwelling@ieee.org>
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.
Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
---
kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
1 file changed, 229 insertions(+), 108 deletions(-)
diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
index 092cecc..2c93789 100644
--- a/kernel/drivers/serial/rt_imx_uart.c
+++ b/kernel/drivers/serial/rt_imx_uart.c
@@ -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)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-08 21:09 [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels Greg Gallagher
@ 2018-01-08 21:16 ` Michael Welling
2018-01-08 21:23 ` Greg Gallagher
0 siblings, 1 reply; 12+ messages in thread
From: Michael Welling @ 2018-01-08 21:16 UTC (permalink / raw)
To: Greg Gallagher; +Cc: xenomai
On Mon, Jan 8, 2018 at 3:09 PM, Greg Gallagher <greg@embeddedgreg.com> wrote:
>
> From: Michael Welling <mwelling@ieee.org>
>
> 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
If you look closely it was a patch from Wolfgang Netbal.
>
>
>
>
> 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.
>
> Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
> ---
> kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
> 1 file changed, 229 insertions(+), 108 deletions(-)
>
> diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
> index 092cecc..2c93789 100644
> --- a/kernel/drivers/serial/rt_imx_uart.c
> +++ b/kernel/drivers/serial/rt_imx_uart.c
> @@ -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)
> --
> 2.7.4
>
--
Michael Welling
Embedded System Architect / Founder
QWERTY Embedded Design, LLC - www.qwertyembedded.com
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-08 21:16 ` Michael Welling
@ 2018-01-08 21:23 ` Greg Gallagher
0 siblings, 0 replies; 12+ messages in thread
From: Greg Gallagher @ 2018-01-08 21:23 UTC (permalink / raw)
To: Michael Welling; +Cc: xenomai@xenomai.org
Had it correct the first time, I'll fix that up.
Thanks
Greg
Original Message
From: mwelling@ieee.org
Sent: January 8, 2018 4:16 PM
To: greg@embeddedgreg.com
Cc: xenomai@xenomai.org
Subject: Re: [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
On Mon, Jan 8, 2018 at 3:09 PM, Greg Gallagher <greg@embeddedgreg.com> wrote:
>
> From: Michael Welling <mwelling@ieee.org>
>
> 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
If you look closely it was a patch from Wolfgang Netbal.
>
>
>
>
> 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.
>
> Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
> ---
> kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
> 1 file changed, 229 insertions(+), 108 deletions(-)
>
> diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
> index 092cecc..2c93789 100644
> --- a/kernel/drivers/serial/rt_imx_uart.c
> +++ b/kernel/drivers/serial/rt_imx_uart.c
> @@ -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)
> --
> 2.7.4
>
--
Michael Welling
Embedded System Architect / Founder
QWERTY Embedded Design, LLC - www.qwertyembedded.com
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
@ 2018-02-02 3:06 Greg Gallagher
0 siblings, 0 replies; 12+ messages in thread
From: Greg Gallagher @ 2018-02-02 3:06 UTC (permalink / raw)
To: xenomai
This patch is based on one that was submitted by Wolfgang Netbal back in Feb
2016 but a formal patch was never submitted.
I added a couple small changes (style errors and imx7 define) 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. The original thread that this
patch was derived from is located here:
https://xenomai.org/pipermail/xenomai/2016-February/035924.html
Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
---
kernel/drivers/serial/rt_imx_uart.c | 326 ++++++++++++++++++++++++------------
1 file changed, 218 insertions(+), 108 deletions(-)
diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
index 092cecc..61836ae 100644
--- a/kernel/drivers/serial/rt_imx_uart.c
+++ b/kernel/drivers/serial/rt_imx_uart.c
@@ -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,24 @@ 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,
+};
+
+/* 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 +220,69 @@ 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,
+ },
+};
+
+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],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(platform, rt_imx_uart_id_table);
+
+static const struct of_device_id rt_imx_uart_dt_ids[] = {
+ {
+ .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 +295,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 +423,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 +432,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 +538,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 +573,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 +604,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 +638,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 +805,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 +934,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 +978,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 +991,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 +1000,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 +1074,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 +1225,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 +1278,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 +1293,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 +1303,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 +1372,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 +1430,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 +1469,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 +1570,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 +1606,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 +1616,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)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
@ 2018-01-31 2:28 Greg Gallagher
2018-02-01 10:02 ` Philippe Gerum
0 siblings, 1 reply; 12+ messages in thread
From: Greg Gallagher @ 2018-01-31 2:28 UTC (permalink / raw)
To: xenomai
This patch is based on one that was submitted by Wolfgang Netbal back in Feb
2016 but a formal patch was never submitted.
I added a couple small changes (style errors and imx7 define) 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. The original thread that this
patch was derived from is located here:
https://xenomai.org/pipermail/xenomai/2016-February/035924.html
Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
---
kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
1 file changed, 229 insertions(+), 108 deletions(-)
diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
index 092cecc..2c93789 100644
--- a/kernel/drivers/serial/rt_imx_uart.c
+++ b/kernel/drivers/serial/rt_imx_uart.c
@@ -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)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-31 2:28 Greg Gallagher
@ 2018-02-01 10:02 ` Philippe Gerum
2018-02-01 15:26 ` Greg Gallagher
0 siblings, 1 reply; 12+ messages in thread
From: Philippe Gerum @ 2018-02-01 10:02 UTC (permalink / raw)
To: Greg Gallagher, xenomai
On 01/31/2018 03:28 AM, Greg Gallagher wrote:
> This patch is based on one that was submitted by Wolfgang Netbal back in Feb
> 2016 but a formal patch was never submitted.
> I added a couple small changes (style errors and imx7 define) 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.
I would drop this additional definition. DT indeed says that imx7d uarts
can be handled by the i.MX serial driver as imx6q devices, and
fsl,imx7d-uart is a mere alias to fsl,imx6q-uart AFAICS in the mainline
tree up to 4.15.
--
Philippe.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-02-01 10:02 ` Philippe Gerum
@ 2018-02-01 15:26 ` Greg Gallagher
0 siblings, 0 replies; 12+ messages in thread
From: Greg Gallagher @ 2018-02-01 15:26 UTC (permalink / raw)
To: Philippe Gerum; +Cc: Xenomai@xenomai.org
Makes sense, after the fact I realized this would diverge from the
mainline structs. Will fix up and update.
On Thu, Feb 1, 2018 at 5:02 AM, Philippe Gerum <rpm@xenomai.org> wrote:
> On 01/31/2018 03:28 AM, Greg Gallagher wrote:
>> This patch is based on one that was submitted by Wolfgang Netbal back in Feb
>> 2016 but a formal patch was never submitted.
>> I added a couple small changes (style errors and imx7 define) 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.
>
> I would drop this additional definition. DT indeed says that imx7d uarts
> can be handled by the i.MX serial driver as imx6q devices, and
> fsl,imx7d-uart is a mere alias to fsl,imx6q-uart AFAICS in the mainline
> tree up to 4.15.
>
> --
> Philippe.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
@ 2018-01-09 0:52 Greg Gallagher
0 siblings, 0 replies; 12+ messages in thread
From: Greg Gallagher @ 2018-01-09 0:52 UTC (permalink / raw)
To: xenomai; +Cc: Wolfgang Netbal
From: Wolfgang Netbal <wolfgang.netbal@sigmatek.at>
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.
Signed-off-by: Greg Gallagher <greg@embeddedgreg.com>
---
kernel/drivers/serial/rt_imx_uart.c | 337 ++++++++++++++++++++++++------------
1 file changed, 229 insertions(+), 108 deletions(-)
diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
index 092cecc..2c93789 100644
--- a/kernel/drivers/serial/rt_imx_uart.c
+++ b/kernel/drivers/serial/rt_imx_uart.c
@@ -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)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
@ 2018-01-08 17:49 Greg Gallagher
2018-01-08 17:52 ` Greg Gallagher
0 siblings, 1 reply; 12+ messages in thread
From: Greg Gallagher @ 2018-01-08 17:49 UTC (permalink / raw)
To: xenomai
---
kernel/drivers/serial/rt_imx_uart.c | 299 ++++++++++++++++++++++++------------
1 file changed, 204 insertions(+), 95 deletions(-)
diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
index 092cecc..db63df6 100644
--- a/kernel/drivers/serial/rt_imx_uart.c
+++ b/kernel/drivers/serial/rt_imx_uart.c
@@ -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)
@@ -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 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,69 @@ 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 */
- unsigned int uartclk; /* base 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 */
@@ -344,6 +423,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 uts_reg = ctx->port->devdata->uts_reg;
for (count = ctx->port->tx_fifo;
(count > 0) && (ctx->out_npend > 0);
@@ -352,7 +432,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;
}
}
@@ -493,9 +573,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 long ucr2 = readl(ctx->port->membase + UCR2);
+ unsigned 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 +604,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,
@@ -723,7 +804,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)
@@ -897,7 +978,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;
@@ -1382,42 +1463,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 +1564,31 @@ 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);
+
+ port->use_hwflow = 1;
- err = rtdm_dev_register(dev);
- if (err)
- goto pdata_exit_out;
+ ret = rtdm_dev_register(dev);
+ if (ret)
+ return ret;
platform_set_drvdata(pdev, port);
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);
-
- 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;
+ "%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;
}
static int rt_imx_uart_remove(struct platform_device *pdev)
@@ -1490,26 +1602,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;
+ 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 +1612,29 @@ 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)
{
- if (!realtime_core_enabled())
+ 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) {
+ printk(KERN_ERR
+ "%s; Could not register driver (err=%d)\n",
+ __func__, ret);
+
+ }
+
+ return ret;;
}
static void __exit rt_imx_uart_exit(void)
--
2.7.4
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-08 17:49 Greg Gallagher
@ 2018-01-08 17:52 ` Greg Gallagher
2018-01-08 18:03 ` Jan Kiszka
0 siblings, 1 reply; 12+ messages in thread
From: Greg Gallagher @ 2018-01-08 17:52 UTC (permalink / raw)
To: Xenomai@xenomai.org
Hi,
The patch I submitted was based on one that was submitted by Wolfgang
Netbal back in Feb
2016. The original thread that this patch was derived from is located here
https://xenomai.org/pipermail/xenomai/2016-February/035924.html
Just wanted to make sure proper credit was given, I think I put this
info in the patch as well.
-Greg
On Mon, Jan 8, 2018 at 12:49 PM, Greg Gallagher <greg@embeddedgreg.com> wrote:
> ---
> kernel/drivers/serial/rt_imx_uart.c | 299 ++++++++++++++++++++++++------------
> 1 file changed, 204 insertions(+), 95 deletions(-)
>
> diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
> index 092cecc..db63df6 100644
> --- a/kernel/drivers/serial/rt_imx_uart.c
> +++ b/kernel/drivers/serial/rt_imx_uart.c
> @@ -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)
> @@ -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 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,69 @@ 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 */
> - unsigned int uartclk; /* base 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 */
>
> @@ -344,6 +423,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 uts_reg = ctx->port->devdata->uts_reg;
>
> for (count = ctx->port->tx_fifo;
> (count > 0) && (ctx->out_npend > 0);
> @@ -352,7 +432,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;
> }
> }
> @@ -493,9 +573,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 long ucr2 = readl(ctx->port->membase + UCR2);
> + unsigned 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 +604,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,
> @@ -723,7 +804,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)
> @@ -897,7 +978,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;
> @@ -1382,42 +1463,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 +1564,31 @@ 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);
> +
> + port->use_hwflow = 1;
>
> - err = rtdm_dev_register(dev);
> - if (err)
> - goto pdata_exit_out;
> + ret = rtdm_dev_register(dev);
> + if (ret)
> + return ret;
>
> platform_set_drvdata(pdev, port);
>
> 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);
> -
> - 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;
> + "%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;
> }
>
> static int rt_imx_uart_remove(struct platform_device *pdev)
> @@ -1490,26 +1602,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;
> + 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 +1612,29 @@ 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)
> {
> - if (!realtime_core_enabled())
> + 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) {
> + printk(KERN_ERR
> + "%s; Could not register driver (err=%d)\n",
> + __func__, ret);
> +
> + }
> +
> + return ret;;
> }
>
> static void __exit rt_imx_uart_exit(void)
> --
> 2.7.4
>
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-08 17:52 ` Greg Gallagher
@ 2018-01-08 18:03 ` Jan Kiszka
2018-01-08 21:09 ` Greg Gallagher
0 siblings, 1 reply; 12+ messages in thread
From: Jan Kiszka @ 2018-01-08 18:03 UTC (permalink / raw)
To: Greg Gallagher, Xenomai@xenomai.org
On 2018-01-08 18:52, Greg Gallagher wrote:
> Hi,
> The patch I submitted was based on one that was submitted by Wolfgang
> Netbal back in Feb
> 2016. The original thread that this patch was derived from is located here
> https://xenomai.org/pipermail/xenomai/2016-February/035924.html
>
> Just wanted to make sure proper credit was given, I think I put this
> info in the patch as well.
Just write a commit message (which is desirable anyway) and mention the
origin there. In case you barely changed the original version, you could
also leave the original author in place by starting the body with "From:
Author <email>" and then just mention your changes at the end of the log
message (usually before your signed-off-by, but Xenomai does not enforce
that protocol yet).
Could you sort out the unrelated style changes? Preferred style is that
of the kernel. The kernel has a checker (scripts/checkpatch.pl), which
does not mean there can be sometimes exceptions, but it should not a
guideline still.
Thanks for picking this up!
Jan
>
> -Greg
>
> On Mon, Jan 8, 2018 at 12:49 PM, Greg Gallagher <greg@embeddedgreg.com> wrote:
>> ---
>> kernel/drivers/serial/rt_imx_uart.c | 299 ++++++++++++++++++++++++------------
>> 1 file changed, 204 insertions(+), 95 deletions(-)
>>
>> diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
>> index 092cecc..db63df6 100644
>> --- a/kernel/drivers/serial/rt_imx_uart.c
>> +++ b/kernel/drivers/serial/rt_imx_uart.c
>> @@ -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)
>> @@ -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 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,69 @@ 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 */
>> - unsigned int uartclk; /* base 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 */
>>
>> @@ -344,6 +423,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 uts_reg = ctx->port->devdata->uts_reg;
>>
>> for (count = ctx->port->tx_fifo;
>> (count > 0) && (ctx->out_npend > 0);
>> @@ -352,7 +432,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;
>> }
>> }
>> @@ -493,9 +573,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 long ucr2 = readl(ctx->port->membase + UCR2);
>> + unsigned 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 +604,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,
>> @@ -723,7 +804,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)
>> @@ -897,7 +978,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;
>> @@ -1382,42 +1463,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 +1564,31 @@ 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);
>> +
>> + port->use_hwflow = 1;
>>
>> - err = rtdm_dev_register(dev);
>> - if (err)
>> - goto pdata_exit_out;
>> + ret = rtdm_dev_register(dev);
>> + if (ret)
>> + return ret;
>>
>> platform_set_drvdata(pdev, port);
>>
>> 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);
>> -
>> - 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;
>> + "%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;
>> }
>>
>> static int rt_imx_uart_remove(struct platform_device *pdev)
>> @@ -1490,26 +1602,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;
>> + 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 +1612,29 @@ 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)
>> {
>> - if (!realtime_core_enabled())
>> + 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) {
>> + printk(KERN_ERR
>> + "%s; Could not register driver (err=%d)\n",
>> + __func__, ret);
>> +
>> + }
>> +
>> + return ret;;
>> }
>>
>> static void __exit rt_imx_uart_exit(void)
>> --
>> 2.7.4
>>
--
Siemens AG, Corporate Technology, CT RDA IOT SES-DE
Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels.
2018-01-08 18:03 ` Jan Kiszka
@ 2018-01-08 21:09 ` Greg Gallagher
0 siblings, 0 replies; 12+ messages in thread
From: Greg Gallagher @ 2018-01-08 21:09 UTC (permalink / raw)
To: Jan Kiszka, Xenomai@xenomai.org
Sounds good, I fixed up the patch and will submit it again. There are
a couple of warnings from checkpath.pl still but I don't
think they need to be fixed up. I can post the output if anyone would
like to see it. I also had the original publisher wrong,
I fixed that up and added the sign off at the bottom.
Let me know if I missed anything.
Thanks
Greg
On Mon, Jan 8, 2018 at 1:03 PM, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> On 2018-01-08 18:52, Greg Gallagher wrote:
>> Hi,
>> The patch I submitted was based on one that was submitted by Wolfgang
>> Netbal back in Feb
>> 2016. The original thread that this patch was derived from is located here
>> https://xenomai.org/pipermail/xenomai/2016-February/035924.html
>>
>> Just wanted to make sure proper credit was given, I think I put this
>> info in the patch as well.
>
> Just write a commit message (which is desirable anyway) and mention the
> origin there. In case you barely changed the original version, you could
> also leave the original author in place by starting the body with "From:
> Author <email>" and then just mention your changes at the end of the log
> message (usually before your signed-off-by, but Xenomai does not enforce
> that protocol yet).
>
> Could you sort out the unrelated style changes? Preferred style is that
> of the kernel. The kernel has a checker (scripts/checkpatch.pl), which
> does not mean there can be sometimes exceptions, but it should not a
> guideline still.
>
> Thanks for picking this up!
> Jan
>
>>
>> -Greg
>>
>> On Mon, Jan 8, 2018 at 12:49 PM, Greg Gallagher <greg@embeddedgreg.com> wrote:
>>> ---
>>> kernel/drivers/serial/rt_imx_uart.c | 299 ++++++++++++++++++++++++------------
>>> 1 file changed, 204 insertions(+), 95 deletions(-)
>>>
>>> diff --git a/kernel/drivers/serial/rt_imx_uart.c b/kernel/drivers/serial/rt_imx_uart.c
>>> index 092cecc..db63df6 100644
>>> --- a/kernel/drivers/serial/rt_imx_uart.c
>>> +++ b/kernel/drivers/serial/rt_imx_uart.c
>>> @@ -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)
>>> @@ -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 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,69 @@ 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 */
>>> - unsigned int uartclk; /* base 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 */
>>>
>>> @@ -344,6 +423,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 uts_reg = ctx->port->devdata->uts_reg;
>>>
>>> for (count = ctx->port->tx_fifo;
>>> (count > 0) && (ctx->out_npend > 0);
>>> @@ -352,7 +432,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;
>>> }
>>> }
>>> @@ -493,9 +573,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 long ucr2 = readl(ctx->port->membase + UCR2);
>>> + unsigned 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 +604,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,
>>> @@ -723,7 +804,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)
>>> @@ -897,7 +978,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;
>>> @@ -1382,42 +1463,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 +1564,31 @@ 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);
>>> +
>>> + port->use_hwflow = 1;
>>>
>>> - err = rtdm_dev_register(dev);
>>> - if (err)
>>> - goto pdata_exit_out;
>>> + ret = rtdm_dev_register(dev);
>>> + if (ret)
>>> + return ret;
>>>
>>> platform_set_drvdata(pdev, port);
>>>
>>> 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);
>>> -
>>> - 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;
>>> + "%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;
>>> }
>>>
>>> static int rt_imx_uart_remove(struct platform_device *pdev)
>>> @@ -1490,26 +1602,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;
>>> + 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 +1612,29 @@ 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)
>>> {
>>> - if (!realtime_core_enabled())
>>> + 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) {
>>> + printk(KERN_ERR
>>> + "%s; Could not register driver (err=%d)\n",
>>> + __func__, ret);
>>> +
>>> + }
>>> +
>>> + return ret;;
>>> }
>>>
>>> static void __exit rt_imx_uart_exit(void)
>>> --
>>> 2.7.4
>>>
>
> --
> Siemens AG, Corporate Technology, CT RDA IOT SES-DE
> Corporate Competence Center Embedded Linux
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2018-02-02 3:06 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-08 21:09 [Xenomai] [PATCH] Fix up the imx uart driver so it now compiles with new kernels Greg Gallagher
2018-01-08 21:16 ` Michael Welling
2018-01-08 21:23 ` Greg Gallagher
-- strict thread matches above, loose matches on Subject: below --
2018-02-02 3:06 Greg Gallagher
2018-01-31 2:28 Greg Gallagher
2018-02-01 10:02 ` Philippe Gerum
2018-02-01 15:26 ` Greg Gallagher
2018-01-09 0:52 Greg Gallagher
2018-01-08 17:49 Greg Gallagher
2018-01-08 17:52 ` Greg Gallagher
2018-01-08 18:03 ` Jan Kiszka
2018-01-08 21:09 ` Greg Gallagher
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.