drivers/gpio/gpio-ixp4xx.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-ixp4xx.c
Extension
.c
Size
9576 bytes
Lines
354
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 ixp4xx_gpio {
	struct gpio_generic_chip chip;
	struct device *dev;
	void __iomem *base;
	unsigned long long irq_edge;
};

static void ixp4xx_gpio_irq_ack(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct ixp4xx_gpio *g = gpiochip_get_data(gc);

	__raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
}

static void ixp4xx_gpio_mask_irq(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);

	irq_chip_mask_parent(d);
	gpiochip_disable_irq(gc, d->hwirq);
}

static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct ixp4xx_gpio *g = gpiochip_get_data(gc);

	/* ACK when unmasking if not edge-triggered */
	if (!(g->irq_edge & BIT(d->hwirq)))
		ixp4xx_gpio_irq_ack(d);

	gpiochip_enable_irq(gc, d->hwirq);
	irq_chip_unmask_parent(d);
}

static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct ixp4xx_gpio *g = gpiochip_get_data(gc);
	int line = d->hwirq;
	u32 int_style;
	u32 int_reg;
	u32 val;

	switch (type) {
	case IRQ_TYPE_EDGE_BOTH:
		irq_set_handler_locked(d, handle_edge_irq);
		int_style = IXP4XX_GPIO_STYLE_TRANSITIONAL;
		g->irq_edge |= BIT(d->hwirq);
		break;
	case IRQ_TYPE_EDGE_RISING:
		irq_set_handler_locked(d, handle_edge_irq);
		int_style = IXP4XX_GPIO_STYLE_RISING_EDGE;
		g->irq_edge |= BIT(d->hwirq);
		break;
	case IRQ_TYPE_EDGE_FALLING:
		irq_set_handler_locked(d, handle_edge_irq);
		int_style = IXP4XX_GPIO_STYLE_FALLING_EDGE;
		g->irq_edge |= BIT(d->hwirq);
		break;
	case IRQ_TYPE_LEVEL_HIGH:
		irq_set_handler_locked(d, handle_level_irq);
		int_style = IXP4XX_GPIO_STYLE_ACTIVE_HIGH;
		g->irq_edge &= ~BIT(d->hwirq);
		break;
	case IRQ_TYPE_LEVEL_LOW:
		irq_set_handler_locked(d, handle_level_irq);
		int_style = IXP4XX_GPIO_STYLE_ACTIVE_LOW;
		g->irq_edge &= ~BIT(d->hwirq);
		break;
	default:
		return -EINVAL;
	}

	if (line >= 8) {
		/* pins 8-15 */
		line -= 8;
		int_reg = IXP4XX_REG_GPIT2;
	} else {
		/* pins 0-7 */
		int_reg = IXP4XX_REG_GPIT1;
	}

	scoped_guard(gpio_generic_lock_irqsave, &g->chip) {
		/* Clear the style for the appropriate pin */
		val = __raw_readl(g->base + int_reg);
		val &= ~(IXP4XX_GPIO_STYLE_MASK << (line * IXP4XX_GPIO_STYLE_SIZE));
		__raw_writel(val, g->base + int_reg);

Annotation

Implementation Notes