gpio / ACPI: Move event handling registration to gpiolib irqchip helpers
[cascardo/linux.git] / drivers / gpio / gpiolib.c
index d9c9cb4..3302275 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
 
 #include "gpiolib.h"
 
  * While any GPIO is requested, its gpio_chip is not removable;
  * each GPIO's "requested" flag serves as a lock and refcount.
  */
-static DEFINE_SPINLOCK(gpio_lock);
+DEFINE_SPINLOCK(gpio_lock);
 
-struct gpio_desc {
-       struct gpio_chip        *chip;
-       unsigned long           flags;
-/* flag symbols are bit numbers */
-#define FLAG_REQUESTED 0
-#define FLAG_IS_OUT    1
-#define FLAG_EXPORT    2       /* protected by sysfs_lock */
-#define FLAG_SYSFS     3       /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 4       /* trigger on falling edge */
-#define FLAG_TRIG_RISE 5       /* trigger on rising edge */
-#define FLAG_ACTIVE_LOW        6       /* value has active low */
-#define FLAG_OPEN_DRAIN        7       /* Gpio is open drain type */
-#define FLAG_OPEN_SOURCE 8     /* Gpio is open source type */
-#define FLAG_USED_AS_IRQ 9     /* GPIO is connected to an IRQ */
-
-#define ID_SHIFT       16      /* add new flags before this one */
-
-#define GPIO_FLAGS_MASK                ((1 << ID_SHIFT) - 1)
-#define GPIO_TRIGGER_MASK      (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
-
-#ifdef CONFIG_DEBUG_FS
-       const char              *label;
-#endif
-};
 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
 
 #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
 
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
-static LIST_HEAD(gpio_chips);
-
-#ifdef CONFIG_GPIO_SYSFS
-static DEFINE_IDR(dirent_idr);
-#endif
-
-static int gpiod_request(struct gpio_desc *desc, const char *label);
-static void gpiod_free(struct gpio_desc *desc);
-
-/* With descriptor prefix */
-
-#ifdef CONFIG_DEBUG_FS
-#define gpiod_emerg(desc, fmt, ...)                                           \
-       pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
-                 ##__VA_ARGS__)
-#define gpiod_crit(desc, fmt, ...)                                            \
-       pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
-                 ##__VA_ARGS__)
-#define gpiod_err(desc, fmt, ...)                                             \
-       pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",  \
-                 ##__VA_ARGS__)
-#define gpiod_warn(desc, fmt, ...)                                            \
-       pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
-                 ##__VA_ARGS__)
-#define gpiod_info(desc, fmt, ...)                                            \
-       pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
-                ##__VA_ARGS__)
-#define gpiod_dbg(desc, fmt, ...)                                             \
-       pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
-                 ##__VA_ARGS__)
-#else
-#define gpiod_emerg(desc, fmt, ...)                                    \
-       pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_crit(desc, fmt, ...)                                     \
-       pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_err(desc, fmt, ...)                                      \
-       pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_warn(desc, fmt, ...)                                     \
-       pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_info(desc, fmt, ...)                                     \
-       pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#define gpiod_dbg(desc, fmt, ...)                                      \
-       pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
-#endif
-
-/* With chip prefix */
-
-#define chip_emerg(chip, fmt, ...)                                     \
-       pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_crit(chip, fmt, ...)                                      \
-       pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_err(chip, fmt, ...)                                       \
-       pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_warn(chip, fmt, ...)                                      \
-       pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_info(chip, fmt, ...)                                      \
-       pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-#define chip_dbg(chip, fmt, ...)                                       \
-       pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
-
-static inline void desc_set_label(struct gpio_desc *d, const char *label)
-{
-#ifdef CONFIG_DEBUG_FS
-       d->label = label;
-#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 - &desc->chip->desc[0];
-}
-
-/**
- * Convert a GPIO number to its descriptor
- */
-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];
-}
-EXPORT_SYMBOL_GPL(gpio_to_desc);
-
-/**
- * Get the GPIO descriptor corresponding to the given hw number for this chip.
- */
-struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
-                                   u16 hwnum)
-{
-       if (hwnum >= chip->ngpio)
-               return ERR_PTR(-EINVAL);
-
-       return &chip->desc[hwnum];
-}
-EXPORT_SYMBOL_GPL(gpiochip_get_desc);
-
-/**
- * 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
- */
-int desc_to_gpio(const struct gpio_desc *desc)
-{
-       return desc - &gpio_desc[0];
-}
-EXPORT_SYMBOL_GPL(desc_to_gpio);
-
-
-/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
- * when setting direction, and otherwise illegal.  Until board setup code
- * and drivers use explicit requests everywhere (which won't happen when
- * those calls have no teeth) we can't avoid autorequesting.  This nag
- * message should motivate switching to explicit requests... so should
- * the weaker cleanup after faults, compared to gpio_request().
- *
- * NOTE: the autorequest mechanism is going away; at this point it's
- * only "legal" in the sense that (old) code using it won't break yet,
- * but instead only triggers a WARN() stack dump.
- */
-static int gpio_ensure_requested(struct gpio_desc *desc)
-{
-       const struct gpio_chip *chip = desc->chip;
-       const int gpio = desc_to_gpio(desc);
-
-       if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
-                       "autorequest GPIO-%d\n", gpio)) {
-               if (!try_module_get(chip->owner)) {
-                       gpiod_err(desc, "%s: module can't be gotten\n",
-                                       __func__);
-                       clear_bit(FLAG_REQUESTED, &desc->flags);
-                       /* lose */
-                       return -EIO;
-               }
-               desc_set_label(desc, "[auto]");
-               /* caller must chip->request() w/o spinlock */
-               if (chip->request)
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
- * @desc:      descriptor to return the chip of
- */
-struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
-{
-       return desc ? desc->chip : NULL;
-}
-EXPORT_SYMBOL_GPL(gpiod_to_chip);
-
-/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
-static int gpiochip_find_base(int ngpio)
-{
-       struct gpio_chip *chip;
-       int base = ARCH_NR_GPIOS - ngpio;
-
-       list_for_each_entry_reverse(chip, &gpio_chips, list) {
-               /* found a free space? */
-               if (chip->base + chip->ngpio <= base)
-                       break;
-               else
-                       /* nope, check the space right before the chip */
-                       base = chip->base - ngpio;
-       }
-
-       if (gpio_is_valid(base)) {
-               pr_debug("%s: found new base at %d\n", __func__, base);
-               return base;
-       } else {
-               pr_err("%s: cannot find free range\n", __func__);
-               return -ENOSPC;
-       }
-}
-
-/**
- * gpiod_get_direction - return the current direction of a GPIO
- * @desc:      GPIO to get the direction of
- *
- * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error.
- *
- * This function may sleep if gpiod_cansleep() is true.
- */
-int gpiod_get_direction(const struct gpio_desc *desc)
-{
-       struct gpio_chip        *chip;
-       unsigned                offset;
-       int                     status = -EINVAL;
-
-       chip = gpiod_to_chip(desc);
-       offset = gpio_chip_hwgpio(desc);
-
-       if (!chip->get_direction)
-               return status;
-
-       status = chip->get_direction(chip, offset);
-       if (status > 0) {
-               /* GPIOF_DIR_IN, or other positive */
-               status = 1;
-               /* FLAG_IS_OUT is just a cache of the result of get_direction(),
-                * so it does not affect constness per se */
-               clear_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
-       }
-       if (status == 0) {
-               /* GPIOF_DIR_OUT */
-               set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
-       }
-       return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_get_direction);
-
-#ifdef CONFIG_GPIO_SYSFS
-
-/* lock protects against unexport_gpio() being called while
- * sysfs files are active.
- */
-static DEFINE_MUTEX(sysfs_lock);
-
-/*
- * /sys/class/gpio/gpioN... only for GPIOs that are exported
- *   /direction
- *      * MAY BE OMITTED if kernel won't allow direction changes
- *      * is read/write as "in" or "out"
- *      * may also be written as "high" or "low", initializing
- *        output value as specified ("out" implies "low")
- *   /value
- *      * always readable, subject to hardware behavior
- *      * may be writable, as zero/nonzero
- *   /edge
- *      * configures behavior of poll(2) on /value
- *      * available only if pin can generate IRQs on input
- *      * is read/write as "none", "falling", "rising", or "both"
- *   /active_low
- *      * configures polarity of /value
- *      * is read/write as zero/nonzero
- *      * also affects existing and subsequent "falling" and "rising"
- *        /edge configuration
- */
-
-static ssize_t gpio_direction_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
-               status = -EIO;
-       } else {
-               gpiod_get_direction(desc);
-               status = sprintf(buf, "%s\n",
-                       test_bit(FLAG_IS_OUT, &desc->flags)
-                               ? "out" : "in");
-       }
-
-       mutex_unlock(&sysfs_lock);
-       return status;
-}
-
-static ssize_t gpio_direction_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
-{
-       struct gpio_desc        *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else if (sysfs_streq(buf, "high"))
-               status = gpiod_direction_output_raw(desc, 1);
-       else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
-               status = gpiod_direction_output_raw(desc, 0);
-       else if (sysfs_streq(buf, "in"))
-               status = gpiod_direction_input(desc);
-       else
-               status = -EINVAL;
-
-       mutex_unlock(&sysfs_lock);
-       return status ? : size;
-}
-
-static /* const */ DEVICE_ATTR(direction, 0644,
-               gpio_direction_show, gpio_direction_store);
-
-static ssize_t gpio_value_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct gpio_desc        *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else
-               status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
-
-       mutex_unlock(&sysfs_lock);
-       return status;
-}
-
-static ssize_t gpio_value_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
-{
-       struct gpio_desc        *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else if (!test_bit(FLAG_IS_OUT, &desc->flags))
-               status = -EPERM;
-       else {
-               long            value;
-
-               status = kstrtol(buf, 0, &value);
-               if (status == 0) {
-                       gpiod_set_value_cansleep(desc, value);
-                       status = size;
-               }
-       }
-
-       mutex_unlock(&sysfs_lock);
-       return status;
-}
-
-static const DEVICE_ATTR(value, 0644,
-               gpio_value_show, gpio_value_store);
-
-static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
-{
-       struct kernfs_node      *value_sd = priv;
-
-       sysfs_notify_dirent(value_sd);
-       return IRQ_HANDLED;
-}
-
-static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
-               unsigned long gpio_flags)
-{
-       struct kernfs_node      *value_sd;
-       unsigned long           irq_flags;
-       int                     ret, irq, id;
-
-       if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
-               return 0;
-
-       irq = gpiod_to_irq(desc);
-       if (irq < 0)
-               return -EIO;
-
-       id = desc->flags >> ID_SHIFT;
-       value_sd = idr_find(&dirent_idr, id);
-       if (value_sd)
-               free_irq(irq, value_sd);
-
-       desc->flags &= ~GPIO_TRIGGER_MASK;
-
-       if (!gpio_flags) {
-               gpiod_unlock_as_irq(desc);
-               ret = 0;
-               goto free_id;
-       }
-
-       irq_flags = IRQF_SHARED;
-       if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
-               irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
-                       IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
-       if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
-               irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
-                       IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
-
-       if (!value_sd) {
-               value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
-               if (!value_sd) {
-                       ret = -ENODEV;
-                       goto err_out;
-               }
-
-               ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
-               if (ret < 0)
-                       goto free_sd;
-               id = ret;
-
-               desc->flags &= GPIO_FLAGS_MASK;
-               desc->flags |= (unsigned long)id << ID_SHIFT;
-
-               if (desc->flags >> ID_SHIFT != id) {
-                       ret = -ERANGE;
-                       goto free_id;
-               }
-       }
-
-       ret = request_any_context_irq(irq, gpio_sysfs_irq, irq_flags,
-                               "gpiolib", value_sd);
-       if (ret < 0)
-               goto free_id;
-
-       ret = gpiod_lock_as_irq(desc);
-       if (ret < 0) {
-               gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
-               goto free_id;
-       }
-
-       desc->flags |= gpio_flags;
-       return 0;
-
-free_id:
-       idr_remove(&dirent_idr, id);
-       desc->flags &= GPIO_FLAGS_MASK;
-free_sd:
-       if (value_sd)
-               sysfs_put(value_sd);
-err_out:
-       return ret;
-}
+LIST_HEAD(gpio_chips);
 
