Commit 372e722e authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Grant Likely

gpiolib: use descriptors internally

Make sure gpiolib works internally with descriptors and (chip, offset)
pairs instead of using the global integer namespace. This prepares the
ground for the removal of the global gpio_desc[] array and the
introduction of the descriptor-based GPIO API.
Signed-off-by: default avatarAlexandre Courbot <acourbot@nvidia.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
[grant.likely: Squash in fix for link error when CONFIG_SYSFS=n]
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent 83cabe33
...@@ -78,6 +78,28 @@ static LIST_HEAD(gpio_chips); ...@@ -78,6 +78,28 @@ static LIST_HEAD(gpio_chips);
static DEFINE_IDR(dirent_idr); static DEFINE_IDR(dirent_idr);
#endif #endif
/*
* Internal gpiod_* API using descriptors instead of the integer namespace.
* Most of this should eventually go public.
*/
static int gpiod_request(struct gpio_desc *desc, const char *label);
static void gpiod_free(struct gpio_desc *desc);
static int gpiod_direction_input(struct gpio_desc *desc);
static int gpiod_direction_output(struct gpio_desc *desc, int value);
static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
static int gpiod_get_value_cansleep(struct gpio_desc *desc);
static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
static int gpiod_get_value(struct gpio_desc *desc);
static void gpiod_set_value(struct gpio_desc *desc, int value);
static int gpiod_cansleep(struct gpio_desc *desc);
static int gpiod_to_irq(struct gpio_desc *desc);
static int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
static int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
static void gpiod_unexport(struct gpio_desc *desc);
static inline void desc_set_label(struct gpio_desc *d, const char *label) static inline void desc_set_label(struct gpio_desc *d, const char *label)
{ {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -85,6 +107,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) ...@@ -85,6 +107,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
#endif #endif
} }
/*
* Return the GPIO number of the passed descriptor relative to its chip
*/
static int gpio_chip_hwgpio(const struct gpio_desc *desc)
{
return (desc - &gpio_desc[0]) - desc->chip->base;
}
/**
* Convert a GPIO number to its descriptor
*/
static struct gpio_desc *gpio_to_desc(unsigned gpio)
{
if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
return NULL;
else
return &gpio_desc[gpio];
}
/**
* Convert a GPIO descriptor to the integer namespace.
* This should disappear in the future but is needed since we still
* use GPIO numbers for error messages and sysfs nodes
*/
static int desc_to_gpio(const struct gpio_desc *desc)
{
return desc - &gpio_desc[0];
}
/* Warn when drivers omit gpio_request() calls -- legal but ill-advised /* Warn when drivers omit gpio_request() calls -- legal but ill-advised
* when setting direction, and otherwise illegal. Until board setup code * when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when * and drivers use explicit requests everywhere (which won't happen when
...@@ -96,10 +148,10 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) ...@@ -96,10 +148,10 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
* only "legal" in the sense that (old) code using it won't break yet, * only "legal" in the sense that (old) code using it won't break yet,
* but instead only triggers a WARN() stack dump. * but instead only triggers a WARN() stack dump.
*/ */
static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) static int gpio_ensure_requested(struct gpio_desc *desc)
{ {
const struct gpio_chip *chip = desc->chip; const struct gpio_chip *chip = desc->chip;
const int gpio = chip->base + offset; const int gpio = desc_to_gpio(desc);
if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
"autorequest GPIO-%d\n", gpio)) { "autorequest GPIO-%d\n", gpio)) {
...@@ -118,9 +170,14 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) ...@@ -118,9 +170,14 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
} }
/* caller holds gpio_lock *OR* gpio is marked as requested */ /* caller holds gpio_lock *OR* gpio is marked as requested */
static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc)
{
return desc->chip;
}
struct gpio_chip *gpio_to_chip(unsigned gpio) struct gpio_chip *gpio_to_chip(unsigned gpio)
{ {
return gpio_desc[gpio].chip; return gpiod_to_chip(gpio_to_desc(gpio));
} }
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */ /* dynamic allocation of GPIOs, e.g. on a hotplugged device */
...@@ -148,19 +205,19 @@ static int gpiochip_find_base(int ngpio) ...@@ -148,19 +205,19 @@ static int gpiochip_find_base(int ngpio)
} }
/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ /* caller ensures gpio is valid and requested, chip->get_direction may sleep */
static int gpio_get_direction(unsigned gpio) static int gpiod_get_direction(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio]; unsigned offset;
int status = -EINVAL; int status = -EINVAL;
chip = gpio_to_chip(gpio); chip = gpiod_to_chip(desc);
gpio -= chip->base; offset = gpio_chip_hwgpio(desc);
if (!chip->get_direction) if (!chip->get_direction)
return status; return status;
status = chip->get_direction(chip, gpio); status = chip->get_direction(chip, offset);
if (status > 0) { if (status > 0) {
/* GPIOF_DIR_IN, or other positive */ /* GPIOF_DIR_IN, or other positive */
status = 1; status = 1;
...@@ -204,8 +261,7 @@ static DEFINE_MUTEX(sysfs_lock); ...@@ -204,8 +261,7 @@ static DEFINE_MUTEX(sysfs_lock);
static ssize_t gpio_direction_show(struct device *dev, static ssize_t gpio_direction_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -213,7 +269,7 @@ static ssize_t gpio_direction_show(struct device *dev, ...@@ -213,7 +269,7 @@ static ssize_t gpio_direction_show(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags)) { if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO; status = -EIO;
} else { } else {
gpio_get_direction(gpio); gpiod_get_direction(desc);
status = sprintf(buf, "%s\n", status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags) test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in"); ? "out" : "in");
...@@ -226,8 +282,7 @@ static ssize_t gpio_direction_show(struct device *dev, ...@@ -226,8 +282,7 @@ static ssize_t gpio_direction_show(struct device *dev,
static ssize_t gpio_direction_store(struct device *dev, static ssize_t gpio_direction_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size) struct device_attribute *attr, const char *buf, size_t size)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -235,11 +290,11 @@ static ssize_t gpio_direction_store(struct device *dev, ...@@ -235,11 +290,11 @@ static ssize_t gpio_direction_store(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags)) if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO; status = -EIO;
else if (sysfs_streq(buf, "high")) else if (sysfs_streq(buf, "high"))
status = gpio_direction_output(gpio, 1); status = gpiod_direction_output(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low")) else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
status = gpio_direction_output(gpio, 0); status = gpiod_direction_output(desc, 0);
else if (sysfs_streq(buf, "in")) else if (sysfs_streq(buf, "in"))
status = gpio_direction_input(gpio); status = gpiod_direction_input(desc);
else else
status = -EINVAL; status = -EINVAL;
...@@ -253,8 +308,7 @@ static /* const */ DEVICE_ATTR(direction, 0644, ...@@ -253,8 +308,7 @@ static /* const */ DEVICE_ATTR(direction, 0644,
static ssize_t gpio_value_show(struct device *dev, static ssize_t gpio_value_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -264,7 +318,7 @@ static ssize_t gpio_value_show(struct device *dev, ...@@ -264,7 +318,7 @@ static ssize_t gpio_value_show(struct device *dev,
} else { } else {
int value; int value;
value = !!gpio_get_value_cansleep(gpio); value = !!gpiod_get_value_cansleep(desc);
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
...@@ -278,8 +332,7 @@ static ssize_t gpio_value_show(struct device *dev, ...@@ -278,8 +332,7 @@ static ssize_t gpio_value_show(struct device *dev,
static ssize_t gpio_value_store(struct device *dev, static ssize_t gpio_value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size) struct device_attribute *attr, const char *buf, size_t size)
{ {
const struct gpio_desc *desc = dev_get_drvdata(dev); struct gpio_desc *desc = dev_get_drvdata(dev);
unsigned gpio = desc - gpio_desc;
ssize_t status; ssize_t status;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
...@@ -295,7 +348,7 @@ static ssize_t gpio_value_store(struct device *dev, ...@@ -295,7 +348,7 @@ static ssize_t gpio_value_store(struct device *dev,
if (status == 0) { if (status == 0) {
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
value = !value; value = !value;
gpio_set_value_cansleep(gpio, value != 0); gpiod_set_value_cansleep(desc, value != 0);
status = size; status = size;
} }
} }
...@@ -325,7 +378,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, ...@@ -325,7 +378,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags) if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
return 0; return 0;
irq = gpio_to_irq(desc - gpio_desc); irq = gpiod_to_irq(desc);
if (irq < 0) if (irq < 0)
return -EIO; return -EIO;
...@@ -596,28 +649,31 @@ static ssize_t export_store(struct class *class, ...@@ -596,28 +649,31 @@ static ssize_t export_store(struct class *class,
const char *buf, size_t len) const char *buf, size_t len)
{ {
long gpio; long gpio;
struct gpio_desc *desc;
int status; int status;
status = strict_strtol(buf, 0, &gpio); status = strict_strtol(buf, 0, &gpio);
if (status < 0) if (status < 0)
goto done; goto done;
desc = gpio_to_desc(gpio);
/* No extra locking here; FLAG_SYSFS just signifies that the /* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so * request and export were done by on behalf of userspace, so
* they may be undone on its behalf too. * they may be undone on its behalf too.
*/ */
status = gpio_request(gpio, "sysfs"); status = gpiod_request(desc, "sysfs");
if (status < 0) { if (status < 0) {
if (status == -EPROBE_DEFER) if (status == -EPROBE_DEFER)
status = -ENODEV; status = -ENODEV;
goto done; goto done;
} }
status = gpio_export(gpio, true); status = gpiod_export(desc, true);
if (status < 0) if (status < 0)
gpio_free(gpio); gpiod_free(desc);
else else
set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags); set_bit(FLAG_SYSFS, &desc->flags);
done: done:
if (status) if (status)
...@@ -630,6 +686,7 @@ static ssize_t unexport_store(struct class *class, ...@@ -630,6 +686,7 @@ static ssize_t unexport_store(struct class *class,
const char *buf, size_t len) const char *buf, size_t len)
{ {
long gpio; long gpio;
struct gpio_desc *desc;
int status; int status;
status = strict_strtol(buf, 0, &gpio); status = strict_strtol(buf, 0, &gpio);
...@@ -638,17 +695,18 @@ static ssize_t unexport_store(struct class *class, ...@@ -638,17 +695,18 @@ static ssize_t unexport_store(struct class *class,
status = -EINVAL; status = -EINVAL;
desc = gpio_to_desc(gpio);
/* reject bogus commands (gpio_unexport ignores them) */ /* reject bogus commands (gpio_unexport ignores them) */
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
/* No extra locking here; FLAG_SYSFS just signifies that the /* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so * request and export were done by on behalf of userspace, so
* they may be undone on its behalf too. * they may be undone on its behalf too.
*/ */
if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) { if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
status = 0; status = 0;
gpio_free(gpio); gpiod_free(desc);
} }
done: done:
if (status) if (status)
...@@ -685,13 +743,13 @@ static struct class gpio_class = { ...@@ -685,13 +743,13 @@ static struct class gpio_class = {
* *
* Returns zero on success, else an error. * Returns zero on success, else an error.
*/ */
int gpio_export(unsigned gpio, bool direction_may_change) static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{ {
unsigned long flags; unsigned long flags;
struct gpio_desc *desc;
int status; int status;
const char *ioname = NULL; const char *ioname = NULL;
struct device *dev; struct device *dev;
int offset;
/* can't export until sysfs is available ... */ /* can't export until sysfs is available ... */
if (!gpio_class.p) { if (!gpio_class.p) {
...@@ -699,20 +757,19 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -699,20 +757,19 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -ENOENT; return -ENOENT;
} }
if (!gpio_is_valid(gpio)) { if (!desc) {
pr_debug("%s: gpio %d is not valid\n", __func__, gpio); pr_debug("%s: invalid gpio descriptor\n", __func__);
return -EINVAL; return -EINVAL;
} }
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
if (!test_bit(FLAG_REQUESTED, &desc->flags) || if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags)) { test_bit(FLAG_EXPORT, &desc->flags)) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n",
__func__, gpio, __func__, desc_to_gpio(desc),
test_bit(FLAG_REQUESTED, &desc->flags), test_bit(FLAG_REQUESTED, &desc->flags),
test_bit(FLAG_EXPORT, &desc->flags)); test_bit(FLAG_EXPORT, &desc->flags));
status = -EPERM; status = -EPERM;
...@@ -723,11 +780,13 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -723,11 +780,13 @@ int gpio_export(unsigned gpio, bool direction_may_change)
direction_may_change = false; direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) offset = gpio_chip_hwgpio(desc);
ioname = desc->chip->names[gpio - desc->chip->base]; if (desc->chip->names && desc->chip->names[offset])
ioname = desc->chip->names[offset];
dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
desc, ioname ? ioname : "gpio%u", gpio); desc, ioname ? ioname : "gpio%u",
desc_to_gpio(desc));
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
status = PTR_ERR(dev); status = PTR_ERR(dev);
goto fail_unlock; goto fail_unlock;
...@@ -743,7 +802,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -743,7 +802,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
goto fail_unregister_device; goto fail_unregister_device;
} }
if (gpio_to_irq(gpio) >= 0 && (direction_may_change || if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
!test_bit(FLAG_IS_OUT, &desc->flags))) { !test_bit(FLAG_IS_OUT, &desc->flags))) {
status = device_create_file(dev, &dev_attr_edge); status = device_create_file(dev, &dev_attr_edge);
if (status) if (status)
...@@ -758,9 +817,15 @@ int gpio_export(unsigned gpio, bool direction_may_change) ...@@ -758,9 +817,15 @@ int gpio_export(unsigned gpio, bool direction_may_change)
device_unregister(dev); device_unregister(dev);
fail_unlock: fail_unlock:
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
status);
return status; return status;
} }
int gpio_export(unsigned gpio, bool direction_may_change)
{
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
EXPORT_SYMBOL_GPL(gpio_export); EXPORT_SYMBOL_GPL(gpio_export);
static int match_export(struct device *dev, void *data) static int match_export(struct device *dev, void *data)
...@@ -779,18 +844,16 @@ static int match_export(struct device *dev, void *data) ...@@ -779,18 +844,16 @@ static int match_export(struct device *dev, void *data)
* *
* Returns zero on success, else an error. * Returns zero on success, else an error.
*/ */
int gpio_export_link(struct device *dev, const char *name, unsigned gpio) static int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc)
{ {
struct gpio_desc *desc;
int status = -EINVAL; int status = -EINVAL;
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
struct device *tdev; struct device *tdev;
...@@ -807,12 +870,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) ...@@ -807,12 +870,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
done: done:
if (status) if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
status);
return status; return status;
} }
EXPORT_SYMBOL_GPL(gpio_export_link);
int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
{
return gpiod_export_link(dev, name, gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_export_link);
/** /**
* gpio_sysfs_set_active_low - set the polarity of gpio sysfs value * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value
...@@ -826,19 +894,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link); ...@@ -826,19 +894,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link);
* *
* Returns zero on success, else an error. * Returns zero on success, else an error.
*/ */
int gpio_sysfs_set_active_low(unsigned gpio, int value) static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
{ {
struct gpio_desc *desc;
struct device *dev = NULL; struct device *dev = NULL;
int status = -EINVAL; int status = -EINVAL;
if (!gpio_is_valid(gpio)) if (!desc)
goto done; goto done;
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export); dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev == NULL) { if (dev == NULL) {
...@@ -854,10 +919,16 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value) ...@@ -854,10 +919,16 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value)
done: done:
if (status) if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
status);
return status; return status;
} }
int gpio_sysfs_set_active_low(unsigned gpio, int value)
{
return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value);
}
EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
/** /**
...@@ -866,21 +937,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low); ...@@ -866,21 +937,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
* *
* This is implicit on gpio_free(). * This is implicit on gpio_free().
*/ */
void gpio_unexport(unsigned gpio) static void gpiod_unexport(struct gpio_desc *desc)
{ {
struct gpio_desc *desc;
int status = 0; int status = 0;
struct device *dev = NULL; struct device *dev = NULL;
if (!gpio_is_valid(gpio)) { if (!desc) {
status = -EINVAL; status = -EINVAL;
goto done; goto done;
} }
mutex_lock(&sysfs_lock); mutex_lock(&sysfs_lock);
desc = &gpio_desc[gpio];
if (test_bit(FLAG_EXPORT, &desc->flags)) { if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export); dev = class_find_device(&gpio_class, NULL, desc, match_export);
...@@ -892,13 +960,20 @@ void gpio_unexport(unsigned gpio) ...@@ -892,13 +960,20 @@ void gpio_unexport(unsigned gpio)
} }
mutex_unlock(&sysfs_lock); mutex_unlock(&sysfs_lock);
if (dev) { if (dev) {
device_unregister(dev); device_unregister(dev);
put_device(dev); put_device(dev);
} }
done: done:
if (status) if (status)
pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
status);
}
void gpio_unexport(unsigned gpio)
{
gpiod_unexport(gpio_to_desc(gpio));
} }
EXPORT_SYMBOL_GPL(gpio_unexport); EXPORT_SYMBOL_GPL(gpio_unexport);
...@@ -1007,6 +1082,27 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) ...@@ -1007,6 +1082,27 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
{ {
} }
static inline int gpiod_export(struct gpio_desc *desc,
bool direction_may_change)
{
return -ENOSYS;
}
static inline int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc)
{
return -ENOSYS;
}
static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
{
return -ENOSYS;
}
static inline void gpiod_unexport(struct gpio_desc *desc)
{
}
#endif /* CONFIG_GPIO_SYSFS */ #endif /* CONFIG_GPIO_SYSFS */
/* /*
...@@ -1282,20 +1378,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); ...@@ -1282,20 +1378,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
* on each other, and help provide better diagnostics in debugfs. * on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls. * They're called even less than the "set direction" calls.
*/ */
int gpio_request(unsigned gpio, const char *label) static int gpiod_request(struct gpio_desc *desc, const char *label)
{ {
struct gpio_desc *desc;
struct gpio_chip *chip; struct gpio_chip *chip;
int status = -EPROBE_DEFER; int status = -EPROBE_DEFER;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) { if (!desc) {
status = -EINVAL; status = -EINVAL;
goto done; goto done;
} }
desc = &gpio_desc[gpio];
chip = desc->chip; chip = desc->chip;
if (chip == NULL) if (chip == NULL)
goto done; goto done;
...@@ -1319,7 +1413,7 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -1319,7 +1413,7 @@ int gpio_request(unsigned gpio, const char *label)
if (chip->request) { if (chip->request) {
/* chip->request may sleep */ /* chip->request may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
status = chip->request(chip, gpio - chip->base); status = chip->request(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (status < 0) { if (status < 0) {
...@@ -1332,42 +1426,46 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -1332,42 +1426,46 @@ int gpio_request(unsigned gpio, const char *label)
if (chip->get_direction) { if (chip->get_direction) {
/* chip->get_direction may sleep */ /* chip->get_direction may sleep */
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
gpio_get_direction(gpio); gpiod_get_direction(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
done: done:
if (status) if (status)
pr_debug("gpio_request: gpio-%d (%s) status %d\n", pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
gpio, label ? : "?", status); desc ? desc_to_gpio(desc) : -1,
label ? : "?", status);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
return status; return status;
} }
int gpio_request(unsigned gpio, const char *label)
{
return gpiod_request(gpio_to_desc(gpio), label);
}
EXPORT_SYMBOL_GPL(gpio_request); EXPORT_SYMBOL_GPL(gpio_request);
void gpio_free(unsigned gpio) static void gpiod_free(struct gpio_desc *desc)
{ {
unsigned long flags; unsigned long flags;
struct gpio_desc *desc;
struct gpio_chip *chip; struct gpio_chip *chip;
might_sleep(); might_sleep();
if (!gpio_is_valid(gpio)) { if (!desc) {
WARN_ON(extra_checks); WARN_ON(extra_checks);
return; return;
} }
gpio_unexport(gpio); gpiod_unexport(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
chip = desc->chip; chip = desc->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) { if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
if (chip->free) { if (chip->free) {
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
chip->free(chip, gpio - chip->base); chip->free(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
} }
desc_set_label(desc, NULL); desc_set_label(desc, NULL);
...@@ -1381,6 +1479,11 @@ void gpio_free(unsigned gpio) ...@@ -1381,6 +1479,11 @@ void gpio_free(unsigned gpio)
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
} }
void gpio_free(unsigned gpio)
{
gpiod_free(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_free); EXPORT_SYMBOL_GPL(gpio_free);
/** /**
...@@ -1391,29 +1494,32 @@ EXPORT_SYMBOL_GPL(gpio_free); ...@@ -1391,29 +1494,32 @@ EXPORT_SYMBOL_GPL(gpio_free);
*/ */
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
{ {
struct gpio_desc *desc;
int err; int err;
err = gpio_request(gpio, label); desc = gpio_to_desc(gpio);
err = gpiod_request(desc, label);
if (err) if (err)
return err; return err;
if (flags & GPIOF_OPEN_DRAIN) if (flags & GPIOF_OPEN_DRAIN)
set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags); set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (flags & GPIOF_OPEN_SOURCE) if (flags & GPIOF_OPEN_SOURCE)
set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags); set_bit(FLAG_OPEN_SOURCE, &desc->flags);
if (flags & GPIOF_DIR_IN) if (flags & GPIOF_DIR_IN)
err = gpio_direction_input(gpio); err = gpiod_direction_input(desc);
else else
err = gpio_direction_output(gpio, err = gpiod_direction_output(desc,
(flags & GPIOF_INIT_HIGH) ? 1 : 0); (flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err) if (err)
goto free_gpio; goto free_gpio;
if (flags & GPIOF_EXPORT) { if (flags & GPIOF_EXPORT) {
err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE); err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
if (err) if (err)
goto free_gpio; goto free_gpio;
} }
...@@ -1421,7 +1527,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) ...@@ -1421,7 +1527,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
return 0; return 0;
free_gpio: free_gpio:
gpio_free(gpio); gpiod_free(desc);
return err; return err;
} }
EXPORT_SYMBOL_GPL(gpio_request_one); EXPORT_SYMBOL_GPL(gpio_request_one);
...@@ -1477,13 +1583,14 @@ EXPORT_SYMBOL_GPL(gpio_free_array); ...@@ -1477,13 +1583,14 @@ EXPORT_SYMBOL_GPL(gpio_free_array);
const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset) const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
{ {
unsigned gpio = chip->base + offset; unsigned gpio = chip->base + offset;
struct gpio_desc *desc = &gpio_desc[gpio];
if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip) if (!gpio_is_valid(gpio) || desc->chip != chip)
return NULL; return NULL;
if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0) if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
return NULL; return NULL;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
return gpio_desc[gpio].label; return desc->label;
#else #else
return "?"; return "?";
#endif #endif
...@@ -1500,24 +1607,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); ...@@ -1500,24 +1607,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* rely on gpio_request() having been called beforehand. * rely on gpio_request() having been called beforehand.
*/ */
int gpio_direction_input(unsigned gpio) static int gpiod_direction_input(struct gpio_desc *desc)
{ {
unsigned long flags; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->get || !chip->direction_input) if (!chip || !chip->get || !chip->direction_input)
goto fail; goto fail;
gpio -= chip->base; status = gpio_ensure_requested(desc);
if (gpio >= chip->ngpio)
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1527,11 +1631,12 @@ int gpio_direction_input(unsigned gpio) ...@@ -1527,11 +1631,12 @@ int gpio_direction_input(unsigned gpio)
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
offset = gpio_chip_hwgpio(desc);
if (status) { if (status) {
status = chip->request(chip, gpio); status = chip->request(chip, offset);
if (status < 0) { if (status < 0) {
pr_debug("GPIO-%d: chip request fail, %d\n", pr_debug("GPIO-%d: chip request fail, %d\n",
chip->base + gpio, status); desc_to_gpio(desc), status);
/* and it's not available to anyone else ... /* and it's not available to anyone else ...
* gpio_request() is the fully clean solution. * gpio_request() is the fully clean solution.
*/ */
...@@ -1539,48 +1644,54 @@ int gpio_direction_input(unsigned gpio) ...@@ -1539,48 +1644,54 @@ int gpio_direction_input(unsigned gpio)
} }
} }
status = chip->direction_input(chip, gpio); status = chip->direction_input(chip, offset);
if (status == 0) if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags); clear_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_direction(chip->base + gpio, 1, status); trace_gpio_direction(desc_to_gpio(desc), 1, status);
lose: lose:
return status; return status;
fail: fail:
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (status) if (status) {
int gpio = -1;
if (desc)
gpio = desc_to_gpio(desc);
pr_debug("%s: gpio-%d status %d\n", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return status; return status;
} }
int gpio_direction_input(unsigned gpio)
{
return gpiod_direction_input(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_direction_input); EXPORT_SYMBOL_GPL(gpio_direction_input);
int gpio_direction_output(unsigned gpio, int value) static int gpiod_direction_output(struct gpio_desc *desc, int value)
{ {
unsigned long flags; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
/* Open drain pin should not be driven to 1 */ /* Open drain pin should not be driven to 1 */
if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags)) if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
return gpio_direction_input(gpio); return gpiod_direction_input(desc);
/* Open source pin should not be driven to 0 */ /* Open source pin should not be driven to 0 */
if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags)) if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
return gpio_direction_input(gpio); return gpiod_direction_input(desc);
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->set || !chip->direction_output) if (!chip || !chip->set || !chip->direction_output)
goto fail; goto fail;
gpio -= chip->base; status = gpio_ensure_requested(desc);
if (gpio >= chip->ngpio)
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1590,11 +1701,12 @@ int gpio_direction_output(unsigned gpio, int value) ...@@ -1590,11 +1701,12 @@ int gpio_direction_output(unsigned gpio, int value)
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
offset = gpio_chip_hwgpio(desc);
if (status) { if (status) {
status = chip->request(chip, gpio); status = chip->request(chip, offset);
if (status < 0) { if (status < 0) {
pr_debug("GPIO-%d: chip request fail, %d\n", pr_debug("GPIO-%d: chip request fail, %d\n",
chip->base + gpio, status); desc_to_gpio(desc), status);
/* and it's not available to anyone else ... /* and it's not available to anyone else ...
* gpio_request() is the fully clean solution. * gpio_request() is the fully clean solution.
*/ */
...@@ -1602,20 +1714,29 @@ int gpio_direction_output(unsigned gpio, int value) ...@@ -1602,20 +1714,29 @@ int gpio_direction_output(unsigned gpio, int value)
} }
} }
status = chip->direction_output(chip, gpio, value); status = chip->direction_output(chip, offset, value);
if (status == 0) if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags); set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(chip->base + gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
trace_gpio_direction(chip->base + gpio, 0, status); trace_gpio_direction(desc_to_gpio(desc), 0, status);
lose: lose:
return status; return status;
fail: fail:
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (status) if (status) {
int gpio = -1;
if (desc)
gpio = desc_to_gpio(desc);
pr_debug("%s: gpio-%d status %d\n", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return status; return status;
} }
int gpio_direction_output(unsigned gpio, int value)
{
return gpiod_direction_output(gpio_to_desc(gpio), value);
}
EXPORT_SYMBOL_GPL(gpio_direction_output); EXPORT_SYMBOL_GPL(gpio_direction_output);
/** /**
...@@ -1623,24 +1744,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output); ...@@ -1623,24 +1744,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output);
* @gpio: the gpio to set debounce time * @gpio: the gpio to set debounce time
* @debounce: debounce time is microseconds * @debounce: debounce time is microseconds
*/ */
int gpio_set_debounce(unsigned gpio, unsigned debounce) static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{ {
unsigned long flags; unsigned long flags;
struct gpio_chip *chip; struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL; int status = -EINVAL;
int offset;
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio)) if (!desc)
goto fail; goto fail;
chip = desc->chip; chip = desc->chip;
if (!chip || !chip->set || !chip->set_debounce) if (!chip || !chip->set || !chip->set_debounce)
goto fail; goto fail;
gpio -= chip->base;
if (gpio >= chip->ngpio) status = gpio_ensure_requested(desc);
goto fail;
status = gpio_ensure_requested(desc, gpio);
if (status < 0) if (status < 0)
goto fail; goto fail;
...@@ -1650,16 +1769,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce) ...@@ -1650,16 +1769,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
might_sleep_if(chip->can_sleep); might_sleep_if(chip->can_sleep);
return chip->set_debounce(chip, gpio, debounce); offset = gpio_chip_hwgpio(desc);
return chip->set_debounce(chip, offset, debounce);
fail: fail:
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
if (status) if (status) {
int gpio = -1;
if (desc)
gpio = desc_to_gpio(desc);
pr_debug("%s: gpio-%d status %d\n", pr_debug("%s: gpio-%d status %d\n",
__func__, gpio, status); __func__, gpio, status);
}
return status; return status;
} }
int gpio_set_debounce(unsigned gpio, unsigned debounce)
{
return gpiod_set_debounce(gpio_to_desc(gpio), debounce);
}
EXPORT_SYMBOL_GPL(gpio_set_debounce); EXPORT_SYMBOL_GPL(gpio_set_debounce);
/* I/O calls are only valid after configuration completed; the relevant /* I/O calls are only valid after configuration completed; the relevant
...@@ -1693,18 +1822,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce); ...@@ -1693,18 +1822,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
* It returns the zero or nonzero value provided by the associated * It returns the zero or nonzero value provided by the associated
* gpio_chip.get() method; or zero if no such method is provided. * gpio_chip.get() method; or zero if no such method is provided.
*/ */
int __gpio_get_value(unsigned gpio) static int gpiod_get_value(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
int value; int value;
int offset;
chip = gpio_to_chip(gpio); chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
/* Should be using gpio_get_value_cansleep() */ /* Should be using gpio_get_value_cansleep() */
WARN_ON(chip->can_sleep); WARN_ON(chip->can_sleep);
value = chip->get ? chip->get(chip, gpio - chip->base) : 0; value = chip->get ? chip->get(chip, offset) : 0;
trace_gpio_value(gpio, 1, value); trace_gpio_value(desc_to_gpio(desc), 1, value);
return value; return value;
} }
int __gpio_get_value(unsigned gpio)
{
return gpiod_get_value(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(__gpio_get_value); EXPORT_SYMBOL_GPL(__gpio_get_value);
/* /*
...@@ -1713,23 +1849,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value); ...@@ -1713,23 +1849,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value);
* @chip: Gpio chip. * @chip: Gpio chip.
* @value: Non-zero for setting it HIGH otherise it will set to LOW. * @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/ */
static void _gpio_set_open_drain_value(unsigned gpio, static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
struct gpio_chip *chip, int value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip;
int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
err = chip->direction_input(chip, gpio - chip->base); err = chip->direction_input(chip, offset);
if (!err) if (!err)
clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); clear_bit(FLAG_IS_OUT, &desc->flags);
} else { } else {
err = chip->direction_output(chip, gpio - chip->base, 0); err = chip->direction_output(chip, offset, 0);
if (!err) if (!err)
set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); set_bit(FLAG_IS_OUT, &desc->flags);
} }
trace_gpio_direction(gpio, value, err); trace_gpio_direction(desc_to_gpio(desc), value, err);
if (err < 0) if (err < 0)
pr_err("%s: Error in set_value for open drain gpio%d err %d\n", pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
__func__, gpio, err); __func__, desc_to_gpio(desc), err);
} }
/* /*
...@@ -1738,26 +1876,27 @@ static void _gpio_set_open_drain_value(unsigned gpio, ...@@ -1738,26 +1876,27 @@ static void _gpio_set_open_drain_value(unsigned gpio,
* @chip: Gpio chip. * @chip: Gpio chip.
* @value: Non-zero for setting it HIGH otherise it will set to LOW. * @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/ */
static void _gpio_set_open_source_value(unsigned gpio, static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
struct gpio_chip *chip, int value)
{ {
int err = 0; int err = 0;
struct gpio_chip *chip = desc->chip;
int offset = gpio_chip_hwgpio(desc);
if (value) { if (value) {
err = chip->direction_output(chip, gpio - chip->base, 1); err = chip->direction_output(chip, offset, 1);
if (!err) if (!err)
set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); set_bit(FLAG_IS_OUT, &desc->flags);
} else { } else {
err = chip->direction_input(chip, gpio - chip->base); err = chip->direction_input(chip, offset);
if (!err) if (!err)
clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags); clear_bit(FLAG_IS_OUT, &desc->flags);
} }
trace_gpio_direction(gpio, !value, err); trace_gpio_direction(desc_to_gpio(desc), !value, err);
if (err < 0) if (err < 0)
pr_err("%s: Error in set_value for open source gpio%d err %d\n", pr_err("%s: Error in set_value for open source gpio%d err %d\n",
__func__, gpio, err); __func__, desc_to_gpio(desc), err);
} }
/** /**
* __gpio_set_value() - assign a gpio's value * __gpio_set_value() - assign a gpio's value
* @gpio: gpio whose value will be assigned * @gpio: gpio whose value will be assigned
...@@ -1767,20 +1906,25 @@ static void _gpio_set_open_source_value(unsigned gpio, ...@@ -1767,20 +1906,25 @@ static void _gpio_set_open_source_value(unsigned gpio,
* This is used directly or indirectly to implement gpio_set_value(). * This is used directly or indirectly to implement gpio_set_value().
* It invokes the associated gpio_chip.set() method. * It invokes the associated gpio_chip.set() method.
*/ */
void __gpio_set_value(unsigned gpio, int value) static void gpiod_set_value(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
chip = gpio_to_chip(gpio); chip = desc->chip;
/* Should be using gpio_set_value_cansleep() */ /* Should be using gpio_set_value_cansleep() */
WARN_ON(chip->can_sleep); WARN_ON(chip->can_sleep);
trace_gpio_value(gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(gpio, chip, value); _gpio_set_open_drain_value(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
_gpio_set_open_source_value(gpio, chip, value); _gpio_set_open_source_value(desc, value);
else else
chip->set(chip, gpio - chip->base, value); chip->set(chip, gpio_chip_hwgpio(desc), value);
}
void __gpio_set_value(unsigned gpio, int value)
{
return gpiod_set_value(gpio_to_desc(gpio), value);
} }
EXPORT_SYMBOL_GPL(__gpio_set_value); EXPORT_SYMBOL_GPL(__gpio_set_value);
...@@ -1792,14 +1936,15 @@ EXPORT_SYMBOL_GPL(__gpio_set_value); ...@@ -1792,14 +1936,15 @@ EXPORT_SYMBOL_GPL(__gpio_set_value);
* This is used directly or indirectly to implement gpio_cansleep(). It * This is used directly or indirectly to implement gpio_cansleep(). It
* returns nonzero if access reading or writing the GPIO value can sleep. * returns nonzero if access reading or writing the GPIO value can sleep.
*/ */
int __gpio_cansleep(unsigned gpio) static int gpiod_cansleep(struct gpio_desc *desc)
{ {
struct gpio_chip *chip;
/* only call this on GPIOs that are valid! */ /* only call this on GPIOs that are valid! */
chip = gpio_to_chip(gpio); return desc->chip->can_sleep;
}
return chip->can_sleep; int __gpio_cansleep(unsigned gpio)
{
return gpiod_cansleep(gpio_to_desc(gpio));
} }
EXPORT_SYMBOL_GPL(__gpio_cansleep); EXPORT_SYMBOL_GPL(__gpio_cansleep);
...@@ -1812,50 +1957,67 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep); ...@@ -1812,50 +1957,67 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep);
* It returns the number of the IRQ signaled by this (input) GPIO, * It returns the number of the IRQ signaled by this (input) GPIO,
* or a negative errno. * or a negative errno.
*/ */
int __gpio_to_irq(unsigned gpio) static int gpiod_to_irq(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
int offset;
chip = gpio_to_chip(gpio); chip = desc->chip;
return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; offset = gpio_chip_hwgpio(desc);
return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
} }
EXPORT_SYMBOL_GPL(__gpio_to_irq);
int __gpio_to_irq(unsigned gpio)
{
return gpiod_to_irq(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(__gpio_to_irq);
/* There's no value in making it easy to inline GPIO calls that may sleep. /* There's no value in making it easy to inline GPIO calls that may sleep.
* Common examples include ones connected to I2C or SPI chips. * Common examples include ones connected to I2C or SPI chips.
*/ */
int gpio_get_value_cansleep(unsigned gpio) static int gpiod_get_value_cansleep(struct gpio_desc *desc)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
int value; int value;
int offset;
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio); chip = desc->chip;
value = chip->get ? chip->get(chip, gpio - chip->base) : 0; offset = gpio_chip_hwgpio(desc);
trace_gpio_value(gpio, 1, value); value = chip->get ? chip->get(chip, offset) : 0;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value; return value;
} }
int gpio_get_value_cansleep(unsigned gpio)
{
return gpiod_get_value_cansleep(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_get_value_cansleep); EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
void gpio_set_value_cansleep(unsigned gpio, int value) static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
{ {
struct gpio_chip *chip; struct gpio_chip *chip;
might_sleep_if(extra_checks); might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio); chip = desc->chip;
trace_gpio_value(gpio, 0, value); trace_gpio_value(desc_to_gpio(desc), 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags)) if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
_gpio_set_open_drain_value(gpio, chip, value); _gpio_set_open_drain_value(desc, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags)) else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
_gpio_set_open_source_value(gpio, chip, value); _gpio_set_open_source_value(desc, value);
else else
chip->set(chip, gpio - chip->base, value); chip->set(chip, gpio_chip_hwgpio(desc), value);
} }
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
void gpio_set_value_cansleep(unsigned gpio, int value)
{
return gpiod_set_value_cansleep(gpio_to_desc(gpio), value);
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -1870,7 +2032,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) ...@@ -1870,7 +2032,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue; continue;
gpio_get_direction(gpio); gpiod_get_direction(gdesc);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
gpio, gdesc->label, gpio, gdesc->label,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment