drivers/tty/serial/8250/8250_lpc18xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_lpc18xx.c
Extension
.c
Size
5537 bytes
Lines
209
Domain
Driver Families
Bucket
drivers/tty
Inferred role
Driver Families: implementation source
Status
source 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

struct lpc18xx_uart_data {
	struct uart_8250_dma dma;
	struct clk *clk_uart;
	struct clk *clk_reg;
	int line;
};

static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios,
				struct serial_rs485 *rs485)
{
	struct uart_8250_port *up = up_to_u8250p(port);
	u32 rs485_ctrl_reg = 0;
	u32 rs485_dly_reg = 0;
	unsigned baud_clk;

	if (rs485->flags & SER_RS485_ENABLED) {
		rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
				  LPC18XX_UART_RS485CTRL_DCTRL;

		if (rs485->flags & SER_RS485_RTS_ON_SEND)
			rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
	}

	if (rs485->delay_rts_after_send) {
		baud_clk = port->uartclk / up->dl_read(up);
		rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send
						* baud_clk, MSEC_PER_SEC);

		if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX)
			rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX;

		/* Calculate the resulting delay in ms */
		rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC)
						/ baud_clk;
	}

	serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
	serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);

	return 0;
}

static void lpc18xx_uart_serial_out(struct uart_port *p, unsigned int offset, u32 value)
{
	/*
	 * For DMA mode one must ensure that the UART_FCR_DMA_SELECT
	 * bit is set when FIFO is enabled. Even if DMA is not used
	 * setting this bit doesn't seem to affect anything.
	 */
	if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO))
		value |= UART_FCR_DMA_SELECT;

	offset = offset << p->regshift;
	writel(value, p->membase + offset);
}

static const struct serial_rs485 lpc18xx_rs485_supported = {
	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
	.delay_rts_after_send = 1,
	/* Delay RTS before send is not supported */
};

static int lpc18xx_serial_probe(struct platform_device *pdev)
{
	struct lpc18xx_uart_data *data;
	struct uart_8250_port uart;
	struct resource *res;
	int ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "memory resource not found");
		return -EINVAL;
	}

	memset(&uart, 0, sizeof(uart));

	uart.port.membase = devm_ioremap(&pdev->dev, res->start,
					 resource_size(res));
	if (!uart.port.membase)
		return -ENOMEM;

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

	data->clk_uart = devm_clk_get(&pdev->dev, "uartclk");
	if (IS_ERR(data->clk_uart)) {
		dev_err(&pdev->dev, "uart clock not found\n");
		return PTR_ERR(data->clk_uart);

Annotation

Implementation Notes