From 1526438a9305f98cdf6e40e5b73d8dd517c45636 Mon Sep 17 00:00:00 2001 From: Neha Malcom Francis Date: Tue, 21 Apr 2026 13:51:45 +0530 Subject: [PATCH 1/6] power: regulator: tps65941: Enable FPWM bits Depending on the phase selection (single or multi), the FPWM bits configured forces the regulator to operate in PWM mode. In case of multi-phase selection, the FPWM_MP bits enforce the regulator to also operate in multi-phase. This fixes correct multi-phase operation. While at this, correct incorrect macro alignment as well. Fixes: 065a452ae6a1 ("power: regulator: tps65941: add regulator support") Link: https://www.ti.com/lit/ds/symlink/tps6594-q1.pdf Signed-off-by: Keerthy Signed-off-by: Takuma Fujiwara Signed-off-by: Neha Malcom Francis Reviewed-by: Udit Kumar Signed-off-by: Peng Fan --- drivers/power/regulator/tps65941_regulator.c | 15 ++++++++++++--- include/power/tps65941.h | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/power/regulator/tps65941_regulator.c b/drivers/power/regulator/tps65941_regulator.c index 2561d6f4c6c..209968b5718 100644 --- a/drivers/power/regulator/tps65941_regulator.c +++ b/drivers/power/regulator/tps65941_regulator.c @@ -63,13 +63,14 @@ static inline int tps65941_get_chip_id(struct udevice *dev) static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable) { - int ret; + int ret, idx; unsigned int adr; struct dm_regulator_uclass_plat *uc_pdata; uc_pdata = dev_get_uclass_plat(dev); adr = uc_pdata->ctrl_reg; + idx = dev->driver_data; ret = pmic_reg_read(dev->parent, adr); if (ret < 0) return ret; @@ -84,10 +85,18 @@ static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable) return 0; } else if (op == PMIC_OP_SET) { - if (*enable) + if (*enable) { ret |= TPS65941_BUCK_MODE_MASK; - else + /* Enable FPWM */ + ret |= TPS65941_BUCK_FPWM_MASK; + /* If Multiphase enable FPWM_MP */ + if (idx == TPS65941_BUCK_ID_12 || + idx == TPS65941_BUCK_ID_123 || + idx == TPS65941_BUCK_ID_1234) + ret |= TPS65941_BUCK_FPWM_MP_MASK; + } else { ret &= ~TPS65941_BUCK_MODE_MASK; + } ret = pmic_reg_write(dev->parent, adr, ret); if (ret) return ret; diff --git a/include/power/tps65941.h b/include/power/tps65941.h index a026ec56958..78e48a15972 100644 --- a/include/power/tps65941.h +++ b/include/power/tps65941.h @@ -19,7 +19,9 @@ #define TPS65941_BUCK_VOLT_MASK 0xFF #define TPS65941_BUCK_VOLT_MAX_HEX 0xFF #define TPS65941_BUCK_VOLT_MAX 3340000 -#define TPS65941_BUCK_MODE_MASK 0x1 +#define TPS65941_BUCK_MODE_MASK 0x1 +#define TPS65941_BUCK_FPWM_MASK 0x2 +#define TPS65941_BUCK_FPWM_MP_MASK 0x4 #define TPS65941_LDO_VOLT_MASK 0x7E #define TPS65941_LDO_VOLT_MAX_HEX 0x3A From 356b7598cd35833fdf5890b4fbabc76e4af17f95 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 18 Apr 2026 20:37:32 +0800 Subject: [PATCH 2/6] power: regulator: pfuze100: Fix min_uV usage regulator-min-microvolt in device tree is not always match the minimal voltage in the pmic datasheet, direclty using the min value from device tree as base may cause wrong voltage settings being written. Directly use the min_uV from datasheet to avoid wrong settings. Signed-off-by: Peng Fan --- drivers/power/regulator/pfuze100.c | 87 ++++++++++++++++-------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index f864b1d8834..f055c610ad1 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -19,6 +19,7 @@ * @name: Identify name for the regulator. * @type: Indicates the regulator type. * @uV_step: Voltage increase for each selector. + * @min_uV: Indicates the minimal voltage supported. * @vsel_reg: Register for adjust regulator voltage for normal. * @vsel_mask: Mask bit for setting regulator voltage for normal. * @stby_reg: Register for adjust regulator voltage for standby. @@ -30,6 +31,7 @@ struct pfuze100_regulator_desc { char *name; enum regulator_type type; unsigned int uV_step; + unsigned int min_uV; unsigned int vsel_reg; unsigned int vsel_mask; unsigned int stby_reg; @@ -54,11 +56,12 @@ struct pfuze100_regulator_plat { .voltage = (vol), \ } -#define PFUZE100_SW_REG(_name, base, step) \ +#define PFUZE100_SW_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3F, \ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ @@ -84,32 +87,35 @@ struct pfuze100_regulator_plat { .volt_table = (voltages), \ } -#define PFUZE100_VGEN_REG(_name, base, step) \ +#define PFUZE100_VGEN_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_LDO, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base), \ .vsel_mask = 0xF, \ .stby_reg = (base), \ .stby_mask = 0x20, \ } -#define PFUZE3000_VCC_REG(_name, base, step) \ +#define PFUZE3000_VCC_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_LDO, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base), \ .vsel_mask = 0x3, \ .stby_reg = (base), \ .stby_mask = 0x20, \ } -#define PFUZE3000_SW1_REG(_name, base, step) \ +#define PFUZE3000_SW1_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ + .min_uV = (min), \ .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x1F, \ @@ -128,11 +134,12 @@ struct pfuze100_regulator_plat { .stby_mask = 0x7, \ } -#define PFUZE3000_SW3_REG(_name, base, step) \ +#define PFUZE3000_SW3_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0xF, \ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ @@ -157,55 +164,55 @@ static unsigned int pfuze3000_sw2lo[] = { /* 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_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000), + PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, 300000), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000), + PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, 400000), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), - PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), - PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), - PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), - PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000, 1800000), + PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000, 1800000), }; /* 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_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), - PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), - PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), - PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), - PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000, 1800000), }; /* PFUZE3000 */ static struct pfuze100_regulator_desc pfuze3000_regulators[] = { - PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000), - PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000), + PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000, 700000), + PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000, 700000), PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo), - PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000), + PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000, 900000), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze3000_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000), - PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000), - PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000), - PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000), - PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000, 800000), + PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000, 2850000), + PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000, 2850000), + PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000, 1800000), }; #define MODE(_id, _val, _name) { \ @@ -436,7 +443,7 @@ static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable) static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) { int i; - int val; + int val, min_uV; struct pfuze100_regulator_plat *plat = dev_get_plat(dev); struct pfuze100_regulator_desc *desc = plat->desc; struct dm_regulator_uclass_plat *uc_pdata = @@ -461,7 +468,8 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) if (val < 0) return val; val &= desc->vsel_mask; - *uV = uc_pdata->min_uV + (int)val * desc->uV_step; + min_uV = desc->min_uV ?: uc_pdata->min_uV; + *uV = min_uV + (int)val * desc->uV_step; } return 0; @@ -487,9 +495,10 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) debug("Need to provide min_uV in dts.\n"); return -EINVAL; } + min_uV = desc->min_uV ?: uc_pdata->min_uV; return pmic_clrsetbits(dev->parent, desc->vsel_reg, desc->vsel_mask, - (*uV - uc_pdata->min_uV) / desc->uV_step); + (*uV - min_uV) / desc->uV_step); } return 0; From b7b7aa741f9dd37a25cf44f3a2771ec9bfd497dc Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 18 Apr 2026 20:37:33 +0800 Subject: [PATCH 3/6] power: regulator: pfuze100: support high output voltage mode Some PFUZE regulators can operate in either low or high output voltage mode, with different minimum voltages and voltage step sizes selected by a hardware control bit. However, the current PFUZE100 regulator driver assumes low output voltage mode only, resulting in incorrect voltage calculation and programming when high voltage mode is enabled. Extend the regulator descriptor to describe high output voltage mode by adding a mask to detect the mode and a dedicated voltage description (min_uV and step size). Update voltage get/set handling to dynamically select the correct voltage parameters based on the high voltage mode bit. Signed-off-by: Peng Fan --- drivers/power/regulator/pfuze100.c | 62 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index f055c610ad1..ed69e6e14c3 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -13,6 +13,11 @@ #include #include +struct pfuze100_high_volt_desc { + unsigned int uV_step; + unsigned int min_uV; +}; + /** * struct pfuze100_regulator_desc - regulator descriptor * @@ -26,6 +31,8 @@ * @stby_mask: Mask bit for setting regulator voltage for standby. * @volt_table: Voltage mapping table (if table based mapping). * @voltage: Current voltage for REGULATOR_TYPE_FIXED type regulator. + * @high_volt_mask: Low or High Output voltage mode mask + * @high_volt_desc: High Output voltage description */ struct pfuze100_regulator_desc { char *name; @@ -38,6 +45,8 @@ struct pfuze100_regulator_desc { unsigned int stby_mask; unsigned int *volt_table; unsigned int voltage; + unsigned int high_volt_mask; + struct pfuze100_high_volt_desc *high_volt_desc; }; /** @@ -56,7 +65,7 @@ struct pfuze100_regulator_plat { .voltage = (vol), \ } -#define PFUZE100_SW_REG(_name, base, step, min) \ +#define PFUZE100_SW_REG(_name, base, step, min, desc, mask) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ @@ -66,6 +75,8 @@ struct pfuze100_regulator_plat { .vsel_mask = 0x3F, \ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ .stby_mask = 0x3F, \ + .high_volt_desc = (desc), \ + .high_volt_mask = (mask), \ } #define PFUZE100_SWB_REG(_name, base, mask, step, voltages) \ @@ -162,14 +173,19 @@ static unsigned int pfuze3000_sw2lo[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000 }; +static struct pfuze100_high_volt_desc high_desc = { + .min_uV = 800000, + .uV_step = 50000, +}; + /* PFUZE100 */ static struct pfuze100_regulator_desc pfuze100_regulators[] = { - PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000), - PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, 300000), - PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000), - PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000), - PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000), - PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, 400000), + PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), @@ -183,10 +199,10 @@ static struct pfuze100_regulator_desc pfuze100_regulators[] = { /* PFUZE200 */ static struct pfuze100_regulator_desc pfuze200_regulators[] = { - PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000), - PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000), - PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000), - PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000), + PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), @@ -443,7 +459,7 @@ static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable) static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) { int i; - int val, min_uV; + int val, min_uV, uV_step; struct pfuze100_regulator_plat *plat = dev_get_plat(dev); struct pfuze100_regulator_desc *desc = plat->desc; struct dm_regulator_uclass_plat *uc_pdata = @@ -467,9 +483,15 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) val = pmic_reg_read(dev->parent, desc->vsel_reg); if (val < 0) return val; + if (desc->high_volt_mask && (val & desc->high_volt_mask)) { + min_uV = desc->high_volt_desc->min_uV; + uV_step = desc->high_volt_desc->uV_step; + } else { + min_uV = desc->min_uV ?: uc_pdata->min_uV; + uV_step = desc->uV_step; + } val &= desc->vsel_mask; - min_uV = desc->min_uV ?: uc_pdata->min_uV; - *uV = min_uV + (int)val * desc->uV_step; + *uV = min_uV + (int)val * uV_step; } return 0; @@ -495,10 +517,18 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) debug("Need to provide min_uV in dts.\n"); return -EINVAL; } - min_uV = desc->min_uV ?: uc_pdata->min_uV; + val = pmic_reg_read(dev->parent, desc->vsel_reg); + if (desc->high_volt_mask && (val & desc->high_volt_mask)) { + min_uV = desc->high_volt_desc->min_uV; + uV_step = desc->high_volt_desc->uV_step; + } else { + min_uV = desc->min_uV ?: uc_pdata->min_uV; + uV_step = desc->uV_step; + } + return pmic_clrsetbits(dev->parent, desc->vsel_reg, desc->vsel_mask, - (*uV - min_uV) / desc->uV_step); + (*uV - min_uV) / uV_step); } return 0; From e015bc1b8d3d9974494581eec1321e59ffe2b355 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 18 Apr 2026 20:37:34 +0800 Subject: [PATCH 4/6] power: regulator: pfuze100: support non-independent mode Some BUCKs could work in single/dual phase mode, not in independent mode. In single/dual phase mode, registers of both regulators, must be identically set. So configure mode and value for both BUCKs. CONF registers are not touched, leave them as default OTP settings. PFUZE100/200 SW3A/B, could work in single/dual phase mode, so introduce a new macro by adding a pointer to the SW3B descriptor. Signed-off-by: Peng Fan --- drivers/power/regulator/pfuze100.c | 49 +++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index ed69e6e14c3..77c82a00b65 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -33,6 +33,8 @@ struct pfuze100_high_volt_desc { * @voltage: Current voltage for REGULATOR_TYPE_FIXED type regulator. * @high_volt_mask: Low or High Output voltage mode mask * @high_volt_desc: High Output voltage description + * @b: Some regulators could work together to provide one output when working + * in single phase or dual phase mode. */ struct pfuze100_regulator_desc { char *name; @@ -47,6 +49,7 @@ struct pfuze100_regulator_desc { unsigned int voltage; unsigned int high_volt_mask; struct pfuze100_high_volt_desc *high_volt_desc; + struct pfuze100_regulator_desc *b; }; /** @@ -79,6 +82,21 @@ struct pfuze100_regulator_plat { .high_volt_mask = (mask), \ } +#define PFUZE100_SWAB_REG(_name, base, step, min, volt_desc, mask, desc) \ + { \ + .name = #_name, \ + .type = REGULATOR_TYPE_BUCK, \ + .uV_step = (step), \ + .min_uV = (min), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0x3F, \ + .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ + .stby_mask = 0x3F, \ + .high_volt_desc = (volt_desc), \ + .high_volt_mask = (mask), \ + .b = (desc), \ + } + #define PFUZE100_SWB_REG(_name, base, mask, step, voltages) \ { \ .name = #_name, \ @@ -184,6 +202,8 @@ static struct pfuze100_regulator_desc pfuze100_regulators[] = { PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, 300000, NULL, 0), PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SWAB_REG(sw3ab, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6), + &pfuze100_regulators[5]), PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), @@ -202,6 +222,8 @@ static struct pfuze100_regulator_desc pfuze200_regulators[] = { PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000, NULL, 0), PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SWAB_REG(sw3ab, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6), + &pfuze200_regulators[4]), PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), @@ -380,6 +402,16 @@ static int pfuze100_regulator_mode(struct udevice *dev, int op, int *opmode) desc->vsel_reg + PFUZE100_MODE_OFFSET, SW_MODE_MASK, *opmode << SW_MODE_SHIFT); + if (val) + return val; + + if (desc->b) { + desc = desc->b; + val = pmic_clrsetbits(dev->parent, + desc->vsel_reg + PFUZE100_MODE_OFFSET, + SW_MODE_MASK, + *opmode << SW_MODE_SHIFT); + } } else if (desc->type == REGULATOR_TYPE_LDO) { val = pmic_clrsetbits(dev->parent, desc->vsel_reg, @@ -458,7 +490,7 @@ static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable) static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) { - int i; + int i, ret; int val, min_uV, uV_step; struct pfuze100_regulator_plat *plat = dev_get_plat(dev); struct pfuze100_regulator_desc *desc = plat->desc; @@ -526,9 +558,18 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) uV_step = desc->uV_step; } - return pmic_clrsetbits(dev->parent, desc->vsel_reg, - desc->vsel_mask, - (*uV - min_uV) / uV_step); + ret = pmic_clrsetbits(dev->parent, desc->vsel_reg, + desc->vsel_mask, (*uV - min_uV) / uV_step); + if (ret) + return ret; + + if (desc->b) { + desc = desc->b; + ret = pmic_clrsetbits(dev->parent, desc->vsel_reg, + desc->vsel_mask, (*uV - min_uV) / uV_step); + if (ret) + return ret; + } } return 0; From 2a628fee83c1f8d0f260f51b93c342d9a788986a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sat, 18 Apr 2026 20:37:35 +0800 Subject: [PATCH 5/6] power: regulator: Correct Kconfig for PFUZE100 Use CONFIG_$(PHASE_)DM_REGULATOR_PFUZE100 as the build condition for pfuze100 regulator driver. Add Kconfig option for SPL_DM_REGULATOR_PFUZE100. To avoid break current platforms, set the Kconfig default value same as PMIC_PFUZE100. Signed-off-by: Peng Fan --- drivers/power/regulator/Kconfig | 10 ++++++++++ drivers/power/regulator/Makefile | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index a4ee5f1335a..ca5de5b8726 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -126,6 +126,16 @@ config SPL_DM_REGULATOR_DA9063 config DM_REGULATOR_PFUZE100 bool "Enable Driver Model for REGULATOR PFUZE100" depends on DM_REGULATOR && DM_PMIC_PFUZE100 + default DM_PMIC_PFUZE100 + ---help--- + This config enables implementation of driver-model regulator uclass + features for REGULATOR PFUZE100. The driver implements get/set api for: + value, enable and mode. + +config SPL_DM_REGULATOR_PFUZE100 + bool "Enable Driver Model for REGULATOR PFUZE100 in SPL" + depends on SPL_DM_REGULATOR && SPL_DM_PMIC_PFUZE100 + default SPL_DM_PMIC_PFUZE100 ---help--- This config enables implementation of driver-model regulator uclass features for REGULATOR PFUZE100. The driver implements get/set api for: diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 9e303d4f7f8..36a84e7cd71 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_$(PHASE_)DM_REGULATOR_MAX77663) += max77663_regulator.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_MAX8907) += max8907_regulator.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o -obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PFUZE100) += pfuze100.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_BD71837) += bd71837.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PCA9450) += pca9450.o obj-$(CONFIG_$(PHASE_)REGULATOR_PWM) += pwm_regulator.o From f07c15c16a1bbdf8eaa9ad79af774e31948bcba3 Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Thu, 16 Apr 2026 10:41:51 +0530 Subject: [PATCH 6/6] mmc: msm_sdhci: Use max-frequency to get clock rate msm_sdc_clk_init() uses clock-frequency to get the clock rate for SDC clocks. However, the DT files seem to use max-frequency for the same. Since msm_sdc_clk_init() doesn't find clock-frequency in the DT, it sets 201500000 as the clock rate and this results in timeout errors on IPQ platforms. Additionally, clock-frequency is not DT bindings compliant. Hence, get clock rate using DT bindings compliant max-frequency. Signed-off-by: Varadarajan Narayanan Reviewed-by: Sumit Garg Signed-off-by: Peng Fan --- drivers/mmc/msm_sdhci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 66f3cf2de4f..aaa87923604 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -71,8 +71,7 @@ static int msm_sdc_clk_init(struct udevice *dev) var_info = (void *)dev_get_driver_data(dev); - ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate)); - if (ret) + if (ofnode_read_u32(node, "max-frequency", (uint *)(&clk_rate))) clk_rate = 201500000; ret = clk_get_bulk(dev, &prv->clks);