drivers/gpio/gpio-syscon.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-syscon.c
Extension
.c
Size
7231 bytes
Lines
273
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 syscon_gpio_data {
	unsigned int	flags;
	unsigned int	bit_count;
	unsigned int	dat_bit_offset;
	unsigned int	dir_bit_offset;
	int		(*set)(struct gpio_chip *chip, unsigned int offset,
			       int value);
};

struct syscon_gpio_priv {
	struct gpio_chip		chip;
	struct regmap			*syscon;
	const struct syscon_gpio_data	*data;
	u32				dreg_offset;
	u32				dir_reg_offset;
};

static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
	unsigned int val, offs;
	int ret;

	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;

	ret = regmap_read(priv->syscon,
			  (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
	if (ret)
		return ret;

	return !!(val & BIT(offs % SYSCON_REG_BITS));
}

static int syscon_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
{
	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);
	unsigned int offs;

	offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;

	return regmap_update_bits(priv->syscon,
				  (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
				  BIT(offs % SYSCON_REG_BITS),
				  val ? BIT(offs % SYSCON_REG_BITS) : 0);
}

static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);

	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
		unsigned int offs;

		offs = priv->dir_reg_offset +
		       priv->data->dir_bit_offset + offset;

		regmap_update_bits(priv->syscon,
				   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
				   BIT(offs % SYSCON_REG_BITS), 0);
	}

	return 0;
}

static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
{
	struct syscon_gpio_priv *priv = gpiochip_get_data(chip);

	if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
		unsigned int offs;

		offs = priv->dir_reg_offset +
		       priv->data->dir_bit_offset + offset;

		regmap_update_bits(priv->syscon,
				   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
				   BIT(offs % SYSCON_REG_BITS),
				   BIT(offs % SYSCON_REG_BITS));
	}

	return chip->set(chip, offset, val);
}

static const struct syscon_gpio_data clps711x_mctrl_gpio = {
	/* ARM CLPS711X SYSFLG1 Bits 8-10 */
	.flags		= GPIO_SYSCON_FEAT_IN,
	.bit_count	= 3,
	.dat_bit_offset	= 0x40 * 8 + 8,
};

Annotation

Implementation Notes