drivers/gpio/gpio-hlwd.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-hlwd.c
Extension
.c
Size
9058 bytes
Lines
323
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 hlwd_gpio {
	struct gpio_generic_chip gpioc;
	struct device *dev;
	void __iomem *regs;
	int irq;
	u32 edge_emulation;
	u32 rising_edge, falling_edge;
};

static void hlwd_gpio_irqhandler(struct irq_desc *desc)
{
	struct hlwd_gpio *hlwd =
		gpiochip_get_data(irq_desc_get_handler_data(desc));
	struct irq_chip *chip = irq_desc_get_chip(desc);
	unsigned long pending;
	int hwirq;
	u32 emulated_pending;

	scoped_guard(gpio_generic_lock_irqsave, &hlwd->gpioc) {
		pending = ioread32be(hlwd->regs + HW_GPIOB_INTFLAG);
		pending &= ioread32be(hlwd->regs + HW_GPIOB_INTMASK);

		/* Treat interrupts due to edge trigger emulation separately */
		emulated_pending = hlwd->edge_emulation & pending;
		pending &= ~emulated_pending;
		if (emulated_pending) {
			u32 level, rising, falling;

			level = ioread32be(hlwd->regs + HW_GPIOB_INTLVL);
			rising = level & emulated_pending;
			falling = ~level & emulated_pending;

			/* Invert the levels */
			iowrite32be(level ^ emulated_pending,
				    hlwd->regs + HW_GPIOB_INTLVL);

			/* Ack all emulated-edge interrupts */
			iowrite32be(emulated_pending, hlwd->regs + HW_GPIOB_INTFLAG);

			/* Signal interrupts only on the correct edge */
			rising &= hlwd->rising_edge;
			falling &= hlwd->falling_edge;

			/* Mark emulated interrupts as pending */
			pending |= rising | falling;
		}
	}

	chained_irq_enter(chip, desc);

	for_each_set_bit(hwirq, &pending, 32)
		generic_handle_domain_irq(hlwd->gpioc.gc.irq.domain, hwirq);

	chained_irq_exit(chip, desc);
}

static void hlwd_gpio_irq_ack(struct irq_data *data)
{
	struct hlwd_gpio *hlwd =
		gpiochip_get_data(irq_data_get_irq_chip_data(data));

	iowrite32be(BIT(data->hwirq), hlwd->regs + HW_GPIOB_INTFLAG);
}

static void hlwd_gpio_irq_mask(struct irq_data *data)
{
	struct hlwd_gpio *hlwd =
		gpiochip_get_data(irq_data_get_irq_chip_data(data));
	u32 mask;

	scoped_guard(gpio_generic_lock_irqsave, &hlwd->gpioc) {
		mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
		mask &= ~BIT(data->hwirq);
		iowrite32be(mask, hlwd->regs + HW_GPIOB_INTMASK);
	}
	gpiochip_disable_irq(&hlwd->gpioc.gc, irqd_to_hwirq(data));
}

static void hlwd_gpio_irq_unmask(struct irq_data *data)
{
	struct hlwd_gpio *hlwd =
		gpiochip_get_data(irq_data_get_irq_chip_data(data));
	u32 mask;

	gpiochip_enable_irq(&hlwd->gpioc.gc, irqd_to_hwirq(data));

	guard(gpio_generic_lock_irqsave)(&hlwd->gpioc);

	mask = ioread32be(hlwd->regs + HW_GPIOB_INTMASK);
	mask |= BIT(data->hwirq);

Annotation

Implementation Notes