---
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
_______________________________________________
Xenomai mailing list
[email protected]
https://xenomai.org/mailman/listinfo/xenomai