gpiolib: use const parameters when possible
[firefly-linux-kernel-4.4.55.git] / drivers / gpio / gpiolib.c
index 5359ca78130fe09376210395f964770562b70798..a33bfc23e9f5486acdc94f3b09c83da4e0368224 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
+#include <linux/list.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/debugfs.h>
@@ -52,14 +53,13 @@ struct gpio_desc {
 /* flag symbols are bit numbers */
 #define FLAG_REQUESTED 0
 #define FLAG_IS_OUT    1
-#define FLAG_RESERVED  2
-#define FLAG_EXPORT    3       /* protected by sysfs_lock */
-#define FLAG_SYSFS     4       /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 5       /* trigger on falling edge */
-#define FLAG_TRIG_RISE 6       /* trigger on rising edge */
-#define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
-#define FLAG_OPEN_DRAIN        8       /* Gpio is open drain type */
-#define FLAG_OPEN_SOURCE 9     /* Gpio is open source type */
+#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       /* sysfs 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 ID_SHIFT       16      /* add new flags before this one */
 
@@ -72,10 +72,37 @@ struct gpio_desc {
 };
 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
 
+#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
+
+static LIST_HEAD(gpio_chips);
+
 #ifdef CONFIG_GPIO_SYSFS
 static DEFINE_IDR(dirent_idr);
 #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_get_direction(const struct gpio_desc *desc);
+static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
+static int gpiod_get_value_cansleep(const struct gpio_desc *desc);
+static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
+static int gpiod_get_value(const struct gpio_desc *desc);
+static void gpiod_set_value(struct gpio_desc *desc, int value);
+static int gpiod_cansleep(const struct gpio_desc *desc);
+static int gpiod_to_irq(const 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)
 {
 #ifdef CONFIG_DEBUG_FS
@@ -83,6 +110,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *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
+ */
+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->chip->base + gpio_chip_hwgpio(desc);
+}
+
+
 /* 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
@@ -94,10 +151,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,
  * 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 int gpio = chip->base + offset;
+       const int gpio = desc_to_gpio(desc);
 
        if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
                        "autorequest GPIO-%d\n", gpio)) {
@@ -116,103 +173,64 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 }
 
 /* caller holds gpio_lock *OR* gpio is marked as requested */
+static struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
+{
+       return desc ? desc->chip : NULL;
+}
+
 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 */
 static int gpiochip_find_base(int ngpio)
 {
-       int i;
-       int spare = 0;
-       int base = -ENOSPC;
+       struct gpio_chip *chip;
+       int base = ARCH_NR_GPIOS - ngpio;
 
-       for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
-               struct gpio_desc *desc = &gpio_desc[i];
-               struct gpio_chip *chip = desc->chip;
-
-               if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
-                       spare++;
-                       if (spare == ngpio) {
-                               base = i;
-                               break;
-                       }
-               } else {
-                       spare = 0;
-                       if (chip)
-                               i -= chip->ngpio - 1;
-               }
+       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))
+       if (gpio_is_valid(base)) {
                pr_debug("%s: found new base at %d\n", __func__, base);
-       return base;
-}
-
-/**
- * gpiochip_reserve() - reserve range of gpios to use with platform code only
- * @start: starting gpio number
- * @ngpio: number of gpios to reserve
- * Context: platform init, potentially before irqs or kmalloc will work
- *
- * Returns a negative errno if any gpio within the range is already reserved
- * or registered, else returns zero as a success code.  Use this function
- * to mark a range of gpios as unavailable for dynamic gpio number allocation,
- * for example because its driver support is not yet loaded.
- */
-int __init gpiochip_reserve(int start, int ngpio)
-{
-       int ret = 0;
-       unsigned long flags;
-       int i;
-
-       if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
-               return -EINVAL;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       for (i = start; i < start + ngpio; i++) {
-               struct gpio_desc *desc = &gpio_desc[i];
-
-               if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
-                       ret = -EBUSY;
-                       goto err;
-               }
-
-               set_bit(FLAG_RESERVED, &desc->flags);
+               return base;
+       } else {
+               pr_err("%s: cannot find free range\n", __func__);
+               return -ENOSPC;
        }
