mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
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: e992d54c6f ("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/
Reviewed-by: Linus Walleij <linusw@kernel.org>
Link: https://patch.msgid.link/20260630-gpio-shared-dynamic-voting-v3-1-8ecf0542953b@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
52 lines
1.2 KiB
C
52 lines
1.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
#ifndef __LINUX_GPIO_SHARED_H
|
|
#define __LINUX_GPIO_SHARED_H
|
|
|
|
#include <linux/mutex.h>
|
|
|
|
struct gpio_device;
|
|
struct gpio_desc;
|
|
struct device;
|
|
struct fwnode_handle;
|
|
|
|
#if IS_ENABLED(CONFIG_GPIO_SHARED)
|
|
|
|
int gpiochip_setup_shared(struct gpio_chip *gc);
|
|
void gpio_device_teardown_shared(struct gpio_device *gdev);
|
|
int gpio_shared_add_proxy_lookup(struct device *consumer,
|
|
struct fwnode_handle *fwnode,
|
|
const char *con_id, unsigned long lflags);
|
|
|
|
#else
|
|
|
|
static inline int gpiochip_setup_shared(struct gpio_chip *gc)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { }
|
|
|
|
static inline int gpio_shared_add_proxy_lookup(struct device *consumer,
|
|
struct fwnode_handle *fwnode,
|
|
const char *con_id,
|
|
unsigned long lflags)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_GPIO_SHARED */
|
|
|
|
struct gpio_shared_desc {
|
|
struct gpio_desc *desc;
|
|
unsigned long cfg;
|
|
unsigned int usecnt;
|
|
unsigned int votecnt;
|
|
int def_val;
|
|
struct mutex mutex; /* serializes all proxy operations on this descriptor */
|
|
};
|
|
|
|
struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev);
|
|
|
|
#endif /* __LINUX_GPIO_SHARED_H */
|