drivers/gpio/gpio-rda.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-rda.c
Extension
.c
Size
8038 bytes
Lines
300
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 rda_gpio {
	struct gpio_generic_chip chip;
	void __iomem *base;
	spinlock_t lock;
	int irq;
};

static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset,
				   u16 reg, int val)
{
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	unsigned long flags;
	u32 tmp;

	spin_lock_irqsave(&rda_gpio->lock, flags);
	tmp = readl_relaxed(base + reg);

	if (val)
		tmp |= BIT(offset);
	else
		tmp &= ~BIT(offset);

	writel_relaxed(tmp, base + reg);
	spin_unlock_irqrestore(&rda_gpio->lock, flags);
}

static void rda_gpio_irq_mask(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	u32 offset = irqd_to_hwirq(data);
	u32 value;

	value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
	value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;

	writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
	gpiochip_disable_irq(chip, offset);
}

static void rda_gpio_irq_ack(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	u32 offset = irqd_to_hwirq(data);

	rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1);
}

static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset,
			    unsigned int flow_type)
{
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	u32 value;

	switch (flow_type) {
	case IRQ_TYPE_EDGE_RISING:
		/* Set rising edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_EDGE_FALLING:
		/* Set falling edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_EDGE_BOTH:
		/* Set both edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
		value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_LEVEL_HIGH:

Annotation

Implementation Notes