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 <jnea...@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);
 
-- 
2.25.1

Reply via email to