Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92de6bc3 authored by Linus Walleij's avatar Linus Walleij
Browse files

Merge branch 'ib-pca953x-config' into devel

parents 5340f23d 15add068
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -67,6 +67,18 @@ Optional standard bitfield specifiers for the last cell:
           https://en.wikipedia.org/wiki/Open_collector
- Bit 3: 0 means the output should be maintained during sleep/low-power mode
         1 means the output state can be lost during sleep/low-power mode
- Bit 4: 0 means no pull-up resistor should be enabled
         1 means a pull-up resistor should be enabled
         This setting only applies to hardware with a simple on/off
         control for pull-up configuration. If the hardware has more
         elaborate pull-up configuration, it should be represented
         using a pin control binding.
- Bit 5: 0 means no pull-down resistor should be enabled
         1 means a pull-down resistor should be enabled
         This setting only applies to hardware with a simple on/off
         control for pull-down configuration. If the hardware has more
         elaborate pull-down configuration, it should be represented
         using a pin control binding.

1.1) GPIO specifier best practices
----------------------------------
+64 −2
Original line number Diff line number Diff line
@@ -179,6 +179,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
#define PCA957x_BANK_OUTPUT	BIT(5)

#define PCAL9xxx_BANK_IN_LATCH	BIT(8 + 2)
#define PCAL9xxx_BANK_PULL_EN	BIT(8 + 3)
#define PCAL9xxx_BANK_PULL_SEL	BIT(8 + 4)
#define PCAL9xxx_BANK_IRQ_MASK	BIT(8 + 5)
#define PCAL9xxx_BANK_IRQ_STAT	BIT(8 + 6)

@@ -200,6 +202,8 @@ static int pca953x_bank_shift(struct pca953x_chip *chip)
 * - Extended set, above 0x40, often chip specific.
 *   - PCAL6524/PCAL9555A with custom PCAL IRQ handling:
 *     Input latch register		0x40 + 2 * bank_size	RW
 *     Pull-up/pull-down enable reg	0x40 + 3 * bank_size    RW
 *     Pull-up/pull-down select reg	0x40 + 4 * bank_size    RW
 *     Interrupt mask register		0x40 + 5 * bank_size	RW
 *     Interrupt status register	0x40 + 6 * bank_size	R
 *
@@ -248,7 +252,8 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
	}

	if (chip->driver_data & PCA_PCAL) {
		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK |
		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
			PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK |
			PCAL9xxx_BANK_IRQ_STAT;
	}

@@ -269,7 +274,8 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
	}

	if (chip->driver_data & PCA_PCAL)
		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_IRQ_MASK;
		bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
			PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;

	return pca953x_check_register(chip, reg, bank);
}
@@ -474,6 +480,61 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
	mutex_unlock(&chip->i2c_lock);
}

static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
					 unsigned int offset,
					 unsigned long config)
{
	u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset,
					     true, false);
	u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset,
					      true, false);
	u8 bit = BIT(offset % BANK_SZ);
	int ret;

	/*
	 * pull-up/pull-down configuration requires PCAL extended
	 * registers
	 */
	if (!(chip->driver_data & PCA_PCAL))
		return -ENOTSUPP;

	mutex_lock(&chip->i2c_lock);

	/* Disable pull-up/pull-down */
	ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
	if (ret)
		goto exit;

	/* Configure pull-up/pull-down */
	if (config == PIN_CONFIG_BIAS_PULL_UP)
		ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
	else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
		ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
	if (ret)
		goto exit;

	/* Enable pull-up/pull-down */
	ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);

exit:
	mutex_unlock(&chip->i2c_lock);
	return ret;
}

static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
				   unsigned long config)
{
	struct pca953x_chip *chip = gpiochip_get_data(gc);

	switch (config) {
	case PIN_CONFIG_BIAS_PULL_UP:
	case PIN_CONFIG_BIAS_PULL_DOWN:
		return pca953x_gpio_set_pull_up_down(chip, offset, config);
	default:
		return -ENOTSUPP;
	}
}

