drivers/gpio/gpio-brcmstb.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-brcmstb.c
Extension
.c
Size
21962 bytes
Lines
810
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 brcmstb_gpio_bank {
	struct list_head node;
	int id;
	struct gpio_generic_chip chip;
	struct brcmstb_gpio_priv *parent_priv;
	u32 width;
	u32 wake_active;
	u32 saved_regs[GIO_REG_STAT]; /* Don't save and restore GIO_REG_STAT */
};

struct brcmstb_gpio_priv {
	struct list_head bank_list;
	void __iomem *reg_base;
	struct platform_device *pdev;
	struct irq_domain *irq_domain;
	struct irq_chip irq_chip;
	int parent_irq;
	int num_gpios;
	int parent_wake_irq;
	bool suspended;
};

#define MAX_GPIO_PER_BANK       32
#define GPIO_BANK(gpio)         ((gpio) >> 5)
/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
#define GPIO_BIT(gpio)          ((gpio) & (MAX_GPIO_PER_BANK - 1))

static inline struct brcmstb_gpio_priv *
brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
{
	struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
	return bank->parent_priv;
}

static unsigned long
__brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
{
	void __iomem *reg_base = bank->parent_priv->reg_base;

	return gpio_generic_read_reg(&bank->chip, reg_base + GIO_STAT(bank->id)) &
	       gpio_generic_read_reg(&bank->chip, reg_base + GIO_MASK(bank->id));
}

static unsigned long
brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
{
	unsigned long status;

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

	status = __brcmstb_gpio_get_active_irqs(bank);

	return status;
}

static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq,
					struct brcmstb_gpio_bank *bank)
{
	return hwirq - bank->chip.gc.offset;
}

static void __brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
				     irq_hw_number_t hwirq, bool enable)
{
	struct brcmstb_gpio_priv *priv = bank->parent_priv;
	u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(hwirq, bank));
	u32 imask;

	imask = gpio_generic_read_reg(&bank->chip,
				      priv->reg_base + GIO_MASK(bank->id));
	if (enable)
		imask |= mask;
	else
		imask &= ~mask;
	gpio_generic_write_reg(&bank->chip,
			       priv->reg_base + GIO_MASK(bank->id), imask);
}

static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
				   irq_hw_number_t hwirq, bool enable)
{
	guard(gpio_generic_lock_irqsave)(&bank->chip);
	__brcmstb_gpio_set_imask(bank, hwirq, enable);
}

static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
	struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
	/* gc_offset is relative to this gpio_chip; want real offset */
	int hwirq = offset + gc->offset;

Annotation

Implementation Notes