-
-       pr_debug("%s: reserved gpios from %d to %d\n",
-                __func__, start, start + ngpio - 1);
-err:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       return ret;
 }
 
 /* caller ensures gpio is valid and requested, chip->get_direction may sleep  */
-static int gpio_get_direction(unsigned gpio)
+static int gpiod_get_direction(const struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
+       unsigned                offset;
        int                     status = -EINVAL;
 
-       chip = gpio_to_chip(gpio);
-       gpio -= chip->base;
+       chip = gpiod_to_chip(desc);
+       offset = gpio_chip_hwgpio(desc);
 
        if (!chip->get_direction)
                return status;
 
-       status = chip->get_direction(chip, gpio);
+       status = chip->get_direction(chip, offset);
        if (status > 0) {
                /* GPIOF_DIR_IN, or other positive */
                status = 1;
-               clear_bit(FLAG_IS_OUT, &desc->flags);
+               /* 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, &desc->flags);
+               set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
        }
        return status;
 }
@@ -249,18 +267,18 @@ static ssize_t gpio_direction_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
 
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
+       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
                status = -EIO;
-       else
-               gpio_get_direction(gpio);
+       } 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;
@@ -269,8 +287,7 @@ static ssize_t gpio_direction_show(struct device *dev,
 static ssize_t gpio_direction_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -278,11 +295,11 @@ static ssize_t gpio_direction_store(struct device *dev,
        if (!test_bit(FLAG_EXPORT, &desc->flags))
                status = -EIO;
        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"))
-               status = gpio_direction_output(gpio, 0);
+               status = gpiod_direction_output(desc, 0);
        else if (sysfs_streq(buf, "in"))
-               status = gpio_direction_input(gpio);
+               status = gpiod_direction_input(desc);
        else
                status = -EINVAL;
 
@@ -296,8 +313,7 @@ static /* const */ DEVICE_ATTR(direction, 0644,
 static ssize_t gpio_value_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -307,7 +323,7 @@ static ssize_t gpio_value_show(struct device *dev,
        } else {
                int value;
 
-               value = !!gpio_get_value_cansleep(gpio);
+               value = !!gpiod_get_value_cansleep(desc);
                if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                        value = !value;
 
@@ -321,8 +337,7 @@ static ssize_t gpio_value_show(struct device *dev,
 static ssize_t gpio_value_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -338,7 +353,7 @@ static ssize_t gpio_value_store(struct device *dev,
                if (status == 0) {
                        if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                                value = !value;
-                       gpio_set_value_cansleep(gpio, value != 0);
+                       gpiod_set_value_cansleep(desc, value != 0);
                        status = size;
                }
        }
@@ -368,7 +383,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
        if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
                return 0;
 
-       irq = gpio_to_irq(desc - gpio_desc);
+       irq = gpiod_to_irq(desc);
        if (irq < 0)
                return -EIO;
 
@@ -399,15 +414,10 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
                        goto err_out;
                }
 
-               do {
-                       ret = -ENOMEM;
-                       if (idr_pre_get(&dirent_idr, GFP_KERNEL))
-                               ret = idr_get_new_above(&dirent_idr, value_sd,
-                                                       1, &id);
-               } while (ret == -EAGAIN);
-
-               if (ret)
+               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;
@@ -638,29 +648,37 @@ static ssize_t export_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t len)
 {
-       long    gpio;
-       int     status;
+       long                    gpio;
+       struct gpio_desc        *desc;
+       int                     status;
 
        status = strict_strtol(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 = gpio_request(gpio, "sysfs");
+       status = gpiod_request(desc, "sysfs");
        if (status < 0) {
                if (status == -EPROBE_DEFER)
                        status = -ENODEV;
                goto done;
        }
-       status = gpio_export(gpio, true);
+       status = gpiod_export(desc, true);
        if (status < 0)
-               gpio_free(gpio);
+               gpiod_free(desc);
        else
-               set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags);
+               set_bit(FLAG_SYSFS, &desc->flags);
 
 done:
        if (status)
@@ -672,26 +690,30 @@ static ssize_t unexport_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t len)
 {
-       long    gpio;
-       int     status;
+       long                    gpio;
+       struct gpio_desc        *desc;
+       int                     status;
 
        status = strict_strtol(buf, 0, &gpio);
        if (status < 0)
                goto done;
 
-       status = -EINVAL;
-
+       desc = gpio_to_desc(gpio);
        /* reject bogus commands (gpio_unexport ignores them) */
-       if (!gpio_is_valid(gpio))
-               goto done;
+       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, &gpio_desc[gpio].flags)) {
+       if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
                status = 0;
-               gpio_free(gpio);
+               gpiod_free(desc);
        }
 done:
        if (status)
@@ -728,13 +750,13 @@ static struct class gpio_class = {
  *
  * 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;
-       struct gpio_desc        *desc;
        int                     status;
        const char              *ioname = NULL;
        struct device           *dev;
+       int                     offset;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -742,20 +764,19 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                return -ENOENT;
        }
 
-       if (!gpio_is_valid(gpio)) {
-               pr_debug("%s: gpio %d is not valid\n", __func__, gpio);
+       if (!desc) {
+               pr_debug("%s: invalid gpio descriptor\n", __func__);
                return -EINVAL;
        }
 
        mutex_lock(&sysfs_lock);
 
        spin_lock_irqsave(&gpio_lock, flags);
-       desc = &gpio_desc[gpio];
        if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
             test_bit(FLAG_EXPORT, &desc->flags)) {
                spin_unlock_irqrestore(&gpio_lock, flags);
                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_EXPORT, &desc->flags));
                status = -EPERM;
@@ -766,11 +787,13 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                direction_may_change = false;
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
-               ioname = desc->chip->names[gpio - desc->chip->base];
+       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", gpio);
+                           desc, ioname ? ioname : "gpio%u",
+                           desc_to_gpio(desc));
        if (IS_ERR(dev)) {
                status = PTR_ERR(dev);
                goto fail_unlock;
@@ -786,7 +809,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                        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))) {
                status = device_create_file(dev, &dev_attr_edge);
                if (status)
@@ -801,9 +824,15 @@ fail_unregister_device:
        device_unregister(dev);
 fail_unlock:
        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;
 }
