drivers/gpio/gpio-74x164.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-74x164.c
Extension
.c
Size
5713 bytes
Lines
210
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 gen_74x164_chip {
	struct gpio_chip	gpio_chip;
	struct mutex		lock;
	struct gpio_desc	*gpiod_oe;
	u32			registers;
	/*
	 * Since the registers are chained, every byte sent will make
	 * the previous byte shift to the next register in the
	 * chain. Thus, the first byte sent will end up in the last
	 * register at the end of the transfer. So, to have a logical
	 * numbering, store the bytes in reverse order.
	 */
	u8			buffer[] __counted_by(registers);
};

static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
{
	return spi_write(to_spi_device(chip->gpio_chip.parent), chip->buffer,
			 chip->registers);
}

static int gen_74x164_get_value(struct gpio_chip *gc, unsigned offset)
{
	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
	u8 bank = chip->registers - 1 - offset / 8;
	u8 pin = offset % 8;

	guard(mutex)(&chip->lock);

	return !!(chip->buffer[bank] & BIT(pin));
}

static int gen_74x164_set_value(struct gpio_chip *gc,
				unsigned int offset, int val)
{
	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
	u8 bank = chip->registers - 1 - offset / 8;
	u8 pin = offset % 8;

	guard(mutex)(&chip->lock);

	if (val)
		chip->buffer[bank] |= BIT(pin);
	else
		chip->buffer[bank] &= ~BIT(pin);

	return __gen_74x164_write_config(chip);
}

static int gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
				   unsigned long *bits)
{
	struct gen_74x164_chip *chip = gpiochip_get_data(gc);
	unsigned long offset;
	unsigned long bankmask;
	size_t bank;
	unsigned long bitmask;

	guard(mutex)(&chip->lock);

	for_each_set_clump8(offset, bankmask, mask, chip->registers * 8) {
		bank = chip->registers - 1 - offset / 8;
		bitmask = bitmap_get_value8(bits, offset) & bankmask;

		chip->buffer[bank] &= ~bankmask;
		chip->buffer[bank] |= bitmask;
	}
	return __gen_74x164_write_config(chip);
}

static int gen_74x164_direction_output(struct gpio_chip *gc,
		unsigned offset, int val)
{
	gen_74x164_set_value(gc, offset, val);
	return 0;
}

static void gen_74x164_deactivate(void *data)
{
	struct gen_74x164_chip *chip = data;

	gpiod_set_value_cansleep(chip->gpiod_oe, 0);
}

static int gen_74x164_activate(struct device *dev, struct gen_74x164_chip *chip)
{
	gpiod_set_value_cansleep(chip->gpiod_oe, 1);
	return devm_add_action_or_reset(dev, gen_74x164_deactivate, chip);
}

Annotation

Implementation Notes