drivers/gpio/gpio-uniphier.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-uniphier.c
Extension
.c
Size
13533 bytes
Lines
499
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 uniphier_gpio_priv {
	struct gpio_chip chip;
	struct irq_chip irq_chip;
	struct irq_domain *domain;
	void __iomem *regs;
	spinlock_t lock;
	u32 saved_vals[];
};

static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
{
	unsigned int reg;

	reg = (bank + 1) * 8;

	/*
	 * Unfortunately, the GPIO port registers are not contiguous because
	 * offset 0x90-0x9f is used for IRQ.  Add 0x10 when crossing the region.
	 */
	if (reg >= UNIPHIER_GPIO_IRQ_EN)
		reg += 0x10;

	return reg;
}

static void uniphier_gpio_get_bank_and_mask(unsigned int offset,
					    unsigned int *bank, u32 *mask)
{
	*bank = offset / UNIPHIER_GPIO_LINES_PER_BANK;
	*mask = BIT(offset % UNIPHIER_GPIO_LINES_PER_BANK);
}

static void uniphier_gpio_reg_update(struct uniphier_gpio_priv *priv,
				     unsigned int reg, u32 mask, u32 val)
{
	unsigned long flags;
	u32 tmp;

	spin_lock_irqsave(&priv->lock, flags);
	tmp = readl(priv->regs + reg);
	tmp &= ~mask;
	tmp |= mask & val;
	writel(tmp, priv->regs + reg);
	spin_unlock_irqrestore(&priv->lock, flags);
}

static void uniphier_gpio_bank_write(struct gpio_chip *chip, unsigned int bank,
				     unsigned int reg, u32 mask, u32 val)
{
	struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);

	if (!mask)
		return;

	uniphier_gpio_reg_update(priv, uniphier_gpio_bank_to_reg(bank) + reg,
				 mask, val);
}

static void uniphier_gpio_offset_write(struct gpio_chip *chip,
				       unsigned int offset, unsigned int reg,
				       int val)
{
	unsigned int bank;
	u32 mask;

	uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);

	uniphier_gpio_bank_write(chip, bank, reg, mask, val ? mask : 0);
}

static int uniphier_gpio_offset_read(struct gpio_chip *chip,
				     unsigned int offset, unsigned int reg)
{
	struct uniphier_gpio_priv *priv = gpiochip_get_data(chip);
	unsigned int bank, reg_offset;
	u32 mask;

	uniphier_gpio_get_bank_and_mask(offset, &bank, &mask);
	reg_offset = uniphier_gpio_bank_to_reg(bank) + reg;

	return !!(readl(priv->regs + reg_offset) & mask);
}

static int uniphier_gpio_get_direction(struct gpio_chip *chip,
				       unsigned int offset)
{
	if (uniphier_gpio_offset_read(chip, offset, UNIPHIER_GPIO_PORT_DIR))
		return GPIO_LINE_DIRECTION_IN;

	return GPIO_LINE_DIRECTION_OUT;

Annotation

Implementation Notes