+
+int gpio_export(unsigned gpio, bool direction_may_change)
+{
+       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+}
 EXPORT_SYMBOL_GPL(gpio_export);
 
 static int match_export(struct device *dev, const void *data)
@@ -822,18 +851,18 @@ static int match_export(struct device *dev, const void *data)
  *
  * 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;
 
-       if (!gpio_is_valid(gpio))
-               goto done;
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                struct device *tdev;
 
@@ -848,14 +877,18 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
 
        mutex_unlock(&sysfs_lock);
 
-done:
        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;
 }
-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
@@ -869,19 +902,18 @@ EXPORT_SYMBOL_GPL(gpio_export_link);
  *
  * 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;
        int                     status = -EINVAL;
 
-       if (!gpio_is_valid(gpio))
-               goto done;
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
                if (dev == NULL) {
@@ -895,12 +927,17 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value)
 unlock:
        mutex_unlock(&sysfs_lock);
 
-done:
        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;
 }
+
+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);
 
 /**
@@ -909,21 +946,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
  *
  * 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;
        struct device           *dev = NULL;
 
-       if (!gpio_is_valid(gpio)) {
-               status = -EINVAL;
-               goto done;
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return;
        }
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
 
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
@@ -935,13 +969,20 @@ void gpio_unexport(unsigned gpio)
        }
 
        mutex_unlock(&sysfs_lock);
+
        if (dev) {
                device_unregister(dev);
                put_device(dev);
        }
-done:
+
        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);
 
@@ -975,9 +1016,9 @@ static int gpiochip_export(struct gpio_chip *chip)
                unsigned        gpio;
 
                spin_lock_irqsave(&gpio_lock, flags);
-               gpio = chip->base;
-               while (gpio_desc[gpio].chip == chip)
-                       gpio_desc[gpio++].chip = NULL;
+               gpio = 0;
+               while (gpio < chip->ngpio)
+                       chip->desc[gpio++].chip = NULL;
                spin_unlock_irqrestore(&gpio_lock, flags);
 
                pr_debug("%s: chip %s status %d\n", __func__,
@@ -1012,7 +1053,7 @@ static int __init gpiolib_sysfs_init(void)
 {
        int             status;
        unsigned long   flags;
-       unsigned        gpio;
+       struct gpio_chip *chip;
 
        status = class_register(&gpio_class);
        if (status < 0)
@@ -1025,10 +1066,7 @@ static int __init gpiolib_sysfs_init(void)
         * registered, and so arch_initcall() can always gpio_export().
         */
        spin_lock_irqsave(&gpio_lock, flags);
