in serial/fsl_lpuart.c [2655:2783]
static int lpuart_probe(struct platform_device *pdev)
{
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct lpuart_port *sport;
struct resource *res;
int ret;
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sport->port.membase))
return PTR_ERR(sport->port.membase);
sport->port.membase += sdata->reg_off;
sport->port.mapbase = res->start + sdata->reg_off;
sport->port.dev = &pdev->dev;
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
sport->port.irq = ret;
sport->port.iotype = sdata->iotype;
if (lpuart_is_32(sport))
sport->port.ops = &lpuart32_pops;
else
sport->port.ops = &lpuart_pops;
sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LPUART_CONSOLE);
sport->port.flags = UPF_BOOT_AUTOCONF;
if (lpuart_is_32(sport))
sport->port.rs485_config = lpuart32_config_rs485;
else
sport->port.rs485_config = lpuart_config_rs485;
sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->ipg_clk)) {
ret = PTR_ERR(sport->ipg_clk);
dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
return ret;
}
sport->baud_clk = NULL;
if (is_imx8qxp_lpuart(sport)) {
sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
if (IS_ERR(sport->baud_clk)) {
ret = PTR_ERR(sport->baud_clk);
dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
return ret;
}
}
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
if (ret < 0) {
dev_err(&pdev->dev, "port line is full, add device failed\n");
return ret;
}
sport->id_allocated = true;
}
if (ret >= ARRAY_SIZE(lpuart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", ret);
ret = -EINVAL;
goto failed_out_of_range;
}
sport->port.line = ret;
ret = lpuart_enable_clks(sport);
if (ret)
goto failed_clock_enable;
sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
lpuart_ports[sport->port.line] = sport;
platform_set_drvdata(pdev, &sport->port);
if (lpuart_is_32(sport)) {
lpuart_reg.cons = LPUART32_CONSOLE;
ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart32_int, 0,
DRIVER_NAME, sport);
} else {
lpuart_reg.cons = LPUART_CONSOLE;
ret = devm_request_irq(&pdev->dev, sport->port.irq, lpuart_int, 0,
DRIVER_NAME, sport);
}
if (ret)
goto failed_irq_request;
ret = uart_add_one_port(&lpuart_reg, &sport->port);
if (ret)
goto failed_attach_port;
ret = lpuart_global_reset(sport);
if (ret)
goto failed_reset;
ret = uart_get_rs485_mode(&sport->port);
if (ret)
goto failed_get_rs485;
if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
dev_err(&pdev->dev, "driver doesn't support RX during TX\n");
if (sport->port.rs485.delay_rts_before_send ||
sport->port.rs485.delay_rts_after_send)
dev_err(&pdev->dev, "driver doesn't support RTS delays\n");
sport->port.rs485_config(&sport->port, &sport->port.rs485);
return 0;
failed_get_rs485:
failed_reset:
uart_remove_one_port(&lpuart_reg, &sport->port);
failed_attach_port:
failed_irq_request:
lpuart_disable_clks(sport);
failed_clock_enable:
failed_out_of_range:
if (sport->id_allocated)
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
return ret;
}