From: Bartosz Golaszewski <[email protected]> Provide an interface allowing consumers to check if a GPIO descriptor represents a GPIO that can potentially be shared by multiple consumers at the same time. This is exposed to allow subsystems that already work around the limitations of the current non-exclusive GPIO handling in some ways, to gradually convert to relying on the new shared GPIO feature of GPIOLIB.
Extend the gpiolib-shared module to mark the GPIO shared proxy descriptors with a flag checked by the new interface. Reviewed-by: Linus Walleij <[email protected]> Acked-by: Linus Walleij <[email protected]> Signed-off-by: Bartosz Golaszewski <[email protected]> --- drivers/gpio/gpiolib-shared.c | 18 ++++++++++++++++++ drivers/gpio/gpiolib.c | 20 ++++++++++++++++++++ drivers/gpio/gpiolib.h | 1 + include/linux/gpio/consumer.h | 9 +++++++++ 4 files changed, 48 insertions(+) diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 56b9b03cbb6dbcdf095a656fc36ff321770035da..c22eaf05eef23a7f5f111708c3db9412c4c30231 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -314,6 +314,24 @@ int gpio_device_setup_shared(struct gpio_device *gdev) guard(mutex)(&gpio_shared_lock); + list_for_each_entry(entry, &gpio_shared_list, list) { + list_for_each_entry(ref, &entry->refs, list) { + if (gdev->dev.parent == &ref->adev.dev) { + /* + * This is a shared GPIO proxy. Mark its + * descriptor as such and return here. + */ + __set_bit(GPIOD_FLAG_SHARED_PROXY, + &gdev->descs[0].flags); + return 0; + } + } + } + + /* + * This is not a shared GPIO proxy but it still may be the device + * exposing shared pins. Find them and create the proxy devices. + */ list_for_each_entry(entry, &gpio_shared_list, list) { if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c59fe05c838e073b4bc99c4a7667cb1ff40c26b4..91e0c384f34ae5c0ed61ccd3a978685d4f72e867 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3997,6 +3997,26 @@ int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) } EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); +/** + * gpiod_is_shared() - check if this GPIO can be shared by multiple consumers + * @desc: GPIO to inspect + * + * Returns: + * True if this GPIO can be shared by multiple consumers at once. False if it's + * a regular, exclusive GPIO. + * + * Note: + * This function returning true does not mean that this GPIO is currently being + * shared. It means the GPIO core has registered the fact that the firmware + * configuration indicates that it can be shared by multiple consumers and is + * in charge of arbitrating the access. + */ +bool gpiod_is_shared(const struct gpio_desc *desc) +{ + return test_bit(GPIOD_FLAG_SHARED_PROXY, &desc->flags); +} +EXPORT_SYMBOL_GPL(gpiod_is_shared); + /** * gpiod_to_irq() - return the IRQ corresponding to a GPIO * @desc: gpio whose IRQ will be returned (already requested) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index c9de4bb10584206f4888c0f28468762a3680aae6..77f6f2936dc263a67b31a38799a841128a57603a 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -205,6 +205,7 @@ struct gpio_desc { #define GPIOD_FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */ #define GPIOD_FLAG_EVENT_CLOCK_HTE 19 /* GPIO CDEV reports hardware timestamps in events */ #define GPIOD_FLAG_SHARED 20 /* GPIO is shared by multiple consumers */ +#define GPIOD_FLAG_SHARED_PROXY 21 /* GPIO is a virtual proxy to a physically shared pin. */ /* Connection label */ struct gpio_desc_label __rcu *label; diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 994d46874d560416175c9099e18180237839bd4c..cafeb7a40ad1c25aeb7deaf598410d5f2f004a82 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -167,6 +167,8 @@ int gpiod_cansleep(const struct gpio_desc *desc); int gpiod_to_irq(const struct gpio_desc *desc); int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name); +bool gpiod_is_shared(const struct gpio_desc *desc); + /* Convert between the old gpio_ and new gpiod_ interfaces */ struct gpio_desc *gpio_to_desc(unsigned gpio); int desc_to_gpio(const struct gpio_desc *desc); @@ -522,6 +524,13 @@ static inline int gpiod_set_consumer_name(struct gpio_desc *desc, return -EINVAL; } +static inline bool gpiod_is_shared(const struct gpio_desc *desc) +{ + /* GPIO can never have been requested */ + WARN_ON(desc); + return false; +} + static inline struct gpio_desc *gpio_to_desc(unsigned gpio) { return NULL; -- 2.51.0