-       for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
-               struct gpio_chip        *chip;
-
-               chip = gpio_desc[gpio].chip;
+       list_for_each_entry(chip, &gpio_chips, list) {
                if (!chip || chip->exported)
                        continue;
 
@@ -1053,8 +1091,66 @@ 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 */
 
+/*
+ * Add a new chip to the global chips list, keeping the list of chips sorted
+ * by base order.
+ *
+ * Return -EBUSY if the new chip overlaps with some other chip's integer
+ * space.
+ */
+static int gpiochip_add_to_list(struct gpio_chip *chip)
+{
+       struct list_head *pos = &gpio_chips;
+       struct gpio_chip *_chip;
+       int err = 0;
+
+       /* find where to insert our chip */
+       list_for_each(pos, &gpio_chips) {
+               _chip = list_entry(pos, struct gpio_chip, list);
+               /* shall we insert before _chip? */
+               if (_chip->base >= chip->base + chip->ngpio)
+                       break;
+       }
+
+       /* are we stepping on the chip right before? */
+       if (pos != &gpio_chips && pos->prev != &gpio_chips) {
+               _chip = list_entry(pos->prev, struct gpio_chip, list);
+               if (_chip->base + _chip->ngpio > chip->base) {
+                       dev_err(chip->dev,
+                              "GPIO integer space overlap, cannot add chip\n");
+                       err = -EBUSY;
+               }
+       }
+
+       if (!err)
+               list_add_tail(&chip->list, pos);
+
+       return err;
+}
+
 /**
  * gpiochip_add() - register a gpio_chip
  * @chip: the chip to register, with chip->base initialized
@@ -1096,16 +1192,14 @@ int gpiochip_add(struct gpio_chip *chip)
                chip->base = base;
        }
 
-       /* these GPIO numbers must not be managed by another gpio_chip */
-       for (id = base; id < base + chip->ngpio; id++) {
-               if (gpio_desc[id].chip != NULL) {
-                       status = -EBUSY;
-                       break;
-               }
-       }
+       status = gpiochip_add_to_list(chip);
+
        if (status == 0) {
-               for (id = base; id < base + chip->ngpio; id++) {
-                       gpio_desc[id].chip = chip;
+               chip->desc = &gpio_desc[chip->base];
+
+               for (id = 0; id < chip->ngpio; id++) {
+                       struct gpio_desc *desc = &chip->desc[id];
+                       desc->chip = chip;
 
                        /* REVISIT:  most hardware initializes GPIOs as
                         * inputs (often with pullups enabled) so power
@@ -1114,7 +1208,7 @@ int gpiochip_add(struct gpio_chip *chip)
                         * and in case chip->get_direction is not set,
                         * we may expose the wrong direction in sysfs.
                         */
-                       gpio_desc[id].flags = !chip->direction_input
+                       desc->flags = !chip->direction_input
                                ? (1 << FLAG_IS_OUT)
                                : 0;
                }
@@ -1167,15 +1261,17 @@ int gpiochip_remove(struct gpio_chip *chip)
        gpiochip_remove_pin_ranges(chip);
        of_gpiochip_remove(chip);
 
-       for (id = chip->base; id < chip->base + chip->ngpio; id++) {
-               if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
+       for (id = 0; id < chip->ngpio; id++) {
+               if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
                        status = -EBUSY;
                        break;
                }
        }
        if (status == 0) {
-               for (id = chip->base; id < chip->base + chip->ngpio; id++)
-                       gpio_desc[id].chip = NULL;
+               for (id = 0; id < chip->ngpio; id++)
+                       chip->desc[id].chip = NULL;
+
+               list_del(&chip->list);
        }
 
        spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1202,20 +1298,17 @@ struct gpio_chip *gpiochip_find(void *data,
                                int (*match)(struct gpio_chip *chip,
                                             void *data))
 {
-       struct gpio_chip *chip = NULL;
+       struct gpio_chip *chip;
        unsigned long flags;
-       int i;
 
        spin_lock_irqsave(&gpio_lock, flags);
-       for (i = 0; i < ARCH_NR_GPIOS; i++) {
-               if (!gpio_desc[i].chip)
-                       continue;
-
-               if (match(gpio_desc[i].chip, data)) {
-                       chip = gpio_desc[i].chip;
+       list_for_each_entry(chip, &gpio_chips, list)
+               if (match(chip, data))
                        break;
-               }
-       }
+
+       /* No match? */
+       if (&chip->list == &gpio_chips)
+               chip = NULL;
        spin_unlock_irqrestore(&gpio_lock, flags);
 
        return chip;
@@ -1297,20 +1390,19 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
  * on each other, and help provide better diagnostics in debugfs.
  * 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;
        int                     status = -EPROBE_DEFER;
        unsigned long           flags;
 
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
+
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio)) {
-               status = -EINVAL;
-               goto done;
-       }
-       desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip == NULL)
                goto done;
@@ -1334,7 +1426,7 @@ int gpio_request(unsigned gpio, const char *label)
        if (chip->request) {
                /* chip->request may sleep */
                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);
 
                if (status < 0) {
@@ -1347,42 +1439,45 @@ int gpio_request(unsigned gpio, const char *label)
        if (chip->get_direction) {
                /* chip->get_direction may sleep */
                spin_unlock_irqrestore(&gpio_lock, flags);
-               gpio_get_direction(gpio);
+               gpiod_get_direction(desc);
                spin_lock_irqsave(&gpio_lock, flags);
        }
 done:
        if (status)
-               pr_debug("gpio_request: gpio-%d (%s) status %d\n",
-                       gpio, label ? : "?", status);
+               pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
+                        desc_to_gpio(desc), label ? : "?", status);
        spin_unlock_irqrestore(&gpio_lock, flags);
        return status;
 }
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       return gpiod_request(gpio_to_desc(gpio), label);
+}
 EXPORT_SYMBOL_GPL(gpio_request);
 
