static int cdns_uart_probe()

in serial/xilinx_uartps.c [1434:1629]


static int cdns_uart_probe(struct platform_device *pdev)
{
	int rc, id, irq;
	struct uart_port *port;
	struct resource *res;
	struct cdns_uart *cdns_uart_data;
	const struct of_device_id *match;

	cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
			GFP_KERNEL);
	if (!cdns_uart_data)
		return -ENOMEM;
	port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
	if (!port)
		return -ENOMEM;

	/* Look for a serialN alias */
	id = of_alias_get_id(pdev->dev.of_node, "serial");
	if (id < 0)
		id = 0;

	if (id >= CDNS_UART_NR_PORTS) {
		dev_err(&pdev->dev, "Cannot get uart_port structure\n");
		return -ENODEV;
	}

	if (!cdns_uart_uart_driver.state) {
		cdns_uart_uart_driver.owner = THIS_MODULE;
		cdns_uart_uart_driver.driver_name = CDNS_UART_NAME;
		cdns_uart_uart_driver.dev_name = CDNS_UART_TTY_NAME;
		cdns_uart_uart_driver.major = CDNS_UART_MAJOR;
		cdns_uart_uart_driver.minor = CDNS_UART_MINOR;
		cdns_uart_uart_driver.nr = CDNS_UART_NR_PORTS;
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
		cdns_uart_uart_driver.cons = &cdns_uart_console;
#endif

		rc = uart_register_driver(&cdns_uart_uart_driver);
		if (rc < 0) {
			dev_err(&pdev->dev, "Failed to register driver\n");
			return rc;
		}
	}

	cdns_uart_data->cdns_uart_driver = &cdns_uart_uart_driver;

	match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
	if (match && match->data) {
		const struct cdns_platform_data *data = match->data;

		cdns_uart_data->quirks = data->quirks;
	}

	cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
	if (PTR_ERR(cdns_uart_data->pclk) == -EPROBE_DEFER) {
		rc = PTR_ERR(cdns_uart_data->pclk);
		goto err_out_unregister_driver;
	}

	if (IS_ERR(cdns_uart_data->pclk)) {
		cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
		if (IS_ERR(cdns_uart_data->pclk)) {
			rc = PTR_ERR(cdns_uart_data->pclk);
			goto err_out_unregister_driver;
		}
		dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n");
	}

	cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
	if (PTR_ERR(cdns_uart_data->uartclk) == -EPROBE_DEFER) {
		rc = PTR_ERR(cdns_uart_data->uartclk);
		goto err_out_unregister_driver;
	}

	if (IS_ERR(cdns_uart_data->uartclk)) {
		cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk");
		if (IS_ERR(cdns_uart_data->uartclk)) {
			rc = PTR_ERR(cdns_uart_data->uartclk);
			goto err_out_unregister_driver;
		}
		dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
	}

	rc = clk_prepare_enable(cdns_uart_data->pclk);
	if (rc) {
		dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
		goto err_out_unregister_driver;
	}
	rc = clk_prepare_enable(cdns_uart_data->uartclk);
	if (rc) {
		dev_err(&pdev->dev, "Unable to enable device clock.\n");
		goto err_out_clk_dis_pclk;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		rc = -ENODEV;
		goto err_out_clk_disable;
	}

	irq = platform_get_irq(pdev, 0);
	if (irq <= 0) {
		rc = -ENXIO;
		goto err_out_clk_disable;
	}

#ifdef CONFIG_COMMON_CLK
	cdns_uart_data->clk_rate_change_nb.notifier_call =
			cdns_uart_clk_notifier_cb;
	if (clk_notifier_register(cdns_uart_data->uartclk,
				&cdns_uart_data->clk_rate_change_nb))
		dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
#endif

	/* At this point, we've got an empty uart_port struct, initialize it */
	spin_lock_init(&port->lock);
	port->type	= PORT_UNKNOWN;
	port->iotype	= UPIO_MEM32;
	port->flags	= UPF_BOOT_AUTOCONF;
	port->ops	= &cdns_uart_ops;
	port->fifosize	= CDNS_UART_FIFO_SIZE;
	port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE);
	port->line	= id;

	/*
	 * Register the port.
	 * This function also registers this device with the tty layer
	 * and triggers invocation of the config_port() entry point.
	 */
	port->mapbase = res->start;
	port->irq = irq;
	port->dev = &pdev->dev;
	port->uartclk = clk_get_rate(cdns_uart_data->uartclk);
	port->private_data = cdns_uart_data;
	cdns_uart_data->port = port;
	platform_set_drvdata(pdev, port);

	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
	device_init_wakeup(port->dev, true);

#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
	/*
	 * If console hasn't been found yet try to assign this port
	 * because it is required to be assigned for console setup function.
	 * If register_console() don't assign value, then console_port pointer
	 * is cleanup.
	 */
	if (!console_port) {
		cdns_uart_console.index = id;
		console_port = port;
	}
#endif

	rc = uart_add_one_port(&cdns_uart_uart_driver, port);
	if (rc) {
		dev_err(&pdev->dev,
			"uart_add_one_port() failed; err=%i\n", rc);
		goto err_out_pm_disable;
	}

#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
	/* This is not port which is used for console that's why clean it up */
	if (console_port == port &&
	    !(cdns_uart_uart_driver.cons->flags & CON_ENABLED)) {
		console_port = NULL;
		cdns_uart_console.index = -1;
	}
#endif

	cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node,
							     "cts-override");

	instances++;

	return 0;

err_out_pm_disable:
	pm_runtime_disable(&pdev->dev);
	pm_runtime_set_suspended(&pdev->dev);
	pm_runtime_dont_use_autosuspend(&pdev->dev);
#ifdef CONFIG_COMMON_CLK
	clk_notifier_unregister(cdns_uart_data->uartclk,
			&cdns_uart_data->clk_rate_change_nb);
#endif
err_out_clk_disable:
	clk_disable_unprepare(cdns_uart_data->uartclk);
err_out_clk_dis_pclk:
	clk_disable_unprepare(cdns_uart_data->pclk);
err_out_unregister_driver:
	if (!instances)
		uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
	return rc;
}