drivers/tty/serial/8250/8250_dwlib.c

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

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_dwlib.c
Extension
.c
Size
8997 bytes
Lines
301
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

if (rs485->flags & SER_RS485_ADDR_RECV) {
			u32 delta = p->rs485.flags ^ rs485->flags;

			/*
			 * rs485 (param) is equal to uart_port's rs485 only during init
			 * (during init, delta is not yet applicable).
			 */
			if (unlikely(&p->rs485 == rs485))
				delta = rs485->flags;

			if ((delta & SER_RS485_ADDR_RECV) ||
			    (p->rs485.addr_recv != rs485->addr_recv))
				dw8250_update_rar(p, rs485->addr_recv);
			lcr |= DW_UART_LCR_EXT_ADDR_MATCH;
		} else {
			lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH;
		}
		if (rs485->flags & SER_RS485_ADDR_DEST) {
			/*
			 * Don't skip writes here as another endpoint could
			 * have changed communication line's destination
			 * address in between.
			 */
			dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest);
			lcr |= DW_UART_LCR_EXT_SEND_ADDR;
		}
	} else {
		lcr = 0;
	}
	dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr);
}

static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios,
			       struct serial_rs485 *rs485)
{
	u32 tcr;

	tcr = dw8250_readl_ext(p, DW_UART_TCR);
	tcr &= ~DW_UART_TCR_XFER_MODE;

	if (rs485->flags & SER_RS485_ENABLED) {
		tcr |= DW_UART_TCR_RS485_EN;

		if (rs485->flags & SER_RS485_RX_DURING_TX)
			tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE;
		else
			tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE;
		dw8250_writel_ext(p, DW_UART_DE_EN, 1);
		dw8250_writel_ext(p, DW_UART_RE_EN, 1);
	} else {
		if (termios)
			termios->c_cflag &= ~ADDRB;

		tcr &= ~DW_UART_TCR_RS485_EN;
	}

	/* Reset to default polarity */
	tcr |= DW_UART_TCR_DE_POL;
	tcr &= ~DW_UART_TCR_RE_POL;

	if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
		tcr &= ~DW_UART_TCR_DE_POL;
	if (device_property_read_bool(p->dev, "rs485-rx-active-high"))
		tcr |= DW_UART_TCR_RE_POL;

	dw8250_writel_ext(p, DW_UART_TCR, tcr);

	/* Addressing mode can only be set up after TCR */
	if (rs485->flags & SER_RS485_ENABLED)
		dw8250_rs485_set_addr(p, rs485, termios);

	return 0;
}

/*
 * Tests if RE_EN register can have non-zero value to see if RS-485 HW support
 * is present.
 */
static bool dw8250_detect_rs485_hw(struct uart_port *p)
{
	u32 reg;

	dw8250_writel_ext(p, DW_UART_RE_EN, 1);
	reg = dw8250_readl_ext(p, DW_UART_RE_EN);
	dw8250_writel_ext(p, DW_UART_RE_EN, 0);
	return reg;
}

static const struct serial_rs485 dw8250_rs485_supported = {
	.flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND |

Annotation

Implementation Notes