Merge commit 'gpio-lw/devel' into spear-for-3.8
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 26 Nov 2012 10:18:53 +0000 (15:48 +0530)
committerViresh Kumar <viresh.kumar@linaro.org>
Mon, 26 Nov 2012 10:18:53 +0000 (15:48 +0530)
This merges dependency branch gpio-lw/devel for SPEAr DT updates.

1  2 
arch/arm/Kconfig
drivers/gpio/Kconfig
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpiolib.c
include/asm-generic/gpio.h

diff --combined arch/arm/Kconfig
index ade7e924bef5faaf00de76c0354e025ed4371b35,f456cf4ae3ca4634dc3976fddf4eeed43e3adb3a..b673d65449f85e4285037bfa91d9084b9de4d020
@@@ -364,6 -364,7 +364,7 @@@ config ARCH_CNS3XX
  
  config ARCH_CLPS711X
        bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
+       select ARCH_REQUIRE_GPIOLIB
        select ARCH_USES_GETTIMEOFFSET
        select CLKDEV_LOOKUP
        select COMMON_CLK
@@@ -1603,8 -1604,8 +1604,8 @@@ config NR_CPU
        default "4"
  
  config HOTPLUG_CPU
 -      bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
 -      depends on SMP && HOTPLUG && EXPERIMENTAL
 +      bool "Support for hot-pluggable CPUs"
 +      depends on SMP && HOTPLUG
        help
          Say Y here to experiment with turning CPUs off and on.  CPUs
          can be controlled through /sys/devices/system/cpu.
@@@ -1645,8 -1646,8 +1646,8 @@@ config H
        default 100
  
  config THUMB2_KERNEL
 -      bool "Compile the kernel in Thumb-2 mode (EXPERIMENTAL)"
 -      depends on CPU_V7 && !CPU_V6 && !CPU_V6K && EXPERIMENTAL
 +      bool "Compile the kernel in Thumb-2 mode"
 +      depends on CPU_V7 && !CPU_V6 && !CPU_V6K
        select AEABI
        select ARM_ASM_UNIFIED
        select ARM_UNWIND
@@@ -1850,7 -1851,6 +1851,7 @@@ config XEN_DOM
  config XEN
        bool "Xen guest support on ARM (EXPERIMENTAL)"
        depends on EXPERIMENTAL && ARM && OF
 +      depends on CPU_V7 && !CPU_V6
        help
          Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
  
diff --combined drivers/gpio/Kconfig
index 47150f5ded04ea4df13c14434fc3fa553141abaf,4f592c61599083b9faa107e9efb5feaae3578930..b0e67b200aa0469eba033ebd5a621aedb3598c83
@@@ -47,7 -47,7 +47,7 @@@ if GPIOLI
  
  config OF_GPIO
        def_bool y
 -      depends on OF && !SPARC
 +      depends on OF
  
  config DEBUG_GPIO
        bool "Debug GPIO calls"
@@@ -86,11 -86,26 +86,26 @@@ config GPIO_DA905
        help
          Say yes here to enable the GPIO driver for the DA9052 chip.
  
+ config GPIO_DA9055
+       tristate "Dialog Semiconductor DA9055 GPIO"
+       depends on MFD_DA9055
+       help
+         Say yes here to enable the GPIO driver for the DA9055 chip.
+         The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
+         be controller by this driver.
+         If driver is built as a module it will be called gpio-da9055.
  config GPIO_MAX730X
        tristate
  
  comment "Memory mapped GPIO drivers:"
  
+ config GPIO_CLPS711X
+       def_bool y
+       depends on ARCH_CLPS711X
  config GPIO_GENERIC_PLATFORM
        tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
        select GPIO_GENERIC
@@@ -181,6 -196,13 +196,13 @@@ config GPIO_PX
        help
          Say yes here to support the PXA GPIO device
  
+ config GPIO_SPEAR_SPICS
+       bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+       depends on PLAT_SPEAR
+       select GENERIC_IRQ_CHIP
+       help
+         Say yes here to support ST SPEAr SPI Chip Select as GPIO device
  config GPIO_STA2X11
        bool "STA2x11/ConneXt GPIO support"
        depends on MFD_STA2X11
@@@ -466,7 -488,7 +488,7 @@@ config GPIO_ADP5588_IR
  
  config GPIO_ADNP
        tristate "Avionic Design N-bit GPIO expander"
 -      depends on I2C && OF
 +      depends on I2C && OF_GPIO
        help
          This option enables support for N GPIOs found on Avionic Design
          I2C GPIO expanders. The register space will be extended by powers
index be65c0451ad556e174b961f3542cc8d7b40e201c,8b30657035662183fe8f2ce5b26114ff117393fb..a515b9294e92672ce69f09d042ccb7addedc97b5
@@@ -92,11 -92,6 +92,11 @@@ static inline void __iomem *mvebu_gpior
        return mvchip->membase + GPIO_OUT_OFF;
  }
  
 +static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
 +{
 +      return mvchip->membase + GPIO_BLINK_EN_OFF;
 +}
 +
  static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
  {
        return mvchip->membase + GPIO_IO_CONF_OFF;
@@@ -168,12 -163,12 +168,12 @@@ static void __iomem *mvebu_gpioreg_leve
   * Functions implementing the gpio_chip methods
   */
  
- int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
  {
        return pinctrl_request_gpio(chip->base + pin);
  }
  
- void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
  {
        pinctrl_free_gpio(chip->base + pin);
  }
@@@ -211,23 -206,6 +211,23 @@@ static int mvebu_gpio_get(struct gpio_c
        return (u >> pin) & 1;
  }
  
 +static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
 +{
 +      struct mvebu_gpio_chip *mvchip =
 +              container_of(chip, struct mvebu_gpio_chip, chip);
 +      unsigned long flags;
 +      u32 u;
 +
 +      spin_lock_irqsave(&mvchip->lock, flags);
 +      u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
 +      if (value)
 +              u |= 1 << pin;
 +      else
 +              u &= ~(1 << pin);
 +      writel_relaxed(u, mvebu_gpioreg_blink(mvchip));
 +      spin_unlock_irqrestore(&mvchip->lock, flags);
 +}
 +
  static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
  {
        struct mvebu_gpio_chip *mvchip =
@@@ -266,9 -244,6 +266,9 @@@ static int mvebu_gpio_direction_output(
        if (ret)
                return ret;
  
 +      mvebu_gpio_blink(chip, pin, 0);
 +      mvebu_gpio_set(chip, pin, value);
 +
        spin_lock_irqsave(&mvchip->lock, flags);
        u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
        u &= ~(1 << pin);
@@@ -406,13 -381,11 +406,13 @@@ static int mvebu_gpio_irq_set_type(stru
                u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
                u &= ~(1 << pin);
                writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
 +              break;
        case IRQ_TYPE_EDGE_FALLING:
        case IRQ_TYPE_LEVEL_LOW:
                u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
                u |= 1 << pin;
                writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
 +              break;
        case IRQ_TYPE_EDGE_BOTH: {
                u32 v;
  
                else
                        u &= ~(1 << pin);       /* rising */
                writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
 +              break;
        }
        }
        return 0;
@@@ -546,6 -518,7 +546,7 @@@ static int __devinit mvebu_gpio_probe(s
        mvchip->chip.label = dev_name(&pdev->dev);
        mvchip->chip.dev = &pdev->dev;
        mvchip->chip.request = mvebu_gpio_request;
+       mvchip->chip.free = mvebu_gpio_free;
        mvchip->chip.direction_input = mvebu_gpio_direction_input;
        mvchip->chip.get = mvebu_gpio_get;
        mvchip->chip.direction_output = mvebu_gpio_direction_output;
        ct->handler = handle_edge_irq;
        ct->chip.name = mvchip->chip.label;
  
 -      irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE,
 +      irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
                               IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
  
        /* Setup irq domain on top of the generic chip. */
-       mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
-                                              mvchip->irqbase, 0,
+       mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
+                                              mvchip->irqbase,
                                               &irq_domain_simple_ops,
                                               mvchip);
        if (!mvchip->domain) {
diff --combined drivers/gpio/gpio-omap.c
index d335af1d4d858da39b2825fd9144c01e76f877e5,eb73dee0ab337fc23d5c7c4f2f521726ddaeaa9c..d71e5bdf7b9741fe93587032fe7b66ea73e05b21
@@@ -251,40 -251,6 +251,40 @@@ static void _set_gpio_debounce(struct g
        }
  }
  
 +/**
 + * _clear_gpio_debounce - clear debounce settings for a gpio
 + * @bank: the gpio bank we're acting upon
 + * @gpio: the gpio number on this @gpio
 + *
 + * If a gpio is using debounce, then clear the debounce enable bit and if
 + * this is the only gpio in this bank using debounce, then clear the debounce
 + * time too. The debounce clock will also be disabled when calling this function
 + * if this is the only gpio in the bank using debounce.
 + */
 +static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
 +{
 +      u32 gpio_bit = GPIO_BIT(bank, gpio);
 +
 +      if (!bank->dbck_flag)
 +              return;
 +
 +      if (!(bank->dbck_enable_mask & gpio_bit))
 +              return;
 +
 +      bank->dbck_enable_mask &= ~gpio_bit;
 +      bank->context.debounce_en &= ~gpio_bit;
 +      __raw_writel(bank->context.debounce_en,
 +                   bank->base + bank->regs->debounce_en);
 +
 +      if (!bank->dbck_enable_mask) {
 +              bank->context.debounce = 0;
 +              __raw_writel(bank->context.debounce, bank->base +
 +                           bank->regs->debounce);
 +              clk_disable(bank->dbck);
 +              bank->dbck_enabled = false;
 +      }
 +}
 +
  static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
                                                unsigned trigger)
  {
@@@ -573,7 -539,6 +573,7 @@@ static void _reset_gpio(struct gpio_ban
        _set_gpio_irqenable(bank, gpio, 0);
        _clear_gpio_irqstatus(bank, gpio);
        _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
 +      _clear_gpio_debounce(bank, gpio);
  }
  
  /* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
@@@ -1105,7 -1070,7 +1105,7 @@@ static int __devinit omap_gpio_probe(st
        if (!pdata)
                return -EINVAL;
  
-       bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
+       bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
        if (!bank) {
                dev_err(dev, "Memory alloc failed\n");
                return -ENOMEM;
diff --combined drivers/gpio/gpiolib.c
index c5f650095faafa9e3f1b1a71759671c411bb17c6,fd2b71c7099769f12e48be87d80f5f9714894deb..b667f768c23b6d3d5ce707bbeb0a639bfa2e2b62
@@@ -191,6 -191,32 +191,32 @@@ err
        return ret;
  }
  
+ /* caller ensures gpio is valid and requested, chip->get_direction may sleep  */
+ static int gpio_get_direction(unsigned gpio)
+ {
+       struct gpio_chip        *chip;
+       struct gpio_desc        *desc = &gpio_desc[gpio];
+       int                     status = -EINVAL;
+       chip = gpio_to_chip(gpio);
+       gpio -= chip->base;
+       if (!chip->get_direction)
+               return status;
+       status = chip->get_direction(chip, gpio);
+       if (status > 0) {
+               /* GPIOF_DIR_IN, or other positive */
+               status = 1;
+               clear_bit(FLAG_IS_OUT, &desc->flags);
+       }
+       if (status == 0) {
+               /* GPIOF_DIR_OUT */
+               set_bit(FLAG_IS_OUT, &desc->flags);
+       }
+       return status;
+ }
  #ifdef CONFIG_GPIO_SYSFS
  
  /* lock protects against unexport_gpio() being called while
@@@ -223,6 -249,7 +249,7 @@@ static ssize_t gpio_direction_show(stru
                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))
                status = -EIO;
        else
+               gpio_get_direction(gpio);
                status = sprintf(buf, "%s\n",
                        test_bit(FLAG_IS_OUT, &desc->flags)
                                ? "out" : "in");
@@@ -623,11 -651,9 +651,11 @@@ static ssize_t export_store(struct clas
         */
  
        status = gpio_request(gpio, "sysfs");
 -      if (status < 0)
 +      if (status < 0) {
 +              if (status == -EPROBE_DEFER)
 +                      status = -ENODEV;
                goto done;
 -
 +      }
        status = gpio_export(gpio, true);
        if (status < 0)
                gpio_free(gpio);
@@@ -704,8 -730,9 +732,9 @@@ int gpio_export(unsigned gpio, bool dir
  {
        unsigned long           flags;
        struct gpio_desc        *desc;
-       int                     status = -EINVAL;
+       int                     status;
        const char              *ioname = NULL;
+       struct device           *dev;
  
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
                return -ENOENT;
        }
  
-       if (!gpio_is_valid(gpio))
-               goto done;
+       if (!gpio_is_valid(gpio)) {
+               pr_debug("%s: gpio %d is not valid\n", __func__, gpio);
+               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)) {
-               status = 0;
-               if (!desc->chip->direction_input
-                               || !desc->chip->direction_output)
-                       direction_may_change = false;
+       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,
+                               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);
  
        if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
                ioname = desc->chip->names[gpio - desc->chip->base];
  
-       if (status == 0) {
-               struct device   *dev;
-               dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                               desc, ioname ? ioname : "gpio%u", gpio);
-               if (!IS_ERR(dev)) {
-                       status = sysfs_create_group(&dev->kobj,
-                                               &gpio_attr_group);
-                       if (!status && direction_may_change)
-                               status = device_create_file(dev,
-                                               &dev_attr_direction);
-                       if (!status && gpio_to_irq(gpio) >= 0
-                                       && (direction_may_change
-                                               || !test_bit(FLAG_IS_OUT,
-                                                       &desc->flags)))
-                               status = device_create_file(dev,
-                                               &dev_attr_edge);
-                       if (status != 0)
-                               device_unregister(dev);
-               } else
-                       status = PTR_ERR(dev);
-               if (status == 0)
-                       set_bit(FLAG_EXPORT, &desc->flags);
+       dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
+                           desc, ioname ? ioname : "gpio%u", gpio);
+       if (IS_ERR(dev)) {
+               status = PTR_ERR(dev);
+               goto fail_unlock;
        }
  
-       mutex_unlock(&sysfs_lock);
- done:
+       status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
        if (status)
-               pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+               goto fail_unregister_device;
  
+       if (direction_may_change) {
+               status = device_create_file(dev, &dev_attr_direction);
+               if (status)
+                       goto fail_unregister_device;
+       }
+       if (gpio_to_irq(gpio) >= 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);
+       pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
        return status;
  }
  EXPORT_SYMBOL_GPL(gpio_export);
@@@ -1075,6 -1109,7 +1111,7 @@@ int gpiochip_add(struct gpio_chip *chip
                         * inputs (often with pullups enabled) so power
                         * usage is minimized.  Linux code should set the
                         * gpio direction first thing; but until it does,
+                        * and in case chip->get_direction is not set,
                         * we may expose the wrong direction in sysfs.
                         */
                        gpio_desc[id].flags = !chip->direction_input
                }
        }
  
 +#ifdef CONFIG_PINCTRL
 +      INIT_LIST_HEAD(&chip->pin_ranges);
 +#endif
 +
        of_gpiochip_add(chip);
  
  unlock:
@@@ -1127,7 -1158,6 +1164,7 @@@ int gpiochip_remove(struct gpio_chip *c
  
        spin_lock_irqsave(&gpio_lock, flags);
  
 +      gpiochip_remove_pin_ranges(chip);
        of_gpiochip_remove(chip);
  
        for (id = chip->base; id < chip->base + chip->ngpio; id++) {
@@@ -1185,47 -1215,6 +1222,47 @@@ struct gpio_chip *gpiochip_find(void *d
  }
  EXPORT_SYMBOL_GPL(gpiochip_find);
  
 +#ifdef CONFIG_PINCTRL
 +
 +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
 +                         unsigned int pin_base, unsigned int npins)
 +{
 +      struct gpio_pin_range *pin_range;
 +
 +      pin_range = devm_kzalloc(chip->dev, sizeof(*pin_range), GFP_KERNEL);
 +      if (!pin_range) {
 +              pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
 +                              chip->label);
 +              return -ENOMEM;
 +      }
 +
 +      pin_range->range.name = chip->label;
 +      pin_range->range.base = chip->base;
 +      pin_range->range.pin_base = pin_base;
 +      pin_range->range.npins = npins;
 +      pin_range->pctldev = find_pinctrl_and_add_gpio_range(pinctl_name,
 +                      &pin_range->range);
 +
 +      list_add_tail(&pin_range->node, &chip->pin_ranges);
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
 +
 +void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
 +{
 +      struct gpio_pin_range *pin_range, *tmp;
 +
 +      list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
 +              list_del(&pin_range->node);
 +              pinctrl_remove_gpio_range(pin_range->pctldev,
 +                              &pin_range->range);
 +      }
 +}
 +EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
 +
 +#endif /* CONFIG_PINCTRL */
 +
  /* These "optional" allocation calls help prevent drivers from stomping
   * on each other, and help provide better diagnostics in debugfs.
   * They're called even less than the "set direction" calls.
@@@ -1239,10 -1228,8 +1276,10 @@@ int gpio_request(unsigned gpio, const c
  
        spin_lock_irqsave(&gpio_lock, flags);
  
 -      if (!gpio_is_valid(gpio))
 +      if (!gpio_is_valid(gpio)) {
 +              status = -EINVAL;
                goto done;
 +      }
        desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip == NULL)
                        desc_set_label(desc, NULL);
                        module_put(chip->owner);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
+                       goto done;
                }
        }
+       if (chip->get_direction) {
+               /* chip->get_direction may sleep */
+               spin_unlock_irqrestore(&gpio_lock, flags);
+               gpio_get_direction(gpio);
+               spin_lock_irqsave(&gpio_lock, flags);
+       }
  done:
        if (status)
                pr_debug("gpio_request: gpio-%d (%s) status %d\n",
@@@ -1812,6 -1805,7 +1855,7 @@@ static void gpiolib_dbg_show(struct seq
                if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
                        continue;
  
+               gpio_get_direction(gpio);
                is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
                seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
                        gpio, gdesc->label,
index 2b84fc32fae2bf9f861104ebd8d8c0adc4d9006a,eb70ca295971ea4f76f34987ebeedc2bad7ac4db..b6516f32280de4cf7e7f11f1daa46c3e32160de6
@@@ -5,7 -5,6 +5,7 @@@
  #include <linux/types.h>
  #include <linux/errno.h>
  #include <linux/of.h>
 +#include <linux/pinctrl/pinctrl.h>
  
  #ifdef CONFIG_GPIOLIB
  
@@@ -57,6 -56,8 +57,8 @@@ struct device_node
   *    enabling module power and clock; may sleep
   * @free: optional hook for chip-specific deactivation, such as
   *    disabling module power and clock; may sleep
+  * @get_direction: returns direction for signal "offset", 0=out, 1=in,
+  *    (same as GPIOF_DIR_XXX), or negative error
   * @direction_input: configures signal "offset" as input, or returns error
   * @get: returns value for signal "offset"; for output signals this
   *    returns either the value actually sensed, or zero
@@@ -101,7 -102,8 +103,8 @@@ struct gpio_chip 
                                                unsigned offset);
        void                    (*free)(struct gpio_chip *chip,
                                                unsigned offset);
+       int                     (*get_direction)(struct gpio_chip *chip,
+                                               unsigned offset);
        int                     (*direction_input)(struct gpio_chip *chip,
                                                unsigned offset);
        int                     (*get)(struct gpio_chip *chip,
        int (*of_xlate)(struct gpio_chip *gc,
                        const struct of_phandle_args *gpiospec, u32 *flags);
  #endif
 +#ifdef CONFIG_PINCTRL
 +      /*
 +       * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
 +       * describe the actual pin range which they serve in an SoC. This
 +       * information would be used by pinctrl subsystem to configure
 +       * corresponding pins for gpio usage.
 +       */
 +      struct list_head pin_ranges;
 +#endif
  };
  
  extern const char *gpiochip_is_requested(struct gpio_chip *chip,
@@@ -267,39 -260,4 +270,39 @@@ static inline void gpio_unexport(unsign
  }
  #endif        /* CONFIG_GPIO_SYSFS */
  
 +#ifdef CONFIG_PINCTRL
 +
 +/**
 + * struct gpio_pin_range - pin range controlled by a gpio chip
 + * @head: list for maintaining set of pin ranges, used internally
 + * @pctldev: pinctrl device which handles corresponding pins
 + * @range: actual range of pins controlled by a gpio controller
 + */
 +
 +struct gpio_pin_range {
 +      struct list_head node;
 +      struct pinctrl_dev *pctldev;
 +      struct pinctrl_gpio_range range;
 +};
 +
 +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
 +                         unsigned int pin_base, unsigned int npins);
 +void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
 +
 +#else
 +
 +static inline int
 +gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
 +                     unsigned int pin_base, unsigned int npins)
 +{
 +      return 0;
 +}
 +
 +static inline void
 +gpiochip_remove_pin_ranges(struct gpio_chip *chip)
 +{
 +}
 +
 +#endif /* CONFIG_PINCTRL */
 +
  #endif /* _ASM_GENERIC_GPIO_H */