-void gpio_free(unsigned gpio)
+static void gpiod_free(struct gpio_desc *desc)
 {
        unsigned long           flags;
-       struct gpio_desc        *desc;
        struct gpio_chip        *chip;
 
        might_sleep();
 
-       if (!gpio_is_valid(gpio)) {
+       if (!desc) {
                WARN_ON(extra_checks);
                return;
        }
 
-       gpio_unexport(gpio);
+       gpiod_unexport(desc);
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
                if (chip->free) {
                        spin_unlock_irqrestore(&gpio_lock, flags);
                        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);
                }
                desc_set_label(desc, NULL);
@@ -1396,6 +1491,11 @@ void gpio_free(unsigned gpio)
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 }
+
+void gpio_free(unsigned gpio)
+{
+       gpiod_free(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(gpio_free);
 
 /**
@@ -1406,29 +1506,32 @@ EXPORT_SYMBOL_GPL(gpio_free);
  */
 int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
 {
+       struct gpio_desc *desc;
        int err;
 
-       err = gpio_request(gpio, label);
+       desc = gpio_to_desc(gpio);
+
+       err = gpiod_request(desc, label);
        if (err)
                return err;
 
        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)
-               set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 
        if (flags & GPIOF_DIR_IN)
-               err = gpio_direction_input(gpio);
+               err = gpiod_direction_input(desc);
        else
-               err = gpio_direction_output(gpio,
+               err = gpiod_direction_output(desc,
                                (flags & GPIOF_INIT_HIGH) ? 1 : 0);
 
        if (err)
                goto free_gpio;
 
        if (flags & GPIOF_EXPORT) {
-               err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE);
+               err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
                if (err)
                        goto free_gpio;
        }
@@ -1436,7 +1539,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
        return 0;
 
  free_gpio:
-       gpio_free(gpio);
+       gpiod_free(desc);
        return err;
 }
 EXPORT_SYMBOL_GPL(gpio_request_one);
@@ -1491,14 +1594,17 @@ EXPORT_SYMBOL_GPL(gpio_free_array);
  */
 const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
 {
-       unsigned gpio = chip->base + offset;
+       struct gpio_desc *desc;
 
-       if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
+       if (!GPIO_OFFSET_VALID(chip, offset))
                return NULL;
-       if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
+
+       desc = &chip->desc[offset];
+
+       if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
                return NULL;
 #ifdef CONFIG_DEBUG_FS
-       return gpio_desc[gpio].label;
+       return desc->label;
 #else
        return "?";
 #endif
@@ -1515,24 +1621,24 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
  * 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;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int                     offset;
+
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
-               goto fail;
        chip = desc->chip;
        if (!chip || !chip->get || !chip->direction_input)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1542,11 +1648,12 @@ int gpio_direction_input(unsigned gpio)
 
        might_sleep_if(chip->can_sleep);
 
+       offset = gpio_chip_hwgpio(desc);
        if (status) {
-               status = chip->request(chip, gpio);
+               status = chip->request(chip, offset);
                if (status < 0) {
                        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 ...
                         * gpio_request() is the fully clean solution.
                         */
@@ -1554,48 +1661,53 @@ int gpio_direction_input(unsigned gpio)
                }
        }
 
-       status = chip->direction_input(chip, gpio);
+       status = chip->direction_input(chip, offset);
        if (status == 0)
                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:
        return status;
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
        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;
 }
+
+int gpio_direction_input(unsigned gpio)
+{
+       return gpiod_direction_input(gpio_to_desc(gpio));
+}
 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;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int offset;
+
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
 
        /* Open drain pin should not be driven to 1 */
        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 */
        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);
 
