drivers/gpio/gpio-bcm-kona.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-bcm-kona.c
Extension
.c
Size
18170 bytes
Lines
673
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 bcm_kona_gpio_bank {
	int id;
	int irq;
	/*
	 * Used to keep track of lock/unlock operations for each GPIO in the
	 * bank.
	 *
	 * All GPIOs are locked by default (see bcm_kona_gpio_reset), and the
	 * unlock count for all GPIOs is 0 by default. Each unlock increments
	 * the counter, and each lock decrements the counter.
	 *
	 * The lock function only locks the GPIO once its unlock counter is
	 * down to 0. This is necessary because the GPIO is unlocked in two
	 * places in this driver: once for requested GPIOs, and once for
	 * requested IRQs. Since it is possible for a GPIO to be requested
	 * as both a GPIO and an IRQ, we need to ensure that we don't lock it
	 * too early.
	 */
	u8 gpio_unlock_count[GPIO_PER_BANK];
	/* Used in the interrupt handler */
	struct bcm_kona_gpio *kona_gpio;
};

struct bcm_kona_gpio {
	void __iomem *reg_base;
	int num_bank;
	raw_spinlock_t lock;
	struct gpio_chip gpio_chip;
	struct irq_domain *irq_domain;
	struct bcm_kona_gpio_bank banks[] __counted_by(num_bank);
};

static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
						int bank_id, u32 lockcode)
{
	writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET);
	writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id));
}

static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio,
					unsigned gpio)
{
	u32 val;
	int bank_id = GPIO_BANK(gpio);
	int bit = GPIO_BIT(gpio);
	struct bcm_kona_gpio_bank *bank = &kona_gpio->banks[bank_id];

	if (bank->gpio_unlock_count[bit] == 0) {
		dev_err(kona_gpio->gpio_chip.parent,
			"Unbalanced locks for GPIO %u\n", gpio);
		return;
	}

	if (--bank->gpio_unlock_count[bit] == 0) {
		guard(raw_spinlock_irqsave)(&kona_gpio->lock);

		val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
		val |= BIT(bit);
		bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
	}
}

static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
					unsigned gpio)
{
	u32 val;
	int bank_id = GPIO_BANK(gpio);
	int bit = GPIO_BIT(gpio);
	struct bcm_kona_gpio_bank *bank = &kona_gpio->banks[bank_id];

	if (bank->gpio_unlock_count[bit] == 0) {
		guard(raw_spinlock_irqsave)(&kona_gpio->lock);

		val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
		val &= ~BIT(bit);
		bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
	}

	++bank->gpio_unlock_count[bit];
}

static int bcm_kona_gpio_get_dir(struct gpio_chip *chip, unsigned gpio)
{
	struct bcm_kona_gpio *kona_gpio = gpiochip_get_data(chip);
	void __iomem *reg_base = kona_gpio->reg_base;
	u32 val;

	val = readl(reg_base + GPIO_CONTROL(gpio)) & GPIO_GPCTR0_IOTR_MASK;
	return val ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}

Annotation

Implementation Notes