drivers/gpio/gpio-tps65219.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-tps65219.c
Extension
.c
Size
7557 bytes
Lines
270
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 tps65219_gpio {
	int (*change_dir)(struct gpio_chip *gc, unsigned int offset, unsigned int dir);
	struct gpio_chip gpio_chip;
	struct tps65219 *tps;
};

static int tps65214_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
	struct tps65219_gpio *gpio = gpiochip_get_data(gc);
	int ret, val;

	if (offset != TPS6521X_GPIO0_IDX)
		return GPIO_LINE_DIRECTION_OUT;

	ret = regmap_read(gpio->tps->regmap, TPS65219_REG_GENERAL_CONFIG, &val);
	if (ret)
		return ret;

	return !(val & TPS65214_GPIO0_DIR_MASK);
}

static int tps65219_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
	struct tps65219_gpio *gpio = gpiochip_get_data(gc);
	int ret, val;

	if (offset != TPS6521X_GPIO0_IDX)
		return GPIO_LINE_DIRECTION_OUT;

	ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, &val);
	if (ret)
		return ret;

	return !!(val & TPS65219_GPIO0_DIR_MASK);
}

static int tps65219_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
	struct tps65219_gpio *gpio = gpiochip_get_data(gc);
	struct device *dev = gpio->tps->dev;
	int ret, val;

	if (offset != TPS6521X_GPIO0_IDX) {
		dev_err(dev, "GPIO%d is output only, cannot get\n", offset);
		return -ENOTSUPP;
	}

	ret = regmap_read(gpio->tps->regmap, TPS65219_REG_MFP_CTRL, &val);
	if (ret)
		return ret;

	ret = !!(val & BIT(TPS65219_MFP_GPIO_STATUS_MASK));
	dev_warn(dev, "GPIO%d = %d, MULTI_DEVICE_ENABLE, not a standard GPIO\n", offset, ret);

	/*
	 * Depending on NVM config, return an error if direction is output, otherwise the GPIO0
	 * status bit.
	 */

	if (tps65219_gpio_get_direction(gc, offset) == GPIO_LINE_DIRECTION_OUT)
		return -ENOTSUPP;

	return ret;
}

static int tps65219_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
	struct tps65219_gpio *gpio = gpiochip_get_data(gc);
	int v, mask, bit;

	bit = (offset == TPS6521X_GPIO0_IDX) ? TPS6521X_GPIO0_OFFSET : offset - 1;

	mask = BIT(bit);
	v = value ? mask : 0;

	return regmap_update_bits(gpio->tps->regmap,
				  TPS65219_REG_GENERAL_CONFIG, mask, v);
}

static int tps65219_gpio_change_direction(struct gpio_chip *gc, unsigned int offset,
					  unsigned int direction)
{
	struct tps65219_gpio *gpio = gpiochip_get_data(gc);
	struct device *dev = gpio->tps->dev;

	/*
	 * Documentation is stating that GPIO0 direction must not be changed in Linux:
	 * Table 8-34. MFP_1_CONFIG(3): MULTI_DEVICE_ENABLE, should only be changed in INITIALIZE
	 * state (prior to ON Request).
	 * Set statically by NVM, changing direction in application can cause a hang.

Annotation

Implementation Notes