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

