In case we have the "reg" provided by the DTS, let's avoid probing
to avoid "noises" on the i2c bus. Let's run a scan only on purpose
when "mps,auto-probe" is requested.

The scan notes on the mpq tests for the pmbus are irrelevant and they
were using only for the mpq bringup.

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

---

 doc/develop/pmbus.rst             |   2 +
 drivers/power/regulator/mpq8785.c | 113 ++++++++++++++++--------------
 2 files changed, 61 insertions(+), 54 deletions(-)

diff --git a/doc/develop/pmbus.rst b/doc/develop/pmbus.rst
index f5550541e83..efc9f9a95e5 100644
--- a/doc/develop/pmbus.rst
+++ b/doc/develop/pmbus.rst
@@ -532,6 +532,8 @@ The per chip quirks that carry over:
   flag for this case.
 * ``mps,vout-fb-divider-ratio-permille`` DT property maps to
   ``VOUT_SCALE_LOOP`` write at probe time.
+* ``mps,auto-probe`` the chip decodes its PMBus address using a scan
+  to find ``MFR_ID = "MPS"``. Ignore ``reg``.
 
 The quirks that do not carry over:
 
diff --git a/drivers/power/regulator/mpq8785.c 
b/drivers/power/regulator/mpq8785.c
index 72bfaa5bf8c..e8896d7ebad 100644
--- a/drivers/power/regulator/mpq8785.c
+++ b/drivers/power/regulator/mpq8785.c
@@ -11,8 +11,8 @@
  * Hooks the shared pmbus_helper UCLASS_REGULATOR ops + adds the MPS
  * specific identify (VOUT_MODE switch between LINEAR16 and DIRECT
  * m=64 R=1 for the chip's "VID" mode), the MPS vendor extension
- * (pmbus mps last|clear last|clear force), and ADDR_VBOOT auto
- * promotion when the DT declared address fails the MFR_ID probe.
+ * (pmbus mps last|clear last|clear force), and an address scan
+ * ("mps,auto-probe") for the eight MFR_ADDR_PMBUS.
  */
 
 #include <command.h>
@@ -320,39 +320,44 @@ static const struct pmbus_vendor_op mps_vendor_op = {
                   "pmbus mps clear force  : force clear via MFR_CFG_EXT bit[6] 
(DESTRUCTIVE)\n",
 };
 
-static void mpq8785_identify_vout(struct udevice *i2c_dev)
+static int mpq8785_identify(struct udevice *i2c_dev)
 {
-       enum pmbus_data_format fmt;
+       u8 vout_mode = 0;
+       int ret;
 
-       /*
-        * Let the shared helper read VOUT_MODE and pick the base format
-        * (the single source of truth for the bit layout). The MPS quirk:
-        * this family encodes VOUT in DIRECT with m=64 R=1 whenever
-        * VOUT_MODE reports VID *or* DIRECT -- override the helper's
-        * generic DIRECT m=1 / VID-unwired result in those two modes.
-        * LINEAR and IEEE754 keep the helper's selection unchanged.
-        */
-       fmt = pmbus_regulator_identify_vout(i2c_dev, &mpq8785_info);
-       if (fmt == pmbus_fmt_vid || fmt == pmbus_fmt_direct) {
+       ret = pmbus_read_byte(i2c_dev, PMBUS_VOUT_MODE, &vout_mode);
+       if (ret < 0)
+               return ret;
+       if (vout_mode == 0xff)
+               return -ENODEV;
+
+       switch (vout_mode >> 5) {
+       case 0:
+               mpq8785_info.format[PSC_VOLTAGE_OUT] = pmbus_fmt_linear;
+               break;
+       case 1:
+       case 2:
                mpq8785_info.format[PSC_VOLTAGE_OUT] = pmbus_fmt_direct;
                mpq8785_info.m[PSC_VOLTAGE_OUT] = 64;
                mpq8785_info.b[PSC_VOLTAGE_OUT] = 0;
                mpq8785_info.R[PSC_VOLTAGE_OUT] = 1;
+               break;
+       default:
+               return -ENODEV;
        }
+       return 0;
 }
 
 /*
- * The MPQ8785 datasheet revision letter changes which window the
- * analog ADDR_VBOOT level resolves to. Boards have been observed at
- * 0x10 (later die rev) versus the 0x20 the original driver assumed.
- * If the DT declared address fails the MFR_ID probe at probe time,
- * walk the three documented windows looking for an MPS responder.
+ * Address selection has two modes, chosen by the DT:
  *
- * Each window covers 16 consecutive 7 bit I2C addresses; the low
- * nibble selects the chip's MFR_ADDR_PMBUS slot within the window.
+ *   default            "reg" is the address. follow the Linux driver.
+ *
+ *   mps,auto-probe     boolean. If set, "reg" is ignored, then
+ *                      scan for MFR_ID="MPS"
  */
-#define MPS_ADDR_VBOOT_WINDOW_SIZE     16
-static const u8 mps_addr_window_starts[] = { 0x10, 0x20, 0x60 };
+#define MPS_ADDR_WINDOWS               8
+#define MPS_ADDR_WINDOW_SIZE           16
 
 static int mpq8785_probe_addr(struct udevice *bus, u8 addr,
                              struct udevice **chip_out)
@@ -376,12 +381,15 @@ static int mpq8785_probe_addr(struct udevice *bus, u8 
addr,
 static int mpq8785_scan_windows(struct udevice *bus, u8 *found_addr,
                                struct udevice **chip_out)
 {
-       unsigned int i, j;
+       unsigned int x, slot;
 
-       for (i = 0; i < ARRAY_SIZE(mps_addr_window_starts); i++) {
-               for (j = 0; j < MPS_ADDR_VBOOT_WINDOW_SIZE; j++) {
-                       u8 addr = mps_addr_window_starts[i] + j;
+       for (x = 0; x < MPS_ADDR_WINDOWS; x++) {
+               for (slot = 0; slot < MPS_ADDR_WINDOW_SIZE; slot++) {
+                       u8 addr = (x << 4) | slot;
 
+                       /* 0x00 is the PMBus all-call address, never a chip. */
+                       if (!addr)
+                               continue;
                        if (mpq8785_probe_addr(bus, addr, chip_out) == 0) {
                                *found_addr = addr;
                                return 0;
@@ -419,36 +427,33 @@ static int mpq8785_probe(struct udevice *dev)
        if (ret)
                return ret;
 
-       /*
-        * Verify the chip answers MFR_ID="MPS" at the DT declared
-        * address. If it doesn't, walk the documented ADDR_VBOOT windows
-        * looking for it (a die rev address shift). On a hit, replace
-        * priv->i2c_dev with the discovered chip handle and continue.
-        */
-       {
-               char id[PMBUS_MFR_STRING_MAX] = "";
-
-               ret = pmbus_read_string(priv->i2c_dev, PMBUS_MFR_ID, id,
-                                       sizeof(id), true);
-               if (ret < 0 || strncmp(id, "MPS", 3) != 0) {
-                       struct udevice *bus = dev_get_parent(dev);
-                       struct udevice *promoted;
-                       u8 found = 0;
-
-                       if (mpq8785_scan_windows(bus, &found, &promoted) == 0) {
-                               printf("MPQ8785: DT addr 0x%02x silent, auto 
promoted to 0x%02x\n",
-                                      (unsigned int)dev_read_addr(dev), found);
-                               priv->i2c_dev = promoted;
-                       } else {
-                               printf("MPQ8785: no MPS responder found in 
0x10..0x1f / 0x20..0x2f / 0x60..0x6f\n");
-                               return -ENODEV;
-                       }
+       /* mps,auto-probe: ignore the DTS "reg" address, scan */
+       if (dev_read_bool(dev, "mps,auto-probe")) {
+               struct udevice *bus = dev_get_parent(dev);
+               struct udevice *found_dev;
+               u8 found = 0;
+
+               if (mpq8785_scan_windows(bus, &found, &found_dev)) {
+                       printf("MPQ8785: auto-probe: no MPS responder in 
0x01..0x7f\n");
+                       return -ENODEV;
                }
+               if (found != (u8)dev_read_addr(dev))
+                       printf("MPQ8785: auto-probe: MPS chip at 0x%02x, DT reg 
0x%02x ignored\n",
+                              found, (unsigned int)dev_read_addr(dev));
+               priv->i2c_dev = found_dev;
        }
 
-       /* MPQ8785/MPQ8646 specific: refine VOUT format from VOUT_MODE. */
-       if (chip_id == MPQ_MPQ8785 || chip_id == MPQ_MPQ8646)
-               mpq8785_identify_vout(priv->i2c_dev);
+       /* VOUT_MODE sets the VOUT format, use it for the presence check. */
+       if (chip_id == MPQ_MPQ8785 || chip_id == MPQ_MPQ8646) {
+               ret = mpq8785_identify(priv->i2c_dev);
+               if (ret) {
+                       struct dm_i2c_chip *chip = 
dev_get_parent_plat(priv->i2c_dev);
+
+                       printf("MPQ8785: no usable chip at 0x%02x (VOUT_MODE: 
%d)\n",
+                              chip->chip_addr, ret);
+                       return ret;
+               }
+       }
 
        /* Apply mps,vout-fb-divider-ratio-permille if present in DT. */
        fb_div = dev_read_u32_default(dev, 
"mps,vout-fb-divider-ratio-permille", 0);
---
base-commit: b8e0086b585791a771416ce51b58ce0097bc0b28
branch: for-upstream/power-mpq8785-auto-probe-v1

-- 
2.43.0

Reply via email to