[PATCH v2 2/2] regulator: da9121: Allow caching BUCK registers
From: André Svensson
Date: Fri Mar 20 2026 - 03:34:51 EST
Some BUCK registers may change without software writes when GPIO pins
are configured for functions DVC/RELOAD/EN. If the board does
not use these pin-controlled features, caching is possible.
Caching BUCK registers removes unnecessary I2C reads when performing
register updates. For example, updating regulator mode can result in
two I2C reads, one from the regulator core regulator_set_mode() and one
from the DA9121 driver, where da9121_buck_set_mode() uses
regmap_update_bits() (read/modify/write).
Check for the optional DT property dlg,no-gpio-control. When present,
select the regmap configuration that does not mark the BUCK1 register
block (DA9121_REG_BUCK_BUCK1_0..DA9121_REG_BUCK_BUCK1_6) as volatile, so
that regmap can cache BUCK1 registers and avoid unnecessary I2C reads.
The property dlg,no-gpio-control is required to ensure that BUCK1
registers can be cached, as the absence of relevant GPIO DT properties
does not imply that the RELOAD/DVC/EN GPIO functions are unused. These
functions are provided by DA91xx GPIO pins and may be controlled by
external hardware without corresponding GPIO DT properties. The
dlg,no-gpio-control property explicitly indicates that none of these
GPIO functions are used.
The dlg,no-gpio-control property is mutually exclusive with
enable-gpios, regardless of whether the referenced GPIO is connected to
a GPIO pin or the IC_EN pin, since pulling IC_EN low powers down the
regulator and registers are reinitialized at startup, leaving cached
values stale.
Co-developed-by: Waqar Hameed <waqar.hameed@xxxxxxxx>
Signed-off-by: Waqar Hameed <waqar.hameed@xxxxxxxx>
Signed-off-by: André Svensson <andre.svensson@xxxxxxxx>
---
drivers/regulator/da9121-regulator.c | 43 ++++++++++++++++++++++++++++++------
1 file changed, 36 insertions(+), 7 deletions(-)
diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index ef161eb0ca27..2b150bb4d471 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -400,8 +400,14 @@ static int da9121_of_parse_cb(struct device_node *np,
GPIOD_OUT_HIGH |
GPIOD_FLAGS_BIT_NONEXCLUSIVE,
"da9121-enable");
- if (!IS_ERR(ena_gpiod))
+ if (!IS_ERR(ena_gpiod)) {
+ if (of_property_read_bool(chip->dev->of_node, "dlg,no-gpio-control")) {
+ gpiod_put(ena_gpiod);
+ dev_err(chip->dev, "dlg,no-gpio-control conflicts with enable-gpios\n");
+ return -EINVAL;
+ }
config->ena_gpiod = ena_gpiod;
+ }
if (variant_parameters[chip->variant_id].num_bucks == 2) {
uint32_t ripple_cancel;
@@ -864,6 +870,21 @@ static const struct regmap_access_table da9121_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(da9121_volatile_ranges),
};
+/*
+ * When GPIO functions DVC/RELOAD/EN are not used, the registers in the range
+ * DA9121_REG_BUCK_BUCK1_0 to DA9121_REG_BUCK_BUCK1_6 need not be volatile
+ * because register writes to these registers can only be performed via I2C.
+ */
+static const struct regmap_range da9121_volatile_ranges_no_gpio_ctrl[] = {
+ regmap_reg_range(DA9121_REG_SYS_STATUS_0, DA9121_REG_SYS_EVENT_2),
+ regmap_reg_range(DA9121_REG_SYS_GPIO0_0, DA9121_REG_SYS_GPIO2_1),
+};
+
+static const struct regmap_access_table da9121_volatile_table_no_gpio_ctrl = {
+ .yes_ranges = da9121_volatile_ranges_no_gpio_ctrl,
+ .n_yes_ranges = ARRAY_SIZE(da9121_volatile_ranges_no_gpio_ctrl),
+};
+
/* DA9121 regmap config for 1 channel variants */
static const struct regmap_config da9121_1ch_regmap_config = {
.reg_bits = 8,
@@ -994,10 +1015,18 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
struct da9121 *chip)
{
const struct regmap_config *regmap;
+ struct regmap_config regmap_config_1ch = da9121_1ch_regmap_config;
+ struct regmap_config regmap_config_2ch = da9121_2ch_regmap_config;
+
int ret = 0;
chip->dev = &i2c->dev;
+ if (of_property_read_bool(i2c->dev.of_node, "dlg,no-gpio-control")) {
+ regmap_config_1ch.volatile_table = &da9121_volatile_table_no_gpio_ctrl;
+ regmap_config_2ch.volatile_table = &da9121_volatile_table_no_gpio_ctrl;
+ }
+
/* Use configured subtype to select the regulator descriptor index and
* register map, common to both consumer and automotive grade variants
*/
@@ -1005,29 +1034,29 @@ static int da9121_assign_chip_model(struct i2c_client *i2c,
case DA9121_SUBTYPE_DA9121:
case DA9121_SUBTYPE_DA9130:
chip->variant_id = DA9121_TYPE_DA9121_DA9130;
- regmap = &da9121_1ch_regmap_config;
+ regmap = ®map_config_1ch;
break;
case DA9121_SUBTYPE_DA9217:
chip->variant_id = DA9121_TYPE_DA9217;
- regmap = &da9121_1ch_regmap_config;
+ regmap = ®map_config_1ch;
break;
case DA9121_SUBTYPE_DA9122:
case DA9121_SUBTYPE_DA9131:
chip->variant_id = DA9121_TYPE_DA9122_DA9131;
- regmap = &da9121_2ch_regmap_config;
+ regmap = ®map_config_2ch;
break;
case DA9121_SUBTYPE_DA9220:
case DA9121_SUBTYPE_DA9132:
chip->variant_id = DA9121_TYPE_DA9220_DA9132;
- regmap = &da9121_2ch_regmap_config;
+ regmap = ®map_config_2ch;
break;
case DA9121_SUBTYPE_DA9141:
chip->variant_id = DA9121_TYPE_DA9141;
- regmap = &da9121_1ch_regmap_config;
+ regmap = ®map_config_1ch;
break;
case DA9121_SUBTYPE_DA9142:
chip->variant_id = DA9121_TYPE_DA9142;
- regmap = &da9121_2ch_regmap_config;
+ regmap = ®map_config_2ch;
break;
default:
return -EINVAL;
--
2.43.0