All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Trimarchi <michael@amarulasolutions.com>
To: Peng Fan <peng.fan@nxp.com>, Jaehoon Chung <jh80.chung@samsung.com>
Cc: Tom Rini <trini@konsulko.com>,
	Dario Binacchi <dario.binacchi@amarulasolutions.com>,
	u-boot@lists.denx.de, linux-amarula@amarulasolutions.com,
	Michael Trimarchi <michael@amarulasolutions.com>
Subject: [PATCH V2 1/2] power: regulator: pfuze100: support high voltage range bit
Date: Sun, 11 Jan 2026 09:23:46 +0100	[thread overview]
Message-ID: <20260111082347.1302003-2-michael@amarulasolutions.com> (raw)
In-Reply-To: <20260111082347.1302003-1-michael@amarulasolutions.com>

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>
---
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	other threads:[~2026-01-11  8:24 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-11  8:23 [PATCH V2 0/2] power: regulator: pfuze100: Fix voltage calculation and support high-range Michael Trimarchi
2026-01-11  8:23 ` Michael Trimarchi [this message]
2026-01-11  8:23 ` [PATCH V2 2/2] power: regulator: pfuze100: Decouple hardware base voltage from DTS constraints Michael Trimarchi
2026-01-13  8:58 ` [PATCH V2 0/2] power: regulator: pfuze100: Fix voltage calculation and support high-range Peng Fan
2026-01-13 10:46   ` Michael Nazzareno Trimarchi
2026-01-13 12:16     ` Peng Fan
2026-01-13 18:16       ` Michael Nazzareno Trimarchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260111082347.1302003-2-michael@amarulasolutions.com \
    --to=michael@amarulasolutions.com \
    --cc=dario.binacchi@amarulasolutions.com \
    --cc=jh80.chung@samsung.com \
    --cc=linux-amarula@amarulasolutions.com \
    --cc=peng.fan@nxp.com \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.