drivers/gpio/gpio-spacemit-k1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-spacemit-k1.c
Extension
.c
Size
10269 bytes
Lines
377
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 spacemit_gpio_data {
	const unsigned int *offsets;
	u32 bank_offsets[SPACEMIT_NR_BANKS];
};

struct spacemit_gpio_bank {
	struct gpio_generic_chip chip;
	struct spacemit_gpio *sg;
	void __iomem *base;
	u32 irq_mask;
	u32 irq_rising_edge;
	u32 irq_falling_edge;
};

struct spacemit_gpio {
	struct device *dev;
	const struct spacemit_gpio_data *data;
	struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
};

static u32 spacemit_gpio_read(struct spacemit_gpio_bank *gb,
			      enum spacemit_gpio_registers reg)
{
	return readl(gb->base + to_spacemit_gpio_regs(gb)[reg]);
}

static void spacemit_gpio_write(struct spacemit_gpio_bank *gb,
				enum spacemit_gpio_registers reg, u32 val)
{
	writel(val, gb->base + to_spacemit_gpio_regs(gb)[reg]);
}

static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
{
	return (u32)(gb - gb->sg->sgb);
}

static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
{
	struct spacemit_gpio_bank *gb = dev_id;
	unsigned long pending;
	u32 n, gedr;

	gedr = spacemit_gpio_read(gb, SPACEMIT_GEDR);
	if (!gedr)
		return IRQ_NONE;
	spacemit_gpio_write(gb, SPACEMIT_GEDR, gedr);

	pending = gedr & gb->irq_mask;
	if (!pending)
		return IRQ_NONE;

	for_each_set_bit(n, &pending, BITS_PER_LONG)
		handle_nested_irq(irq_find_mapping(gb->chip.gc.irq.domain, n));

	return IRQ_HANDLED;
}

static void spacemit_gpio_irq_ack(struct irq_data *d)
{
	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);

	spacemit_gpio_write(gb, SPACEMIT_GEDR, BIT(irqd_to_hwirq(d)));
}

static void spacemit_gpio_irq_mask(struct irq_data *d)
{
	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
	u32 bit = BIT(irqd_to_hwirq(d));

	gb->irq_mask &= ~bit;
	spacemit_gpio_write(gb, SPACEMIT_GAPMASK, gb->irq_mask);

	if (bit & gb->irq_rising_edge)
		spacemit_gpio_write(gb, SPACEMIT_GCRER, bit);

	if (bit & gb->irq_falling_edge)
		spacemit_gpio_write(gb, SPACEMIT_GCFER, bit);
}

static void spacemit_gpio_irq_unmask(struct irq_data *d)
{
	struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
	u32 bit = BIT(irqd_to_hwirq(d));

	gb->irq_mask |= bit;

	if (bit & gb->irq_rising_edge)
		spacemit_gpio_write(gb, SPACEMIT_GSRER, bit);

Annotation

Implementation Notes