diff --git a/drivers/regulator/CMakeLists.txt b/drivers/regulator/CMakeLists.txt index 3f06708b65441..fb3bc095c5bba 100644 --- a/drivers/regulator/CMakeLists.txt +++ b/drivers/regulator/CMakeLists.txt @@ -26,4 +26,5 @@ zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9422 regulator_pca9422.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_PF1550 regulator_pf1550.c) zephyr_library_sources_ifdef(CONFIG_REGULATOR_RPI_PICO regulator_rpi_pico.c) +zephyr_library_sources_ifdef(CONFIG_REGULATOR_TPS55287 regulator_tps55287.c) # zephyr-keep-sorted-stop diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ffc0a6c69f13a..f18f111b6e96a 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -46,6 +46,7 @@ source "drivers/regulator/Kconfig.pca9420" source "drivers/regulator/Kconfig.pca9422" source "drivers/regulator/Kconfig.pf1550" source "drivers/regulator/Kconfig.rpi_pico" +source "drivers/regulator/Kconfig.tps55287" # zephyr-keep-sorted-stop endif # REGULATOR diff --git a/drivers/regulator/Kconfig.tps55287 b/drivers/regulator/Kconfig.tps55287 new file mode 100644 index 0000000000000..d8345898ffae6 --- /dev/null +++ b/drivers/regulator/Kconfig.tps55287 @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +config REGULATOR_TPS55287 + bool "TPS55287 regulator driver" + default y + depends on DT_HAS_TI_TPS55287_ENABLED + select I2C + help + Enable support for the TPS55287 regulator. + +if REGULATOR_TPS55287 + +config REGULATOR_TPS55287_INIT_PRIORITY + int "TPS55287 regulator driver init priority" + default I2C_INIT_PRIORITY + help + Init priority for the TPS55287 regulator driver. This must be higher + or equal to the parent I2C bus init priority. + +endif diff --git a/drivers/regulator/regulator_tps55287.c b/drivers/regulator/regulator_tps55287.c new file mode 100644 index 0000000000000..9444fc3e52058 --- /dev/null +++ b/drivers/regulator/regulator_tps55287.c @@ -0,0 +1,183 @@ +/* + * SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tps55287 + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(tps55287, CONFIG_REGULATOR_LOG_LEVEL); + +#define TPS55287_REG_REF 0x00U +#define TPS55287_REG_VOUT_FS 0x04U +#define TPS55287_REG_MODE 0x06U + +#define TPS55287_REG_VOUT_FS_INTFB_MASK BIT_MASK(2) +#define TPS55287_REG_MODE_OE BIT(7) + +/* The order of the voltage ranges is important, as it maps to the VOUT_FS register */ +static const struct linear_range core_ranges[] = { + LINEAR_RANGE_INIT(800000u, 2500u, 0xf0, BIT_MASK(11)), + LINEAR_RANGE_INIT(800000u, 5000u, 0x50, BIT_MASK(11)), + LINEAR_RANGE_INIT(800000u, 7500u, 0x1a, BIT_MASK(11)), + LINEAR_RANGE_INIT(800000u, 10000u, 0x00, BIT_MASK(11)), +}; + +struct regulator_tps55287_config { + struct regulator_common_config common; + struct i2c_dt_spec i2c; +}; + +struct regulator_tps55287_data { + struct regulator_common_data data; +}; + +static unsigned int regulator_tps55287_count_voltages(const struct device *dev) +{ + return linear_range_group_values_count(core_ranges, ARRAY_SIZE(core_ranges)); +} + +static int regulator_tps55287_list_voltage(const struct device *dev, unsigned int idx, + int32_t *volt_uv) +{ + for (uint8_t i = 0U; i < ARRAY_SIZE(core_ranges); i++) { + if (linear_range_get_value(&core_ranges[i], idx, volt_uv) == 0) { + return 0; + } + idx -= linear_range_values_count(&core_ranges[i]); + } + + return -EINVAL; +} + +static int regulator_tps55287_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv) +{ + const struct regulator_tps55287_config *config = dev->config; + uint8_t buf[3] = {0}; + uint16_t idx; + uint8_t vout_fs_reg; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, TPS55287_REG_VOUT_FS, &vout_fs_reg); + if (ret < 0) { + return ret; + } + + vout_fs_reg &= TPS55287_REG_VOUT_FS_INTFB_MASK; + + ret = linear_range_get_win_index(&core_ranges[vout_fs_reg], min_uv, max_uv, &idx); + + /* If we couldn't find a matching voltage in the current range, check the other ranges */ + if (ret < 0) { + vout_fs_reg = ARRAY_SIZE(core_ranges); + /* We start with the highest voltage range and work our way down */ + do { + vout_fs_reg--; + + ret = linear_range_get_win_index(&core_ranges[vout_fs_reg], min_uv, max_uv, + &idx); + } while ((ret < 0) && (vout_fs_reg > 0U)); + + if (ret < 0) { + return ret; + } + + ret = i2c_reg_write_byte_dt(&config->i2c, TPS55287_REG_VOUT_FS, vout_fs_reg); + if (ret < 0) { + return ret; + } + } + + LOG_DBG("%s: Setting voltage to range %u, index %u", dev->name, vout_fs_reg, idx); + + buf[0] = TPS55287_REG_REF; + + sys_put_be16(idx, &buf[1]); + + return i2c_write_dt(&config->i2c, buf, sizeof(buf)); +} + +static int regulator_tps55287_get_voltage(const struct device *dev, int32_t *volt_uv) +{ + const struct regulator_tps55287_config *config = dev->config; + uint8_t vout_fs_reg = 0; + uint8_t buf[2] = {0}; + uint16_t idx; + int ret; + + ret = i2c_reg_read_byte_dt(&config->i2c, TPS55287_REG_VOUT_FS, &vout_fs_reg); + if (ret < 0) { + return ret; + } + + ret = i2c_burst_read_dt(&config->i2c, TPS55287_REG_REF, buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + + vout_fs_reg &= TPS55287_REG_VOUT_FS_INTFB_MASK; + idx = sys_get_be16(buf); + + ret = linear_range_get_value(&core_ranges[vout_fs_reg], idx, volt_uv); + + LOG_DBG("%s: Got voltage: %d uV (range %u, index %u)", dev->name, *volt_uv, vout_fs_reg, + idx); + + return ret; +} + +static int regulator_tps55287_enable(const struct device *dev) +{ + const struct regulator_tps55287_config *config = dev->config; + + return i2c_reg_update_byte_dt(&config->i2c, TPS55287_REG_MODE, TPS55287_REG_MODE_OE, + TPS55287_REG_MODE_OE); +} + +static int regulator_tps55287_disable(const struct device *dev) +{ + const struct regulator_tps55287_config *config = dev->config; + + return i2c_reg_update_byte_dt(&config->i2c, TPS55287_REG_MODE, TPS55287_REG_MODE_OE, 0); +} + +static int regulator_tps55287_init(const struct device *dev) +{ + int ret; + + regulator_common_data_init(dev); + + ret = regulator_common_init(dev, false); + if (ret < 0) { + LOG_ERR("%s: Failed to initialize regulator: %d", dev->name, ret); + } + return ret; +} + +static DEVICE_API(regulator, api) = { + .enable = regulator_tps55287_enable, + .disable = regulator_tps55287_disable, + .count_voltages = regulator_tps55287_count_voltages, + .list_voltage = regulator_tps55287_list_voltage, + .set_voltage = regulator_tps55287_set_voltage, + .get_voltage = regulator_tps55287_get_voltage, +}; + +#define REGULATOR_TPS55287_DEFINE_ALL(inst) \ + static struct regulator_tps55287_data data_##inst; \ + \ + static const struct regulator_tps55287_config config_##inst = { \ + .common = REGULATOR_DT_INST_COMMON_CONFIG_INIT(inst), \ + .i2c = I2C_DT_SPEC_INST_GET(inst), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(inst, regulator_tps55287_init, NULL, &data_##inst, &config_##inst, \ + POST_KERNEL, CONFIG_REGULATOR_TPS55287_INIT_PRIORITY, &api); + +DT_INST_FOREACH_STATUS_OKAY(REGULATOR_TPS55287_DEFINE_ALL) diff --git a/dts/bindings/regulator/ti,tps55287.yaml b/dts/bindings/regulator/ti,tps55287.yaml new file mode 100644 index 0000000000000..962014d19679c --- /dev/null +++ b/dts/bindings/regulator/ti,tps55287.yaml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright The Zephyr Project Contributors +# SPDX-License-Identifier: Apache-2.0 + +description: | + TPS55287 core supply regulator + +compatible: "ti,tps55287" + +include: + - name: i2c-device.yaml + - name: regulator.yaml diff --git a/tests/drivers/build_all/regulator/i2c.dtsi b/tests/drivers/build_all/regulator/i2c.dtsi index e9c75ac0a1300..befb27c27255d 100644 --- a/tests/drivers/build_all/regulator/i2c.dtsi +++ b/tests/drivers/build_all/regulator/i2c.dtsi @@ -13,8 +13,11 @@ pca9420@0 { reg = <0x0>; BUCK1 {}; + BUCK2 {}; + LDO1 {}; + LDO2 {}; }; @@ -26,10 +29,15 @@ npm6001@1 { compatible = "nordic,npm6001-regulator"; BUCK0 {}; + BUCK1 {}; + BUCK2 {}; + BUCK3 {}; + LDO0 {}; + LDO1 {}; }; }; @@ -42,8 +50,11 @@ npm1300@2 { compatible = "nordic,npm1300-regulator"; BUCK1 {}; + BUCK2 {}; + LDO1 {}; + LDO2 {}; }; }; @@ -56,6 +67,7 @@ apd356x@3 { compatible = "adi,adp5360-regulator"; BUCK {}; + BUCKBOOST {}; }; }; @@ -68,11 +80,17 @@ axp192@4 { compatible = "x-powers,axp192-regulator"; DCDC1 {}; + DCDC2 {}; + DCDC3 {}; + LDOIO0 {}; + LDO1 {}; + LDO2 {}; + LDO3 {}; }; }; @@ -85,18 +103,31 @@ axp2101@7 { compatible = "x-powers,axp2101-regulator"; DCDC1 {}; + DCDC2 {}; + DCDC3 {}; + DCDC4 {}; + DCDC5 {}; + ALDO1 {}; + ALDO2 {}; + ALDO3 {}; + ALDO4 {}; + BLDO1 {}; + BLDO2 {}; + CPUSLDO {}; + DLDO1 {}; + DLDO2 {}; }; }; @@ -109,9 +140,13 @@ max20335@5 { compatible = "maxim,max20335-regulator"; BUCK1 {}; + BUCK2 {}; + LDO1 {}; + LDO2 {}; + LDO3 {}; }; }; @@ -128,8 +163,11 @@ mpm54304@7 { reg = <0x7>; BUCK1 {}; + BUCK2 {}; + BUCK3 {}; + BUCK4 {}; }; @@ -141,6 +179,7 @@ npm2100@8 { compatible = "nordic,npm2100-regulator"; BOOST {}; + LDOSW {}; }; }; @@ -153,8 +192,16 @@ npm1304@9 { compatible = "nordic,npm1304-regulator"; BUCK1 {}; + BUCK2 {}; + LDO1 {}; + LDO2 {}; }; }; + +tps55287@a { + compatible = "ti,tps55287"; + reg = <0xa>; +};