diff options
| author | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2025-11-12 14:55:32 +0100 |
|---|---|---|
| committer | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2025-11-17 10:16:51 +0100 |
| commit | a060b8c511abb0997381b397e52149a5e3e5259a (patch) | |
| tree | ea03d4d2d25a860dedba9afe684d351fccbfb5a4 /drivers/gpio/gpiolib-shared.h | |
| parent | d4340ff75eaa083f261e16d49f13191236bfad06 (diff) | |
gpiolib: implement low-level, shared GPIO support
This module scans the device tree (for now only OF nodes are supported
but care is taken to make other fwnode implementations easy to
integrate) and determines which GPIO lines are shared by multiple users.
It stores that information in memory. When the GPIO chip exposing shared
lines is registered, the shared GPIO descriptors it exposes are marked
as shared and virtual "proxy" devices that mediate access to the shared
lines are created. When a consumer of a shared GPIO looks it up, its
fwnode lookup is redirected to a just-in-time machine lookup that points
to this proxy device.
This code can be compiled out on platforms which don't use shared GPIOs.
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20251112-gpio-shared-v4-3-b51f97b1abd8@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Diffstat (limited to 'drivers/gpio/gpiolib-shared.h')
| -rw-r--r-- | drivers/gpio/gpiolib-shared.h | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h new file mode 100644 index 000000000000..667dbdff3585 --- /dev/null +++ b/drivers/gpio/gpiolib-shared.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_GPIO_SHARED_H +#define __LINUX_GPIO_SHARED_H + +#include <linux/cleanup.h> +#include <linux/lockdep.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> + +struct gpio_device; +struct gpio_desc; +struct device; + +#if IS_ENABLED(CONFIG_GPIO_SHARED) + +int gpio_device_setup_shared(struct gpio_device *gdev); +void gpio_device_teardown_shared(struct gpio_device *gdev); +int gpio_shared_add_proxy_lookup(struct device *consumer, unsigned long lflags); + +#else + +static inline int gpio_device_setup_shared(struct gpio_device *gdev) +{ + return 0; +} + +static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { } + +static inline int gpio_shared_add_proxy_lookup(struct device *consumer, + unsigned long lflags) +{ + return 0; +} + +#endif /* CONFIG_GPIO_SHARED */ + +struct gpio_shared_desc { + struct gpio_desc *desc; + bool can_sleep; + unsigned long cfg; + unsigned int usecnt; + unsigned int highcnt; + union { + struct mutex mutex; + spinlock_t spinlock; + }; +}; + +struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev); + +DEFINE_LOCK_GUARD_1(gpio_shared_desc_lock, struct gpio_shared_desc, + if (_T->lock->can_sleep) + mutex_lock(&_T->lock->mutex); + else + spin_lock_irqsave(&_T->lock->spinlock, _T->flags), + if (_T->lock->can_sleep) + mutex_unlock(&_T->lock->mutex); + else + spin_unlock_irqrestore(&_T->lock->spinlock, _T->flags), + unsigned long flags) + +static inline void gpio_shared_lockdep_assert(struct gpio_shared_desc *shared_desc) +{ + if (shared_desc->can_sleep) + lockdep_assert_held(&shared_desc->mutex); + else + lockdep_assert_held(&shared_desc->spinlock); +} + +#endif /* __LINUX_GPIO_SHARED_H */ |
