drivers/gpio/gpio-realtek-otto.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-realtek-otto.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-realtek-otto.c
Extension
.c
Size
13775 bytes
Lines
472
Domain
Driver Families
Bucket
drivers/gpio
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 realtek_gpio_ctrl {
	struct gpio_generic_chip chip;
	void __iomem *base;
	void __iomem *cpumask_base;
	struct cpumask cpu_irq_maskable;
	raw_spinlock_t lock;
	u8 intr_mask[REALTEK_GPIO_MAX];
	u8 intr_type[REALTEK_GPIO_MAX];
	u32 (*bank_read)(void __iomem *reg);
	void (*bank_write)(void __iomem *reg, u32 value);
	unsigned int (*line_imr_pos)(unsigned int line);
};

/* Expand with more flags as devices with other quirks are added */
enum realtek_gpio_flags {
	/*
	 * Allow disabling interrupts, for cases where the port order is
	 * unknown. This may result in a port mismatch between ISR and IMR.
	 * An interrupt would appear to come from a different line than the
	 * line the IRQ handler was assigned to, causing uncaught interrupts.
	 */
	GPIO_INTERRUPTS_DISABLED = BIT(0),
	/*
	 * Port order is reversed, meaning DCBA register layout for 1-bit
	 * fields, and [BA, DC] for 2-bit fields.
	 */
	GPIO_PORTS_REVERSED = BIT(1),
	/*
	 * Interrupts can be enabled per cpu. This requires a secondary IO
	 * range, where the per-cpu enable masks are located.
	 */
	GPIO_INTERRUPTS_PER_CPU = BIT(2),
};

static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);

	return container_of(to_gpio_generic_chip(gc), struct realtek_gpio_ctrl, chip);
}

/*
 * Normal port order register access
 *
 * Port information is stored with the first port at offset 0, followed by the
 * second, etc. Most registers store one bit per GPIO and use a u8 value per
 * port. The two interrupt mask registers store two bits per GPIO, so use u16
 * values.
 */
static u32 realtek_gpio_bank_read_swapped(void __iomem *reg)
{
	return ioread32be(reg);
}

static void realtek_gpio_bank_write_swapped(void __iomem *reg, u32 value)
{
	iowrite32be(value, reg);
}

static unsigned int realtek_gpio_line_imr_pos_swapped(unsigned int line)
{
	unsigned int port_pin = line % 8;
	unsigned int port = line / 8;

	return 2 * (8 * (port ^ 1) + port_pin);
}

/*
 * Reversed port order register access
 *
 * For registers with one bit per GPIO, all ports are stored as u8-s in one
 * register in reversed order. The two interrupt mask registers store two bits
 * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
 * second ports 3 and 2.
 */
static u32 realtek_gpio_bank_read(void __iomem *reg)
{
	return ioread32(reg);
}

static void realtek_gpio_bank_write(void __iomem *reg, u32 value)
{
	iowrite32(value, reg);
}

static unsigned int realtek_gpio_line_imr_pos(unsigned int line)
{
	return 2 * line;
}

Annotation

Implementation Notes