[PATCH net-next 4/4] net: pse-pd: check the PI vpwr supply before registering the controller

From: Carlo Szelinsky

Date: Sun Oct 18 2026 - 04:21:06 EST


A regulator registers even when its supply is not there yet. So a PSE
controller registers while its vpwr supply is missing, and every PI
lookup returns -EPROBE_DEFER until the supply appears. Today the MDIO
bus owner keeps deferring until then, but a consumer that only looks a
PI up when a controller registers, as phylib will with the PSE
notifier, would never get it.

Check every PI's vpwr supply before the PI regulators are registered,
and defer the PSE driver's probe if one is missing. The check runs
after setup_pi_matrix(), because pd692x0 registers the supply
regulators there.

The check is simpler than the regulator core's: a supply that is
registered, but whose device is not bound yet, still passes, and that
PI then gets no power domain. On the other hand, a PI whose supply
appears late now gets a power domain; before, pse_register_pw_ds()
skipped it.

Signed-off-by: Carlo Szelinsky <github@xxxxxxxxxxxx>
---
drivers/net/pse-pd/pse_core.c | 81 +++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)

diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 05b02d736931..44986749600e 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/pse-pd/pse.h>
+#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/rtnetlink.h>
@@ -826,6 +827,65 @@ static const struct regulator_ops pse_pi_ops = {
.set_current_limit = pse_pi_set_current_limit,
};

+/* Look up PI @id's vpwr supply on its own node, as the regulator core
+ * will. Only if the PI node has a vpwr-supply phandle: otherwise the
+ * lookup falls back to of_get_child_regulator() on the controller node,
+ * which can return a sibling PI's supply.
+ *
+ * Return: 0 if this PI needs nothing more, 1 if the controller node has
+ * to answer for it, or a negative error such as -EPROBE_DEFER.
+ */
+static int pse_pi_check_supply(struct pse_controller_dev *pcdev, int id)
+{
+ struct device_node *np;
+ struct regulator *supply;
+ int ret;
+
+ /* The PIs the registration loop skips. */
+ if (!pcdev->no_of_pse_pi && !pcdev->pi[id].np)
+ return 0;
+
+ np = pcdev->pi[id].np ?
+ of_parse_phandle(pcdev->pi[id].np, "vpwr-supply", 0) : NULL;
+ if (!np)
+ return 1;
+
+ of_node_put(np);
+ supply = of_regulator_get_optional(pcdev->dev, pcdev->pi[id].np,
+ "vpwr");
+ if (!IS_ERR(supply)) {
+ regulator_put(supply);
+ return 0;
+ }
+
+ ret = PTR_ERR(supply);
+ if (ret == -ENODEV)
+ return 1;
+
+ return dev_err_probe(pcdev->dev, ret,
+ "PI %d: failed to get vpwr supply\n", id);
+}
+
+/* The core's fallback: a vpwr-supply on the controller node. */
+static int pse_controller_check_supply(struct pse_controller_dev *pcdev)
+{
+ struct regulator *supply;
+ int ret;
+
+ supply = regulator_get_optional(pcdev->dev, "vpwr");
+ if (!IS_ERR(supply)) {
+ regulator_put(supply);
+ return 0;
+ }
+
+ ret = PTR_ERR(supply);
+ if (ret == -ENODEV)
+ return 0;
+
+ return dev_err_probe(pcdev->dev, ret,
+ "failed to get vpwr supply\n");
+}
+
static int
devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
char *name, int id)
@@ -1068,6 +1128,7 @@ static void pse_send_ntf_worker(struct work_struct *work)
*/
int pse_controller_register(struct pse_controller_dev *pcdev)
{
+ bool ctrl_supply_ok = false;
size_t reg_name_len;
int ret, i;

@@ -1102,6 +1163,26 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
goto release_pis;
}

+ /* Check vpwr supplies while pcdev->pi can still be freed. Not before
+ * setup_pi_matrix(): pd692x0 registers the regulators its PIs name
+ * there.
+ */
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ ret = pse_pi_check_supply(pcdev, i);
+ if (ret < 0)
+ goto release_pis;
+
+ /* Same answer for every PI: ask once. */
+ if (!ret || ctrl_supply_ok)
+ continue;
+
+ ret = pse_controller_check_supply(pcdev);
+ if (ret)
+ goto release_pis;
+
+ ctrl_supply_ok = true;
+ }
+
/* Each regulator name len is pcdev dev name + 7 char +
* int max digit number (10) + 1
*/
--
2.43.0