-       if (!gpio_is_valid(gpio))
-               goto fail;
        chip = desc->chip;
        if (!chip || !chip->set || !chip->direction_output)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1605,11 +1717,12 @@ int gpio_direction_output(unsigned gpio, int value)
 
        might_sleep_if(chip->can_sleep);
 
+       offset = gpio_chip_hwgpio(desc);
        if (status) {
-               status = chip->request(chip, gpio);
+               status = chip->request(chip, offset);
                if (status < 0) {
                        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 ...
                         * gpio_request() is the fully clean solution.
                         */
@@ -1617,20 +1730,25 @@ 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)
                set_bit(FLAG_IS_OUT, &desc->flags);
-       trace_gpio_value(chip->base + gpio, 0, value);
-       trace_gpio_direction(chip->base + gpio, 0, status);
+       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)
-               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;
 }
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       return gpiod_direction_output(gpio_to_desc(gpio), value);
+}
 EXPORT_SYMBOL_GPL(gpio_direction_output);
 
 /**
@@ -1638,24 +1756,25 @@ EXPORT_SYMBOL_GPL(gpio_direction_output);
  * @gpio: the gpio to set debounce time
  * @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;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int                     offset;
+
+       if (!desc) {
+               pr_warn("%s: invalid GPIO\n", __func__);
+               return -EINVAL;
+       }
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
-               goto fail;
        chip = desc->chip;
        if (!chip || !chip->set || !chip->set_debounce)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1665,16 +1784,22 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
 
        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:
        spin_unlock_irqrestore(&gpio_lock, flags);
        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;
 }
+
+int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return gpiod_set_debounce(gpio_to_desc(gpio), debounce);
+}
 EXPORT_SYMBOL_GPL(gpio_set_debounce);
 
 /* I/O calls are only valid after configuration completed; the relevant
@@ -1708,18 +1833,27 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
  * It returns the zero or nonzero value provided by the associated
  * gpio_chip.get() method; or zero if no such method is provided.
  */
