@@ -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;
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(-)