static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{
	struct gpio_chip *gc;
@@ -486,6 +547,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
	gc->set = pca953x_gpio_set_value;
	gc->get_direction = pca953x_gpio_get_direction;
	gc->set_multiple = pca953x_gpio_set_multiple;
	gc->set_config = pca953x_gpio_set_config;
	gc->can_sleep = true;

	gc->base = chip->gpio_start;
+5 −0
Original line number Diff line number Diff line
@@ -345,6 +345,11 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
	if (of_flags & OF_GPIO_TRANSITORY)
		*flags |= GPIO_TRANSITORY;

	if (of_flags & OF_GPIO_PULL_UP)
		*flags |= GPIO_PULL_UP;
	if (of_flags & OF_GPIO_PULL_DOWN)
		*flags |= GPIO_PULL_DOWN;

	return desc;
}

+34 −16
Original line number Diff line number Diff line
@@ -2555,6 +2555,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
 * rely on gpio_request() having been called beforehand.
 */

static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
			   enum pin_config_param mode)
{
	unsigned long config = { PIN_CONF_PACKED(mode, 0) };

	return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
}

/**
 * gpiod_direction_input - set the GPIO direction to input
 * @desc:	GPIO to set to input
@@ -2602,20 +2610,19 @@ int gpiod_direction_input(struct gpio_desc *desc)
	if (status == 0)
		clear_bit(FLAG_IS_OUT, &desc->flags);

	if (test_bit(FLAG_PULL_UP, &desc->flags))
		gpio_set_config(chip, gpio_chip_hwgpio(desc),
				PIN_CONFIG_BIAS_PULL_UP);
	else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
		gpio_set_config(chip, gpio_chip_hwgpio(desc),
				PIN_CONFIG_BIAS_PULL_DOWN);

	trace_gpio_direction(desc_to_gpio(desc), 1, status);

	return status;
}
EXPORT_SYMBOL_GPL(gpiod_direction_input);

static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
				       enum pin_config_param mode)
{
	unsigned long config = { PIN_CONF_PACKED(mode, 0) };

	return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
}

static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
{
	struct gpio_chip *gc = desc->gdev->chip;
@@ -2712,7 +2719,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
	gc = desc->gdev->chip;
	if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
		/* First see if we can enable open drain in hardware */
		ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
		ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
				      PIN_CONFIG_DRIVE_OPEN_DRAIN);
		if (!ret)
			goto set_output_value;
@@ -2721,7 +2728,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
			return gpiod_direction_input(desc);
	}
	else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
		ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
		ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
				      PIN_CONFIG_DRIVE_OPEN_SOURCE);
		if (!ret)
			goto set_output_value;
@@ -2729,7 +2736,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
		if (!value)
			return gpiod_direction_input(desc);
	} else {
		gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
		gpio_set_config(gc, gpio_chip_hwgpio(desc),
				PIN_CONFIG_DRIVE_PUSH_PULL);
	}

@@ -2762,7 +2769,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
	}

	config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
	return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
	return gpio_set_config(chip, gpio_chip_hwgpio(desc), config);
}
EXPORT_SYMBOL_GPL(gpiod_set_debounce);

@@ -2799,7 +2806,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
	packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
					  !transitory);
	gpio = gpio_chip_hwgpio(desc);
	rc = chip->set_config(chip, gpio, packed);
	rc = gpio_set_config(chip, gpio, packed);
	if (rc == -ENOTSUPP) {
		dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
				gpio);
@@ -4087,6 +4094,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
	if (lflags & GPIO_OPEN_SOURCE)
		set_bit(FLAG_OPEN_SOURCE, &desc->flags);

	if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) {
		gpiod_err(desc,
			  "both pull-up and pull-down enabled, invalid configuration\n");
		return -EINVAL;
	}

	if (lflags & GPIO_PULL_UP)
		set_bit(FLAG_PULL_UP, &desc->flags);
	else if (lflags & GPIO_PULL_DOWN)
		set_bit(FLAG_PULL_DOWN, &desc->flags);

	status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
	if (status < 0)
		return status;
+2 −0
Original line number Diff line number Diff line
@@ -219,6 +219,8 @@ struct gpio_desc {
#define FLAG_IRQ_IS_ENABLED 10	/* GPIO is connected to an enabled IRQ */
#define FLAG_IS_HOGGED	11	/* GPIO is hogged */
#define FLAG_TRANSITORY 12	/* GPIO may lose value in sleep or reset */
#define FLAG_PULL_UP    13	/* GPIO has pull up enabled */
#define FLAG_PULL_DOWN  14	/* GPIO has pull down enabled */

	/* Connection label */
	const char		*label;
Loading