-static const struct {
-       const char *name;
-       unsigned long flags;
-} trigger_types[] = {
-       { "none",    0 },
-       { "falling", BIT(FLAG_TRIG_FALL) },
-       { "rising",  BIT(FLAG_TRIG_RISE) },
-       { "both",    BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE) },
-};
-
-static ssize_t gpio_edge_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else {
-               int i;
-
-               status = 0;
-               for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
-                       if ((desc->flags & GPIO_TRIGGER_MASK)
-                                       == trigger_types[i].flags) {
-                               status = sprintf(buf, "%s\n",
-                                                trigger_types[i].name);
-                               break;
-                       }
-       }
-
-       mutex_unlock(&sysfs_lock);
-       return status;
-}
-
-static ssize_t gpio_edge_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
-{
-       struct gpio_desc        *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-       int                     i;
-
-       for (i = 0; i < ARRAY_SIZE(trigger_types); i++)
-               if (sysfs_streq(trigger_types[i].name, buf))
-                       goto found;
-       return -EINVAL;
-
-found:
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else {
-               status = gpio_setup_irq(desc, dev, trigger_types[i].flags);
-               if (!status)
-                       status = size;
-       }
-
-       mutex_unlock(&sysfs_lock);
-
-       return status;
-}
-
-static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
-
-static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
-                               int value)
-{
-       int                     status = 0;
-
-       if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
-               return 0;
-
-       if (value)
-               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
-       else
-               clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
-
-       /* reconfigure poll(2) support if enabled on one edge only */
-       if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
-                               !!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
-               unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
-
-               gpio_setup_irq(desc, dev, 0);
-               status = gpio_setup_irq(desc, dev, trigger_flags);
-       }
-
-       return status;
-}
-
-static ssize_t gpio_active_low_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
-               status = -EIO;
-       else
-               status = sprintf(buf, "%d\n",
-                               !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
-
-       mutex_unlock(&sysfs_lock);
-
-       return status;
-}
-
-static ssize_t gpio_active_low_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t size)
-{
-       struct gpio_desc        *desc = dev_get_drvdata(dev);
-       ssize_t                 status;
-
-       mutex_lock(&sysfs_lock);
-
-       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
-               status = -EIO;
-       } else {
-               long            value;
-
-               status = kstrtol(buf, 0, &value);
-               if (status == 0)
-                       status = sysfs_set_active_low(desc, dev, value != 0);
-       }
-
-       mutex_unlock(&sysfs_lock);
-
-       return status ? : size;
-}
-
-static const DEVICE_ATTR(active_low, 0644,
-               gpio_active_low_show, gpio_active_low_store);
-
-static const struct attribute *gpio_attrs[] = {
-       &dev_attr_value.attr,
-       &dev_attr_active_low.attr,
-       NULL,
-};
-
-static const struct attribute_group gpio_attr_group = {
-       .attrs = (struct attribute **) gpio_attrs,
-};
-
-/*
- * /sys/class/gpio/gpiochipN/
- *   /base ... matching gpio_chip.base (N)
- *   /label ... matching gpio_chip.label
- *   /ngpio ... matching gpio_chip.ngpio
- */
-
-static ssize_t chip_base_show(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       const struct gpio_chip  *chip = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%d\n", chip->base);
-}
-static DEVICE_ATTR(base, 0444, chip_base_show, NULL);
-
-static ssize_t chip_label_show(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       const struct gpio_chip  *chip = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%s\n", chip->label ? : "");
-}
-static DEVICE_ATTR(label, 0444, chip_label_show, NULL);
-
-static ssize_t chip_ngpio_show(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       const struct gpio_chip  *chip = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%u\n", chip->ngpio);
-}
-static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
-
-static const struct attribute *gpiochip_attrs[] = {
-       &dev_attr_base.attr,
-       &dev_attr_label.attr,
-       &dev_attr_ngpio.attr,
-       NULL,
-};
-
-static const struct attribute_group gpiochip_attr_group = {
-       .attrs = (struct attribute **) gpiochip_attrs,
-};
-
-/*
- * /sys/class/gpio/export ... write-only
- *     integer N ... number of GPIO to export (full access)
- * /sys/class/gpio/unexport ... write-only
- *     integer N ... number of GPIO to unexport
- */
-static ssize_t export_store(struct class *class,
-                               struct class_attribute *attr,
-                               const char *buf, size_t len)
-{
-       long                    gpio;
-       struct gpio_desc        *desc;
-       int                     status;
-
-       status = kstrtol(buf, 0, &gpio);
-       if (status < 0)
-               goto done;
-
-       desc = gpio_to_desc(gpio);
-       /* reject invalid GPIOs */
-       if (!desc) {
-               pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
-               return -EINVAL;
-       }
-
-       /* No extra locking here; FLAG_SYSFS just signifies that the
-        * request and export were done by on behalf of userspace, so
-        * they may be undone on its behalf too.
-        */
-
-       status = gpiod_request(desc, "sysfs");
-       if (status < 0) {
-               if (status == -EPROBE_DEFER)
-                       status = -ENODEV;
-               goto done;
-       }
-       status = gpiod_export(desc, true);
-       if (status < 0)
-               gpiod_free(desc);
-       else
-               set_bit(FLAG_SYSFS, &desc->flags);
-
-done:
-       if (status)
-               pr_debug("%s: status %d\n", __func__, status);
-       return status ? : len;
-}
-
-static ssize_t unexport_store(struct class *class,
-                               struct class_attribute *attr,
-                               const char *buf, size_t len)
-{
-       long                    gpio;
-       struct gpio_desc        *desc;
-       int                     status;
-
-       status = kstrtol(buf, 0, &gpio);
-       if (status < 0)
-               goto done;
-
-       desc = gpio_to_desc(gpio);
-       /* reject bogus commands (gpio_unexport ignores them) */
-       if (!desc) {
-               pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
-               return -EINVAL;
-       }
-
-       status = -EINVAL;
-
-       /* No extra locking here; FLAG_SYSFS just signifies that the
-        * request and export were done by on behalf of userspace, so
-        * they may be undone on its behalf too.
-        */
-       if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
-               status = 0;
-               gpiod_free(desc);
-       }
-done:
-       if (status)
-               pr_debug("%s: status %d\n", __func__, status);
-       return status ? : len;
-}
-
-static struct class_attribute gpio_class_attrs[] = {
-       __ATTR(export, 0200, NULL, export_store),
-       __ATTR(unexport, 0200, NULL, unexport_store),
-       __ATTR_NULL,
-};
-
-static struct class gpio_class = {
-       .name =         "gpio",
-       .owner =        THIS_MODULE,
-
-       .class_attrs =  gpio_class_attrs,
-};
-
-
-/**
- * gpiod_export - export a GPIO through sysfs
- * @gpio: gpio to make available, already requested
- * @direction_may_change: true if userspace may change gpio direction
- * Context: arch_initcall or later
- *
- * When drivers want to make a GPIO accessible to userspace after they
- * have requested it -- perhaps while debugging, or as part of their
- * public interface -- they may use this routine.  If the GPIO can
- * change direction (some can't) and the caller allows it, userspace
- * will see "direction" sysfs attribute which may be used to change
- * the gpio's direction.  A "value" attribute will always be provided.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
-{
-       unsigned long           flags;
-       int                     status;
-       const char              *ioname = NULL;
-       struct device           *dev;
-       int                     offset;
-
-       /* can't export until sysfs is available ... */
-       if (!gpio_class.p) {
-               pr_debug("%s: called too early!\n", __func__);
-               return -ENOENT;
-       }
-
-       if (!desc) {
-               pr_debug("%s: invalid gpio descriptor\n", __func__);
-               return -EINVAL;
-       }
-
-       mutex_lock(&sysfs_lock);
-
-       spin_lock_irqsave(&gpio_lock, flags);
-       if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
-            test_bit(FLAG_EXPORT, &desc->flags)) {
-               spin_unlock_irqrestore(&gpio_lock, flags);
-               gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
-                               __func__,
-                               test_bit(FLAG_REQUESTED, &desc->flags),
-                               test_bit(FLAG_EXPORT, &desc->flags));
-               status = -EPERM;
-               goto fail_unlock;
-       }
-
-       if (!desc->chip->direction_input || !desc->chip->direction_output)
-               direction_may_change = false;
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       offset = gpio_chip_hwgpio(desc);
-       if (desc->chip->names && desc->chip->names[offset])
-               ioname = desc->chip->names[offset];
-
-       dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                           desc, ioname ? ioname : "gpio%u",
-                           desc_to_gpio(desc));
-       if (IS_ERR(dev)) {
-               status = PTR_ERR(dev);
-               goto fail_unlock;
-       }
-
-       status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
-       if (status)
-               goto fail_unregister_device;
-
-       if (direction_may_change) {
-               status = device_create_file(dev, &dev_attr_direction);
-               if (status)
-                       goto fail_unregister_device;
-       }
-
-       if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
-                                      !test_bit(FLAG_IS_OUT, &desc->flags))) {
-               status = device_create_file(dev, &dev_attr_edge);
-               if (status)
-                       goto fail_unregister_device;
-       }
-
-       set_bit(FLAG_EXPORT, &desc->flags);
-       mutex_unlock(&sysfs_lock);
-       return 0;
-
-fail_unregister_device:
-       device_unregister(dev);
-fail_unlock:
-       mutex_unlock(&sysfs_lock);
-       gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-       return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_export);
-
-static int match_export(struct device *dev, const void *data)
-{
-       return dev_get_drvdata(dev) == data;
-}
-
-/**
- * gpiod_export_link - create a sysfs link to an exported GPIO node
- * @dev: device under which to create symlink
- * @name: name of the symlink
- * @gpio: gpio to create symlink to, already exported
- *
- * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
- * node. Caller is responsible for unlinking.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_export_link(struct device *dev, const char *name,
-                     struct gpio_desc *desc)
-{
-       int                     status = -EINVAL;
-
-       if (!desc) {
-               pr_warn("%s: invalid GPIO\n", __func__);
-               return -EINVAL;
-       }
-
-       mutex_lock(&sysfs_lock);
-
-       if (test_bit(FLAG_EXPORT, &desc->flags)) {
-               struct device *tdev;
-
-               tdev = class_find_device(&gpio_class, NULL, desc, match_export);
-               if (tdev != NULL) {
-                       status = sysfs_create_link(&dev->kobj, &tdev->kobj,
-                                               name);
-               } else {
-                       status = -ENODEV;
-               }
-       }
-
-       mutex_unlock(&sysfs_lock);
-
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
-       return status;
-}
-EXPORT_SYMBOL_GPL(gpiod_export_link);
-
-/**
- * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
- * @gpio: gpio to change
- * @value: non-zero to use active low, i.e. inverted values
- *
- * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
- * The GPIO does not have to be exported yet.  If poll(2) support has
- * been enabled for either rising or falling edge, it will be
- * reconfigured to follow the new polarity.
- *
- * Returns zero on success, else an error.
- */
-int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
-{
-       struct device           *dev = NULL;
-       int                     status = -EINVAL;
-
-       if (!desc) {
-               pr_warn("%s: invalid GPIO\n", __func__);
-               return -EINVAL;
-       }
-
-       mutex_lock(&sysfs_lock);
-
-       if (test_bit(FLAG_EXPORT, &desc->flags)) {
-               dev = class_find_device(&gpio_class, NULL, desc, match_export);
-               if (dev == NULL) {
-                       status = -ENODEV;
-                       goto unlock;
-               }
-       }
-
-       status = sysfs_set_active_low(desc, dev, value);
-
-unlock:
-       mutex_unlock(&sysfs_lock);
-
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
-       return status;
+static inline void desc_set_label(struct gpio_desc *d, const char *label)
+{
+       d->label = label;
 }
-EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
 
 /**
- * gpiod_unexport - reverse effect of gpio_export()
- * @gpio: gpio to make unavailable
- *
- * This is implicit on gpio_free().
+ * Convert a GPIO number to its descriptor
  */
-void gpiod_unexport(struct gpio_desc *desc)
+struct gpio_desc *gpio_to_desc(unsigned gpio)
 {
-       int                     status = 0;
-       struct device           *dev = NULL;
-
-       if (!desc) {
-               pr_warn("%s: invalid GPIO\n", __func__);
-               return;
-       }
-
-       mutex_lock(&sysfs_lock);
-
-       if (test_bit(FLAG_EXPORT, &desc->flags)) {
-
-               dev = class_find_device(&gpio_class, NULL, desc, match_export);
-               if (dev) {
-                       gpio_setup_irq(desc, dev, 0);
-                       clear_bit(FLAG_EXPORT, &desc->flags);
-               } else
-                       status = -ENODEV;
-       }
-
-       mutex_unlock(&sysfs_lock);
+       if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
+               return NULL;
+       else
+               return &gpio_desc[gpio];
+}
+EXPORT_SYMBOL_GPL(gpio_to_desc);
 
-       if (dev) {
-               device_unregister(dev);
-               put_device(dev);
-       }
+/**
+ * Get the GPIO descriptor corresponding to the given hw number for this chip.
+ */
+struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
+                                   u16 hwnum)
+{
+       if (hwnum >= chip->ngpio)
+               return ERR_PTR(-EINVAL);
 
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       return &chip->desc[hwnum];
 }
