drivers/gpio/gpio-mlxbf3.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-mlxbf3.c
Extension
.c
Size
8174 bytes
Lines
292
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 mlxbf3_gpio_context {
	struct gpio_generic_chip chip;

	/* YU GPIO block address */
	void __iomem *gpio_set_io;
	void __iomem *gpio_clr_io;
	void __iomem *gpio_io;

	/* YU GPIO cause block address */
	void __iomem *gpio_cause_io;
};

static void mlxbf3_gpio_irq_enable(struct irq_data *irqd)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
	struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
	irq_hw_number_t offset = irqd_to_hwirq(irqd);
	u32 val;

	gpiochip_enable_irq(gc, offset);

	guard(gpio_generic_lock_irqsave)(&gs->chip);

	writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);

	val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
	val |= BIT(offset);
	writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
}

static void mlxbf3_gpio_irq_disable(struct irq_data *irqd)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
	struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
	irq_hw_number_t offset = irqd_to_hwirq(irqd);
	u32 val;

	scoped_guard(gpio_generic_lock_irqsave, &gs->chip) {
		val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
		val &= ~BIT(offset);
		writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);

		writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
	}

	gpiochip_disable_irq(gc, offset);
}

static irqreturn_t mlxbf3_gpio_irq_handler(int irq, void *ptr)
{
	struct mlxbf3_gpio_context *gs = ptr;
	struct gpio_chip *gc = &gs->chip.gc;
	unsigned long pending;
	u32 level;

	pending = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CAUSE_EVTEN0);
	writel(pending, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);

	for_each_set_bit(level, &pending, gc->ngpio)
		generic_handle_domain_irq(gc->irq.domain, level);

	return IRQ_RETVAL(pending);
}

static int
mlxbf3_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
	struct mlxbf3_gpio_context *gs = gpiochip_get_data(gc);
	irq_hw_number_t offset = irqd_to_hwirq(irqd);
	u32 val;

	scoped_guard(gpio_generic_lock_irqsave, &gs->chip) {
		switch (type & IRQ_TYPE_SENSE_MASK) {
		case IRQ_TYPE_EDGE_BOTH:
			val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
			val |= BIT(offset);
			writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
			val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
			val |= BIT(offset);
			writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
			break;
		case IRQ_TYPE_EDGE_RISING:
			val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
			val |= BIT(offset);
			writel(val, gs->gpio_io + MLXBF_GPIO_CAUSE_RISE_EN);
			break;
		case IRQ_TYPE_EDGE_FALLING:
			val = readl(gs->gpio_io + MLXBF_GPIO_CAUSE_FALL_EN);
			val |= BIT(offset);

Annotation

Implementation Notes