
Fixes: 065a452ae6a power: regulator: tps65941: add regulator support
LDO voltage conversion was incorrect. This was checked by writing and reading back value.
Signed-off-by: Jerome Neanne jneanne@baylibre.com --- drivers/power/regulator/tps65941_regulator.c | 71 +++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-)
diff --git a/drivers/power/regulator/tps65941_regulator.c b/drivers/power/regulator/tps65941_regulator.c index b041126775..7afd68c5c4 100644 --- a/drivers/power/regulator/tps65941_regulator.c +++ b/drivers/power/regulator/tps65941_regulator.c @@ -212,12 +212,55 @@ static int tps65941_ldo_enable(struct udevice *dev, int op, bool *enable) return 0; }
-static int tps65941_ldo_val2volt(int val) +static int tps65941_ldo_volt2val(int idx, int uV) { - if (val > TPS65941_LDO_VOLT_MAX_HEX || val < TPS65941_LDO_VOLT_MIN_HEX) + int base = TPS65941_LDO123_VOLT_MIN; + int max = TPS65941_LDO_VOLT_MAX; + int offset = TPS65941_LDO123_VSET_MIN; + int step = TPS65941_LDO123_STEP; + + if (idx > 2) { + base = TPS65941_LDO4_VOLT_MIN; + offset = TPS65941_LDO4_VSET_MIN; + step = TPS65941_LDO4_STEP; + } + + if (uV > max) return -EINVAL; - else if (val >= TPS65941_LDO_VOLT_MIN_HEX) - return 600000 + (val - TPS65941_LDO_VOLT_MIN_HEX) * 50000; + else if (uV >= base) + return (uV - base) / step + offset; + else + return -EINVAL; +} + +static int tps65941_ldo_val2volt(int idx, int val) +{ + int reg_base = TPS65941_LDO123_VSET_MIN; + int reg_max = TPS65941_LDO123_VSET_MAX; + int base = TPS65941_LDO123_VOLT_MIN; + int max = TPS65941_LDO_VOLT_MAX; + int step = TPS65941_LDO123_STEP; + int mask = TPS65941_LDO_VOLT_MASK >> 1; + + if (idx > 2) { + base = TPS65941_LDO4_VOLT_MIN; + max = TPS65941_LDO_VOLT_MAX; + reg_base = TPS65941_LDO4_VSET_MIN; + reg_max = TPS65941_LDO4_VSET_MAX; + step = TPS65941_LDO4_STEP; + mask = TPS65941_LDO_VOLT_MASK; + } else { + val = val >> 1; + } + + if (val > mask || val < 0) + return -EINVAL; + else if (val >= reg_max) + return max; + else if (val <= reg_base) + return base; + else if (val >= 0) + return base + (step * (val - reg_base)); else return -EINVAL; } @@ -227,7 +270,9 @@ static int tps65941_ldo_val(struct udevice *dev, int op, int *uV) unsigned int hex, adr; int ret; struct dm_regulator_uclass_plat *uc_pdata; + int idx;
+ idx = dev->driver_data - 1; uc_pdata = dev_get_uclass_plat(dev);
if (op == PMIC_OP_GET) @@ -240,7 +285,8 @@ static int tps65941_ldo_val(struct udevice *dev, int op, int *uV) return ret;
ret &= TPS65941_LDO_VOLT_MASK; - ret = tps65941_ldo_val2volt(ret); + ret = tps65941_ldo_val2volt(idx, ret); + if (ret < 0) return ret;
@@ -249,12 +295,21 @@ static int tps65941_ldo_val(struct udevice *dev, int op, int *uV) return 0; }
- hex = tps65941_buck_volt2val(*uV); + /* LDO1, LDO2 & LDO3 in BYPASS mode only supports 1.7V min to 3.6V max */ + if (idx < 2 && + (ret & BIT(TPS65941_LDO123_BYP_CONFIG)) && + *uV < TPS65941_LDO123_VOLT_BYP_MIN) + return -EINVAL; + + hex = tps65941_ldo_volt2val(idx, *uV); if (hex < 0) return hex;
- ret &= 0x0; - ret = hex; + if (idx < 2) + hex = hex << 1; + + ret &= ~TPS65941_LDO_VOLT_MASK; + ret |= hex;
ret = pmic_reg_write(dev->parent, adr, ret);