diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index f2d9f6275e6..c539e1169ee 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -90,6 +90,9 @@ int regulator_common_init(const struct device *dev, bool is_enabled) if (is_enabled) { data->refcnt++; + if ((config->flags & REGULATOR_BOOT_OFF) != 0U) { + return regulator_disable(dev); + } } else if ((config->flags & REGULATOR_INIT_ENABLED) != 0U) { ret = api->enable(dev); if (ret < 0) { diff --git a/drivers/regulator/regulator_fake.c b/drivers/regulator/regulator_fake.c index 129ef2f215e..c2c71593c61 100644 --- a/drivers/regulator/regulator_fake.c +++ b/drivers/regulator/regulator_fake.c @@ -15,6 +15,7 @@ struct regulator_fake_config { struct regulator_common_config common; + bool is_enabled; }; struct regulator_fake_data { @@ -64,9 +65,11 @@ static struct regulator_driver_api api = { static int regulator_fake_init(const struct device *dev) { + const struct regulator_fake_config *config = dev->config; + regulator_common_data_init(dev); - return regulator_common_init(dev, false); + return regulator_common_init(dev, config->is_enabled); } /* parent regulator */ @@ -90,6 +93,7 @@ static struct regulator_parent_driver_api parent_api = { \ static const struct regulator_fake_config FAKE_CONF_NAME(node_id) = { \ .common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \ + .is_enabled = DT_PROP(node_id, fake_is_enabled_in_hardware), \ }; \ \ DEVICE_DT_DEFINE(node_id, regulator_fake_init, NULL, \ diff --git a/dts/bindings/regulator/adi,adp5360-regulator.yaml b/dts/bindings/regulator/adi,adp5360-regulator.yaml index d683bd694ef..e54a305e80f 100644 --- a/dts/bindings/regulator/adi,adp5360-regulator.yaml +++ b/dts/bindings/regulator/adi,adp5360-regulator.yaml @@ -34,6 +34,7 @@ child-binding: property-allowlist: - regulator-always-on - regulator-boot-on + - regulator-boot-off - regulator-init-microvolt - regulator-min-microvolt - regulator-max-microvolt diff --git a/dts/bindings/regulator/nordic,npm1300-regulator.yaml b/dts/bindings/regulator/nordic,npm1300-regulator.yaml index c5364a49fe0..e0fc28ff8be 100644 --- a/dts/bindings/regulator/nordic,npm1300-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm1300-regulator.yaml @@ -53,6 +53,7 @@ child-binding: property-allowlist: - regulator-always-on - regulator-boot-on + - regulator-boot-off - regulator-min-microvolt - regulator-max-microvolt - regulator-init-microvolt diff --git a/dts/bindings/regulator/nordic,npm6001-regulator.yaml b/dts/bindings/regulator/nordic,npm6001-regulator.yaml index 34c90c78640..378f6c0a8ec 100644 --- a/dts/bindings/regulator/nordic,npm6001-regulator.yaml +++ b/dts/bindings/regulator/nordic,npm6001-regulator.yaml @@ -45,6 +45,7 @@ child-binding: property-allowlist: - regulator-always-on - regulator-boot-on + - regulator-boot-off - regulator-max-microamp - regulator-min-microvolt - regulator-max-microvolt diff --git a/dts/bindings/regulator/regulator.yaml b/dts/bindings/regulator/regulator.yaml index 635bfa49596..b072ce8c920 100644 --- a/dts/bindings/regulator/regulator.yaml +++ b/dts/bindings/regulator/regulator.yaml @@ -61,6 +61,11 @@ properties: This property is intended to only be used for regulators where software cannot read the state of the regulator. + regulator-boot-off: + type: boolean + description: | + Regulator should be disabled on boot. + regulator-allow-bypass: type: boolean description: allow the regulator to go into bypass mode diff --git a/dts/bindings/regulator/x-powers,axp192-regulator.yaml b/dts/bindings/regulator/x-powers,axp192-regulator.yaml index 98599731c3b..9072e80727b 100644 --- a/dts/bindings/regulator/x-powers,axp192-regulator.yaml +++ b/dts/bindings/regulator/x-powers,axp192-regulator.yaml @@ -51,6 +51,7 @@ child-binding: - regulator-max-microvolt - regulator-always-on - regulator-boot-on + - regulator-boot-off - regulator-initial-mode - regulator-allowed-modes diff --git a/dts/bindings/regulator/zephyr,fake-regulator.yaml b/dts/bindings/regulator/zephyr,fake-regulator.yaml index 7a6894948b2..833dc8ca115 100644 --- a/dts/bindings/regulator/zephyr,fake-regulator.yaml +++ b/dts/bindings/regulator/zephyr,fake-regulator.yaml @@ -10,3 +10,10 @@ compatible: "zephyr,fake-regulator" child-binding: include: regulator.yaml + + properties: + fake-is-enabled-in-hardware: + type: boolean + description: | + Sets the is_enabled flag passed to regulator_common_init. + Allows test cases where the regulator is enabled in hardware. diff --git a/include/zephyr/drivers/regulator.h b/include/zephyr/drivers/regulator.h index 77e441d0dae..46a085d9239 100644 --- a/include/zephyr/drivers/regulator.h +++ b/include/zephyr/drivers/regulator.h @@ -141,6 +141,8 @@ __subsystem struct regulator_driver_api { /** Regulator active discharge get bits */ #define REGULATOR_ACTIVE_DISCHARGE_GET_BITS(x) \ (((x) & REGULATOR_ACTIVE_DISCHARGE_MASK) >> REGULATOR_ACTIVE_DISCHARGE_POS) +/** Indicates regulator must be initialized OFF */ +#define REGULATOR_BOOT_OFF BIT(4) /** @} */ @@ -212,7 +214,9 @@ struct regulator_common_config { REGULATOR_BOOT_ON) | \ (REGULATOR_ACTIVE_DISCHARGE_SET_BITS( \ DT_PROP_OR(node_id, regulator_active_discharge, \ - REGULATOR_ACTIVE_DISCHARGE_DEFAULT)))), \ + REGULATOR_ACTIVE_DISCHARGE_DEFAULT))) | \ + (DT_PROP_OR(node_id, regulator_boot_off, 0U) * \ + REGULATOR_BOOT_OFF)), \ } /** @@ -254,6 +258,7 @@ void regulator_common_data_init(const struct device *dev); * * - Automatically enable the regulator if it is set to `regulator-boot-on` * or `regulator-always-on` and increase its usage count. + * - Automatically disable the regulator if it is set to `regulator-boot-off`. * - Configure the regulator mode if `regulator-initial-mode` is set. * - Ensure regulator voltage is set to a valid range. * diff --git a/tests/drivers/regulator/api/app.overlay b/tests/drivers/regulator/api/app.overlay index 25d1d8bb795..6dfeefed18f 100644 --- a/tests/drivers/regulator/api/app.overlay +++ b/tests/drivers/regulator/api/app.overlay @@ -26,5 +26,14 @@ regulator-initial-mode = <1>; regulator-active-discharge = <1>; }; + + reg4: REG4 { + regulator-boot-off; + }; + + reg5: REG5 { + regulator-boot-off; + fake-is-enabled-in-hardware; + }; }; }; diff --git a/tests/drivers/regulator/api/src/main.c b/tests/drivers/regulator/api/src/main.c index 648d761a8b4..93fa7863085 100644 --- a/tests/drivers/regulator/api/src/main.c +++ b/tests/drivers/regulator/api/src/main.c @@ -19,6 +19,10 @@ static const struct device *const reg1 = DEVICE_DT_GET(DT_NODELABEL(reg1)); static const struct device *const reg2 = DEVICE_DT_GET(DT_NODELABEL(reg2)); /* REG3: regulator-max/min-microvolt/microamp, regulator-allowed-modes */ static const struct device *const reg3 = DEVICE_DT_GET(DT_NODELABEL(reg3)); +/* REG4: regulator-boot-off */ +static const struct device *const reg4 = DEVICE_DT_GET(DT_NODELABEL(reg4)); +/* REG5: regulator-boot-off and is_enabled */ +static const struct device *const reg5 = DEVICE_DT_GET(DT_NODELABEL(reg5)); ZTEST(regulator_api, test_parent_dvs_state_set_not_implemented) { @@ -129,6 +133,10 @@ ZTEST(regulator_api, test_common_config) zassert_equal(config->allowed_modes[1], 10U); zassert_equal(config->allowed_modes_cnt, 2U); zassert_equal(REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags), 1U); + + /* reg4: regulator-boot-off */ + config = reg4->config; + zassert_equal(config->flags & REGULATOR_BOOT_OFF, REGULATOR_BOOT_OFF); } ZTEST(regulator_api, test_common_is_init_enabled) @@ -137,6 +145,8 @@ ZTEST(regulator_api, test_common_is_init_enabled) zassert_true(regulator_common_is_init_enabled(reg1)); zassert_true(regulator_common_is_init_enabled(reg2)); zassert_false(regulator_common_is_init_enabled(reg3)); + zassert_false(regulator_common_is_init_enabled(reg4)); + zassert_false(regulator_common_is_init_enabled(reg5)); } ZTEST(regulator_api, test_enable_disable) @@ -171,6 +181,16 @@ ZTEST(regulator_api, test_enable_disable) zassert_equal(regulator_disable(reg0), 0); zassert_equal(regulator_fake_disable_fake.arg0_val, reg0); zassert_equal(regulator_fake_disable_fake.call_count, 2U); + + /* REG5: disabled at boot, can be enabled again */ + zassert_equal(regulator_enable(reg5), 0); + zassert_equal(regulator_fake_enable_fake.call_count, 3U); + + /* REG5: disable */ + zassert_equal(regulator_disable(reg5), 0); + zassert_equal(regulator_fake_disable_fake.call_count, 3U); + + } ZTEST(regulator_api, test_count_voltages_not_implemented) @@ -776,6 +796,8 @@ void *setup(void) zassert_true(device_is_ready(reg1)); zassert_true(device_is_ready(reg2)); zassert_true(device_is_ready(reg3)); + zassert_true(device_is_ready(reg4)); + zassert_true(device_is_ready(reg5)); /* REG1, REG2 initialized at init time (always-on/boot-on) */ zassert_equal(regulator_fake_enable_fake.call_count, 2U); @@ -785,6 +807,13 @@ void *setup(void) /* REG3 mode set at init time (initial-mode) */ zassert_equal(regulator_fake_set_mode_fake.call_count, 1U); + /* REG4 already disabled at init time (boot-off) */ + zassert_false(regulator_is_enabled(reg4)); + + /* REG5 explicitly disabled at init time (boot-off) */ + zassert_equal(regulator_fake_disable_fake.call_count, 1U); + zassert_false(regulator_is_enabled(reg5)); + return NULL; }