in serial/imx.c [2199:2420]
static int imx_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct imx_port *sport;
void __iomem *base;
u32 dma_buf_conf[2];
int ret = 0;
u32 ucr1;
struct resource *res;
int txirq, rxirq, rtsirq;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
return -ENOMEM;
sport->devdata = of_device_get_match_data(&pdev->dev);
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;
}
sport->port.line = ret;
if (of_get_property(np, "uart-has-rtscts", NULL) ||
of_get_property(np, "fsl,uart-has-rtscts", NULL) /* deprecated */)
sport->have_rtscts = 1;
if (of_get_property(np, "fsl,dte-mode", NULL))
sport->dte_mode = 1;
if (of_get_property(np, "rts-gpios", NULL))
sport->have_rtsgpio = 1;
if (of_get_property(np, "fsl,inverted-tx", NULL))
sport->inverted_tx = 1;
if (of_get_property(np, "fsl,inverted-rx", NULL))
sport->inverted_rx = 1;
if (!of_property_read_u32_array(np, "fsl,dma-info", dma_buf_conf, 2)) {
sport->rx_period_length = dma_buf_conf[0];
sport->rx_periods = dma_buf_conf[1];
} else {
sport->rx_period_length = RX_DMA_PERIOD_LEN;
sport->rx_periods = RX_DMA_PERIODS;
}
if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n",
sport->port.line);
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
rxirq = platform_get_irq(pdev, 0);
if (rxirq < 0)
return rxirq;
txirq = platform_get_irq_optional(pdev, 1);
rtsirq = platform_get_irq_optional(pdev, 2);
sport->port.dev = &pdev->dev;
sport->port.mapbase = res->start;
sport->port.membase = base;
sport->port.type = PORT_IMX;
sport->port.iotype = UPIO_MEM;
sport->port.irq = rxirq;
sport->port.fifosize = 32;
sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE);
sport->port.ops = &imx_uart_pops;
sport->port.rs485_config = imx_uart_rs485_config;
sport->port.flags = UPF_BOOT_AUTOCONF;
timer_setup(&sport->timer, imx_uart_timeout, 0);
sport->gpios = mctrl_gpio_init(&sport->port, 0);
if (IS_ERR(sport->gpios))
return PTR_ERR(sport->gpios);
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->clk_ipg)) {
ret = PTR_ERR(sport->clk_ipg);
dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
return ret;
}
sport->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(sport->clk_per)) {
ret = PTR_ERR(sport->clk_per);
dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
return ret;
}
sport->port.uartclk = clk_get_rate(sport->clk_per);
/* For register access, we only need to enable the ipg clock. */
ret = clk_prepare_enable(sport->clk_ipg);
if (ret) {
dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret);
return ret;
}
/* initialize shadow register values */
sport->ucr1 = readl(sport->port.membase + UCR1);
sport->ucr2 = readl(sport->port.membase + UCR2);
sport->ucr3 = readl(sport->port.membase + UCR3);
sport->ucr4 = readl(sport->port.membase + UCR4);
sport->ufcr = readl(sport->port.membase + UFCR);
ret = uart_get_rs485_mode(&sport->port);
if (ret) {
clk_disable_unprepare(sport->clk_ipg);
return ret;
}
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
(!sport->have_rtscts && !sport->have_rtsgpio))
dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
/*
* If using the i.MX UART RTS/CTS control then the RTS (CTS_B)
* signal cannot be set low during transmission in case the
* receiver is off (limitation of the i.MX UART IP).
*/
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
sport->have_rtscts && !sport->have_rtsgpio &&
(!(sport->port.rs485.flags & SER_RS485_RTS_ON_SEND) &&
!(sport->port.rs485.flags & SER_RS485_RX_DURING_TX)))
dev_err(&pdev->dev,
"low-active RTS not possible when receiver is off, enabling receiver\n");
imx_uart_rs485_config(&sport->port, &sport->port.rs485);
/* Disable interrupts before requesting them */
ucr1 = imx_uart_readl(sport, UCR1);
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
imx_uart_writel(sport, ucr1, UCR1);
if (!imx_uart_is_imx1(sport) && sport->dte_mode) {
/*
* The DCEDTE bit changes the direction of DSR, DCD, DTR and RI
* and influences if UCR3_RI and UCR3_DCD changes the level of RI
* and DCD (when they are outputs) or enables the respective
* irqs. So set this bit early, i.e. before requesting irqs.
*/
u32 ufcr = imx_uart_readl(sport, UFCR);
if (!(ufcr & UFCR_DCEDTE))
imx_uart_writel(sport, ufcr | UFCR_DCEDTE, UFCR);
/*
* Disable UCR3_RI and UCR3_DCD irqs. They are also not
* enabled later because they cannot be cleared
* (confirmed on i.MX25) which makes them unusable.
*/
imx_uart_writel(sport,
IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR,
UCR3);
} else {
u32 ucr3 = UCR3_DSR;
u32 ufcr = imx_uart_readl(sport, UFCR);
if (ufcr & UFCR_DCEDTE)
imx_uart_writel(sport, ufcr & ~UFCR_DCEDTE, UFCR);
if (!imx_uart_is_imx1(sport))
ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP;
imx_uart_writel(sport, ucr3, UCR3);
}
clk_disable_unprepare(sport->clk_ipg);
hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sport->trigger_start_tx.function = imx_trigger_start_tx;
sport->trigger_stop_tx.function = imx_trigger_stop_tx;
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt.
*/
if (txirq > 0) {
ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_rxint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request rx irq: %d\n",
ret);
return ret;
}
ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request tx irq: %d\n",
ret);
return ret;
}
ret = devm_request_irq(&pdev->dev, rtsirq, imx_uart_rtsint, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request rts irq: %d\n",
ret);
return ret;
}
} else {
ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
return ret;
}
}
imx_uart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, sport);
return uart_add_one_port(&imx_uart_uart_driver, &sport->port);
}