[PATCH] gpio: shared: make the voting mechanism adaptable

Bartosz Golaszewski posted 1 patch 1 month ago
There is a newer version of this series
drivers/gpio/gpio-shared-proxy.c | 62 +++++++++++++++++++---------------------
drivers/gpio/gpiolib-shared.h    |  3 +-
2 files changed, 32 insertions(+), 33 deletions(-)
[PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Bartosz Golaszewski 1 month ago
The current voting mechanism in GPIO shared proxy assumes that "low" is
always the default value and users can only vote for driving the GPIO
"high" in which case it will remain high as long as there's at least one
user voting.

This makes it impossible to use the automatic sharing management for
certain use-cases such as the write-protect GPIOs of EEPROMs which are
requested "high" and driven "low" to enable writing. In this case, if
the WP GPIO is shared by multiple EEPROMs, and at least one of them
wants to enable writing, the pin must be set to "low".

Modify the voting heuristic to assume the value set by the first user on
request to be the "default" and subseqent calls to gpiod_set_value()
will constitute votes for a change of the value to the opposite. In the
wp-gpios case it will mean that the nvmem core requests the GPIO as
"out-high" for all EEPROMs sharing the pin, and when one of them wants
to write, the pin will be driven low, enabling it.

Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
Reported-by: Marek Vasut <marex@nabladev.com>
Closes: https://lore.kernel.org/all/20260511163518.51104-1-marex@nabladev.com/
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
Hi Marek!

Please see if you can make your setup work with shared GPIOs with this
patch. You need to enable CONFIG_HAVE_SHARED_GPIOS on your platform. I
indend to slowly enable it on all platforms and eventually make it
default to 'y'. Currently it's enabled in arm64 defconfig via the
Qualcomm platforms.

Thanks,
Bartosz
---
 drivers/gpio/gpio-shared-proxy.c | 62 +++++++++++++++++++---------------------
 drivers/gpio/gpiolib-shared.h    |  3 +-
 2 files changed, 32 insertions(+), 33 deletions(-)

diff --git a/drivers/gpio/gpio-shared-proxy.c b/drivers/gpio/gpio-shared-proxy.c
index 29d7d2e4dfc02c34fb3f2abc343ee30b61579b66..4fb4bb6b712ee2f349182aa61d0aa46703ace3bb 100644
--- a/drivers/gpio/gpio-shared-proxy.c
+++ b/drivers/gpio/gpio-shared-proxy.c
@@ -20,7 +20,7 @@ struct gpio_shared_proxy_data {
 	struct gpio_chip gc;
 	struct gpio_shared_desc *shared_desc;
 	struct device *dev;
-	bool voted_high;
+	bool voted_change;
 };
 
 static int
@@ -34,52 +34,54 @@ gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy,
 
 	gpio_shared_lockdep_assert(shared_desc);
 
-	if (value) {
-	       /* User wants to set value to high. */
-		if (proxy->voted_high)
-			/* Already voted for high, nothing to do. */
+	if (value != shared_desc->def_val) {
+	       /* User wants to vote for a value change. */
+		if (proxy->voted_change)
+			/* Already voted for a change, nothing to do. */
 			goto out;
 
-		/* Haven't voted for high yet. */
-		if (!shared_desc->highcnt) {
+		/* Haven't voted for a value change yet. */
+		if (!shared_desc->votecnt) {
 			/*
-			 * Current value is low, need to actually set value
-			 * to high.
+			 * Current value is default, need to actually set value
+			 * to the opposite.
 			 */
-			ret = set_func(desc, 1);
+			ret = set_func(desc, value);
 			if (ret)
 				goto out;
 		}
 
-		shared_desc->highcnt++;
-		proxy->voted_high = true;
+		shared_desc->votecnt++;
+		proxy->voted_change = true;
 
 		goto out;
 	}
 
-	/* Desired value is low. */
-	if (!proxy->voted_high)
-		/* We didn't vote for high, nothing to do. */
+	/* Desired value is the default. */
+	if (!proxy->voted_change)
+		/* We didn't vote for change previously, nothing to do. */
 		goto out;
 
-	/* We previously voted for high. */
-	if (shared_desc->highcnt == 1) {
-		/* This is the last remaining vote for high, set value  to low. */
-		ret = set_func(desc, 0);
+	/* We previously voted for change. */
+	if (shared_desc->votecnt == 1) {
+		/* This is the last remaining vote for change, set value to default. */
+		ret = set_func(desc, shared_desc->def_val);
 		if (ret)
 			goto out;
 	}
 
-	shared_desc->highcnt--;
-	proxy->voted_high = false;
+	shared_desc->votecnt--;
+	proxy->voted_change = false;
 
 out:
-	if (shared_desc->highcnt)
+	if (shared_desc->votecnt)
 		dev_dbg(proxy->dev,
-			"Voted for value '%s', effective value is 'high', number of votes for 'high': %u\n",
-			str_high_low(value), shared_desc->highcnt);
+			"Voted for value '%s', effective value is '%s', number of votes: %u\n",
+			str_high_low(value), str_high_low(!shared_desc->def_val),
+			shared_desc->votecnt);
 	else
-		dev_dbg(proxy->dev, "Voted for value 'low', effective value is 'low'\n");
+		dev_dbg(proxy->dev, "Voted for value '%s', effective value is '%s'\n",
+			str_high_low(value), str_high_low(shared_desc->def_val));
 
 	return ret;
 }
@@ -189,13 +191,9 @@ static int gpio_shared_proxy_direction_output(struct gpio_chip *gc,
 		if (ret)
 			return ret;
 
-		if (value) {
-			proxy->voted_high = true;
-			shared_desc->highcnt = 1;
-		} else {
-			proxy->voted_high = false;
-			shared_desc->highcnt = 0;
-		}
+		shared_desc->def_val = value;
+		shared_desc->votecnt = 0;
+		proxy->voted_change = false;
 
 		return 0;
 	}
diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h
index 15e72a8dcdb138f19ce000a33d3f53cb8f140bce..f6cbab85c65fc979e2891d19b799baaf91fd6dca 100644
--- a/drivers/gpio/gpiolib-shared.h
+++ b/drivers/gpio/gpiolib-shared.h
@@ -45,7 +45,8 @@ struct gpio_shared_desc {
 	bool can_sleep;
 	unsigned long cfg;
 	unsigned int usecnt;
-	unsigned int highcnt;
+	unsigned int votecnt;
+	int def_val;
 	union {
 		struct mutex mutex;
 		spinlock_t spinlock;

---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260512-gpio-shared-dynamic-voting-9aab4689f5e9

Best regards,
-- 
Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Re: [PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Linus Walleij 3 weeks, 3 days ago
On Wed, May 13, 2026 at 11:14 AM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:

> The current voting mechanism in GPIO shared proxy assumes that "low" is
> always the default value and users can only vote for driving the GPIO
> "high" in which case it will remain high as long as there's at least one
> user voting.
>
> This makes it impossible to use the automatic sharing management for
> certain use-cases such as the write-protect GPIOs of EEPROMs which are
> requested "high" and driven "low" to enable writing. In this case, if
> the WP GPIO is shared by multiple EEPROMs, and at least one of them
> wants to enable writing, the pin must be set to "low".
>
> Modify the voting heuristic to assume the value set by the first user on
> request to be the "default" and subseqent calls to gpiod_set_value()
> will constitute votes for a change of the value to the opposite. In the
> wp-gpios case it will mean that the nvmem core requests the GPIO as
> "out-high" for all EEPROMs sharing the pin, and when one of them wants
> to write, the pin will be driven low, enabling it.
>
> Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
> Reported-by: Marek Vasut <marex@nabladev.com>
> Closes: https://lore.kernel.org/all/20260511163518.51104-1-marex@nabladev.com/
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>

I like this idea.
Reviewed-by: Linus Walleij <linusw@kernel.org>

BTW was this "voting" system inspired by the hardware "vote" thing
that Qualcomm is using for power management? That's the only place
I've seen it before.

Yours,
Linus Walleij
Re: [PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Bartosz Golaszewski 3 weeks, 3 days ago
On Tue, May 19, 2026 at 10:34 AM Linus Walleij <linusw@kernel.org> wrote:
>
> On Wed, May 13, 2026 at 11:14 AM Bartosz Golaszewski
> <bartosz.golaszewski@oss.qualcomm.com> wrote:
>
> > The current voting mechanism in GPIO shared proxy assumes that "low" is
> > always the default value and users can only vote for driving the GPIO
> > "high" in which case it will remain high as long as there's at least one
> > user voting.
> >
> > This makes it impossible to use the automatic sharing management for
> > certain use-cases such as the write-protect GPIOs of EEPROMs which are
> > requested "high" and driven "low" to enable writing. In this case, if
> > the WP GPIO is shared by multiple EEPROMs, and at least one of them
> > wants to enable writing, the pin must be set to "low".
> >
> > Modify the voting heuristic to assume the value set by the first user on
> > request to be the "default" and subseqent calls to gpiod_set_value()
> > will constitute votes for a change of the value to the opposite. In the
> > wp-gpios case it will mean that the nvmem core requests the GPIO as
> > "out-high" for all EEPROMs sharing the pin, and when one of them wants
> > to write, the pin will be driven low, enabling it.
> >
> > Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
> > Reported-by: Marek Vasut <marex@nabladev.com>
> > Closes: https://lore.kernel.org/all/20260511163518.51104-1-marex@nabladev.com/
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> I like this idea.
> Reviewed-by: Linus Walleij <linusw@kernel.org>
>
> BTW was this "voting" system inspired by the hardware "vote" thing
> that Qualcomm is using for power management? That's the only place
> I've seen it before.
>

Really only the name, it's not much different from what we already
have in clocks or regulators IMO.

Bart
Re: [PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Linus Walleij 2 weeks, 4 days ago
On Tue, May 19, 2026 at 10:56 AM Bartosz Golaszewski <brgl@kernel.org> wrote:
> On Tue, May 19, 2026 at 10:34 AM Linus Walleij <linusw@kernel.org> wrote:

> > BTW was this "voting" system inspired by the hardware "vote" thing
> > that Qualcomm is using for power management? That's the only place
> > I've seen it before.
>
> Really only the name, it's not much different from what we already
> have in clocks or regulators IMO.

My thinking is:

- refcount = any request enables, all consumers must disable before
  resource goes offline

- vote = some kind of majority or first-come-first-served decision and
  consumers could be denied the resource

If the semantics are the same I will be confused... this seems to
be a first-come-first-served scheme so I comprehend it.

Yours,
Linus Walleij
Re: [PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Marek Vasut 3 weeks, 3 days ago
On 5/13/26 11:13 AM, Bartosz Golaszewski wrote:
> The current voting mechanism in GPIO shared proxy assumes that "low" is
> always the default value and users can only vote for driving the GPIO
> "high" in which case it will remain high as long as there's at least one
> user voting.
> 
> This makes it impossible to use the automatic sharing management for
> certain use-cases such as the write-protect GPIOs of EEPROMs which are
> requested "high" and driven "low" to enable writing. In this case, if
> the WP GPIO is shared by multiple EEPROMs, and at least one of them
> wants to enable writing, the pin must be set to "low".
> 
> Modify the voting heuristic to assume the value set by the first user on
> request to be the "default" and subseqent calls to gpiod_set_value()
> will constitute votes for a change of the value to the opposite. In the
> wp-gpios case it will mean that the nvmem core requests the GPIO as
> "out-high" for all EEPROMs sharing the pin, and when one of them wants
> to write, the pin will be driven low, enabling it.

Shouldn't this polarity inversion be handled by DT GPIO_ACTIVE_* flag ?

> Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
> Reported-by: Marek Vasut <marex@nabladev.com>
> Closes: https://lore.kernel.org/all/20260511163518.51104-1-marex@nabladev.com/
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
> Hi Marek!
> 
> Please see if you can make your setup work with shared GPIOs with this
> patch. You need to enable CONFIG_HAVE_SHARED_GPIOS on your platform.

Why can this shared GPIO not be enabled generically for any GPIO 
controller ?

[...]
Re: [PATCH] gpio: shared: make the voting mechanism adaptable
Posted by Bartosz Golaszewski 3 weeks, 3 days ago
On Tue, May 19, 2026 at 5:59 AM Marek Vasut <marex@nabladev.com> wrote:
>
> On 5/13/26 11:13 AM, Bartosz Golaszewski wrote:
> > The current voting mechanism in GPIO shared proxy assumes that "low" is
> > always the default value and users can only vote for driving the GPIO
> > "high" in which case it will remain high as long as there's at least one
> > user voting.
> >
> > This makes it impossible to use the automatic sharing management for
> > certain use-cases such as the write-protect GPIOs of EEPROMs which are
> > requested "high" and driven "low" to enable writing. In this case, if
> > the WP GPIO is shared by multiple EEPROMs, and at least one of them
> > wants to enable writing, the pin must be set to "low".
> >
> > Modify the voting heuristic to assume the value set by the first user on
> > request to be the "default" and subseqent calls to gpiod_set_value()
> > will constitute votes for a change of the value to the opposite. In the
> > wp-gpios case it will mean that the nvmem core requests the GPIO as
> > "out-high" for all EEPROMs sharing the pin, and when one of them wants
> > to write, the pin will be driven low, enabling it.
>
> Shouldn't this polarity inversion be handled by DT GPIO_ACTIVE_* flag ?
>

We could but that would require DT changes, you probably don't want
this? That's a different thing though too. Here's it's purely logical
- either we default to high and vote for low or default to low and
vote for high with at least one vote needed to switch.

> > Fixes: e992d54c6f97 ("gpio: shared-proxy: implement the shared GPIO proxy driver")
> > Reported-by: Marek Vasut <marex@nabladev.com>
> > Closes: https://lore.kernel.org/all/20260511163518.51104-1-marex@nabladev.com/
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> > ---
> > Hi Marek!
> >
> > Please see if you can make your setup work with shared GPIOs with this
> > patch. You need to enable CONFIG_HAVE_SHARED_GPIOS on your platform.
>
> Why can this shared GPIO not be enabled generically for any GPIO
> controller ?
>
> [...]

That's the plan. I enabled it in arm64 defconfig for now (via Qualcomm
platforms selecting it). It caused quite a lot of fallout and a slew
of fixes so I'm doing it slowly. But yes - eventually it should be
enabled for all OF systems and potentially also verify software node
references as there are some intel systems that have GPIOs shared by
platform devices described in ACPI *and* software nodes.

Bart