diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/regulator/Kconfig | 18 | ||||
-rw-r--r-- | drivers/power/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/regulator/fixed.c | 21 | ||||
-rw-r--r-- | drivers/power/regulator/qcom-rpmh-regulator.c | 136 | ||||
-rw-r--r-- | drivers/power/regulator/tps6287x_regulator.c | 172 |
5 files changed, 344 insertions, 4 deletions
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index bc061c20d75..958f337c7e7 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -383,6 +383,15 @@ config DM_REGULATOR_TPS80031 features for TPS80031/TPS80032 PMICs. The driver implements get/set api for: value and enable. +config DM_REGULATOR_TPS6287X + bool "Enable driver for TPS6287x Power Regulator" + depends on DM_REGULATOR + help + The TPS6287X is a step down converter with a fast transient + response. This driver supports all four variants of the chip + (TPS62870, TPS62871, TPS62872, TPS62873). It implements the + get/set api for value only, as the power line is always on. + config DM_REGULATOR_STPMIC1 bool "Enable driver for STPMIC1 regulators" depends on DM_REGULATOR && PMIC_STPMIC1 @@ -402,6 +411,15 @@ config DM_REGULATOR_ANATOP regulators. It is recommended that this option be enabled on i.MX6 platform. +config SPL_DM_REGULATOR_TPS6287X + bool "Enable driver for TPS6287x Power Regulator" + depends on SPL_DM_REGULATOR + help + The TPS6287X is a step down converter with a fast transient + response. This driver supports all four variants of the chip + (TPS62870, TPS62871, TPS62872, TPS62873). It implements the + get/set api for value only, as the power line is always on. + config SPL_DM_REGULATOR_STPMIC1 bool "Enable driver for STPMIC1 regulators in SPL" depends on SPL_DM_REGULATOR && PMIC_STPMIC1 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 56a527612b7..54db0885657 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS65911) += tps65911_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS6287X) += tps6287x_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_TPS80031) += tps80031_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index 98c89bf2aff..996da41546a 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -17,7 +17,7 @@ #include "regulator_common.h" -struct fixed_clock_regulator_plat { +struct fixed_clock_regulator_priv { struct clk *enable_clock; unsigned int clk_enable_counter; }; @@ -83,14 +83,14 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable) static int fixed_clock_regulator_get_enable(struct udevice *dev) { - struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); + struct fixed_clock_regulator_priv *priv = dev_get_priv(dev); return priv->clk_enable_counter > 0; } static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) { - struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); + struct fixed_clock_regulator_priv *priv = dev_get_priv(dev); struct regulator_common_plat *plat = dev_get_plat(dev); int ret = 0; @@ -113,6 +113,17 @@ static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) return ret; } +static int fixed_clock_regulator_probe(struct udevice *dev) +{ + struct fixed_clock_regulator_priv *priv = dev_get_priv(dev); + + priv->enable_clock = devm_clk_get(dev, NULL); + if (IS_ERR(priv->enable_clock)) + return PTR_ERR(priv->enable_clock); + + return 0; +} + static const struct dm_regulator_ops fixed_regulator_ops = { .get_value = fixed_regulator_get_value, .get_current = fixed_regulator_get_current, @@ -149,6 +160,8 @@ U_BOOT_DRIVER(regulator_fixed_clock) = { .id = UCLASS_REGULATOR, .ops = &fixed_clock_regulator_ops, .of_match = fixed_clock_regulator_ids, + .probe = fixed_clock_regulator_probe, .of_to_plat = fixed_regulator_of_to_plat, - .plat_auto = sizeof(struct fixed_clock_regulator_plat), + .plat_auto = sizeof(struct regulator_common_plat), + .priv_auto = sizeof(struct fixed_clock_regulator_priv), }; diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 06fd3f31956..2dc261d83e3 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -357,6 +357,69 @@ static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = { .get_mode = rpmh_regulator_vrm_get_mode, }; +static struct dm_regulator_mode pmic_mode_map_pmic5_bob[] = { + { + .id = REGULATOR_MODE_LPM, + .register_value = PMIC5_BOB_MODE_PFM, + .name = "PMIC5_BOB_MODE_PFM" + }, { + .id = REGULATOR_MODE_AUTO, + .register_value = PMIC5_BOB_MODE_AUTO, + .name = "PMIC5_BOB_MODE_AUTO" + }, { + .id = REGULATOR_MODE_HPM, + .register_value = PMIC5_BOB_MODE_PWM, + .name = "PMIC5_BOB_MODE_PWM" + }, +}; + +static struct dm_regulator_mode pmic_mode_map_pmic5_smps[] = { + { + .id = REGULATOR_MODE_RETENTION, + .register_value = PMIC5_SMPS_MODE_RETENTION, + .name = "PMIC5_SMPS_MODE_RETENTION" + }, { + .id = REGULATOR_MODE_LPM, + .register_value = PMIC5_SMPS_MODE_PFM, + .name = "PMIC5_SMPS_MODE_PFM" + }, { + .id = REGULATOR_MODE_AUTO, + .register_value = PMIC5_SMPS_MODE_AUTO, + .name = "PMIC5_SMPS_MODE_AUTO" + }, { + .id = REGULATOR_MODE_HPM, + .register_value = PMIC5_SMPS_MODE_PWM, + .name = "PMIC5_SMPS_MODE_PWM" + }, +}; + +static const struct rpmh_vreg_hw_data pmic5_bob = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000), + .n_voltages = 32, + .pmic_mode_map = pmic_mode_map_pmic5_bob, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_bob), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000), + .n_voltages = 268, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000), + .n_voltages = 268, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_smps), +}; + static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = { { .id = REGULATOR_MODE_RETENTION, @@ -393,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), }; +static const struct rpmh_vreg_hw_data pmic5_nldo515 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000), + .n_voltages = 211, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + #define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ { \ .name = _name, \ @@ -412,6 +485,57 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8550_vreg_data[] = { + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"), + RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"), + RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"), + {} +}; + +static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + {} +}; + +static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"), + {} +}; + /* probe an individual regulator */ static int rpmh_regulator_probe(struct udevice *dev) { @@ -526,6 +650,18 @@ static const struct udevice_id rpmh_regulator_ids[] = { .compatible = "qcom,pm8150l-rpmh-regulators", .data = (ulong)pm8150l_vreg_data, }, + { + .compatible = "qcom,pm8550-rpmh-regulators", + .data = (ulong)pm8550_vreg_data, + }, + { + .compatible = "qcom,pm8550ve-rpmh-regulators", + .data = (ulong)pm8550ve_vreg_data, + }, + { + .compatible = "qcom,pm8550vs-rpmh-regulators", + .data = (ulong)pm8550vs_vreg_data, + }, { /* sentinal */ }, }; diff --git a/drivers/power/regulator/tps6287x_regulator.c b/drivers/power/regulator/tps6287x_regulator.c new file mode 100644 index 00000000000..6d185719199 --- /dev/null +++ b/drivers/power/regulator/tps6287x_regulator.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + * Keerthy <j-keerthy@ti.com> + */ + +#include <dm.h> +#include <i2c.h> +#include <dm/device_compat.h> +#include <power/regulator.h> + +#define TPS6287X_REG_VSET 0x0 +#define TPS6287X_REG_CONTROL1 0x1 +#define TPS6287X_REG_CONTROL2 0x2 +#define TPS6287X_REG_CONTROL3 0x3 +#define TPS6287X_REG_STATUS 0x4 +#define TPS6287X_REG_VSET_VSET_MASK 0xff +#define TPS6287X_REG_CONTROL2_VRANGE_MASK 0xc + +struct tps6287x_regulator_config { + u32 vmin; + u32 vmax; +}; + +struct tps6287x_regulator_pdata { + u8 vsel_offset; + struct udevice *i2c; + struct tps6287x_regulator_config *config; +}; + +static struct tps6287x_regulator_config tps6287x_data = { + .vmin = 400000, + .vmax = 3350000, +}; + +static int tps6287x_regulator_set_value(struct udevice *dev, int uV) +{ + struct tps6287x_regulator_pdata *pdata = dev_get_plat(dev); + u8 regval, vset; + int ret; + + if (uV < pdata->config->vmin || uV > pdata->config->vmax) + return -EINVAL; + /* + * Based on the value of VRANGE bit field of CONTROL2 reg the range + * varies. + */ + ret = dm_i2c_read(pdata->i2c, TPS6287X_REG_CONTROL2, ®val, 1); + if (ret) { + dev_err(dev, "CTRL2 reg read failed: %d\n", ret); + return ret; + } + + regval &= TPS6287X_REG_CONTROL2_VRANGE_MASK; + regval >>= ffs(TPS6287X_REG_CONTROL2_VRANGE_MASK) - 1; + + /* + * VRANGE = 0. Increment step 1250 uV starting with 0 --> 400000 uV + * VRANGE = 1. Increment step 2500 uV starting with 0 --> 400000 uV + * VRANGE = 2. Increment step 5000 uV starting with 0 --> 400000 uV + * VRANGE = 3. Increment step 10000 uV starting with 0 --> 800000 uV + */ + switch (regval) { + case 0: + vset = (uV - 400000) / 1250; + break; + case 1: + vset = (uV - 400000) / 2500; + break; + case 2: + vset = (uV - 400000) / 5000; + break; + case 3: + vset = (uV - 800000) / 10000; + break; + default: + pr_err("%s: invalid regval %d\n", dev->name, regval); + return -EINVAL; + } + + return dm_i2c_write(pdata->i2c, TPS6287X_REG_VSET, &vset, 1); +} + +static int tps6287x_regulator_get_value(struct udevice *dev) +{ + u8 regval, vset; + int uV; + int ret; + struct tps6287x_regulator_pdata *pdata = dev_get_plat(dev); + + /* + * Based on the value of VRANGE bit field of CONTROL2 reg the range + * varies. + */ + ret = dm_i2c_read(pdata->i2c, TPS6287X_REG_CONTROL2, ®val, 1); + if (ret) { + dev_err(dev, "i2c read failed: %d\n", ret); + return ret; + } + + regval &= TPS6287X_REG_CONTROL2_VRANGE_MASK; + regval >>= ffs(TPS6287X_REG_CONTROL2_VRANGE_MASK) - 1; + + ret = dm_i2c_read(pdata->i2c, TPS6287X_REG_VSET, &vset, 1); + if (ret) { + dev_err(dev, "i2c VSET read failed: %d\n", ret); + return ret; + } + + /* + * VRANGE = 0. Increment step 1250 uV starting with 0 --> 400000 uV + * VRANGE = 1. Increment step 2500 uV starting with 0 --> 400000 uV + * VRANGE = 2. Increment step 5000 uV starting with 0 --> 400000 uV + * VRANGE = 3. Increment step 10000 uV starting with 0 --> 800000 uV + */ + switch (regval) { + case 0: + uV = 400000 + vset * 1250; + break; + case 1: + uV = 400000 + vset * 2500; + break; + case 2: + uV = 400000 + vset * 5000; + break; + case 3: + uV = 800000 + vset * 10000; + break; + default: + pr_err("%s: invalid regval %d\n", dev->name, regval); + return -EINVAL; + } + + return uV; +} + +static int tps6287x_regulator_probe(struct udevice *dev) +{ + struct tps6287x_regulator_pdata *pdata = dev_get_plat(dev); + int ret, slave_id; + + pdata->config = (void *)dev_get_driver_data(dev); + + slave_id = devfdt_get_addr_index(dev, 0); + + ret = i2c_get_chip(dev->parent, slave_id, 1, &pdata->i2c); + if (ret) { + dev_err(dev, "i2c dev get failed.\n"); + return ret; + } + + return 0; +} + +static const struct dm_regulator_ops tps6287x_regulator_ops = { + .get_value = tps6287x_regulator_get_value, + .set_value = tps6287x_regulator_set_value, +}; + +static const struct udevice_id tps6287x_regulator_ids[] = { + { .compatible = "ti,tps62873", .data = (ulong)&tps6287x_data }, + { }, +}; + +U_BOOT_DRIVER(tps6287x_regulator) = { + .name = "tps6287x_regulator", + .id = UCLASS_REGULATOR, + .ops = &tps6287x_regulator_ops, + .of_match = tps6287x_regulator_ids, + .plat_auto = sizeof(struct tps6287x_regulator_pdata), + .probe = tps6287x_regulator_probe, +}; |