drivers/gpio/gpio-novalake-events.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-novalake-events.c
Extension
.c
Size
8938 bytes
Lines
324
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 nvl_gpio {
	struct gpio_chip gc;
	void __iomem *reg_base;
	raw_spinlock_t lock;
	size_t blk_size;
};

static void __iomem *nvl_gpio_get_byte_addr(struct nvl_gpio *priv,
					    unsigned int reg_offset,
					    unsigned long gpio)
{
	return priv->reg_base + reg_offset + gpio;
}

static int nvl_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
	struct nvl_gpio *priv = gpiochip_get_data(gc);
	unsigned int byte_idx = gpio / BITS_PER_BYTE;
	unsigned int bit_idx = gpio % BITS_PER_BYTE;
	void __iomem *addr;
	u8 reg;

	addr = nvl_gpio_get_byte_addr(priv, GPE_STS_REG_OFFSET, byte_idx);

	guard(raw_spinlock_irqsave)(&priv->lock);

	reg = ioread8(addr);

	return !!(reg & BIT(bit_idx));
}

static const struct gpio_chip nvl_gpio_chip = {
	.owner	= THIS_MODULE,
	.get	= nvl_gpio_get,
};

static int nvl_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
	if (type & IRQ_TYPE_EDGE_BOTH)
		irq_set_handler_locked(d, handle_edge_irq);
	else if (type & IRQ_TYPE_LEVEL_MASK)
		irq_set_handler_locked(d, handle_level_irq);

	return 0;
}

static void nvl_gpio_irq_mask_unmask(struct gpio_chip *gc, unsigned long hwirq,
				     bool mask)
{
	struct nvl_gpio *priv = gpiochip_get_data(gc);
	unsigned int byte_idx = hwirq / BITS_PER_BYTE;
	unsigned int bit_idx = hwirq % BITS_PER_BYTE;
	void __iomem *addr;
	u8 reg;

	addr = nvl_gpio_get_byte_addr(priv, GPE_EN_REG_OFFSET(priv->blk_size), byte_idx);

	guard(raw_spinlock_irqsave)(&priv->lock);

	reg = ioread8(addr);
	if (mask)
		reg &= ~BIT(bit_idx);
	else
		reg |= BIT(bit_idx);
	iowrite8(reg, addr);
}

static void nvl_gpio_irq_unmask(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);

	gpiochip_enable_irq(gc, hwirq);
	nvl_gpio_irq_mask_unmask(gc, hwirq, false);
}

static void nvl_gpio_irq_mask(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);

	nvl_gpio_irq_mask_unmask(gc, hwirq, true);
	gpiochip_disable_irq(gc, hwirq);
}

static void nvl_gpio_irq_ack(struct irq_data *d)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
	struct nvl_gpio *priv = gpiochip_get_data(gc);
	irq_hw_number_t hwirq = irqd_to_hwirq(d);

Annotation

Implementation Notes