drivers/tty/serial/pic32_uart.c

Source file repositories/reference/linux-study-clean/drivers/tty/serial/pic32_uart.c

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/pic32_uart.c
Extension
.c
Size
26759 bytes
Lines
1000
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

core_initcall(pic32_late_console_init);

#else
#define PIC32_SCONSOLE NULL
#endif

static struct uart_driver pic32_uart_driver = {
	.owner			= THIS_MODULE,
	.driver_name		= PIC32_DEV_NAME,
	.dev_name		= PIC32_SDEV_NAME,
	.nr			= PIC32_MAX_UARTS,
	.cons			= PIC32_SCONSOLE,
};

static int pic32_uart_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct pic32_sport *sport;
	int uart_idx = 0;
	struct resource *res_mem;
	struct uart_port *port;
	int ret;

	uart_idx = of_alias_get_id(np, "serial");
	if (uart_idx < 0 || uart_idx >= PIC32_MAX_UARTS)
		return -EINVAL;

	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res_mem)
		return -EINVAL;

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

	sport->idx		= uart_idx;
	sport->irq_fault	= irq_of_parse_and_map(np, 0);
	sport->irq_rx		= irq_of_parse_and_map(np, 1);
	sport->irq_tx		= irq_of_parse_and_map(np, 2);
	sport->clk		= devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(sport->clk))
		return PTR_ERR(sport->clk);
	sport->dev		= &pdev->dev;

	/* Hardware flow control: gpios
	 * !Note: Basically, CTS is needed for reading the status.
	 */
	sport->cts_gpiod = devm_gpiod_get_optional(dev, "cts", GPIOD_IN);
	if (IS_ERR(sport->cts_gpiod))
		return dev_err_probe(dev, PTR_ERR(sport->cts_gpiod), "error requesting CTS GPIO\n");
	gpiod_set_consumer_name(sport->cts_gpiod, "CTS");

	pic32_sports[uart_idx] = sport;
	port = &sport->port;
	port->iotype	= UPIO_MEM;
	port->mapbase	= res_mem->start;
	port->ops	= &pic32_uart_ops;
	port->flags	= UPF_BOOT_AUTOCONF;
	port->dev	= &pdev->dev;
	port->fifosize	= PIC32_UART_TX_FIFO_DEPTH;
	port->uartclk	= clk_get_rate(sport->clk);
	port->line	= uart_idx;

	ret = uart_add_one_port(&pic32_uart_driver, port);
	if (ret) {
		port->membase = NULL;
		dev_err(port->dev, "%s: uart add port error!\n", __func__);
		goto err;
	}

#ifdef CONFIG_SERIAL_PIC32_CONSOLE
	if (uart_console_registered(port)) {
		/* The peripheral clock has been enabled by console_setup,
		 * so disable it till the port is used.
		 */
		clk_disable_unprepare(sport->clk);
	}
#endif

	platform_set_drvdata(pdev, port);

	dev_info(&pdev->dev, "%s: uart(%d) driver initialized.\n",
		 __func__, uart_idx);

	return 0;
err:
	/* automatic unroll of sport and gpios */
	return ret;
}

Annotation

Implementation Notes