regulator_get_value() returns READ_VOUT, the output as measured.

On a regulator with a load line (droop) configured, that sits below the
setpoint under load, so a caller cannot tell from it what
regulator_set_value() last wrote, nor whether the setpoint already
has the value it wants.

Add pmbus_regulator_read_vout_command(): let's read VOUT_COMMAND (21h) and
decode it exactly like READ_VOUT, through the chip's pmbus_driver_info and
VOUT_MODE, without exposing pmbus_regulator_priv.

Signed-off-by: Vincent Jardin <[email protected]>
---

 drivers/power/regulator/pmbus_helper.c | 53 ++++++++++++++++++++------
 include/pmbus.h                        | 14 +++++++
 2 files changed, 56 insertions(+), 11 deletions(-)

diff --git a/drivers/power/regulator/pmbus_helper.c 
b/drivers/power/regulator/pmbus_helper.c
index 1809c6cdfb5..6c76ee91c9c 100644
--- a/drivers/power/regulator/pmbus_helper.c
+++ b/drivers/power/regulator/pmbus_helper.c
@@ -34,12 +34,28 @@ static int pmbus_regulator_select_page(struct 
pmbus_regulator_priv *priv)
        return dm_i2c_write(priv->i2c_dev, PMBUS_PAGE, &p, 1);
 }
 
+static int pmbus_regulator_vout_to_uv(struct pmbus_regulator_priv *priv,
+                                     u16 raw, u8 vout_mode)
+{
+       s64 uv;
+
+       if (priv->info)
+               uv = pmbus_reg2data(priv->info, PSC_VOLTAGE_OUT, raw, 
vout_mode);
+       else
+               uv = pmbus_reg2data_linear16(raw, vout_mode);
+
+       if (uv > INT_MAX)
+               uv = INT_MAX;
+       if (uv < INT_MIN)
+               uv = INT_MIN;
+       return (int)uv;
+}
+
 static int pmbus_regulator_get_value(struct udevice *dev)
 {
        struct pmbus_regulator_priv *priv = dev_get_priv(dev);
        u8 vout_mode = 0;
        u16 raw = 0;
-       s64 uv;
        int ret;
 
        ret = pmbus_regulator_select_page(priv);
@@ -49,16 +65,7 @@ static int pmbus_regulator_get_value(struct udevice *dev)
        if (pmbus_read_word(priv->i2c_dev, PMBUS_READ_VOUT, &raw))
                return -EIO;
 
-       if (priv->info)
-               uv = pmbus_reg2data(priv->info, PSC_VOLTAGE_OUT, raw, 
vout_mode);
-       else
-               uv = pmbus_reg2data_linear16(raw, vout_mode);
-
-       if (uv > INT_MAX)
-               uv = INT_MAX;
-       if (uv < INT_MIN)
-               uv = INT_MIN;
-       return (int)uv;
+       return pmbus_regulator_vout_to_uv(priv, raw, vout_mode);
 }
 
 static int pmbus_regulator_set_value(struct udevice *dev, int uV)
@@ -187,6 +194,30 @@ int pmbus_regulator_read_temp(struct udevice *reg_dev, int 
*temp_mc)
        return 0;
 }
 
+int pmbus_regulator_read_vout_command(struct udevice *reg_dev, int *uV)
+{
+       struct pmbus_regulator_priv *priv;
+       u8 vout_mode = 0;
+       u16 raw = 0;
+       int ret;
+
+       if (!reg_dev || !uV)
+               return -EINVAL;
+       priv = pmbus_regulator_dev_priv(reg_dev);
+       if (!priv || !priv->i2c_dev)
+               return -ENODEV;
+
+       ret = pmbus_regulator_select_page(priv);
+       if (ret)
+               return ret;
+       if (pmbus_read_byte(priv->i2c_dev, PMBUS_VOUT_MODE, &vout_mode) ||
+           pmbus_read_word(priv->i2c_dev, PMBUS_VOUT_COMMAND, &raw))
+               return -EIO;
+
+       *uV = pmbus_regulator_vout_to_uv(priv, raw, vout_mode);
+       return 0;
+}
+
 enum pmbus_data_format
 pmbus_regulator_identify_vout(struct udevice *i2c_dev,
                              struct pmbus_driver_info *info)
diff --git a/include/pmbus.h b/include/pmbus.h
index bb85a61e62a..e91d97a0b10 100644
--- a/include/pmbus.h
+++ b/include/pmbus.h
@@ -466,6 +466,20 @@ void pmbus_print_status_word(struct udevice *chip);
  */
 int pmbus_regulator_read_temp(struct udevice *reg_dev, int *temp_mc);
 
+/*
+ * pmbus_regulator_read_vout_command() - the output voltage setpoint
+ *
+ * Read VOUT_COMMAND (21h), decoded like READ_VOUT through the chip's
+ * pmbus_driver_info and VOUT_MODE. regulator_get_value() returns
+ * READ_VOUT, the output as measured, which on a regulator with a load
+ * line (droop) sits below the setpoint under load; this returns the
+ * setpoint itself, which is what regulator_set_value() writes.
+ *
+ * Returns 0 on success, or a negative errno (-ENODEV if reg is not a
+ * probed pmbus regulator, -EIO on bus error).
+ */
+int pmbus_regulator_read_vout_command(struct udevice *reg_dev, int *uV);
+
 /*
  * Look up the pmbus_driver_info of a probed UCLASS_REGULATOR device at
  * (bus_seq, addr) that is driven by a pmbus_helper based chip driver
-- 
2.43.0

Reply via email to