[PATCH v7 6/9] gpio: regmap: Add value_xlate callback
Yu-Chun Lin <[email protected]>
| Newsgroups | org.kernel.vger.linux-gpio,org.kernel.vger.linux-iio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Introduce a new optional 'value_xlate' callback. This routine allows drivers to translate or modify the register value and mask immediately before a write operation. It is particularly useful for hardware that requires additional control bits, such as a write-enable bit, to be appended to the data dynamically. Suggested-by: Michael Walle <[email protected]> Signed-off-by: Yu-Chun Lin <[email protected]> --- Changes in v7: - New patch --- drivers/gpio/gpio-regmap.c | 31 ++++++++++++++++++++++++++++++- include/linux/gpio/regmap.h | 8 ++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-regmap.c b/drivers/gpio/gpio-regmap.c index 1cc9c03ade99..8f58b272b870 100644 --- a/drivers/gpio/gpio-regmap.c +++ b/drivers/gpio/gpio-regmap.c @@ -45,6 +45,12 @@ struct gpio_regmap { unsigned int base, unsigned int offset, unsigned int *reg, unsigned int *mask); + int (*value_xlate)(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, + unsigned int reg, unsigned int *mask, + unsigned int *val); + void *driver_data; }; @@ -125,6 +131,13 @@ static int gpio_regmap_set(struct gpio_chip *chip, unsigned int offset, else mask_val = 0; + if (gpio->value_xlate) { + ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, + reg, &mask, &mask_val); + if (ret) + return ret; + } + /* ignore input values which shadow the old output value */ if (gpio->reg_dat_base == gpio->reg_set_base) ret = regmap_write_bits(gpio->regmap, reg, mask, mask_val); @@ -138,7 +151,7 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip, unsigned int offset, int val) { struct gpio_regmap *gpio = gpiochip_get_data(chip); - unsigned int base, reg, mask; + unsigned int base, reg, mask, value = 0; int ret; if (val) @@ -150,6 +163,13 @@ static int gpio_regmap_set_with_clear(struct gpio_chip *chip, if (ret) return ret; + if (gpio->value_xlate) { + ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_OP, base, offset, + reg, &mask, &value); + if (ret) + return ret; + } + return regmap_write(gpio->regmap, reg, mask); } @@ -259,6 +279,13 @@ static int gpio_regmap_set_direction(struct gpio_chip *chip, else val = output ? mask : 0; + if (gpio->value_xlate) { + ret = gpio->value_xlate(gpio, GPIO_REGMAP_SET_DIR_OP, base, offset, + reg, &mask, &val); + if (ret) + return ret; + } + return regmap_update_bits(gpio->regmap, reg, mask, val); } @@ -426,6 +453,8 @@ struct gpio_regmap *gpio_regmap_register(const struct gpio_regmap_config *config if (!gpio->reg_mask_xlate) gpio->reg_mask_xlate = gpio_regmap_simple_xlate; + gpio->value_xlate = config->value_xlate; + ret = gpiochip_add_data(chip, gpio); if (ret < 0) goto err_free_bitmap_output; diff --git a/include/linux/gpio/regmap.h b/include/linux/gpio/regmap.h index ececc287d519..b77d6371cd9c 100644 --- a/include/linux/gpio/regmap.h +++ b/include/linux/gpio/regmap.h @@ -89,6 +89,10 @@ enum gpio_regmap_operation { * is used. * @init_valid_mask: (Optional) Routine to initialize @valid_mask, to be used * if not all GPIOs are valid. + * @value_xlate: (Optional) Routine to translate the register value and + * mask before writing. This allows driver-specific logic + * to append additional bits (like write-enable masks) + * dynamically based on the current operation. * @drvdata: (Optional) Pointer to driver specific data which is * not used by gpio-remap but is provided "as is" to the * driver callback(s). @@ -146,6 +150,10 @@ struct gpio_regmap_config { unsigned long *valid_mask, unsigned int ngpios); + int (*value_xlate)(struct gpio_regmap *gpio, enum gpio_regmap_operation, + unsigned int base, unsigned int offset, unsigned int reg, + unsigned int *mask, unsigned int *val); + void *drvdata; }; -- 2.43.0