-EXPORT_SYMBOL_GPL(gpiod_unexport);
 
-static int gpiochip_export(struct gpio_chip *chip)
+/**
+ * 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
+ */
+int desc_to_gpio(const struct gpio_desc *desc)
 {
-       int             status;
-       struct device   *dev;
+       return desc - &gpio_desc[0];
+}
+EXPORT_SYMBOL_GPL(desc_to_gpio);
 
-       /* Many systems register gpio chips for SOC support very early,
-        * before driver model support is available.  In those cases we
-        * export this later, in gpiolib_sysfs_init() ... here we just
-        * verify that _some_ field of gpio_class got initialized.
-        */
-       if (!gpio_class.p)
-               return 0;
 
-       /* use chip->base for the ID; it's already known to be unique */
-       mutex_lock(&sysfs_lock);
-       dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
-                               "gpiochip%d", chip->base);
-       if (!IS_ERR(dev)) {
-               status = sysfs_create_group(&dev->kobj,
-                               &gpiochip_attr_group);
-       } else
-               status = PTR_ERR(dev);
-       chip->exported = (status == 0);
-       mutex_unlock(&sysfs_lock);
-
-       if (status) {
-               unsigned long   flags;
-               unsigned        gpio;
+/**
+ * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
+ * @desc:      descriptor to return the chip of
+ */
+struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
+{
+       return desc ? desc->chip : NULL;
+}
+EXPORT_SYMBOL_GPL(gpiod_to_chip);
 
-               spin_lock_irqsave(&gpio_lock, flags);
-               gpio = 0;
-               while (gpio < chip->ngpio)
-                       chip->desc[gpio++].chip = NULL;
-               spin_unlock_irqrestore(&gpio_lock, flags);
+/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
+static int gpiochip_find_base(int ngpio)
+{
+       struct gpio_chip *chip;
+       int base = ARCH_NR_GPIOS - ngpio;
 
-               chip_dbg(chip, "%s: status %d\n", __func__, status);
+       list_for_each_entry_reverse(chip, &gpio_chips, list) {
+               /* found a free space? */
+               if (chip->base + chip->ngpio <= base)
+                       break;
+               else
+                       /* nope, check the space right before the chip */
+                       base = chip->base - ngpio;
        }
 
-       return status;
+       if (gpio_is_valid(base)) {
+               pr_debug("%s: found new base at %d\n", __func__, base);
+               return base;
+       } else {
+               pr_err("%s: cannot find free range\n", __func__);
+               return -ENOSPC;
+       }
 }
 
-static void gpiochip_unexport(struct gpio_chip *chip)
+/**
+ * gpiod_get_direction - return the current direction of a GPIO
+ * @desc:      GPIO to get the direction of
+ *
+ * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error.
+ *
+ * This function may sleep if gpiod_cansleep() is true.
+ */
+int gpiod_get_direction(const struct gpio_desc *desc)
 {
-       int                     status;
-       struct device           *dev;
-
-       mutex_lock(&sysfs_lock);
-       dev = class_find_device(&gpio_class, NULL, chip, match_export);
-       if (dev) {
-               put_device(dev);
-               device_unregister(dev);
-               chip->exported = false;
-               status = 0;
-       } else
-               status = -ENODEV;
-       mutex_unlock(&sysfs_lock);
-
-       if (status)
-               chip_dbg(chip, "%s: status %d\n", __func__, status);
-}
+       struct gpio_chip        *chip;
+       unsigned                offset;
+       int                     status = -EINVAL;
 
-static int __init gpiolib_sysfs_init(void)
-{
-       int             status;
-       unsigned long   flags;
-       struct gpio_chip *chip;
+       chip = gpiod_to_chip(desc);
+       offset = gpio_chip_hwgpio(desc);
 
-       status = class_register(&gpio_class);
-       if (status < 0)
+       if (!chip->get_direction)
                return status;
 
-       /* Scan and register the gpio_chips which registered very
-        * early (e.g. before the class_register above was called).
-        *
-        * We run before arch_initcall() so chip->dev nodes can have
-        * registered, and so arch_initcall() can always gpio_export().
-        */
-       spin_lock_irqsave(&gpio_lock, flags);
-       list_for_each_entry(chip, &gpio_chips, list) {
-               if (!chip || chip->exported)
-                       continue;
-
-               spin_unlock_irqrestore(&gpio_lock, flags);
-               status = gpiochip_export(chip);
-               spin_lock_irqsave(&gpio_lock, flags);
+       status = chip->get_direction(chip, offset);
+       if (status > 0) {
+               /* GPIOF_DIR_IN, or other positive */
+               status = 1;
+               /* FLAG_IS_OUT is just a cache of the result of get_direction(),
+                * so it does not affect constness per se */
+               clear_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
+       }
+       if (status == 0) {
+               /* GPIOF_DIR_OUT */
+               set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
        }
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-
        return status;
 }
-postcore_initcall(gpiolib_sysfs_init);
-
-#else
-static inline int gpiochip_export(struct gpio_chip *chip)
-{
-       return 0;
-}
-
-static inline void gpiochip_unexport(struct gpio_chip *chip)
-{
-}
-
-#endif /* CONFIG_GPIO_SYSFS */
+EXPORT_SYMBOL_GPL(gpiod_get_direction);
 
 /*
  * Add a new chip to the global chips list, keeping the list of chips sorted
@@ -1474,6 +519,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
        unsigned int offset;
 
+       acpi_gpiochip_free_interrupts(gpiochip);
+
        /* Remove all IRQ mappings and delete the domain */
        if (gpiochip->irqdomain) {
                for (offset = 0; offset < gpiochip->ngpio; offset++)
@@ -1567,6 +614,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
                        gpiochip->irq_base = irq_base;
        }
 
+       acpi_gpiochip_request_interrupts(gpiochip);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
@@ -1740,7 +789,7 @@ done:
        return status;
 }
 
-static int gpiod_request(struct gpio_desc *desc, const char *label)
+int gpiod_request(struct gpio_desc *desc, const char *label)
 {
        int status = -EPROBE_DEFER;
        struct gpio_chip *chip;
@@ -1767,12 +816,6 @@ done:
        return status;
 }
 
-int gpio_request(unsigned gpio, const char *label)
-{
-       return gpiod_request(gpio_to_desc(gpio), label);
-}
-EXPORT_SYMBOL_GPL(gpio_request);
-
 static bool __gpiod_free(struct gpio_desc *desc)
 {
        bool                    ret = false;
@@ -1805,7 +848,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
        return ret;
 }
 
-static void gpiod_free(struct gpio_desc *desc)
+void gpiod_free(struct gpio_desc *desc)
 {
        if (desc && __gpiod_free(desc))
                module_put(desc->chip->owner);
@@ -1813,101 +856,14 @@ static void gpiod_free(struct gpio_desc *desc)
                WARN_ON(extra_checks);
 }
 
-void gpio_free(unsigned gpio)
-{
-       gpiod_free(gpio_to_desc(gpio));
-}
-EXPORT_SYMBOL_GPL(gpio_free);
-
-/**
- * gpio_request_one - request a single GPIO with initial configuration
- * @gpio:      the GPIO number
- * @flags:     GPIO configuration as specified by GPIOF_*
- * @label:     a literal description string of this GPIO
- */
-int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
-{
-       struct gpio_desc *desc;
-       int err;
-
-       desc = gpio_to_desc(gpio);
-
-       err = gpiod_request(desc, label);
-       if (err)
-               return err;
-
-       if (flags & GPIOF_OPEN_DRAIN)
-               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
-
-       if (flags & GPIOF_OPEN_SOURCE)
-               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-
-       if (flags & GPIOF_DIR_IN)
-               err = gpiod_direction_input(desc);
-       else
-               err = gpiod_direction_output_raw(desc,
-                               (flags & GPIOF_INIT_HIGH) ? 1 : 0);
-
-       if (err)
-               goto free_gpio;
-
-       if (flags & GPIOF_EXPORT) {
-               err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
-               if (err)
-                       goto free_gpio;
-       }
-
-       return 0;
-
- free_gpio:
-       gpiod_free(desc);
-       return err;
-}
-EXPORT_SYMBOL_GPL(gpio_request_one);
-
-/**
- * gpio_request_array - request multiple GPIOs in a single call
- * @array:     array of the 'struct gpio'
- * @num:       how many GPIOs in the array
- */
-int gpio_request_array(const struct gpio *array, size_t num)
-{
-       int i, err;
-
-       for (i = 0; i < num; i++, array++) {
-               err = gpio_request_one(array->gpio, array->flags, array->label);
-               if (err)
-                       goto err_free;
-       }
-       return 0;
-
-err_free:
-       while (i--)
-               gpio_free((--array)->gpio);
-       return err;
-}
-EXPORT_SYMBOL_GPL(gpio_request_array);
-
-/**
- * gpio_free_array - release multiple GPIOs in a single call
- * @array:     array of the 'struct gpio'
- * @num:       how many GPIOs in the array
- */
-void gpio_free_array(const struct gpio *array, size_t num)
-{
-       while (num--)
-               gpio_free((array++)->gpio);
-}
-EXPORT_SYMBOL_GPL(gpio_free_array);
-
 /**
  * gpiochip_is_requested - return string iff signal was requested
  * @chip: controller managing the signal
  * @offset: of signal within controller's 0..(ngpio - 1) range
  *
  * Returns NULL if the GPIO is not currently requested, else a string.
- * If debugfs support is enabled, the string returned is the label passed
- * to gpio_request(); otherwise it is a meaningless constant.
+ * The string returned is the label passed to gpio_request(); if none has been
+ * passed it is a meaningless, non-NULL constant.
  *
  * This function is for use by GPIO controller drivers.  The label can
  * help with diagnostics, and knowing that the signal is used as a GPIO
@@ -1924,11 +880,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
 
        if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
                return NULL;
-#ifdef CONFIG_DEBUG_FS
        return desc->label;
-#else
-       return "?";
-#endif
 }
 EXPORT_SYMBOL_GPL(gpiochip_is_requested);
 
@@ -1950,6 +902,7 @@ int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
 
        return __gpiod_request(desc, label);
 }
+EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
 
 /**
  * gpiochip_free_own_desc - Free GPIO requested by the chip driver
@@ -1963,6 +916,7 @@ void gpiochip_free_own_desc(struct gpio_desc *desc)
        if (desc)
                __gpiod_free(desc);
 }
+EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
 
 /* Drivers MUST set GPIO direction before making get/set calls.  In
  * some cases this is done in early boot, before IRQs are enabled.
@@ -1984,10 +938,8 @@ void gpiochip_free_own_desc(struct gpio_desc *desc)
  */
 int gpiod_direction_input(struct gpio_desc *desc)
 {
-       unsigned long           flags;
        struct gpio_chip        *chip;
        int                     status = -EINVAL;
-       int                     offset;
 
        if (!desc || !desc->chip) {
                pr_warn("%s: invalid GPIO\n", __func__);
@@ -2002,52 +954,20 @@ int gpiod_direction_input(struct gpio_desc *desc)
                return -EIO;
        }
 
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       status = gpio_ensure_requested(desc);
-       if (status < 0)
-               goto fail;
-
-       /* now we know the gpio is valid and chip won't vanish */
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       might_sleep_if(chip->can_sleep);
-
-       offset = gpio_chip_hwgpio(desc);
-       if (status) {
-               status = chip->request(chip, offset);
-               if (status < 0) {
-                       gpiod_dbg(desc, "%s: chip request fail, %d\n",
-                                       __func__, status);
-                       /* and it's not available to anyone else ...
-                        * gpio_request() is the fully clean solution.
-                        */
-                       goto lose;
-               }
-       }
-
-       status = chip->direction_input(chip, offset);
+       status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
        trace_gpio_direction(desc_to_gpio(desc), 1, status);
-lose:
-       return status;
-fail:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+
        return status;
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
 static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 {
-       unsigned long           flags;
        struct gpio_chip        *chip;
        int                     status = -EINVAL;
-       int offset;
 
        /* GPIOs used for IRQs shall not be set as output */
        if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
@@ -2073,42 +993,11 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
                return -EIO;
        }
 
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       status = gpio_ensure_requested(desc);
-       if (status < 0)
-               goto fail;
-
-       /* now we know the gpio is valid and chip won't vanish */
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       might_sleep_if(chip->can_sleep);
-
-       offset = gpio_chip_hwgpio(desc);
-       if (status) {
-               status = chip->request(chip, offset);
-               if (status < 0) {
-                       gpiod_dbg(desc, "%s: chip request fail, %d\n",
-                                       __func__, status);
-                       /* and it's not available to anyone else ...
-                        * gpio_request() is the fully clean solution.
-                        */
-                       goto lose;
-               }
-       }
-
-       status = chip->direction_output(chip, offset, value);
+       status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value);
        if (status == 0)
                set_bit(FLAG_IS_OUT, &desc->flags);
        trace_gpio_value(desc_to_gpio(desc), 0, value);
        trace_gpio_direction(desc_to_gpio(desc), 0, status);
-lose:
-       return status;
-fail:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
-               gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
        return status;
 }
 
