drivers/tty/serial/8250/8250_of.c

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

File Facts

System
Linux kernel
Corpus path
drivers/tty/serial/8250/8250_of.c
Extension
.c
Size
10344 bytes
Lines
375
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 of_serial_info {
	struct clk *clk;
	struct clk *bus_clk;
	struct reset_control *rst;
	int type;
	int line;
	struct notifier_block clk_notifier;
};

/* Nuvoton NPCM timeout register */
#define UART_NPCM_TOR          7
#define UART_NPCM_TOIE         BIT(7)  /* Timeout Interrupt Enable */

static int npcm_startup(struct uart_port *port)
{
	/*
	 * Nuvoton calls the scratch register 'UART_TOR' (timeout
	 * register). Enable it, and set TIOC (timeout interrupt
	 * comparator) to be 0x20 for correct operation.
	 */
	serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20);

	return serial8250_do_startup(port);
}

/* Nuvoton NPCM UARTs have a custom divisor calculation */
static unsigned int npcm_get_divisor(struct uart_port *port, unsigned int baud,
				     unsigned int *frac)
{
	return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2;
}

static int npcm_setup(struct uart_port *port)
{
	port->get_divisor = npcm_get_divisor;
	port->startup = npcm_startup;
	return 0;
}

static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb)
{
	return container_of(nb, struct of_serial_info, clk_notifier);
}

static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
					      void *data)
{
	struct of_serial_info *info = clk_nb_to_info(nb);
	struct uart_8250_port *port8250 = serial8250_get_port(info->line);
	struct clk_notifier_data *ndata = data;

	if (event == POST_RATE_CHANGE) {
		serial8250_update_uartclk(&port8250->port, ndata->new_rate);
		return NOTIFY_OK;
	}

	return NOTIFY_DONE;
}

/*
 * Fill a struct uart_port for a given device node
 */
static int of_platform_serial_setup(struct platform_device *ofdev,
			int type, struct uart_8250_port *up,
			struct of_serial_info *info)
{
	struct resource resource;
	struct device *dev = &ofdev->dev;
	struct device_node *np = dev->of_node;
	struct uart_port *port = &up->port;
	u32 spd;
	int ret;

	memset(port, 0, sizeof(*port));

	pm_runtime_enable(&ofdev->dev);
	pm_runtime_get_sync(&ofdev->dev);

	ret = of_address_to_resource(np, 0, &resource);
	if (ret) {
		dev_err_probe(dev, ret, "invalid address\n");
		goto err_pmruntime;
	}

	port->dev = &ofdev->dev;
	port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
	spin_lock_init(&port->lock);

	if (resource_type(&resource) == IORESOURCE_IO) {
		port->iobase = resource.start;

Annotation

Implementation Notes