[PATCH v5 3/4] gpio: shared-proxy: Drive the default value when no votes are cast
From: Shawn Guo
Date: Wed Oct 28 2026 - 08:39:44 EST
A consumer that requests a shared line with GPIOD_ASIS never calls
direction_output(), so def_val keeps its initial value of 0. If the
line was left high, for instance by the bootloader, a later
gpiod_set_value(0) from that consumer matches def_val and the proxy
treats it as withdrawing a vote it never cast. It returns success
without writing the hardware, and the line stays high.
The consumer has no way to tell. Its request to drive the line low is
silently ignored until it first votes for high and then withdraws
that vote.
When the requested value is the default and no votes are
outstanding, write it to the hardware instead of returning early.
With votes outstanding the request remains a no-op, as the line must
stay at the voted value.
Do this for all lines, not only GPIOD_ASIS ones. A line configured via
direction_output() can be left at the non-default value as well: when
a proxy releases the line and restoring the default fails, its vote is
dropped regardless, leaving votecnt at 0 with the line at the voted
value. The write lets any remaining user bring it back to the default.
In the common case it is a redundant write of the value the line
already has, and it only happens when a proxy that has not voted sets
the default.
Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
Signed-off-by: Shawn Guo <shengchao.guo@xxxxxxxxxxxxxxxx>
---
drivers/gpio/gpio-shared-proxy.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-shared-proxy.c b/drivers/gpio/gpio-shared-proxy.c
index 4eae3c9a5168..75d0d617941f 100644
--- a/drivers/gpio/gpio-shared-proxy.c
+++ b/drivers/gpio/gpio-shared-proxy.c
@@ -85,9 +85,16 @@ gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy, int value)
}
/* Desired value is the default. */
- if (!proxy->voted_change)
- /* We didn't vote for change previously, nothing to do. */
+ if (!proxy->voted_change) {
+ /*
+ * With no votes outstanding the line should be at the
+ * default, but a GPIOD_ASIS line may have been left at the
+ * opposite value. Drive it there.
+ */
+ if (!shared_desc->votecnt)
+ ret = gpiod_set_value_cansleep(desc, shared_desc->def_val);
goto out;
+ }
/* We previously voted for change. */
if (shared_desc->votecnt == 1) {
--
2.43.0