[PATCH 2/2] regulator: da9121: Allow caching BUCK registers

From: André Svensson

Date: Mon Mar 09 2026 - 11:57:32 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 which 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 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 | 35 +++++++++++++++++++++++++++++------
1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index ef161eb0ca27..ed62a41deb84 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -864,6 +864,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 +1009,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 +1028,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 = &regmap_config_1ch;
break;
case DA9121_SUBTYPE_DA9217:
chip->variant_id = DA9121_TYPE_DA9217;
- regmap = &da9121_1ch_regmap_config;
+ regmap = &regmap_config_1ch;
break;
case DA9121_SUBTYPE_DA9122:
case DA9121_SUBTYPE_DA9131:
chip->variant_id = DA9121_TYPE_DA9122_DA9131;
- regmap = &da9121_2ch_regmap_config;
+ regmap = &regmap_config_2ch;
break;
case DA9121_SUBTYPE_DA9220:
case DA9121_SUBTYPE_DA9132:
chip->variant_id = DA9121_TYPE_DA9220_DA9132;
- regmap = &da9121_2ch_regmap_config;
+ regmap = &regmap_config_2ch;
break;
case DA9121_SUBTYPE_DA9141:
chip->variant_id = DA9121_TYPE_DA9141;
- regmap = &da9121_1ch_regmap_config;
+ regmap = &regmap_config_1ch;
break;
case DA9121_SUBTYPE_DA9142:
chip->variant_id = DA9121_TYPE_DA9142;
- regmap = &da9121_2ch_regmap_config;
+ regmap = &regmap_config_2ch;
break;
default:
return -EINVAL;

--
2.43.0