[PATCH v1 04/23] board: nbxv3: add MPQ8785 PMBus traces + DT regulator

Vincent Jardin <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
Bind through the tree-level PMBus framework and add a board-local
EVT_LAST_STAGE_INIT spy that prints the traces to the serial console.

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

 arch/arm/dts/fsl-lx2160a-nbxv3.dts  |  17 +++++
 board/nxp/lx2160a/Kconfig           |  11 +++
 board/nxp/lx2160a/nbxv3/Makefile    |   1 +
 board/nxp/lx2160a/nbxv3/mps_pmbus.c | 107 ++++++++++++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 board/nxp/lx2160a/nbxv3/mps_pmbus.c

diff --git a/arch/arm/dts/fsl-lx2160a-nbxv3.dts b/arch/arm/dts/fsl-lx2160a-nbxv3.dts
index 8caea051bed..8e336a622f3 100644
--- a/arch/arm/dts/fsl-lx2160a-nbxv3.dts
+++ b/arch/arm/dts/fsl-lx2160a-nbxv3.dts
@@ -40,3 +40,20 @@
 	phy-connection-type = "rgmii-id";
 	u-boot,nickname = "lanconsole0";
 };
+
+&i2c0 { /* IIC1: on module management bus */
+	status = "okay";
+
+	regulator@10 {
+		compatible = "mps,mpq8785";
+		reg = <0x10>;
+		regulator-name = "+0V8_VDD";
+		regulator-min-microvolt = < 600000>;
+		regulator-max-microvolt = <1100000>;
+		/* MPQ8785 datasheet rating: continuous 40 A output (IOUT). */
+		regulator-min-microamp = <       0>;
+		regulator-max-microamp = <40000000>;
+		regulator-boot-on;
+		regulator-always-on;
+	};
+};
diff --git a/board/nxp/lx2160a/Kconfig b/board/nxp/lx2160a/Kconfig
index 37e8f7ff717..e46223d1b43 100644
--- a/board/nxp/lx2160a/Kconfig
+++ b/board/nxp/lx2160a/Kconfig
@@ -65,4 +65,15 @@ config NBXV3_DM_EVENT
 	default y
 	select DM_EVENT
 
+config NBXV3_PMBUS
+	bool
+	default y
+	select PMBUS
+	select CMD_PMBUS
+	select DM_REGULATOR
+	select DM_REGULATOR_PMBUS_HELPER
+	select DM_REGULATOR_MPQ8785
+	select DM_REGULATOR_PMBUS_GENERIC
+	select CMD_REGULATOR
+
 endif
diff --git a/board/nxp/lx2160a/nbxv3/Makefile b/board/nxp/lx2160a/nbxv3/Makefile
index 90ef2734eec..e4aa5309804 100644
--- a/board/nxp/lx2160a/nbxv3/Makefile
+++ b/board/nxp/lx2160a/nbxv3/Makefile
@@ -3,3 +3,4 @@
 #
 
 obj-y += eth_nbxv3.o