@@ -2167,10 +1056,7 @@ EXPORT_SYMBOL_GPL(gpiod_direction_output);
  */
 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
-       unsigned long           flags;
        struct gpio_chip        *chip;
-       int                     status = -EINVAL;
-       int                     offset;
 
        if (!desc || !desc->chip) {
                pr_warn("%s: invalid GPIO\n", __func__);
@@ -2185,27 +1071,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
                return -ENOTSUPP;
        }
 
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       status = gpio_ensure_requested(desc);
-       if (status < 0)
-               goto fail;
-
-       /* now we know the gpio is valid and chip won't vanish */
-
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       might_sleep_if(chip->can_sleep);
-
-       offset = gpio_chip_hwgpio(desc);
-       return chip->set_debounce(chip, offset, debounce);
-
-fail:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
-
-       return status;
+       return chip->set_debounce(chip, gpio_chip_hwgpio(desc), debounce);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_debounce);
 
@@ -2448,54 +1314,44 @@ int gpiod_to_irq(const struct gpio_desc *desc)
 EXPORT_SYMBOL_GPL(gpiod_to_irq);
 
 /**
- * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ
- * @gpio: the GPIO line to lock as used for IRQ
+ * gpio_lock_as_irq() - lock a GPIO to be used as IRQ
+ * @chip: the chip the GPIO to lock belongs to
+ * @offset: the offset of the GPIO to lock as IRQ
  *
  * This is used directly by GPIO drivers that want to lock down
  * a certain GPIO line to be used for IRQs.
  */
