[RFC] power: regulator: pfuze100: support high voltage range bit

Message ID 20260111000251.1278257-1-michael@amarulasolutions.com
State New
Headers show
Series
  • [RFC] power: regulator: pfuze100: support high voltage range bit
Related show

Commit Message

Michael Nazzareno Trimarchi Jan. 11, 2026, 12:02 a.m. UTC
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 <michael@amarulasolutions.com>
---

Note I need to retest it on the board but it's just a propose change

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

Patch

diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c
index f864b1d8834..63d39c21bb8 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,26 @@  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;
+				desc[i].vsel_mask = 0x7;
+				uc_pdata->min_uV = 800000;
+			}
+		}
+	}
+
 	if (uc_pdata->type == REGULATOR_TYPE_BUCK) {
 		if (!strcmp(dev->name, "swbst")) {
 			uc_pdata->mode = pfuze_swbst_modes;