static int lpuart_probe()

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;
}