drivers/gpio/gpio-arizona.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-arizona.c
Extension
.c
Size
5269 bytes
Lines
212
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 arizona_gpio {
	struct arizona *arizona;
	struct gpio_chip gpio_chip;
};

static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
	struct arizona *arizona = arizona_gpio->arizona;
	bool persistent = gpiochip_line_is_persistent(chip, offset);
	bool change;
	int ret;

	ret = regmap_update_bits_check(arizona->regmap,
				       ARIZONA_GPIO1_CTRL + offset,
				       ARIZONA_GPN_DIR, ARIZONA_GPN_DIR,
				       &change);
	if (ret < 0)
		return ret;

	if (change && persistent) {
		pm_runtime_put_autosuspend(chip->parent);
	}

	return 0;
}

static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
{
	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
	struct arizona *arizona = arizona_gpio->arizona;
	unsigned int reg, val;
	int ret;

	reg = ARIZONA_GPIO1_CTRL + offset;
	ret = regmap_read(arizona->regmap, reg, &val);
	if (ret < 0)
		return ret;

	/* Resume to read actual registers for input pins */
	if (val & ARIZONA_GPN_DIR) {
		ret = pm_runtime_get_sync(chip->parent);
		if (ret < 0) {
			dev_err(chip->parent, "Failed to resume: %d\n", ret);
			pm_runtime_put_autosuspend(chip->parent);
			return ret;
		}

		/* Register is cached, drop it to ensure a physical read */
		ret = regcache_drop_region(arizona->regmap, reg, reg);
		if (ret < 0) {
			dev_err(chip->parent, "Failed to drop cache: %d\n",
				ret);
			pm_runtime_put_autosuspend(chip->parent);
			return ret;
		}

		ret = regmap_read(arizona->regmap, reg, &val);
		if (ret < 0) {
			pm_runtime_put_autosuspend(chip->parent);
			return ret;
		}

		pm_runtime_put_autosuspend(chip->parent);
	}

	if (val & ARIZONA_GPN_LVL)
		return 1;
	else
		return 0;
}

static int arizona_gpio_direction_out(struct gpio_chip *chip,
				     unsigned offset, int value)
{
	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
	struct arizona *arizona = arizona_gpio->arizona;
	bool persistent = gpiochip_line_is_persistent(chip, offset);
	unsigned int val;
	int ret;

	ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
	if (ret < 0)
		return ret;

	if ((val & ARIZONA_GPN_DIR) && persistent) {
		ret = pm_runtime_get_sync(chip->parent);
		if (ret < 0) {
			dev_err(chip->parent, "Failed to resume: %d\n", ret);
			pm_runtime_put(chip->parent);

Annotation

Implementation Notes