drivers/tty/serial/8250/8250_loongson.c

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

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_loongson.c
Extension
.c
Size
5878 bytes
Lines
239
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 loongson_uart_ddata {
	bool has_frac;
	u8 mcr_invert;
	u8 msr_invert;
};

static const struct loongson_uart_ddata ls2k0500_uart_data = {
	.has_frac = false,
	.mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
	.msr_invert = UART_MSR_CTS | UART_MSR_DSR,
};

static const struct loongson_uart_ddata ls2k1500_uart_data = {
	.has_frac = true,
	.mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
	.msr_invert = 0,
};

struct loongson_uart_priv {
	int line;
	struct clk *clk;
	struct resource *res;
	struct reset_control *rst;
	const struct loongson_uart_ddata *ddata;
};

static u8 serial_fixup(struct uart_port *p, unsigned int offset, u8 val)
{
	struct loongson_uart_priv *priv = p->private_data;

	switch (offset) {
	case UART_MCR:
		return val ^ priv->ddata->mcr_invert;
	case UART_MSR:
		return val ^ priv->ddata->msr_invert;
	default:
		return val;
	}
}

static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
{
	u8 val;

	val = readb(p->membase + (offset << p->regshift));

	return serial_fixup(p, offset, val);
}

static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
{
	u8 val;

	offset <<= p->regshift;
	val = serial_fixup(p, offset, value);
	writeb(val, p->membase + offset);
}

static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
					      unsigned int *frac)
{
	unsigned int quot;

	quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);
	*frac = FIELD_GET(LOONGSON_QUOT_FRAC_MASK, quot);

	return FIELD_GET(LOONGSON_QUOT_DIV_MASK, quot);
}

static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
				      unsigned int quot, unsigned int quot_frac)
{
	struct uart_8250_port *up = up_to_u8250p(port);

	serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
	serial_dl_write(up, quot);
	serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
}

static int loongson_uart_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct uart_8250_port uart = {};
	struct loongson_uart_priv *priv;
	struct uart_port *port;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

Annotation

Implementation Notes