-int __gpio_get_value(unsigned gpio)
+static int gpiod_get_value(const struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
        int value;
+       int offset;
 
-       chip = gpio_to_chip(gpio);
+       if (!desc)
+               return 0;
+       chip = desc->chip;
+       offset = gpio_chip_hwgpio(desc);
        /* Should be using gpio_get_value_cansleep() */
        WARN_ON(chip->can_sleep);
-       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
-       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;
 }
+
+int __gpio_get_value(unsigned gpio)
+{
+       return gpiod_get_value(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
 /*
@@ -1728,23 +1862,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value);
  * @chip: Gpio chip.
  * @value: Non-zero for setting it HIGH otherise it will set to LOW.
  */
-static void _gpio_set_open_drain_value(unsigned gpio,
-                       struct gpio_chip *chip, int value)
+static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
 {
        int err = 0;
+       struct gpio_chip *chip = desc->chip;
+       int offset = gpio_chip_hwgpio(desc);
+
        if (value) {
-               err = chip->direction_input(chip, gpio - chip->base);
+               err = chip->direction_input(chip, offset);
                if (!err)
-                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       clear_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_output(chip, gpio - chip->base, 0);
+               err = chip->direction_output(chip, offset, 0);
                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)
                pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
-                                       __func__, gpio, err);
+                                       __func__, desc_to_gpio(desc), err);
 }
 
 /*
@@ -1753,26 +1889,27 @@ static void _gpio_set_open_drain_value(unsigned gpio,
  * @chip: Gpio chip.
  * @value: Non-zero for setting it HIGH otherise it will set to LOW.
  */
