drivers/gpio/gpio-sifive.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-sifive.c
Extension
.c
Size
7933 bytes
Lines
276
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 sifive_gpio {
	void __iomem		*base;
	struct gpio_generic_chip gen_gc;
	struct regmap		*regs;
	unsigned long		irq_state;
	unsigned int		trigger[SIFIVE_GPIO_MAX];
	unsigned int		irq_number[SIFIVE_GPIO_MAX];
};

static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
{
	unsigned int trigger;

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

	trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0;
	regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset),
			   (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0);
	regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset),
			   (trigger & IRQ_TYPE_EDGE_FALLING) ? BIT(offset) : 0);
	regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset),
			   (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0);
	regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset),
			   (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0);
}

static int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct sifive_gpio *chip = gpiochip_get_data(gc);
	int offset = irqd_to_hwirq(d);

	if (offset < 0 || offset >= gc->ngpio)
		return -EINVAL;

	chip->trigger[offset] = trigger;
	sifive_gpio_set_ie(chip, offset);
	return 0;
}

static void sifive_gpio_irq_enable(struct irq_data *d)
	{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct sifive_gpio *chip = gpiochip_get_data(gc);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);
	int offset = hwirq % SIFIVE_GPIO_MAX;
	u32 bit = BIT(offset);

	gpiochip_enable_irq(gc, hwirq);
	irq_chip_enable_parent(d);

	/* Switch to input */
	gc->direction_input(gc, offset);

	scoped_guard(gpio_generic_lock_irqsave, &chip->gen_gc) {
		/* Clear any sticky pending interrupts */
		regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
		regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
		regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
		regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
	}

	/* Enable interrupts */
	assign_bit(offset, &chip->irq_state, 1);
	sifive_gpio_set_ie(chip, offset);
}

static void sifive_gpio_irq_disable(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct sifive_gpio *chip = gpiochip_get_data(gc);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);
	int offset = hwirq % SIFIVE_GPIO_MAX;

	assign_bit(offset, &chip->irq_state, 0);
	sifive_gpio_set_ie(chip, offset);
	irq_chip_disable_parent(d);
	gpiochip_disable_irq(gc, hwirq);
}

static void sifive_gpio_irq_eoi(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct sifive_gpio *chip = gpiochip_get_data(gc);
	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
	u32 bit = BIT(offset);

	scoped_guard(gpio_generic_lock_irqsave, &chip->gen_gc) {
		/* Clear all pending interrupts */
		regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);

Annotation

Implementation Notes