drivers/gpio/gpio-xgene-sb.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-xgene-sb.c
Extension
.c
Size
9878 bytes
Lines
362
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 xgene_gpio_sb {
	struct gpio_generic_chip chip;
	void __iomem		*regs;
	struct irq_domain	*irq_domain;
	u16			irq_start;
	u16			nirq;
	u16			parent_irq_base;
};

#define HWIRQ_TO_GPIO(priv, hwirq) ((hwirq) + (priv)->irq_start)
#define GPIO_TO_HWIRQ(priv, gpio) ((gpio) - (priv)->irq_start)

static void xgene_gpio_set_bit(struct gpio_chip *gc,
				void __iomem *reg, u32 gpio, int val)
{
	struct gpio_generic_chip *chip = to_gpio_generic_chip(gc);
	u32 data;

	data = gpio_generic_read_reg(chip, reg);
	if (val)
		data |= GPIO_MASK(gpio);
	else
		data &= ~GPIO_MASK(gpio);
	gpio_generic_write_reg(chip, reg, data);
}

static int xgene_gpio_sb_irq_set_type(struct irq_data *d, unsigned int type)
{
	struct xgene_gpio_sb *priv = irq_data_get_irq_chip_data(d);
	int gpio = HWIRQ_TO_GPIO(priv, d->hwirq);
	int lvl_type = GPIO_INT_LEVEL_H;

	switch (type & IRQ_TYPE_SENSE_MASK) {
	case IRQ_TYPE_EDGE_RISING:
	case IRQ_TYPE_LEVEL_HIGH:
		lvl_type = GPIO_INT_LEVEL_H;
		break;
	case IRQ_TYPE_EDGE_FALLING:
	case IRQ_TYPE_LEVEL_LOW:
		lvl_type = GPIO_INT_LEVEL_L;
		break;
	default:
		break;
	}

	xgene_gpio_set_bit(&priv->chip.gc, priv->regs + MPA_GPIO_SEL_LO,
			gpio * 2, 1);
	xgene_gpio_set_bit(&priv->chip.gc, priv->regs + MPA_GPIO_INT_LVL,
			d->hwirq, lvl_type);

	/* Propagate IRQ type setting to parent */
	if (type & IRQ_TYPE_EDGE_BOTH)
		return irq_chip_set_type_parent(d, IRQ_TYPE_EDGE_RISING);
	else
		return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
}

static void xgene_gpio_sb_irq_mask(struct irq_data *d)
{
	struct xgene_gpio_sb *priv = irq_data_get_irq_chip_data(d);

	irq_chip_mask_parent(d);

	gpiochip_disable_irq(&priv->chip.gc, d->hwirq);
}

static void xgene_gpio_sb_irq_unmask(struct irq_data *d)
{
	struct xgene_gpio_sb *priv = irq_data_get_irq_chip_data(d);

	gpiochip_enable_irq(&priv->chip.gc, d->hwirq);

	irq_chip_unmask_parent(d);
}

static const struct irq_chip xgene_gpio_sb_irq_chip = {
	.name           = "sbgpio",
	.irq_eoi	= irq_chip_eoi_parent,
	.irq_mask       = xgene_gpio_sb_irq_mask,
	.irq_unmask     = xgene_gpio_sb_irq_unmask,
	.irq_set_type   = xgene_gpio_sb_irq_set_type,
	.flags = IRQCHIP_IMMUTABLE,
	GPIOCHIP_IRQ_RESOURCE_HELPERS,
};

static int xgene_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
{
	struct xgene_gpio_sb *priv = gpiochip_get_data(gc);
	struct irq_fwspec fwspec;

Annotation

Implementation Notes