From nobody Mon Feb 9 14:33:43 2026 Received: from mail-ej1-f50.google.com (mail-ej1-f50.google.com [209.85.218.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB81631280C for ; Sat, 27 Dec 2025 12:17:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766837880; cv=none; b=RKJE5oyjS5Loh7M+XRFuLZMuR6G6g45f2ciNHN6APJXN3NNK/1UdLsj0dpGqpupOBRs/wPDQkeqEqq5u8a06g+6fERg/d7LqXPh33/EZOIAgGwfuuGjhCqrzpztps6QwEyt1eD1ZjHk79cja3gSbDdqOjGeA/XD5z4Hl2BWymmA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766837880; c=relaxed/simple; bh=DTt6cIAe+OUCl4SozH/frfTEZ8TJ3BMCApzCKcJiowQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=I9HD4cZFCCo5OuDx3bAxNdo6DOWR0ya3woj63xmFgFKE0YmzWsoPe/H1rNKl7iL8dduypxYX1YXozki5tIOSmp2uajtsd93NhSOVTLjj9MMe0gWM2oaNsgn324vLbH3bSgH/uMm5E3aH6XZEmrA2tW8sITJVAyNO1rmqVIaVRc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=aN6vb0+F; arc=none smtp.client-ip=209.85.218.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="aN6vb0+F" Received: by mail-ej1-f50.google.com with SMTP id a640c23a62f3a-b7cee045187so1396997566b.0 for ; Sat, 27 Dec 2025 04:17:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1766837871; x=1767442671; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=wYPevBhP4Z7tB1bUOGzVebYfDjp810+7VQSE4xcnspw=; b=aN6vb0+FG5UHIvztCHIGnxln6NrnTeRJNj4W1jhCoSG3sAhRGNK6uSffCA7qQbReLO rDsoGAU6TCjDTQ+PrdaazPFLt2eFZ6EgkIAOMUux0f8YgdR6/ktloKgnTr6lH5Bl5GNk YviRktCLcEHxa67J1vCMCY4aW2iBmbglCyvrLxP0Qr/Ogxx3CYLyyayt90b8IkrfqOZV 9PQlwm/ljCqwu6S319XgBSQy9Q040BX0cp080yBJmMEktduXO3SFEu0mCpLZGWjwnBpu zXsXGrlYN1iFs4iiRt1jrlG1GBbxf4aSi3bV75erEX7ArRC78WclTubPTA7Yc0lAmO1O VD4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766837871; x=1767442671; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=wYPevBhP4Z7tB1bUOGzVebYfDjp810+7VQSE4xcnspw=; b=HoPBzBK7cdOvzAcdRR+5hQ06W7iG7JSGs4WkJ3Xt//sS8Mxle78pTKQdhyNPZ+3dqN SR4sIDreStvLsrSpthhwCj261cItEy15O6QAF4/h5g1liPAC2MMEd5Xb3P149fw5vdON uL32mVcpiNFzKPayX/BR4LCVV8HlNUIabEbNdD0sFm7XwvTK855FCvmu9xG9jZddFnlO 8rreflvbs0MGUBzrNcgEA3K1cT6vriOIRlLdJRDLdJ5Q/W9XD5NJx1PeTLTJqCPJxGqv kx0mqnULDLtXlIWG0iTsC/eaTA4VwhfyeAgaDBTFHJM5OlExLukYjRkAhYzd4H9Mcagk BcTw== X-Forwarded-Encrypted: i=1; AJvYcCUpGJ7iTlZlHPvn8yuUmBB6oNLwMHfrpPCT/xEEYFOnhzGmPug7VFxq+aCdDCspPJAjv8eZeVpgUPUEUe0=@vger.kernel.org X-Gm-Message-State: AOJu0YzNbtKK3VO0Ho2I5mrV1ZWVl3L/HNSNHdrXsu7mzb/UUZBhAEAP IRwOnt1OPAWuN6W110ggwS5UmFm1rVFHy1aUhbxg27MvMhujmbQKebdNo1xOj2NfGmw= X-Gm-Gg: AY/fxX4Zv6ZtXs8CMBelKlQ5msAjEfZYqayTKHSp2vdM3YXRfagmtemPVfxVCMxRvap j/qSQTH8lql3hvLdTvbCRysr1Uez9MD8LqJrciZGn5NvsIhaKc5qcyMd0l4k1eLnqEVI7wWO9VI scvprbrQ1T6rcBMjzVA6zQnlnhjocNR/DQ8Nu2YuB0IdQMxQeQvarmprixTjxaYQv1PoiKKhhph 6EIKm3xJof2tob3tAb1w78O7xGQJV2BbFx0Y7y2Fg08hV+MRGtXOFjpxhQPrmhSNuMwCc5iu4+z JkME1o34XuhTILZdBqRK35aPuR8EThBrTeSg8ccGXsj9o4Ik258SEqSguTjEflHBy8RVn+gWhH5 /tMGsZWhvD4D4aVEhWaGyVxB2K1j0yGLEpYjeFr0uizRLkybHz5IAZZQxjy3GYey8hjsb67a9/T HSuCGIAxJw55MSVc4Tx14rhoZGKff/v6DHuS/lLIBRdA9y3uX8BeNnmk2D+05zM7ouv/ILZj3cG JnCQA== X-Google-Smtp-Source: AGHT+IHExlt4c5QXm/HrLuZhwkcKc6ZSYj+mnHkWL3FZeW4sD9O68OjZVkvLZwzWmYDCYzs6y4uDwg== X-Received: by 2002:a17:907:97d4:b0:b80:344b:421a with SMTP id a640c23a62f3a-b8035743e21mr3170118866b.18.1766837871265; Sat, 27 Dec 2025 04:17:51 -0800 (PST) Received: from puffmais2.c.googlers.com (244.175.141.34.bc.googleusercontent.com. [34.141.175.244]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-b8037f18575sm2616274666b.54.2025.12.27.04.17.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 27 Dec 2025 04:17:50 -0800 (PST) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Sat, 27 Dec 2025 12:17:51 +0000 Subject: [PATCH 7/8] regulator: core: reresolve unresolved supplies when available Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251227-regulators-defer-v1-7-3104b22d84cb@linaro.org> References: <20251227-regulators-defer-v1-0-3104b22d84cb@linaro.org> In-Reply-To: <20251227-regulators-defer-v1-0-3104b22d84cb@linaro.org> To: Liam Girdwood , Mark Brown , Javier Martinez Canillas , Jon Hunter , Dmitry Baryshkov , Oleksij Rempel Cc: Peter Griffin , Tudor Ambarus , Will McVicker , Juan Yescas , kernel-team@android.com, linux-kernel@vger.kernel.org, =?utf-8?q?Andr=C3=A9_Draszik?= X-Mailer: b4 0.14.2 When a regulator A and its supply B are provided by different devices, the driver implementing B might be last to probe (with A still pending resolution of its supply B). While we try to resolve all pending supplies for all regulators (including A) during regulator_register() of B via regulator_register_resolve_supply(), Supply resolution will still not work for A as the driver for B hasn't finished binding to the PMIC device corresponding to B at that stage yet. The regulator core explicitly only allows supplies from other devices to be used once the relevant driver has fully bound, mainly to avoid having to deal with cases where B itself might -EPROBE_DEFER. In this case, A's supply will only be resolved as part of the core's regulator_init_complete_work_function(), which currently is scheduled to run after 30s. This was added as a work-around in commit 3827b64dba27 ("regulator: core: Resolve supplies before disabling unused regulators") to cover this situation. There are two problems with that approach: * it potentially runs long after all our consumers have probed * an upcoming change will allow regulator_register() to complete successfully even when required supplies (e.g. due to always-on or boot-on) are missing at register time, deferring full configuration of the regulator (and usability by consumers, i.e. usually consumer probe) until the supply becomes available. Resolving supplies in the late work func can therefore make it impossible for consumers to probe at all, as the driver core will not know to reprobe consumers when supplies have resolved. We could schedule an earlier work to try to resolve supplies sooner, but that'd be racy as consumers of A might try to probe before A's supply gets fully resolved via this extra work. Instead, add a very simple regulator bus and add a dummy device with a corresponding driver to it for each regulator that is missing its supply during regulator_register(). This way, the driver core will call our bus' probe whenever a new (regulator) device was successfully bound, allowing us to retry resolving the supply during (our bus) probe and to bind this dummy device if successful. In turn this means the driver core will see a newly bound device and retry probing of all pending consumers, if any. With that in place, we can avoid walking the full list of all known regulators to try resolve missing supplies during regulator_register(), as the driver core will invoke the bus probe for regulators that are still pending their supplies. We can also drop the code trying to resolve supplies one last time before unused regulators get disabled, as all supplies should have resolved at that point in time, and if they haven't then there's no point in trying again, as the outcome won't change. Note: We can not reuse the existing struct device created for each rail, as a device can not be part of a class and a bus simultaneously. Signed-off-by: Andr=C3=A9 Draszik --- drivers/regulator/core.c | 121 +++++++++++++++++++++++++++++++----= ---- include/linux/regulator/driver.h | 1 + 2 files changed, 98 insertions(+), 24 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 86dbee3ffda0b950619db8b52d6c6eab8be31a53..08e92b1ba2dc2ff9efdabaa1618= 7a4a38cf66fb2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -44,6 +44,8 @@ static LIST_HEAD(regulator_supply_alias_list); static LIST_HEAD(regulator_coupler_list); static bool has_full_constraints; =20 +static const struct bus_type regulator_bus; + static struct dentry *debugfs_root; =20 /* @@ -5694,17 +5696,6 @@ static void rdev_init_debugfs(struct regulator_dev *= rdev) &rdev->bypass_count); } =20 -static int regulator_register_resolve_supply(struct device *dev, void *dat= a) -{ - struct regulator_dev *rdev =3D dev_to_rdev(dev); - - if (regulator_resolve_supply(rdev)) - rdev_dbg(rdev, "unable to resolve supply '%s'\n", - rdev->supply_name); - - return 0; -} - int regulator_coupler_register(struct regulator_coupler *coupler) { mutex_lock(®ulator_list_mutex); @@ -5923,6 +5914,7 @@ regulator_register(struct device *dev, struct regulator_config *config =3D NULL; static atomic_t regulator_no =3D ATOMIC_INIT(-1); struct regulator_dev *rdev; + bool tried_supply_resolve =3D false; bool dangling_cfg_gpiod =3D false; bool dangling_of_gpiod =3D false; int ret, i; @@ -6093,6 +6085,7 @@ regulator_register(struct device *dev, else rdev_dbg(rdev, "unable to resolve supply early: %pe\n", ERR_PTR(ret)); + tried_supply_resolve =3D true; } if (ret < 0) goto wash; @@ -6124,6 +6117,37 @@ regulator_register(struct device *dev, if (ret !=3D 0) goto unset_supplies; =20 + if (!tried_supply_resolve) { + /* + * As an optimisation, try to resolve our supply (if any) now to + * avoid adding the bus device. Errors are not fatal at this + * stage, we'll simply try again later. + */ + ret =3D regulator_resolve_supply(rdev); + if (ret) + rdev_dbg(rdev, + "unable to resolve supply (ignoring): %pe\n", + ERR_PTR(ret)); + } + + /* + * If we have a supply but couldn't resolve it yet, register a device + * with our bus, so that the bus probe gets called whenever any new + * driver binds, allowing us to retry matching supplies and which then + * triggers (re)probe of consumers if successful. + */ + if (rdev->supply_name && !rdev->supply) { + device_initialize(&rdev->bdev); + rdev->bdev.bus =3D ®ulator_bus; + rdev->bdev.parent =3D &rdev->dev; + device_set_pm_not_required(&rdev->dev); + dev_set_name(&rdev->bdev, "%s.bdev", dev_name(&rdev->dev)); + + ret =3D device_add(&rdev->bdev); + if (ret) + goto del_cdev_and_bdev; + } + rdev_init_debugfs(rdev); =20 /* try to resolve regulators coupling since a new one was registered */ @@ -6131,12 +6155,13 @@ regulator_register(struct device *dev, regulator_resolve_coupling(rdev); mutex_unlock(®ulator_list_mutex); =20 - /* try to resolve regulators supply since a new one was registered */ - class_for_each_device(®ulator_class, NULL, NULL, - regulator_register_resolve_supply); kfree(config); return rdev; =20 +del_cdev_and_bdev: + if (rdev->bdev.bus =3D=3D ®ulator_bus) + put_device(&rdev->bdev); + device_del(&rdev->dev); unset_supplies: mutex_lock(®ulator_list_mutex); unset_regulator_supplies(rdev); @@ -6189,6 +6214,9 @@ void regulator_unregister(struct regulator_dev *rdev) unset_regulator_supplies(rdev); list_del(&rdev->list); regulator_ena_gpio_free(rdev); + if (rdev->bdev.bus =3D=3D ®ulator_bus) + /* only if the device was added in the first place */ + device_unregister(&rdev->bdev); device_unregister(&rdev->dev); =20 mutex_unlock(®ulator_list_mutex); @@ -6269,6 +6297,45 @@ const struct class regulator_class =3D { .pm =3D ®ulator_pm_ops, #endif }; + +#define bdev_to_rdev(__bdev) container_of_const(__bdev, struct regulator_d= ev, bdev) + +static int regulator_bus_match(struct device *bdev, + const struct device_driver *drv) +{ + /* Match always succeeds, we only have one driver */ + return 1; +} + +static int regulator_bus_probe(struct device *bdev) +{ + struct regulator_dev *rdev =3D bdev_to_rdev(bdev); + int ret; + + ret =3D regulator_resolve_supply(rdev); + if (ret) + rdev_dbg(rdev, + "unable to resolve supply or constraints '%s': %pe\n", + rdev->supply_name, ERR_PTR(ret)); + else + rdev_dbg(rdev, "resolved supply '%s'\n", rdev->supply_name); + + return ret; +} + +static const struct bus_type regulator_bus =3D { + .name =3D "regulator", + .match =3D regulator_bus_match, + .probe =3D regulator_bus_probe, +}; + +static struct device_driver regulator_bus_driver =3D { + .name =3D "regulator-bus-drv", + .bus =3D ®ulator_bus, + .suppress_bind_attrs =3D true, + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, +}; + /** * regulator_has_full_constraints - the system has fully specified constra= ints * @@ -6602,7 +6669,17 @@ static int __init regulator_init(void) { int ret; =20 + ret =3D bus_register(®ulator_bus); + if (ret) + return ret; + ret =3D class_register(®ulator_class); + if (ret) + goto err_class; + + ret =3D driver_register(®ulator_bus_driver); + if (ret) + goto err_driver; =20 debugfs_root =3D debugfs_create_dir("regulator", NULL); if (IS_ERR(debugfs_root)) @@ -6619,6 +6696,12 @@ static int __init regulator_init(void) =20 regulator_coupler_register(&generic_regulator_coupler); =20 + return 0; + +err_driver: + class_unregister(®ulator_class); +err_class: + bus_unregister(®ulator_bus); return ret; } =20 @@ -6679,16 +6762,6 @@ __setup("regulator_ignore_unused", regulator_ignore_= unused_setup); =20 static void regulator_init_complete_work_function(struct work_struct *work) { - /* - * Regulators may had failed to resolve their input supplies - * when were registered, either because the input supply was - * not registered yet or because its parent device was not - * bound yet. So attempt to resolve the input supplies for - * pending regulators before trying to disable unused ones. - */ - class_for_each_device(®ulator_class, NULL, NULL, - regulator_register_resolve_supply); - /* * For debugging purposes, it may be useful to prevent unused * regulators from being disabled. diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/dri= ver.h index 978cf593b6624228fe1fd9c2a3e186b53ef172f8..d38353f2b56f8bbab865d903ad0= ec97ca0b5c834 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -635,6 +635,7 @@ struct regulator_dev { int ref_cnt; struct module *owner; struct device dev; + struct device bdev; struct regulation_constraints *constraints; struct regulator *supply; /* for tree */ const char *supply_name; --=20 2.52.0.351.gbe84eed79e-goog