+obj-y += mps_pmbus.o
diff --git a/board/nxp/lx2160a/nbxv3/mps_pmbus.c b/board/nxp/lx2160a/nbxv3/mps_pmbus.c
new file mode 100644
index 00000000000..15c0d0d0bc6
--- /dev/null
+++ b/board/nxp/lx2160a/nbxv3/mps_pmbus.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 Free Mobile, Vincent Jardin
+ *
+ * Boot time snapshot of the +0V8_VDD core regulator.
+ *
+ * The MPS MPQ8785 or MPQ8646 chips are bound through DT
+ * thanks to the per chip driver in
+ *   drivers/power/regulator/mpq8785.c.
+ *
+ * The only thing this file still does is the boot time event spy and logs:
+ *  - at `EVT_LAST_STAGE_INIT` it probes the regulator (which triggers
+ *    the chip driver's .probe),
+ *  - it seeds pmbus_active so the `pmbus` command works without the
+ *    operator typing `pmbus dev`,
+ *  - and then it prints a one shot rail snapshot to the serial console.
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <event.h>
+#include <i2c.h>
+#include <log.h>
+#include <pmbus.h>
+#include <vsprintf.h>
+#include <power/regulator.h>
+
+#define NBXV3_VDD_REGULATOR_NAME	"+0V8_VDD"
+
+static void mps_pmbus_print_snapshot(struct udevice *reg)
+{
+	const struct pmbus_active_dev *act;
+	struct udevice *chip;
+	u16 raw, status_word = 0, prot_last = 0;
+	u8 vout_mode = 0;
+	int uV, en;
+
+	uV = regulator_get_value(reg);
+	en = regulator_get_enable(reg);
+
+	act = pmbus_active();
+	if (!act || pmbus_active_get_i2c(&chip)) {
+		printf("MPQ8785 (+0V8_VDD): VOUT=%d uV  enabled=%d  (no PMBus active dev)\n",
+		       uV, en);
+		return;
+	}
+
+	pmbus_read_byte(chip, PMBUS_VOUT_MODE, &vout_mode);
+	pmbus_read_word(chip, PMBUS_STATUS_WORD, &status_word);
+	pmbus_read_word(chip, 0xfb /* MPS_PROTECTION_LAST */, &prot_last);
+
+	{
+		u8 rev_byte = 0;
+
+		(void)pmbus_read_byte(chip, PMBUS_MFR_REVISION, &rev_byte);
+		printf("MPQ8785 @ i2c%d:0x%02x  MFR_ID=\"%s\" MODEL=\"%s\" REV=0x%02x VOUT_MODE=0x%02x\n",
+		       act->bus_seq, act->addr,
+		       act->mfr_id[0] ? act->mfr_id : "?",
+		       act->mfr_model[0] ? act->mfr_model : "?",
+		       rev_byte, vout_mode);
+	}
+	printf("  +0V8_VDD: VOUT=%d uV  enabled=%d\n", uV, en);
+
+	if (pmbus_read_word(chip, PMBUS_READ_VIN, &raw) == 0)
+		printf("            VIN  raw=0x%04x  =%lld uV\n", raw,
+		       (long long)pmbus_reg2data(act->info, PSC_VOLTAGE_IN,
+						 raw, vout_mode));
+	if (pmbus_read_word(chip, PMBUS_READ_IOUT, &raw) == 0)
+		printf("            IOUT raw=0x%04x  =%lld uA\n", raw,
+		       (long long)pmbus_reg2data(act->info, PSC_CURRENT_OUT,
+						 raw, vout_mode));
+	if (pmbus_read_word(chip, PMBUS_READ_TEMPERATURE_1, &raw) == 0)
+		printf("            TEMP raw=0x%04x  =%lld udegC\n", raw,
+		       (long long)pmbus_reg2data(act->info, PSC_TEMPERATURE,
+						 raw & 0x00ff, vout_mode));
+
+	printf("  STATUS_WORD = 0x%04x  [", status_word);
+	pmbus_print_status_bits(PMBUS_STATUS_WORD, status_word,
+				pmbus_status_word_bits,
+				act->info ? act->info->status_overrides : NULL);
+	printf("]\n");
+	printf("  PROTECTION_LAST = 0x%04x (NVM)\n", prot_last);
+	printf("  Use `pmbus telemetry`, `pmbus status`, `pmbus mps last` for details.\n");
+}
+
+static int mps_pmbus_last_stage_init(void)
+{
+	struct udevice *reg = NULL;
+
+	if (regulator_get_by_platname(NBXV3_VDD_REGULATOR_NAME, &reg))
+		return 0;
+	if (!reg)
+		return 0;
+
+	{
+		int bus_seq;
+		u8 addr;
+
+		if (pmbus_resolve_by_name(NBXV3_VDD_REGULATOR_NAME,
+					  &bus_seq, &addr) == 0)
+			pmbus_set_active(bus_seq, addr);
+	}
+
+	mps_pmbus_print_snapshot(reg);
+	return 0;
+}
+EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, mps_pmbus_last_stage_init);
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.