mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
Shared GPIOs may be assigned to child nodes of device nodes which don't
themselves bind to any struct device. We need to pass the firmware node
that is the actual consumer to gpiolib-shared and compare against it
instead of unconditionally using the fwnode of the consumer device.
Fixes: a060b8c511 ("gpiolib: implement low-level, shared GPIO support")
Reported-by: Jon Hunter <jonathanh@nvidia.com>
Closes: https://lore.kernel.org/all/921ba8ce-b18e-4a99-966d-c763d22081e2@nvidia.com/
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260318-gpio-shared-xlate-v2-2-0ce34c707e81@oss.qualcomm.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
77 lines
1.8 KiB
C
77 lines
1.8 KiB
C
/* 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;
|
|
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;
|
|
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 */
|