-static void _gpio_set_open_source_value(unsigned gpio,
-                       struct gpio_chip *chip, int value)
+static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
 {
        int err = 0;
+       struct gpio_chip *chip = desc->chip;
+       int offset = gpio_chip_hwgpio(desc);
+
        if (value) {
-               err = chip->direction_output(chip, gpio - chip->base, 1);
+               err = chip->direction_output(chip, offset, 1);
                if (!err)
-                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       set_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_input(chip, gpio - chip->base);
+               err = chip->direction_input(chip, offset);
                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)
                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: gpio whose value will be assigned
@@ -1782,20 +1919,27 @@ static void _gpio_set_open_source_value(unsigned gpio,
  * This is used directly or indirectly to implement gpio_set_value().
  * 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;
 
-       chip = gpio_to_chip(gpio);
+       if (!desc)
+               return;
+       chip = desc->chip;
        /* Should be using gpio_set_value_cansleep() */
        WARN_ON(chip->can_sleep);
-       trace_gpio_value(gpio, 0, value);
-       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
-               _gpio_set_open_drain_value(gpio, chip, value);
-       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
-               _gpio_set_open_source_value(gpio, chip, value);
+       trace_gpio_value(desc_to_gpio(desc), 0, value);
+       if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+               _gpio_set_open_drain_value(desc, value);
+       else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+               _gpio_set_open_source_value(desc, value);
        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);
 
@@ -1807,14 +1951,17 @@ EXPORT_SYMBOL_GPL(__gpio_set_value);
  * This is used directly or indirectly to implement gpio_cansleep().  It
  * returns nonzero if access reading or writing the GPIO value can sleep.
  */
-int __gpio_cansleep(unsigned gpio)
+static int gpiod_cansleep(const struct gpio_desc *desc)
 {
-       struct gpio_chip        *chip;
-
+       if (!desc)
+               return 0;
        /* 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);
 
@@ -1827,50 +1974,73 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep);
  * It returns the number of the IRQ signaled by this (input) GPIO,
  * or a negative errno.
  */
-int __gpio_to_irq(unsigned gpio)
+static int gpiod_to_irq(const struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
+       int                     offset;
 
-       chip = gpio_to_chip(gpio);
-       return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+       if (!desc)
+               return -EINVAL;
+       chip = desc->chip;
+       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.
  * Common examples include ones connected to I2C or SPI chips.
  */
 
-int gpio_get_value_cansleep(unsigned gpio)
+static int gpiod_get_value_cansleep(const struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
        int value;
+       int offset;
 
        might_sleep_if(extra_checks);
-       chip = gpio_to_chip(gpio);
-       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
-       trace_gpio_value(gpio, 1, value);
+       if (!desc)
+               return 0;
+       chip = desc->chip;
+       offset = gpio_chip_hwgpio(desc);
+       value = chip->get ? chip->get(chip, offset) : 0;
+       trace_gpio_value(desc_to_gpio(desc), 1, 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);
 
-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;
 
        might_sleep_if(extra_checks);
-       chip = gpio_to_chip(gpio);
-       trace_gpio_value(gpio, 0, value);
-       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
-               _gpio_set_open_drain_value(gpio, chip, value);
-       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
-               _gpio_set_open_source_value(gpio, chip, value);
+       if (!desc)
+               return;
+       chip = desc->chip;
+       trace_gpio_value(desc_to_gpio(desc), 0, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
+               _gpio_set_open_drain_value(desc, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
+               _gpio_set_open_source_value(desc, value);
        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
 
@@ -1878,14 +2048,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        unsigned                i;
        unsigned                gpio = chip->base;
-       struct gpio_desc        *gdesc = &gpio_desc[gpio];
+       struct gpio_desc        *gdesc = &chip->desc[0];
        int                     is_out;
 
        for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
                if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
                        continue;
 
-               gpio_get_direction(gpio);
+               gpiod_get_direction(gdesc);
                is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
                seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
                        gpio, gdesc->label,
@@ -1899,46 +2069,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 
 static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_chip *chip = NULL;
-       unsigned int gpio;
-       void *ret = NULL;
-       loff_t index = 0;
-
-       /* REVISIT this isn't locked against gpio_chip removal ... */
-
-       for (gpio = 0; gpio_is_valid(gpio); gpio++) {
-               if (gpio_desc[gpio].chip == chip)
-                       continue;
+       loff_t index = *pos;
 
-               chip = gpio_desc[gpio].chip;
-               if (!chip)
-                       continue;
+       s->private = "";
 
-               if (index++ >= *pos) {
-                       ret = chip;
-                       break;
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_for_each_entry(chip, &gpio_chips, list)
+               if (index-- == 0) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       return chip;
                }
-       }
-
-       s->private = "";
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
-       return ret;
+       return NULL;
 }
 
 static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_chip *chip = v;
-       unsigned int gpio;
        void *ret = NULL;
 
-       /* skip GPIOs provided by the current chip */
-       for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
-               chip = gpio_desc[gpio].chip;
-               if (chip) {
-                       ret = chip;
-                       break;
-               }
-       }
+       spin_lock_irqsave(&gpio_lock, flags);
+       if (list_is_last(&chip->list, &gpio_chips))
+               ret = NULL;
+       else
+               ret = list_entry(chip->list.next, struct gpio_chip, list);
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
        s->private = "\n";
        ++*pos;