-int gpiod_lock_as_irq(struct gpio_desc *desc)
+int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
 {
-       if (!desc)
+       if (offset >= chip->ngpio)
                return -EINVAL;
 
-       if (test_bit(FLAG_IS_OUT, &desc->flags)) {
-               gpiod_err(desc,
+       if (test_bit(FLAG_IS_OUT, &chip->desc[offset].flags)) {
+               chip_err(chip,
                          "%s: tried to flag a GPIO set as output for IRQ\n",
                          __func__);
                return -EIO;
        }
 
-       set_bit(FLAG_USED_AS_IRQ, &desc->flags);
+       set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
        return 0;
 }
-EXPORT_SYMBOL_GPL(gpiod_lock_as_irq);
-
-int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
-{
-       return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset));
-}
 EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
 
 /**
- * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ
- * @gpio: the GPIO line to unlock from IRQ usage
+ * gpio_unlock_as_irq() - unlock a GPIO used as IRQ
+ * @chip: the chip the GPIO to lock belongs to
+ * @offset: the offset of the GPIO to lock as IRQ
  *
  * This is used directly by GPIO drivers that want to indicate
  * that a certain GPIO is no longer used exclusively for IRQ.
  */
-void gpiod_unlock_as_irq(struct gpio_desc *desc)
+void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
 {
-       if (!desc)
+       if (offset >= chip->ngpio)
                return;
 
-       clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
-}
-EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq);
-
-void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
-{
-       return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset));
+       clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
 }
 EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
 
@@ -2614,7 +1470,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
 
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
-               if (!IS_ERR(desc))
+               if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
                        break;
        }