drivers/gpio/gpio-exar.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-exar.c
Extension
.c
Size
6696 bytes
Lines
240
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 exar_gpio_chip {
	struct gpio_chip gpio_chip;
	struct regmap *regmap;
	int index;
	char name[20];
	unsigned int first_pin;
	/*
	 * The offset to the cascaded device's (if existing)
	 * Device Configuration Registers.
	 */
	unsigned int cascaded_offset;
};

static unsigned int
exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
	unsigned int pin = exar_gpio->first_pin + (offset % 16);
	unsigned int cascaded = offset / 16;
	unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;

	return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
}

static unsigned int
exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
	unsigned int pin = exar_gpio->first_pin + (offset % 16);
	unsigned int cascaded = offset / 16;
	unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;

	return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
}

static unsigned int
exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
	unsigned int pin = exar_gpio->first_pin + (offset % 16);

	return pin % 8;
}

static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
{
	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);

	if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)))
		return GPIO_LINE_DIRECTION_IN;

	return GPIO_LINE_DIRECTION_OUT;
}

static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
{
	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
	unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);

	return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)));
}

static int exar_set_value(struct gpio_chip *chip, unsigned int offset,
			  int value)
{
	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
	unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
	unsigned int bit_value = value ? BIT(bit) : 0;

	/*
	 * regmap_write_bits() forces value to be written when an external
	 * pull up/down might otherwise indicate value was already set.
	 */
	return regmap_write_bits(exar_gpio->regmap, addr, BIT(bit), bit_value);
}

static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
				 int value)
{
	struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
	unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
	unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
	int ret;

	ret = exar_set_value(chip, offset, value);
	if (ret)
		return ret;

	return regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));

Annotation

Implementation Notes