[PATCH v3] pinctrl: sunxi: request the per-bank supply optionally

From: Yang Siyuan

Date: Mon Oct 26 2026 - 13:04:15 EST


The per-bank "vcc-pX" supplies are optional in the device tree: the
binding documents them, but notes that many boards do not describe them.
sunxi_pmx_request() uses regulator_get() anyway, so the regulator core
falls back to a dummy regulator and warns for every bank that has no
supply:

sun50i-h616-r-pinctrl 7022000.pinctrl: supply vcc-pl not found, using
dummy regulator

The H616 R_PIO is such a controller, and its PL0/PL1 pins drive the
R_I2C bus, so every H616 board hits the warning during boot.

Use of_regulator_get_optional() instead. A bank supply that is described
in the device tree is still acquired and enabled, as it powers the
physical VCC-Px rail, but one that is absent is skipped without a
warning.

The OF-only lookup matters here: regulator_get_optional() also falls back
to a global regulator-name lookup. If a regulator with the same name as
an absent bank supply is registered later, a subsequent pin request in
that bank could acquire it and start the per-bank refcount at one, after
earlier pins in the bank had already been requested without a regulator.
Freeing any of those pins would then disable the supply while other pins
in the bank are still active. Restricting the lookup to the pinctrl node
makes an absent supply permanent; record that state so later pin requests
do not retry the lookup. The refcount therefore stays balanced.

Signed-off-by: Yang Siyuan <hsyysy@xxxxxxx>
---

Changes in v3:
- Use of_regulator_get_optional() instead of regulator_get_optional().
The latter still performs a global regulator-name lookup, which can
bind an unrelated regulator that appears after some pins were already
requested and unbalance the per-bank refcount.
- Remember that a bank has no supply so later pin requests skip the
lookup, and keep the existing no-regulator check in sunxi_pmx_free().
- Link to v2: https://lore.kernel.org/linux-gpio/20261026152027.1417178-1-hsyysy@xxxxxxx/
- Link to v1: https://lore.kernel.org/linux-gpio/20261026144751.1392715-1-hsyysy@xxxxxxx/
---
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 29 +++++++++++++++++++++++++--
drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 +
2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 70099052d..d2345a85a 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -913,23 +913,44 @@ static int sunxi_pmx_request(struct pinctrl_dev *pctldev, unsigned offset)
PINS_PER_BANK;
struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];
struct regulator *reg = s_reg->regulator;
+ struct device_node *np = dev_of_node(pctl->dev);
char supply[16];
int ret;

if (WARN_ON_ONCE(bank_offset >= ARRAY_SIZE(pctl->regulators)))
return -EINVAL;

+ if (s_reg->supply_absent)
+ return 0;
+
if (reg) {
refcount_inc(&s_reg->refcount);
return 0;
}

+ if (!np) {
+ s_reg->supply_absent = true;
+ return 0;
+ }
+
snprintf(supply, sizeof(supply), "vcc-p%c", 'a' + bank);
- reg = regulator_get(pctl->dev, supply);
- if (IS_ERR(reg))
+ /*
+ * Use the OF-only lookup: regulator_get_optional() would also match
+ * a same-named regulator from another device. Such a regulator can
+ * appear after some pins in this bank have already been requested,
+ * which would unbalance the per-bank refcount.
+ */
+ reg = of_regulator_get_optional(pctl->dev, np, supply);
+ if (IS_ERR(reg)) {
+ if (PTR_ERR(reg) == -ENODEV) {
+ s_reg->supply_absent = true;
+ return 0;
+ }
+
return dev_err_probe(pctl->dev, PTR_ERR(reg),
"Couldn't get bank P%c regulator\n",
'A' + bank);
+ }

ret = regulator_enable(reg);
if (ret) {
@@ -959,6 +980,10 @@ static int sunxi_pmx_free(struct pinctrl_dev *pctldev, unsigned offset)
PINS_PER_BANK;
struct sunxi_pinctrl_regulator *s_reg = &pctl->regulators[bank_offset];

+ /* The per-bank supply is optional, so this bank may not have one. */
+ if (!s_reg->regulator)
+ return 0;
+
if (!refcount_dec_and_test(&s_reg->refcount))
return 0;

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 8bd00c6ff..651249b23 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -162,6 +162,7 @@ struct sunxi_pinctrl_group {
struct sunxi_pinctrl_regulator {
struct regulator *regulator;
refcount_t refcount;
+ bool supply_absent;
};

struct sunxi_pinctrl {
base-commit: 091b06388b117fefdcb63336ac09956a4914b961
--
2.56.0