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.
- 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.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/bitops.hlinux/device.hlinux/errno.hlinux/gpio/driver.hlinux/gpio/generic.hlinux/init.hlinux/platform_device.hlinux/property.hlinux/slab.hlinux/spinlock.hlinux/regmap.h
Detected Declarations
struct sifive_gpiofunction sifive_gpio_set_iefunction sifive_gpio_irq_set_typefunction sifive_gpio_irq_enablefunction scoped_guardfunction sifive_gpio_irq_disablefunction sifive_gpio_irq_eoifunction scoped_guardfunction sifive_gpio_irq_set_affinityfunction sifive_gpio_child_to_parent_hwirqfunction sifive_gpio_probe
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
- Immediate include surface: `linux/bitops.h`, `linux/device.h`, `linux/errno.h`, `linux/gpio/driver.h`, `linux/gpio/generic.h`, `linux/init.h`, `linux/platform_device.h`, `linux/property.h`.
- Detected declarations: `struct sifive_gpio`, `function sifive_gpio_set_ie`, `function sifive_gpio_irq_set_type`, `function sifive_gpio_irq_enable`, `function scoped_guard`, `function sifive_gpio_irq_disable`, `function sifive_gpio_irq_eoi`, `function scoped_guard`, `function sifive_gpio_irq_set_affinity`, `function sifive_gpio_child_to_parent_hwirq`.
- Atlas domain: Driver Families / drivers/gpio.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.