The PFUZE100/200/3000 family of PMICs allow switching regulators (specifically
SW2, SW3A/B, SW4 on PFUZE100/200 and SW2 on PFUZE3000) to operate in a
"high" voltage range mode. This mode is indicated by a specific bit in the
voltage selection register (bit 3 for PFUZE3000, bit 6 for others).

When this bit is set:
- PFUZE100/200 switches from a 25mV step to a 50mV step, with a different
  minimum voltage (800mV).
- PFUZE3000 SW2 switches to a completely different non-linear voltage table.

Currently, the driver uses static descriptors that assume the low/default
range. This results in incorrect voltage readings and settings if the
PMIC is configured for the high range.

This patch updates the driver to:
1. Identify regulators with high-bit support via a new `hi_bit` flag.
2. Read the register during probe to detect the current range configuration.
3. Dynamically update the regulator descriptor (step, mask, min_uV, or table)
   to match the active range.

This aligns the U-Boot driver behavior with the Linux kernel implementation.

Signed-off-by: Michael Trimarchi <[email protected]>
---
V1->V2:
        drop change of uv_mask, it's already fixed for bit 6 and anyway
        0x7 was invalid

---
 drivers/power/regulator/pfuze100.c | 65 +++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 18 deletions(-)

diff --git a/drivers/power/regulator/pfuze100.c 
b/drivers/power/regulator/pfuze100.c
index f864b1d8834..2242bf68f39 100644
--- a/drivers/power/regulator/pfuze100.c
+++ b/drivers/power/regulator/pfuze100.c
@@ -18,6 +18,7 @@
  *
  * @name: Identify name for the regulator.
  * @type: Indicates the regulator type.
+ * @hi_bit: Indicate if support hi voltage range.
  * @uV_step: Voltage increase for each selector.
  * @vsel_reg: Register for adjust regulator voltage for normal.
  * @vsel_mask: Mask bit for setting regulator voltage for normal.
@@ -29,6 +30,7 @@
 struct pfuze100_regulator_desc {
        char *name;
        enum regulator_type type;
+       bool hi_bit;
        unsigned int uV_step;
        unsigned int vsel_reg;
        unsigned int vsel_mask;
@@ -54,10 +56,11 @@ struct pfuze100_regulator_plat {
                .voltage        =       (vol),                          \
        }
 
-#define PFUZE100_SW_REG(_name, base, step)                             \
+#define PFUZE100_SW_REG(_name, base, step, hbit)                       \
        {                                                               \
                .name           =       #_name,                         \
                .type           =       REGULATOR_TYPE_BUCK,            \
+               .hi_bit         =       (hbit),                         \
                .uV_step        =       (step),                         \
                .vsel_reg       =       (base) + PFUZE100_VOL_OFFSET,   \
                .vsel_mask      =       0x3F,                           \
@@ -65,10 +68,11 @@ struct pfuze100_regulator_plat {
                .stby_mask      =       0x3F,                           \
        }
 
-#define PFUZE100_SWB_REG(_name, base, mask, step, voltages)            \
+#define PFUZE100_SWB_REG(_name, base, mask, step, voltages, hbit)      \
        {                                                               \
                .name           =       #_name,                         \
                .type           =       REGULATOR_TYPE_BUCK,            \
+               .hi_bit         =       (hbit),                         \
                .uV_step        =       (step),                         \
                .vsel_reg       =       (base),                         \
                .vsel_mask      =       (mask),                         \
@@ -155,15 +159,19 @@ static unsigned int pfuze3000_sw2lo[] = {
        1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000
 };
 
+static unsigned int pfuze3000_sw2hi[] = {
+       2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000,
+};
+
 /* PFUZE100 */
 static struct pfuze100_regulator_desc pfuze100_regulators[] = {
-       PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000),
-       PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000),
-       PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000),
-       PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000),
-       PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000),
-       PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000),
-       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+       PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, false),
+       PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, false),
+       PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, true),
+       PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, true),
+       PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, true),
+       PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, true),
+       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst, 
false),
        PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
        PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
        PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000),
@@ -176,11 +184,11 @@ static struct pfuze100_regulator_desc 
pfuze100_regulators[] = {
 
 /* PFUZE200 */
 static struct pfuze100_regulator_desc pfuze200_regulators[] = {
-       PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000),
-       PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000),
-       PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000),
-       PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000),
-       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+       PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, false),
+       PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, true),
+       PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, true),
+       PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, true),
+       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst, 
false),
        PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
        PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
        PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000),
@@ -195,9 +203,9 @@ static struct pfuze100_regulator_desc pfuze200_regulators[] 
= {
 static struct pfuze100_regulator_desc pfuze3000_regulators[] = {
        PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000),
        PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000),
-       PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo),
+       PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo, 
true),
        PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000),
-       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst),
+       PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst, 
false),
        PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze3000_vsnvs),
        PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000),
        PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000),
@@ -246,9 +254,10 @@ static int pfuze100_regulator_probe(struct udevice *dev)
        struct dm_regulator_uclass_plat *uc_pdata;
        struct pfuze100_regulator_plat *plat = dev_get_plat(dev);
        struct pfuze100_regulator_desc *desc;
-       int i, size;
+       int i, size, val, sw_hi = 0x40;
+       int version = dev_get_driver_data(dev_get_parent(dev));
 
-       switch (dev_get_driver_data(dev_get_parent(dev))) {
+       switch (version) {
        case PFUZE100:
                desc = pfuze100_regulators;
                size = ARRAY_SIZE(pfuze100_regulators);
@@ -260,6 +269,7 @@ static int pfuze100_regulator_probe(struct udevice *dev)
        case PFUZE3000:
                desc = pfuze3000_regulators;
                size = ARRAY_SIZE(pfuze3000_regulators);
+               sw_hi = 1 << 3;
                break;
        default:
                debug("Unsupported PFUZE\n");
@@ -281,6 +291,25 @@ static int pfuze100_regulator_probe(struct udevice *dev)
        uc_pdata = dev_get_uclass_plat(dev);
 
        uc_pdata->type = desc[i].type;
+
+       /* SW2~SW4 high bit check and modify the voltage value table */
+       if (desc[i].hi_bit) {
+               val = pmic_reg_read(dev->parent, desc[i].vsel_reg);
+               if (val < 0) {
+                       printf("Fails to read from the register.\n");
+                       return -EIO;
+               }
+
+               if (val & sw_hi) {
+                       if (version == PFUZE3000) {
+                               desc[i].volt_table = pfuze3000_sw2hi;
+                       } else {
+                               desc[i].uV_step = 50000;
+                               uc_pdata->min_uV = 800000;
+                       }
+               }
+       }
+
        if (uc_pdata->type == REGULATOR_TYPE_BUCK) {
                if (!strcmp(dev->name, "swbst")) {
                        uc_pdata->mode = pfuze_swbst_modes;
-- 
2.51.0

Reply via email to