From nobody Mon Feb 9 12:24:27 2026 Received: from mail-ej1-f47.google.com (mail-ej1-f47.google.com [209.85.218.47]) (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 8D7B3345CA3 for ; Fri, 9 Jan 2026 08:38:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767947933; cv=none; b=ueFN7ITJL2Z3ajvGHdmWUjEOWkV4tXb/ZQ+HPbeKohLoo2++KsNgFXTl2gmf8cZ3UamhX9QzsisL8s9cGb0rnTyF4dnm8nKxMToyEapHVN5gfMLE/l0U29f4UCOPdZe5debN05Kz08KKzD4r+fdUphjWoG+fOrkH8ferelMPtKs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767947933; c=relaxed/simple; bh=d8cLybDQoqK0ecW63A3vCUhMpI226Ljh6t0Jr/0nVfY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R3Wy162vuJ/SUINUOWuL+QJqmz5WZkVokDe4/oAddei2iwAgOPLIzjZ/7IXbY9n/20IIIXhUj6iZEmU3xjHV4DjpvZvtdMVttOYx0nn90Xn189R0ylHZ/mnFx3bS5UwzQkF19Cf3epk7KQg0eKiVijP2mJyrYIcPdgj8pZ/lxII= 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=lnWGTBOh; arc=none smtp.client-ip=209.85.218.47 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="lnWGTBOh" Received: by mail-ej1-f47.google.com with SMTP id a640c23a62f3a-b7277324054so728118666b.0 for ; Fri, 09 Jan 2026 00:38:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1767947925; x=1768552725; 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=hBGmyLG3qgKnnQ8cOO0a6IdRyzbs/Ys7SdmEW226de0=; b=lnWGTBOhs2ZbeyHYrbsvE/Fh52pcNY5GuJ9Ur6q4F4HqjMcsnKHNkwv2K/QlLA6sjW eqQhyDiSZBkIKT8k5gME8xP1pI4HcLKrFfjN/IxW8+h312KulcqzT9nesNWlMMtB6MoF fBan3xmpAqWZiv3ri78RzxFTY6shKBvttS59XBoQnR8SI8vp/zbXSg6T36XQGG3kJrLO U88JQcJbmbtMP7tI7PMV7sBq6Hhix+yozgTJPcZlYMvOHlw18gd+l+20WuW3q2CNm52T XbeXCZ8nTUvQWdGx/1lLXAokWlOfOVDQTWErNTgyqz/4lEv0joamprwPs8hKpYieE7Vs ne5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767947925; x=1768552725; 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=hBGmyLG3qgKnnQ8cOO0a6IdRyzbs/Ys7SdmEW226de0=; b=f8c99ZoHTQJOimvVUGZQ2jm1EqRHMZ5gS2Qa2bcXfYQKb2+zfPwS1bfqexl1H62K62 LA0xr5Y1hNNzcFCEVA0RAYjClf8cnJ7PmTvAjccppzSn2TRc7eQw1pDu04e+H/LG9W+L CbF+erVoC0+jBlpJ+gJ05zDBWp1DZBDYGyhxxC5gC9r+SC8PPOWGnA9zYRHUWAWX3821 SFq9XoJdsoRG7NxTO+oeAoUN6AyPd5KyDXPaJ+Tv/zHpN3CUzHkXrFEo7Dc006pxT/yJ +WiAmopysZLZtekvvBPkb4mcKzo9xaOWYJB2yB1GQ86HigJLLLF2lRSTq7xnQ45xyoyc 6bdQ== X-Forwarded-Encrypted: i=1; AJvYcCWlxJVgdbP9+sG+SRocmLyZX1W53+W89N6Uw5hk2M4id/9lDXjmsjiC0UiJWLv0SPHHDtLQyk7t6qwre7A=@vger.kernel.org X-Gm-Message-State: AOJu0Yw3cYy+kIsninUAwe1KNV9waoR06nqhky2QlrtRkIH1qQT2HSZN 2p3zHoA3E5NJXq0Or8D8HvTPbLz6YuI3fjQFpCczRAu+yI0LdpTYghl9bruM+ekyeaw= X-Gm-Gg: AY/fxX7e5RPuJ6FK4HeyKoYU/Y3AklCsG3lVS7/WrPZ/bh8S9k3sD+cogH5gj74Khc5 UlA1tZBm/8DwQOlbfWyDrnHExG93s+xq0lwuOoEwC2TBFjmvA9jM560ZP3pc8BSauZiVB9WjQLl lm8h4WkN+xGTNBapU3aYDrZTeNHtXQDh2MdSZK5eWCwQd6jX4mWLq3pu2S1HmNflbn5WQ7CWZFq k1MF73Y4orr07k5lr4btTFu9+x8/wMhEGLwlWygejtbRcG+m3pPAbLaJ1Z1gbJEA+5dCvzo4BHW tdXAsUwJNROQQh/N/aQPRuHvUO6qwtw0oRK6+HWFc+B1SMgQHxNZvzCjE1MSWaAkI2F5IPUfQ1A ogoyarGGssnMwMlIhQlPutASi1XmMgkFme2FzivGgDeptkeGpTz29T6bZGTxeZDKbiLNMJLXJht 5KJ6BoKzV54UGntVfSw6y3ZruFoM+NJuIZMlSsea0rVA1ymhjVChrLkm4z15X4iIdRsVrc2T8vc w6SSg== X-Google-Smtp-Source: AGHT+IH48Qk48+aQ/D0Va34RWZPT5qOOOWj4vaACv8nVBwipDi6uAlqwYVjMBAA1I9Wx/bAc4DcwCQ== X-Received: by 2002:a17:906:7955:b0:b83:dc86:122b with SMTP id a640c23a62f3a-b84451acde1mr819705166b.18.1767947925020; Fri, 09 Jan 2026 00:38:45 -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 4fb4d7f45d1cf-6507be658b3sm9472950a12.18.2026.01.09.00.38.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 00:38:44 -0800 (PST) From: =?utf-8?q?Andr=C3=A9_Draszik?= Date: Fri, 09 Jan 2026 08:38:43 +0000 Subject: [PATCH v2 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: <20260109-regulators-defer-v2-7-1a25dc968e60@linaro.org> References: <20260109-regulators-defer-v2-0-1a25dc968e60@linaro.org> In-Reply-To: <20260109-regulators-defer-v2-0-1a25dc968e60@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.457.g6b5491de43-goog