Merge tag 'gpio-v3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Dec 2014 22:05:05 +0000 (14:05 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 14 Dec 2014 22:05:05 +0000 (14:05 -0800)
Pull take two of the GPIO updates:
 "Same stuff as last time, now with a fixup patch for the previous
  compile error plus I ran a few extra rounds of compile-testing.

  This is the bulk of GPIO changes for the v3.19 series:

   - A new API that allows setting more than one GPIO at the time.  This
     is implemented for the new descriptor-based API only and makes it
     possible to e.g. toggle a clock and data line at the same time, if
     the hardware can do this with a single register write.  Both
     consumers and drivers need new calls, and the core will fall back
     to driving individual lines where needed.  Implemented for the
     MPC8xxx driver initially

   - Patched the mdio-mux-gpio and the serial mctrl driver that drives
     modems to use the new multiple-setting API to set several signals
     simultaneously

   - Get rid of the global GPIO descriptor array, and instead allocate
     descriptors dynamically for each GPIO on a certain GPIO chip.  This
     moves us closer to getting rid of the limitation of using the
     global, static GPIO numberspace

   - New driver and device tree bindings for 74xx ICs

   - New driver and device tree bindings for the VF610 Vybrid

   - Support the RCAR r8a7793 and r8a7794

   - Guidelines for GPIO device tree bindings trying to get things a bit
     more strict with the advent of combined device properties

   - Suspend/resume support for the MVEBU driver

   - A slew of minor fixes and improvements"

* tag 'gpio-v3.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (33 commits)
  gpio: mcp23s08: fix up compilation error
  gpio: pl061: document gpio-ranges property for bindings file
  gpio: pl061: hook request if gpio-ranges avaiable
  gpio: mcp23s08: Add option to configure IRQ output polarity as active high
  gpio: fix deferred probe detection for legacy API
  serial: mctrl_gpio: use gpiod_set_array function
  mdio-mux-gpio: Use GPIO descriptor interface and new gpiod_set_array function
  gpio: remove const modifier from gpiod_get_direction()
  gpio: remove gpio_descs global array
  gpio: mxs: implement get_direction callback
  gpio: em: Use dynamic allocation of GPIOs
  gpio: Check if base is positive before calling gpio_is_valid()
  gpio: mcp23s08: Add simple IRQ support for SPI devices
  gpio: mcp23s08: request a shared interrupt
  gpio: mcp23s08: Do not free unrequested interrupt
  gpio: rcar: Add r8a7793 and r8a7794 support
  gpio-mpc8xxx: add mpc8xxx_gpio_set_multiple function
  gpiolib: allow simultaneous setting of multiple GPIO outputs
  gpio: mvebu: add suspend/resume support
  gpio: gpio-davinci: remove duplicate check on resource
  ..

1  2 
Documentation/gpio/consumer.txt
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-omap.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/samsung/pinctrl-exynos.c
include/linux/gpio/consumer.h

@@@ -199,6 -199,33 +199,33 @@@ The active-low state of a GPIO can als
  Note that these functions should only be used with great moderation ; a driver
  should not have to care about the physical line level.
  
+ Set multiple GPIO outputs with a single function call
+ -----------------------------------------------------
+ The following functions set the output values of an array of GPIOs:
+       void gpiod_set_array(unsigned int array_size,
+                            struct gpio_desc **desc_array,
+                            int *value_array)
+       void gpiod_set_raw_array(unsigned int array_size,
+                                struct gpio_desc **desc_array,
+                                int *value_array)
+       void gpiod_set_array_cansleep(unsigned int array_size,
+                                     struct gpio_desc **desc_array,
+                                     int *value_array)
+       void gpiod_set_raw_array_cansleep(unsigned int array_size,
+                                         struct gpio_desc **desc_array,
+                                         int *value_array)
+ The array can be an arbitrary set of GPIOs. The functions will try to set
+ GPIOs belonging to the same bank or chip simultaneously if supported by the
+ corresponding chip driver. In that case a significantly improved performance
+ can be expected. If simultaneous setting is not possible the GPIOs will be set
+ sequentially.
+ Note that for optimal performance GPIOs belonging to the same chip should be
+ contiguous within the array of descriptors.
  GPIOs mapped to IRQs
  --------------------
  GPIO lines can quite often be used as IRQs. You can get the IRQ number
@@@ -219,24 -246,6 +246,24 @@@ part of the IRQ interface, e.g. IRQF_TR
  capabilities.
  
  
 +GPIOs and ACPI
 +==============
 +
 +On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
 +the _CRS configuration objects of devices.  Those resources do not provide
 +connection IDs (names) for GPIOs, so it is necessary to use an additional
 +mechanism for this purpose.
 +
 +Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
 +which, among other things, may be used to provide connection IDs for specific
 +GPIOs described by the GpioIo()/GpioInt() resources in _CRS.  If that is the
 +case, it will be handled by the GPIO subsystem automatically.  However, if the
 +_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
 +connection IDs need to be provided by device drivers.
 +
 +For details refer to Documentation/acpi/gpio-properties.txt
 +
 +
  Interacting With the Legacy GPIO Subsystem
  ==========================================
  Many kernel subsystems still handle GPIOs using the legacy integer-based
diff --combined drivers/gpio/Kconfig
@@@ -112,6 -112,20 +112,20 @@@ config GPIO_MAX730
  
  comment "Memory mapped GPIO drivers:"
  
+ config GPIO_74XX_MMIO
+       tristate "GPIO driver for 74xx-ICs with MMIO access"
+       depends on OF_GPIO
+       select GPIO_GENERIC
+       help
+         Say yes here to support GPIO functionality for 74xx-compatible ICs
+         with MMIO access. Compatible models include:
+           1 bit:      741G125 (Input), 741G74 (Output)
+           2 bits:     742G125 (Input), 7474 (Output)
+           4 bits:     74125 (Input), 74175 (Output)
+           6 bits:     74365 (Input), 74174 (Output)
+           8 bits:     74244 (Input), 74273 (Output)
+           16 bits:    741624 (Input), 7416374 (Output)
  config GPIO_CLPS711X
        tristate "CLPS711X GPIO support"
        depends on ARCH_CLPS711X || COMPILE_TEST
@@@ -134,6 -148,8 +148,8 @@@ config GPIO_GENERIC_PLATFOR
  
  config GPIO_DWAPB
        tristate "Synopsys DesignWare APB GPIO driver"
+       depends on ARM
+       depends on OF_GPIO
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
        help
@@@ -333,6 -349,13 +349,13 @@@ config GPIO_TZ1090_PD
        help
          Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
  
+ config GPIO_VF610
+       def_bool y
+       depends on ARCH_MXC && SOC_VF610
+       select GPIOLIB_IRQCHIP
+       help
+         Say yes here to support Vybrid vf610 GPIOs.
  config GPIO_XGENE
        bool "APM X-Gene GPIO controller support"
        depends on ARM64 && OF_GPIO
@@@ -905,16 -928,4 +928,16 @@@ config GPIO_VIPERBOAR
            River Tech's viperboard.h for detailed meaning
            of the module parameters.
  
 +config GPIO_DLN2
 +      tristate "Diolan DLN2 GPIO support"
 +      depends on MFD_DLN2
 +      select GPIOLIB_IRQCHIP
 +
 +      help
 +        Select this option to enable GPIO driver for the Diolan DLN2
 +        board.
 +
 +        This driver can also be built as a module. If so, the module
 +        will be called gpio-dln2.
 +
  endif
diff --combined drivers/gpio/Makefile
@@@ -13,6 -13,7 +13,7 @@@ obj-$(CONFIG_GPIO_ACPI)               += gpiolib-acp
  obj-$(CONFIG_GPIO_GENERIC)    += gpio-generic.o
  
  obj-$(CONFIG_GPIO_74X164)     += gpio-74x164.o
+ obj-$(CONFIG_GPIO_74XX_MMIO)  += gpio-74xx-mmio.o
  obj-$(CONFIG_GPIO_ADNP)               += gpio-adnp.o
  obj-$(CONFIG_GPIO_ADP5520)    += gpio-adp5520.o
  obj-$(CONFIG_GPIO_ADP5588)    += gpio-adp5588.o
@@@ -26,7 -27,6 +27,7 @@@ obj-$(CONFIG_GPIO_CRYSTAL_COVE)       += gpio
  obj-$(CONFIG_GPIO_DA9052)     += gpio-da9052.o
  obj-$(CONFIG_GPIO_DA9055)     += gpio-da9055.o
  obj-$(CONFIG_GPIO_DAVINCI)    += gpio-davinci.o
 +obj-$(CONFIG_GPIO_DLN2)               += gpio-dln2.o
  obj-$(CONFIG_GPIO_DWAPB)      += gpio-dwapb.o
  obj-$(CONFIG_GPIO_EM)         += gpio-em.o
  obj-$(CONFIG_GPIO_EP93XX)     += gpio-ep93xx.o
@@@ -96,6 -96,7 +97,7 @@@ obj-$(CONFIG_GPIO_TWL6040)    += gpio-twl6
  obj-$(CONFIG_GPIO_TZ1090)     += gpio-tz1090.o
  obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o
  obj-$(CONFIG_GPIO_UCB1400)    += gpio-ucb1400.o
+ obj-$(CONFIG_GPIO_VF610)      += gpio-vf610.o
  obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
  obj-$(CONFIG_GPIO_VR41XX)     += gpio-vr41xx.o
  obj-$(CONFIG_GPIO_VX855)      += gpio-vx855.o
diff --combined drivers/gpio/gpio-omap.c
@@@ -800,7 -800,7 +800,7 @@@ static void omap_gpio_irq_shutdown(stru
        unsigned offset = GPIO_INDEX(bank, gpio);
  
        spin_lock_irqsave(&bank->lock, flags);
-       gpio_unlock_as_irq(&bank->chip, offset);
+       gpiochip_unlock_as_irq(&bank->chip, offset);
        bank->irq_usage &= ~(BIT(offset));
        omap_disable_gpio_module(bank, offset);
        omap_reset_gpio(bank, gpio);
@@@ -1259,7 -1259,7 +1259,7 @@@ static int omap_gpio_probe(struct platf
  
  #ifdef CONFIG_ARCH_OMAP2PLUS
  
 -#if defined(CONFIG_PM_RUNTIME)
 +#if defined(CONFIG_PM)
  static void omap_gpio_restore_context(struct gpio_bank *bank);
  
  static int omap_gpio_runtime_suspend(struct device *dev)
@@@ -1440,7 -1440,7 +1440,7 @@@ static int omap_gpio_runtime_resume(str
  
        return 0;
  }
 -#endif /* CONFIG_PM_RUNTIME */
 +#endif /* CONFIG_PM */
  
  void omap2_gpio_prepare_for_idle(int pwr_mode)
  {
@@@ -1468,7 -1468,7 +1468,7 @@@ void omap2_gpio_resume_after_idle(void
        }
  }
  
 -#if defined(CONFIG_PM_RUNTIME)
 +#if defined(CONFIG_PM)
  static void omap_gpio_init_context(struct gpio_bank *p)
  {
        struct omap_gpio_reg_offs *regs = p->regs;
@@@ -1525,7 -1525,7 +1525,7 @@@ static void omap_gpio_restore_context(s
        writel_relaxed(bank->context.irqenable2,
                                bank->base + bank->regs->irqenable2);
  }
 -#endif /* CONFIG_PM_RUNTIME */
 +#endif /* CONFIG_PM */
  #else
  #define omap_gpio_runtime_suspend NULL
  #define omap_gpio_runtime_resume NULL
   */
  
  #include <linux/errno.h>
 +#include <linux/gpio.h>
  #include <linux/gpio/consumer.h>
  #include <linux/gpio/driver.h>
  #include <linux/export.h>
  #include <linux/acpi.h>
  #include <linux/interrupt.h>
  #include <linux/mutex.h>
 +#include <linux/pinctrl/pinctrl.h>
  
  #include "gpiolib.h"
  
@@@ -57,58 -55,6 +57,58 @@@ static int acpi_gpiochip_find(struct gp
        return ACPI_HANDLE(gc->dev) == data;
  }
  
 +#ifdef CONFIG_PINCTRL
 +/**
 + * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO
 + * @chip: GPIO chip
 + * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource
 + *
 + * Function takes ACPI GpioIo/GpioInt pin number as a parameter and
 + * translates it to a corresponding offset suitable to be passed to a
 + * GPIO controller driver.
 + *
 + * Typically the returned offset is same as @pin, but if the GPIO
 + * controller uses pin controller and the mapping is not contigous the
 + * offset might be different.
 + */
 +static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin)
 +{
 +      struct gpio_pin_range *pin_range;
 +
 +      /* If there are no ranges in this chip, use 1:1 mapping */
 +      if (list_empty(&chip->pin_ranges))
 +              return pin;
 +
 +      list_for_each_entry(pin_range, &chip->pin_ranges, node) {
 +              const struct pinctrl_gpio_range *range = &pin_range->range;
 +              int i;
 +
 +              if (range->pins) {
 +                      for (i = 0; i < range->npins; i++) {
 +                              if (range->pins[i] == pin)
 +                                      return range->base + i - chip->base;
 +                      }
 +              } else {
 +                      if (pin >= range->pin_base &&
 +                          pin < range->pin_base + range->npins) {
 +                              unsigned gpio_base;
 +
 +                              gpio_base = range->base - chip->base;
 +                              return gpio_base + pin - range->pin_base;
 +                      }
 +              }
 +      }
 +
 +      return -EINVAL;
 +}
 +#else
 +static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
 +                                                 int pin)
 +{
 +      return pin;
 +}
 +#endif
 +
  /**
   * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
   * @path:     ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
@@@ -123,7 -69,6 +123,7 @@@ static struct gpio_desc *acpi_get_gpiod
        struct gpio_chip *chip;
        acpi_handle handle;
        acpi_status status;
 +      int offset;
  
        status = acpi_get_handle(NULL, path, &handle);
        if (ACPI_FAILURE(status))
        if (!chip)
                return ERR_PTR(-ENODEV);
  
 -      if (pin < 0 || pin > chip->ngpio)
 -              return ERR_PTR(-EINVAL);
 +      offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
 +      if (offset < 0)
 +              return ERR_PTR(offset);
  
 -      return gpiochip_get_desc(chip, pin);
 +      return gpiochip_get_desc(chip, offset);
  }
  
  static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
@@@ -209,7 -153,7 +209,7 @@@ static acpi_status acpi_gpiochip_reques
  
        gpiod_direction_input(desc);
  
-       ret = gpio_lock_as_irq(chip, pin);
+       ret = gpiochip_lock_as_irq(chip, pin);
        if (ret) {
                dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
                goto fail_free_desc;
  fail_free_event:
        kfree(event);
  fail_unlock_irq:
-       gpio_unlock_as_irq(chip, pin);
+       gpiochip_unlock_as_irq(chip, pin);
  fail_free_desc:
        gpiochip_free_own_desc(desc);
  
@@@ -336,52 -280,16 +336,52 @@@ void acpi_gpiochip_free_interrupts(stru
                desc = event->desc;
                if (WARN_ON(IS_ERR(desc)))
                        continue;
-               gpio_unlock_as_irq(chip, event->pin);
+               gpiochip_unlock_as_irq(chip, event->pin);
                gpiochip_free_own_desc(desc);
                list_del(&event->node);
                kfree(event);
        }
  }
  
 +int acpi_dev_add_driver_gpios(struct acpi_device *adev,
 +                            const struct acpi_gpio_mapping *gpios)
 +{
 +      if (adev && gpios) {
 +              adev->driver_gpios = gpios;
 +              return 0;
 +      }
 +      return -EINVAL;
 +}
 +EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
 +
 +static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
 +                                    const char *name, int index,
 +                                    struct acpi_reference_args *args)
 +{
 +      const struct acpi_gpio_mapping *gm;
 +
 +      if (!adev->driver_gpios)
 +              return false;
 +
 +      for (gm = adev->driver_gpios; gm->name; gm++)
 +              if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
 +                      const struct acpi_gpio_params *par = gm->data + index;
 +
 +                      args->adev = adev;
 +                      args->args[0] = par->crs_entry_index;
 +                      args->args[1] = par->line_index;
 +                      args->args[2] = par->active_low;
 +                      args->nargs = 3;
 +                      return true;
 +              }
 +
 +      return false;
 +}
 +
  struct acpi_gpio_lookup {
        struct acpi_gpio_info info;
        int index;
 +      int pin_index;
        struct gpio_desc *desc;
        int n;
  };
@@@ -395,24 -303,13 +395,24 @@@ static int acpi_find_gpio(struct acpi_r
  
        if (lookup->n++ == lookup->index && !lookup->desc) {
                const struct acpi_resource_gpio *agpio = &ares->data.gpio;
 +              int pin_index = lookup->pin_index;
 +
 +              if (pin_index >= agpio->pin_table_length)
 +                      return 1;
  
                lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
 -                                            agpio->pin_table[0]);
 +                                            agpio->pin_table[pin_index]);
                lookup->info.gpioint =
                        agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
 -              lookup->info.active_low =
 -                      agpio->polarity == ACPI_ACTIVE_LOW;
 +
 +              /*
 +               * ActiveLow is only specified for GpioInt resource. If
 +               * GpioIo is used then the only way to set the flag is
 +               * to use _DSD "gpios" property.
 +               */
 +              if (lookup->info.gpioint)
 +                      lookup->info.active_low =
 +                              agpio->polarity == ACPI_ACTIVE_LOW;
        }
  
        return 1;
  
  /**
   * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
 - * @dev: pointer to a device to get GPIO from
 + * @adev: pointer to a ACPI device to get GPIO from
 + * @propname: Property name of the GPIO (optional)
   * @index: index of GpioIo/GpioInt resource (starting from %0)
   * @info: info pointer to fill in (optional)
   *
 - * Function goes through ACPI resources for @dev and based on @index looks
 + * Function goes through ACPI resources for @adev and based on @index looks
   * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
   * and returns it. @index matches GpioIo/GpioInt resources only so if there
   * are total %3 GPIO resources, the index goes from %0 to %2.
   *
 + * If @propname is specified the GPIO is looked using device property. In
 + * that case @index is used to select the GPIO entry in the property value
 + * (in case of multiple).
 + *
   * If the GPIO cannot be translated or there is an error an ERR_PTR is
   * returned.
   *
   * Note: if the GPIO resource has multiple entries in the pin list, this
   * function only returns the first.
   */
 -struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
 +struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
 +                                        const char *propname, int index,
                                          struct acpi_gpio_info *info)
  {
        struct acpi_gpio_lookup lookup;
        struct list_head resource_list;
 -      struct acpi_device *adev;
 -      acpi_handle handle;
 +      bool active_low = false;
        int ret;
  
 -      if (!dev)
 -              return ERR_PTR(-EINVAL);
 -
 -      handle = ACPI_HANDLE(dev);
 -      if (!handle || acpi_bus_get_device(handle, &adev))
 +      if (!adev)
                return ERR_PTR(-ENODEV);
  
        memset(&lookup, 0, sizeof(lookup));
        lookup.index = index;
  
 +      if (propname) {
 +              struct acpi_reference_args args;
 +
 +              dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
 +
 +              memset(&args, 0, sizeof(args));
 +              ret = acpi_dev_get_property_reference(adev, propname,
 +                                                    index, &args);
 +              if (ret) {
 +                      bool found = acpi_get_driver_gpio_data(adev, propname,
 +                                                             index, &args);
 +                      if (!found)
 +                              return ERR_PTR(ret);
 +              }
 +
 +              /*
 +               * The property was found and resolved so need to
 +               * lookup the GPIO based on returned args instead.
 +               */
 +              adev = args.adev;
 +              if (args.nargs >= 2) {
 +                      lookup.index = args.args[0];
 +                      lookup.pin_index = args.args[1];
 +                      /*
 +                       * 3rd argument, if present is used to
 +                       * specify active_low.
 +                       */
 +                      if (args.nargs >= 3)
 +                              active_low = !!args.args[2];
 +              }
 +
 +              dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
 +                      dev_name(&adev->dev), args.nargs,
 +                      args.args[0], args.args[1], args.args[2]);
 +      } else {
 +              dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
 +      }
 +
        INIT_LIST_HEAD(&resource_list);
        ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
                                     &lookup);
  
        acpi_dev_free_resource_list(&resource_list);
  
 -      if (lookup.desc && info)
 +      if (lookup.desc && info) {
                *info = lookup.info;
 +              if (active_low)
 +                      info->active_low = active_low;
 +      }
  
        return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
  }
diff --combined drivers/gpio/gpiolib.c
@@@ -47,8 -47,6 +47,6 @@@
   */
  DEFINE_SPINLOCK(gpio_lock);
  
- 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);
@@@ -65,10 -63,24 +63,24 @@@ static inline void desc_set_label(struc
   */
  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];
+       struct gpio_chip *chip;
+       unsigned long flags;
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_for_each_entry(chip, &gpio_chips, list) {
+               if (chip->base <= gpio && chip->base + chip->ngpio > gpio) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       return &chip->desc[gpio - chip->base];
+               }
+       }
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       if (!gpio_is_valid(gpio))
+               WARN(1, "invalid GPIO %d\n", gpio);
+       return NULL;
  }
  EXPORT_SYMBOL_GPL(gpio_to_desc);
  
@@@ -91,7 -103,7 +103,7 @@@ struct gpio_desc *gpiochip_get_desc(str
   */
  int desc_to_gpio(const struct gpio_desc *desc)
  {
-       return desc - &gpio_desc[0];
+       return desc->chip->base + (desc - &desc->chip->desc[0]);
  }
  EXPORT_SYMBOL_GPL(desc_to_gpio);
  
@@@ -138,7 -150,7 +150,7 @@@ static int gpiochip_find_base(int ngpio
   *
   * This function may sleep if gpiod_cansleep() is true.
   */
- int gpiod_get_direction(const struct gpio_desc *desc)
+ int gpiod_get_direction(struct gpio_desc *desc)
  {
        struct gpio_chip        *chip;
        unsigned                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);
+               clear_bit(FLAG_IS_OUT, &desc->flags);
        }
        if (status == 0) {
                /* GPIOF_DIR_OUT */
-               set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
+               set_bit(FLAG_IS_OUT, &desc->flags);
        }
        return status;
  }
@@@ -206,7 -216,7 +216,7 @@@ static int gpiochip_add_to_list(struct 
  /**
   * gpiochip_add() - register a gpio_chip
   * @chip: the chip to register, with chip->base initialized
-  * Context: potentially before irqs or kmalloc will work
+  * Context: potentially before irqs will work
   *
   * Returns a negative errno if the chip can't be registered, such as
   * because the chip->base is invalid or already associated with a
@@@ -226,12 -236,11 +236,11 @@@ int gpiochip_add(struct gpio_chip *chip
        int             status = 0;
        unsigned        id;
        int             base = chip->base;
+       struct gpio_desc *descs;
  
-       if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
-                       && base >= 0) {
-               status = -EINVAL;
-               goto fail;
-       }
+       descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL);
+       if (!descs)
+               return -ENOMEM;
  
        spin_lock_irqsave(&gpio_lock, flags);
  
        status = gpiochip_add_to_list(chip);
  
        if (status == 0) {
-               chip->desc = &gpio_desc[chip->base];
                for (id = 0; id < chip->ngpio; id++) {
-                       struct gpio_desc *desc = &chip->desc[id];
+                       struct gpio_desc *desc = &descs[id];
                        desc->chip = chip;
  
                        /* REVISIT:  most hardware initializes GPIOs as
                }
        }
  
+       chip->desc = descs;
        spin_unlock_irqrestore(&gpio_lock, flags);
  
  #ifdef CONFIG_PINCTRL
  unlock:
        spin_unlock_irqrestore(&gpio_lock, flags);
  fail:
+       kfree(descs);
+       chip->desc = NULL;
        /* failures here can mean systems won't boot... */
        pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
                chip->base, chip->base + chip->ngpio - 1,
@@@ -331,6 -343,9 +343,9 @@@ void gpiochip_remove(struct gpio_chip *
        list_del(&chip->list);
        spin_unlock_irqrestore(&gpio_lock, flags);
        gpiochip_unexport(chip);
+       kfree(chip->desc);
+       chip->desc = NULL;
  }
  EXPORT_SYMBOL_GPL(gpiochip_remove);
  
@@@ -495,7 -510,7 +510,7 @@@ static int gpiochip_irq_reqres(struct i
  {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
  
-       if (gpio_lock_as_irq(chip, d->hwirq)) {
+       if (gpiochip_lock_as_irq(chip, d->hwirq)) {
                chip_err(chip,
                        "unable to lock HW IRQ %lu for IRQ\n",
                        d->hwirq);
@@@ -508,7 -523,7 +523,7 @@@ static void gpiochip_irq_relres(struct 
  {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
  
-       gpio_unlock_as_irq(chip, d->hwirq);
+       gpiochip_unlock_as_irq(chip, d->hwirq);
  }
  
  static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
@@@ -1254,6 -1269,88 +1269,88 @@@ static void _gpiod_set_raw_value(struc
                chip->set(chip, gpio_chip_hwgpio(desc), value);
  }
  
+ /*
+  * set multiple outputs on the same chip;
+  * use the chip's set_multiple function if available;
+  * otherwise set the outputs sequentially;
+  * @mask: bit mask array; one bit per output; BITS_PER_LONG bits per word
+  *        defines which outputs are to be changed
+  * @bits: bit value array; one bit per output; BITS_PER_LONG bits per word
+  *        defines the values the outputs specified by mask are to be set to
+  */
+ static void gpio_chip_set_multiple(struct gpio_chip *chip,
+                                  unsigned long *mask, unsigned long *bits)
+ {
+       if (chip->set_multiple) {
+               chip->set_multiple(chip, mask, bits);
+       } else {
+               int i;
+               for (i = 0; i < chip->ngpio; i++) {
+                       if (mask[BIT_WORD(i)] == 0) {
+                               /* no more set bits in this mask word;
+                                * skip ahead to the next word */
+                               i = (BIT_WORD(i) + 1) * BITS_PER_LONG - 1;
+                               continue;
+                       }
+                       /* set outputs if the corresponding mask bit is set */
+                       if (__test_and_clear_bit(i, mask)) {
+                               chip->set(chip, i, test_bit(i, bits));
+                       }
+               }
+       }
+ }
+ static void gpiod_set_array_priv(bool raw, bool can_sleep,
+                                unsigned int array_size,
+                                struct gpio_desc **desc_array,
+                                int *value_array)
+ {
+       int i = 0;
+       while (i < array_size) {
+               struct gpio_chip *chip = desc_array[i]->chip;
+               unsigned long mask[BITS_TO_LONGS(chip->ngpio)];
+               unsigned long bits[BITS_TO_LONGS(chip->ngpio)];
+               int count = 0;
+               if (!can_sleep) {
+                       WARN_ON(chip->can_sleep);
+               }
+               memset(mask, 0, sizeof(mask));
+               do {
+                       struct gpio_desc *desc = desc_array[i];
+                       int hwgpio = gpio_chip_hwgpio(desc);
+                       int value = value_array[i];
+                       if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+                               value = !value;
+                       trace_gpio_value(desc_to_gpio(desc), 0, value);
+                       /*
+                        * collect all normal outputs belonging to the same chip
+                        * open drain and open source outputs are set individually
+                        */
+                       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 {
+                               __set_bit(hwgpio, mask);
+                               if (value) {
+                                       __set_bit(hwgpio, bits);
+                               } else {
+                                       __clear_bit(hwgpio, bits);
+                               }
+                               count++;
+                       }
+                       i++;
+               } while ((i < array_size) && (desc_array[i]->chip == chip));
+               /* push collected bits to outputs */
+               if (count != 0) {
+                       gpio_chip_set_multiple(chip, mask, bits);
+               }
+       }
+ }
  /**
   * gpiod_set_raw_value() - assign a gpio's raw value
   * @desc: gpio whose value will be assigned
@@@ -1298,6 -1395,48 +1395,48 @@@ void gpiod_set_value(struct gpio_desc *
  }
  EXPORT_SYMBOL_GPL(gpiod_set_value);
  
+ /**
+  * gpiod_set_raw_array() - assign values to an array of GPIOs
+  * @array_size: number of elements in the descriptor / value arrays
+  * @desc_array: array of GPIO descriptors whose values will be assigned
+  * @value_array: array of values to assign
+  *
+  * Set the raw values of the GPIOs, i.e. the values of the physical lines
+  * without regard for their ACTIVE_LOW status.
+  *
+  * This function should be called from contexts where we cannot sleep, and will
+  * complain if the GPIO chip functions potentially sleep.
+  */
+ void gpiod_set_raw_array(unsigned int array_size,
+                        struct gpio_desc **desc_array, int *value_array)
+ {
+       if (!desc_array)
+               return;
+       gpiod_set_array_priv(true, false, array_size, desc_array, value_array);
+ }
+ EXPORT_SYMBOL_GPL(gpiod_set_raw_array);
+ /**
+  * gpiod_set_array() - assign values to an array of GPIOs
+  * @array_size: number of elements in the descriptor / value arrays
+  * @desc_array: array of GPIO descriptors whose values will be assigned
+  * @value_array: array of values to assign
+  *
+  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+  * into account.
+  *
+  * This function should be called from contexts where we cannot sleep, and will
+  * complain if the GPIO chip functions potentially sleep.
+  */
+ void gpiod_set_array(unsigned int array_size,
+                    struct gpio_desc **desc_array, int *value_array)
+ {
+       if (!desc_array)
+               return;
+       gpiod_set_array_priv(false, false, array_size, desc_array, value_array);
+ }
+ EXPORT_SYMBOL_GPL(gpiod_set_array);
  /**
   * gpiod_cansleep() - report whether gpio value access may sleep
   * @desc: gpio to check
@@@ -1332,14 -1471,14 +1471,14 @@@ int gpiod_to_irq(const struct gpio_des
  EXPORT_SYMBOL_GPL(gpiod_to_irq);
  
  /**
-  * gpio_lock_as_irq() - lock a GPIO to be used as IRQ
+  * gpiochip_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 gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
+ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
  {
        if (offset >= chip->ngpio)
                return -EINVAL;
        set_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
        return 0;
  }
- EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
+ EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
  
  /**
-  * gpio_unlock_as_irq() - unlock a GPIO used as IRQ
+  * gpiochip_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 gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
+ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
  {
        if (offset >= chip->ngpio)
                return;
  
        clear_bit(FLAG_USED_AS_IRQ, &chip->desc[offset].flags);
  }
- EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
+ EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
  
  /**
   * gpiod_get_raw_value_cansleep() - return a gpio's raw value
@@@ -1457,6 -1596,50 +1596,50 @@@ void gpiod_set_value_cansleep(struct gp
  }
  EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
  
+ /**
+  * gpiod_set_raw_array_cansleep() - assign values to an array of GPIOs
+  * @array_size: number of elements in the descriptor / value arrays
+  * @desc_array: array of GPIO descriptors whose values will be assigned
+  * @value_array: array of values to assign
+  *
+  * Set the raw values of the GPIOs, i.e. the values of the physical lines
+  * without regard for their ACTIVE_LOW status.
+  *
+  * This function is to be called from contexts that can sleep.
+  */
+ void gpiod_set_raw_array_cansleep(unsigned int array_size,
+                                 struct gpio_desc **desc_array,
+                                 int *value_array)
+ {
+       might_sleep_if(extra_checks);
+       if (!desc_array)
+               return;
+       gpiod_set_array_priv(true, true, array_size, desc_array, value_array);
+ }
+ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_cansleep);
+ /**
+  * gpiod_set_array_cansleep() - assign values to an array of GPIOs
+  * @array_size: number of elements in the descriptor / value arrays
+  * @desc_array: array of GPIO descriptors whose values will be assigned
+  * @value_array: array of values to assign
+  *
+  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
+  * into account.
+  *
+  * This function is to be called from contexts that can sleep.
+  */
+ void gpiod_set_array_cansleep(unsigned int array_size,
+                             struct gpio_desc **desc_array,
+                             int *value_array)
+ {
+       might_sleep_if(extra_checks);
+       if (!desc_array)
+               return;
+       gpiod_set_array_priv(false, true, array_size, desc_array, value_array);
+ }
+ EXPORT_SYMBOL_GPL(gpiod_set_array_cansleep);
  /**
   * gpiod_add_lookup_table() - register GPIO device consumers
   * @table: table of consumers to register
@@@ -1505,36 -1688,14 +1688,36 @@@ static struct gpio_desc *acpi_find_gpio
                                        unsigned int idx,
                                        enum gpio_lookup_flags *flags)
  {
 +      static const char * const suffixes[] = { "gpios", "gpio" };
 +      struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_gpio_info info;
        struct gpio_desc *desc;
 +      char propname[32];
 +      int i;
  
 -      desc = acpi_get_gpiod_by_index(dev, idx, &info);
 -      if (IS_ERR(desc))
 -              return desc;
 +      /* Try first from _DSD */
 +      for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
 +              if (con_id && strcmp(con_id, "gpios")) {
 +                      snprintf(propname, sizeof(propname), "%s-%s",
 +                               con_id, suffixes[i]);
 +              } else {
 +                      snprintf(propname, sizeof(propname), "%s",
 +                               suffixes[i]);
 +              }
 +
 +              desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
 +              if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
 +                      break;
 +      }
  
 -      if (info.gpioint && info.active_low)
 +      /* Then from plain _CRS GPIOs */
 +      if (IS_ERR(desc)) {
 +              desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
 +              if (IS_ERR(desc))
 +                      return desc;
 +      }
 +
 +      if (info.active_low)
                *flags |= GPIO_ACTIVE_LOW;
  
        return desc;
@@@ -1734,61 -1895,6 +1917,61 @@@ struct gpio_desc *__must_check __gpiod_
  }
  EXPORT_SYMBOL_GPL(__gpiod_get_index);
  
 +/**
 + * fwnode_get_named_gpiod - obtain a GPIO from firmware node
 + * @fwnode:   handle of the firmware node
 + * @propname: name of the firmware property representing the GPIO
 + *
 + * This function can be used for drivers that get their configuration
 + * from firmware.
 + *
 + * Function properly finds the corresponding GPIO using whatever is the
 + * underlying firmware interface and then makes sure that the GPIO
 + * descriptor is requested before it is returned to the caller.
 + *
 + * In case of error an ERR_PTR() is returned.
 + */
 +struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
 +                                       const char *propname)
 +{
 +      struct gpio_desc *desc = ERR_PTR(-ENODEV);
 +      bool active_low = false;
 +      int ret;
 +
 +      if (!fwnode)
 +              return ERR_PTR(-EINVAL);
 +
 +      if (is_of_node(fwnode)) {
 +              enum of_gpio_flags flags;
 +
 +              desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
 +                                              &flags);
 +              if (!IS_ERR(desc))
 +                      active_low = flags & OF_GPIO_ACTIVE_LOW;
 +      } else if (is_acpi_node(fwnode)) {
 +              struct acpi_gpio_info info;
 +
 +              desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
 +                                             &info);
 +              if (!IS_ERR(desc))
 +                      active_low = info.active_low;
 +      }
 +
 +      if (IS_ERR(desc))
 +              return desc;
 +
 +      ret = gpiod_request(desc, NULL);
 +      if (ret)
 +              return ERR_PTR(ret);
 +
 +      /* Only value flag can be set from both DT and ACPI is active_low */
 +      if (active_low)
 +              set_bit(FLAG_ACTIVE_LOW, &desc->flags);
 +
 +      return desc;
 +}
 +EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
 +
  /**
   * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
   *                            function
@@@ -25,7 -25,9 +25,7 @@@
  /* Since we request GPIOs from ourself */
  #include <linux/pinctrl/consumer.h>
  
 -#include <mach/hardware.h>
 -#include <mach/at91_pio.h>
 -
 +#include "pinctrl-at91.h"
  #include "core.h"
  
  #define MAX_GPIO_BANKS                5
@@@ -1342,6 -1344,7 +1342,6 @@@ static void at91_gpio_dbg_show(struct s
        for (i = 0; i < chip->ngpio; i++) {
                unsigned mask = pin_to_mask(i);
                const char *gpio_label;
 -              u32 pdsr;
  
                gpio_label = gpiochip_is_requested(chip, i);
                if (!gpio_label)
                seq_printf(s, "[%s] GPIO%s%d: ",
                           gpio_label, chip->label, i);
                if (mode == AT91_MUX_GPIO) {
 -                      pdsr = readl_relaxed(pio + PIO_PDSR);
 -
 -                      seq_printf(s, "[gpio] %s\n",
 -                                 pdsr & mask ?
 -                                 "set" : "clear");
 +                      seq_printf(s, "[gpio] ");
 +                      seq_printf(s, "%s ",
 +                                    readl_relaxed(pio + PIO_OSR) & mask ?
 +                                    "output" : "input");
 +                      seq_printf(s, "%s\n",
 +                                    readl_relaxed(pio + PIO_PDSR) & mask ?
 +                                    "set" : "clear");
                } else {
                        seq_printf(s, "[periph %c]\n",
                                   mode + 'A' - 1);
@@@ -1471,7 -1472,7 +1471,7 @@@ static unsigned int gpio_irq_startup(st
        unsigned        pin = d->hwirq;
        int ret;
  
-       ret = gpio_lock_as_irq(&at91_gpio->chip, pin);
+       ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin);
        if (ret) {
                dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n",
                        d->hwirq);
@@@ -1487,7 -1488,7 +1487,7 @@@ static void gpio_irq_shutdown(struct ir
        unsigned        pin = d->hwirq;
  
        gpio_irq_mask(d);
-       gpio_unlock_as_irq(&at91_gpio->chip, pin);
+       gpiochip_unlock_as_irq(&at91_gpio->chip, pin);
  }
  
  #ifdef CONFIG_PM
@@@ -46,16 -46,22 +46,16 @@@ static inline struct exynos_irq_chip *t
        return container_of(chip, struct exynos_irq_chip, chip);
  }
  
 -static struct samsung_pin_bank_type bank_type_off = {
 +static const struct samsung_pin_bank_type bank_type_off = {
        .fld_width = { 4, 1, 2, 2, 2, 2, },
        .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
  };
  
 -static struct samsung_pin_bank_type bank_type_alive = {
 +static const struct samsung_pin_bank_type bank_type_alive = {
        .fld_width = { 4, 1, 2, 2, },
        .reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
  };
  
 -/* list of external wakeup controllers supported */
 -static const struct of_device_id exynos_wkup_irq_ids[] = {
 -      { .compatible = "samsung,exynos4210-wakeup-eint", },
 -      { }
 -};
 -
  static void exynos_irq_mask(struct irq_data *irqd)
  {
        struct irq_chip *chip = irq_data_get_irq_chip(irqd);
@@@ -165,7 -171,7 +165,7 @@@ static int exynos_irq_request_resources
        struct irq_chip *chip = irq_data_get_irq_chip(irqd);
        struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
 -      struct samsung_pin_bank_type *bank_type = bank->type;
 +      const struct samsung_pin_bank_type *bank_type = bank->type;
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
        unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
        unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
        unsigned int con;
        int ret;
  
-       ret = gpio_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
+       ret = gpiochip_lock_as_irq(&bank->gpio_chip, irqd->hwirq);
        if (ret) {
                dev_err(bank->gpio_chip.dev, "unable to lock pin %s-%lu IRQ\n",
                        bank->name, irqd->hwirq);
@@@ -204,7 -210,7 +204,7 @@@ static void exynos_irq_release_resource
        struct irq_chip *chip = irq_data_get_irq_chip(irqd);
        struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
        struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
 -      struct samsung_pin_bank_type *bank_type = bank->type;
 +      const struct samsung_pin_bank_type *bank_type = bank->type;
        struct samsung_pinctrl_drv_data *d = bank->drvdata;
        unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
        unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
  
        spin_unlock_irqrestore(&bank->slock, flags);
  
-       gpio_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
+       gpiochip_unlock_as_irq(&bank->gpio_chip, irqd->hwirq);
  }
  
  /*
@@@ -248,30 -254,31 +248,30 @@@ static struct exynos_irq_chip exynos_gp
        .eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
  };
  
 -static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
 +static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
                                        irq_hw_number_t hw)
  {
        struct samsung_pin_bank *b = h->host_data;
  
        irq_set_chip_data(virq, b);
 -      irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip.chip,
 +      irq_set_chip_and_handler(virq, &b->irq_chip->chip,
                                        handle_level_irq);
        set_irq_flags(virq, IRQF_VALID);
        return 0;
  }
  
  /*
 - * irq domain callbacks for external gpio interrupt controller.
 + * irq domain callbacks for external gpio and wakeup interrupt controllers.
   */
 -static const struct irq_domain_ops exynos_gpio_irqd_ops = {
 -      .map    = exynos_gpio_irq_map,
 +static const struct irq_domain_ops exynos_eint_irqd_ops = {
 +      .map    = exynos_eint_irq_map,
        .xlate  = irq_domain_xlate_twocell,
  };
  
  static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
  {
        struct samsung_pinctrl_drv_data *d = data;
 -      struct samsung_pin_ctrl *ctrl = d->ctrl;
 -      struct samsung_pin_bank *bank = ctrl->pin_banks;
 +      struct samsung_pin_bank *bank = d->pin_banks;
        unsigned int svc, group, pin, virq;
  
        svc = readl(d->virt_base + EXYNOS_SVC_OFFSET);
@@@ -318,12 -325,12 +318,12 @@@ static int exynos_eint_gpio_init(struc
                return -ENXIO;
        }
  
 -      bank = d->ctrl->pin_banks;
 -      for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
 +      bank = d->pin_banks;
 +      for (i = 0; i < d->nr_banks; ++i, ++bank) {
                if (bank->eint_type != EINT_TYPE_GPIO)
                        continue;
                bank->irq_domain = irq_domain_add_linear(bank->of_node,
 -                              bank->nr_pins, &exynos_gpio_irqd_ops, bank);
 +                              bank->nr_pins, &exynos_eint_irqd_ops, bank);
                if (!bank->irq_domain) {
                        dev_err(dev, "gpio irq domain add failed\n");
                        ret = -ENXIO;
                        ret = -ENOMEM;
                        goto err_domains;
                }
 +
 +              bank->irq_chip = &exynos_gpio_irq_chip;
        }
  
        return 0;
@@@ -378,9 -383,9 +378,9 @@@ static int exynos_wkup_irq_set_wake(str
  /*
   * irq_chip for wakeup interrupts
   */
 -static struct exynos_irq_chip exynos_wkup_irq_chip = {
 +static struct exynos_irq_chip exynos4210_wkup_irq_chip __initdata = {
        .chip = {
 -              .name = "exynos_wkup_irq_chip",
 +              .name = "exynos4210_wkup_irq_chip",
                .irq_unmask = exynos_irq_unmask,
                .irq_mask = exynos_irq_mask,
                .irq_ack = exynos_irq_ack,
        .eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
  };
  
 +static struct exynos_irq_chip exynos7_wkup_irq_chip __initdata = {
 +      .chip = {
 +              .name = "exynos7_wkup_irq_chip",
 +              .irq_unmask = exynos_irq_unmask,
 +              .irq_mask = exynos_irq_mask,
 +              .irq_ack = exynos_irq_ack,
 +              .irq_set_type = exynos_irq_set_type,
 +              .irq_set_wake = exynos_wkup_irq_set_wake,
 +              .irq_request_resources = exynos_irq_request_resources,
 +              .irq_release_resources = exynos_irq_release_resources,
 +      },
 +      .eint_con = EXYNOS7_WKUP_ECON_OFFSET,
 +      .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
 +      .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
 +};
 +
 +/* list of external wakeup controllers supported */
 +static const struct of_device_id exynos_wkup_irq_ids[] = {
 +      { .compatible = "samsung,exynos4210-wakeup-eint",
 +                      .data = &exynos4210_wkup_irq_chip },
 +      { .compatible = "samsung,exynos7-wakeup-eint",
 +                      .data = &exynos7_wkup_irq_chip },
 +      { }
 +};
 +
  /* interrupt handler for wakeup interrupts 0..15 */
  static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
  {
@@@ -465,9 -445,9 +465,9 @@@ static void exynos_irq_demux_eint16_31(
  
        for (i = 0; i < eintd->nr_banks; ++i) {
                struct samsung_pin_bank *b = eintd->banks[i];
 -              pend = readl(d->virt_base + EXYNOS_WKUP_EPEND_OFFSET
 +              pend = readl(d->virt_base + b->irq_chip->eint_pend
                                + b->eint_offset);
 -              mask = readl(d->virt_base + EXYNOS_WKUP_EMASK_OFFSET
 +              mask = readl(d->virt_base + b->irq_chip->eint_mask
                                + b->eint_offset);
                exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
        }
        chained_irq_exit(chip, desc);
  }
  
 -static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq,
 -                                      irq_hw_number_t hw)
 -{
 -      irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip.chip,
 -                                      handle_level_irq);
 -      irq_set_chip_data(virq, h->host_data);
 -      set_irq_flags(virq, IRQF_VALID);
 -      return 0;
 -}
 -
 -/*
 - * irq domain callbacks for external wakeup interrupt controller.
 - */
 -static const struct irq_domain_ops exynos_wkup_irqd_ops = {
 -      .map    = exynos_wkup_irq_map,
 -      .xlate  = irq_domain_xlate_twocell,
 -};
 -
  /*
   * exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
   * @d: driver data of samsung pinctrl driver.
@@@ -487,18 -485,12 +487,18 @@@ static int exynos_eint_wkup_init(struc
        struct samsung_pin_bank *bank;
        struct exynos_weint_data *weint_data;
        struct exynos_muxed_weint_data *muxed_data;
 +      struct exynos_irq_chip *irq_chip;
        unsigned int muxed_banks = 0;
        unsigned int i;
        int idx, irq;
  
        for_each_child_of_node(dev->of_node, np) {
 -              if (of_match_node(exynos_wkup_irq_ids, np)) {
 +              const struct of_device_id *match;
 +
 +              match = of_match_node(exynos_wkup_irq_ids, np);
 +              if (match) {
 +                      irq_chip = kmemdup(match->data,
 +                              sizeof(*irq_chip), GFP_KERNEL);
                        wkup_np = np;
                        break;
                }
        if (!wkup_np)
                return -ENODEV;
  
 -      bank = d->ctrl->pin_banks;
 -      for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
 +      bank = d->pin_banks;
 +      for (i = 0; i < d->nr_banks; ++i, ++bank) {
                if (bank->eint_type != EINT_TYPE_WKUP)
                        continue;
  
                bank->irq_domain = irq_domain_add_linear(bank->of_node,
 -                              bank->nr_pins, &exynos_wkup_irqd_ops, bank);
 +                              bank->nr_pins, &exynos_eint_irqd_ops, bank);
                if (!bank->irq_domain) {
                        dev_err(dev, "wkup irq domain add failed\n");
                        return -ENXIO;
                }
  
 +              bank->irq_chip = irq_chip;
 +
                if (!of_find_property(bank->of_node, "interrupts", NULL)) {
                        bank->eint_type = EINT_TYPE_WKUP_MUX;
                        ++muxed_banks;
        irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
        irq_set_handler_data(irq, muxed_data);
  
 -      bank = d->ctrl->pin_banks;
 +      bank = d->pin_banks;
        idx = 0;
 -      for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
 +      for (i = 0; i < d->nr_banks; ++i, ++bank) {
                if (bank->eint_type != EINT_TYPE_WKUP_MUX)
                        continue;
  
@@@ -600,10 -590,11 +600,10 @@@ static void exynos_pinctrl_suspend_bank
  
  static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
  {
 -      struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
 -      struct samsung_pin_bank *bank = ctrl->pin_banks;
 +      struct samsung_pin_bank *bank = drvdata->pin_banks;
        int i;
  
 -      for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
 +      for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
                if (bank->eint_type == EINT_TYPE_GPIO)
                        exynos_pinctrl_suspend_bank(drvdata, bank);
  }
@@@ -635,16 -626,17 +635,16 @@@ static void exynos_pinctrl_resume_bank
  
  static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
  {
 -      struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
 -      struct samsung_pin_bank *bank = ctrl->pin_banks;
 +      struct samsung_pin_bank *bank = drvdata->pin_banks;
        int i;
  
 -      for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
 +      for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
                if (bank->eint_type == EINT_TYPE_GPIO)
                        exynos_pinctrl_resume_bank(drvdata, bank);
  }
  
  /* pin banks of s5pv210 pin-controller */
 -static struct samsung_pin_bank s5pv210_pin_bank[] = {
 +static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
        EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
  };
  
 -struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
 +const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = s5pv210_pin_bank,
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "s5pv210-gpio-ctrl0",
        },
  };
  
  /* pin banks of exynos3250 pin-controller 0 */
 -static struct samsung_pin_bank exynos3250_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb",  0x08),
  };
  
  /* pin banks of exynos3250 pin-controller 1 */
 -static struct samsung_pin_bank exynos3250_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"),
        EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"),
        EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"),
   * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
   * two gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos3250_pin_banks0,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos3250-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos3250_pin_banks1,
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos3250-gpio-ctrl1",
        },
  };
  
  /* pin banks of exynos4210 pin-controller 0 */
 -static struct samsung_pin_bank exynos4210_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos4210_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
  };
  
  /* pin banks of exynos4210 pin-controller 1 */
 -static struct samsung_pin_bank exynos4210_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos4210_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00),
        EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04),
        EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08),
  };
  
  /* pin banks of exynos4210 pin-controller 2 */
 -static struct samsung_pin_bank exynos4210_pin_banks2[] = {
 +static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst = {
        EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
  };
  
   * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
   * three gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos4210_pin_banks0,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4210-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos4210_pin_banks1,
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4210-gpio-ctrl1",
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos4210_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos4210_pin_banks2),
 -              .label          = "exynos4210-gpio-ctrl2",
        },
  };
  
  /* pin banks of exynos4x12 pin-controller 0 */
 -static struct samsung_pin_bank exynos4x12_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos4x12_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
  };
  
  /* pin banks of exynos4x12 pin-controller 1 */
 -static struct samsung_pin_bank exynos4x12_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos4x12_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08),
        EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
        EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
  };
  
  /* pin banks of exynos4x12 pin-controller 2 */
 -static struct samsung_pin_bank exynos4x12_pin_banks2[] = {
 +static const struct samsung_pin_bank_data exynos4x12_pin_banks2[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
  };
  
  /* pin banks of exynos4x12 pin-controller 3 */
 -static struct samsung_pin_bank exynos4x12_pin_banks3[] = {
 +static const struct samsung_pin_bank_data exynos4x12_pin_banks3[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
        EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08),
   * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes
   * four gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos4x12_pin_banks0,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4x12-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos4x12_pin_banks1,
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4x12-gpio-ctrl1",
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos4x12_pin_banks2,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4x12-gpio-ctrl2",
        }, {
                /* pin-controller instance 3 data */
                .pin_banks      = exynos4x12_pin_banks3,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos4x12-gpio-ctrl3",
 +      },
 +};
 +
 +/* pin banks of exynos4415 pin-controller 0 */
 +static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = {
 +      EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
 +      EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
 +      EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
 +      EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
 +      EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38),
 +};
 +
 +/* pin banks of exynos4415 pin-controller 1 */
 +static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = {
 +      EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08),
 +      EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
 +      EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
 +      EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18),
 +      EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"),
 +      EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"),
 +      EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"),
 +      EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"),
 +      EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"),
 +      EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"),
 +      EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24),
 +      EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28),
 +      EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34),
 +      EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
 +      EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
 +      EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
 +      EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
 +};
 +
 +/* pin banks of exynos4415 pin-controller 2 */
 +static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = {
 +      EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
 +      EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"),
 +};
 +
 +/*
 + * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes
 + * three gpio/pin-mux/pinconfig controllers.
 + */
 +const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = {
 +      {
 +              /* pin-controller instance 0 data */
 +              .pin_banks      = exynos4415_pin_banks0,
 +              .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks0),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +              .suspend        = exynos_pinctrl_suspend,
 +              .resume         = exynos_pinctrl_resume,
 +      }, {
 +              /* pin-controller instance 1 data */
 +              .pin_banks      = exynos4415_pin_banks1,
 +              .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks1),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +              .eint_wkup_init = exynos_eint_wkup_init,
 +              .suspend        = exynos_pinctrl_suspend,
 +              .resume         = exynos_pinctrl_resume,
 +      }, {
 +              /* pin-controller instance 2 data */
 +              .pin_banks      = exynos4415_pin_banks2,
 +              .nr_banks       = ARRAY_SIZE(exynos4415_pin_banks2),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +              .suspend        = exynos_pinctrl_suspend,
 +              .resume         = exynos_pinctrl_resume,
        },
  };
  
  /* pin banks of exynos5250 pin-controller 0 */
 -static struct samsung_pin_bank exynos5250_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
  };
  
  /* pin banks of exynos5250 pin-controller 1 */
 -static struct samsung_pin_bank exynos5250_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos5250_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
        EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
        EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08),
  };
  
  /* pin banks of exynos5250 pin-controller 2 */
 -static struct samsung_pin_bank exynos5250_pin_banks2[] = {
 +static const struct samsung_pin_bank_data exynos5250_pin_banks2[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
        EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
  };
  
  /* pin banks of exynos5250 pin-controller 3 */
 -static struct samsung_pin_bank exynos5250_pin_banks3[] = {
 +static const struct samsung_pin_bank_data exynos5250_pin_banks3[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
  };
  
   * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
   * four gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5250_pin_banks0,
                .eint_wkup_init = exynos_eint_wkup_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos5250-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos5250_pin_banks1,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos5250-gpio-ctrl1",
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos5250_pin_banks2,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos5250-gpio-ctrl2",
        }, {
                /* pin-controller instance 3 data */
                .pin_banks      = exynos5250_pin_banks3,
                .eint_gpio_init = exynos_eint_gpio_init,
                .suspend        = exynos_pinctrl_suspend,
                .resume         = exynos_pinctrl_resume,
 -              .label          = "exynos5250-gpio-ctrl3",
        },
  };
  
  /* pin banks of exynos5260 pin-controller 0 */
 -static struct samsung_pin_bank exynos5260_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos5260_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
  };
  
  /* pin banks of exynos5260 pin-controller 1 */
 -static struct samsung_pin_bank exynos5260_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos5260_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
        EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
  };
  
  /* pin banks of exynos5260 pin-controller 2 */
 -static struct samsung_pin_bank exynos5260_pin_banks2[] = {
 +static const struct samsung_pin_bank_data exynos5260_pin_banks2[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
        EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
  };
   * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
   * three gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5260_pin_banks0,
                .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks0),
                .eint_gpio_init = exynos_eint_gpio_init,
                .eint_wkup_init = exynos_eint_wkup_init,
 -              .label          = "exynos5260-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos5260_pin_banks1,
                .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks1),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5260-gpio-ctrl1",
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos5260_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos5260_pin_banks2),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5260-gpio-ctrl2",
        },
  };
  
  /* pin banks of exynos5420 pin-controller 0 */
 -static struct samsung_pin_bank exynos5420_pin_banks0[] = {
 +static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
        EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
        EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
  };
  
  /* pin banks of exynos5420 pin-controller 1 */
 -static struct samsung_pin_bank exynos5420_pin_banks1[] = {
 +static const struct samsung_pin_bank_data exynos5420_pin_banks1[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpc0", 0x00),
        EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc1", 0x04),
        EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
  };
  
  /* pin banks of exynos5420 pin-controller 2 */
 -static struct samsung_pin_bank exynos5420_pin_banks2[] = {
 +static const struct samsung_pin_bank_data exynos5420_pin_banks2[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
        EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
        EXYNOS_PIN_BANK_EINTG(6, 0x040, "gpf0", 0x08),
  };
  
  /* pin banks of exynos5420 pin-controller 3 */
 -static struct samsung_pin_bank exynos5420_pin_banks3[] = {
 +static const struct samsung_pin_bank_data exynos5420_pin_banks3[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
        EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
        EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
  };
  
  /* pin banks of exynos5420 pin-controller 4 */
 -static struct samsung_pin_bank exynos5420_pin_banks4[] = {
 +static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
  };
  
   * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
   * four gpio/pin-mux/pinconfig controllers.
   */
 -struct samsung_pin_ctrl exynos5420_pin_ctrl[] = {
 +const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5420_pin_banks0,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks0),
                .eint_gpio_init = exynos_eint_gpio_init,
                .eint_wkup_init = exynos_eint_wkup_init,
 -              .label          = "exynos5420-gpio-ctrl0",
        }, {
                /* pin-controller instance 1 data */
                .pin_banks      = exynos5420_pin_banks1,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks1),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5420-gpio-ctrl1",
        }, {
                /* pin-controller instance 2 data */
                .pin_banks      = exynos5420_pin_banks2,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks2),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5420-gpio-ctrl2",
        }, {
                /* pin-controller instance 3 data */
                .pin_banks      = exynos5420_pin_banks3,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks3),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5420-gpio-ctrl3",
        }, {
                /* pin-controller instance 4 data */
                .pin_banks      = exynos5420_pin_banks4,
                .nr_banks       = ARRAY_SIZE(exynos5420_pin_banks4),
                .eint_gpio_init = exynos_eint_gpio_init,
 -              .label          = "exynos5420-gpio-ctrl4",
 +      },
 +};
 +
 +/* pin banks of exynos7 pin-controller - ALIVE */
 +static const struct samsung_pin_bank_data exynos7_pin_banks0[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
 +      EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
 +      EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
 +      EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
 +};
 +
 +/* pin banks of exynos7 pin-controller - BUS0 */
 +static const struct samsung_pin_bank_data exynos7_pin_banks1[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc0", 0x04),
 +      EXYNOS_PIN_BANK_EINTG(2, 0x040, "gpc1", 0x08),
 +      EXYNOS_PIN_BANK_EINTG(6, 0x060, "gpc2", 0x0c),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14),
 +      EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpd2", 0x1c),
 +      EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpd4", 0x20),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x120, "gpd5", 0x24),
 +      EXYNOS_PIN_BANK_EINTG(6, 0x140, "gpd6", 0x28),
 +      EXYNOS_PIN_BANK_EINTG(3, 0x160, "gpd7", 0x2c),
 +      EXYNOS_PIN_BANK_EINTG(2, 0x180, "gpd8", 0x30),
 +      EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34),
 +      EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpg3", 0x38),
 +};
 +
 +/* pin banks of exynos7 pin-controller - NFC */
 +static const struct samsung_pin_bank_data exynos7_pin_banks2[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00),
 +};
 +
 +/* pin banks of exynos7 pin-controller - TOUCH */
 +static const struct samsung_pin_bank_data exynos7_pin_banks3[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00),
 +};
 +
 +/* pin banks of exynos7 pin-controller - FF */
 +static const struct samsung_pin_bank_data exynos7_pin_banks4[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpg4", 0x00),
 +};
 +
 +/* pin banks of exynos7 pin-controller - ESE */
 +static const struct samsung_pin_bank_data exynos7_pin_banks5[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpv7", 0x00),
 +};
 +
 +/* pin banks of exynos7 pin-controller - FSYS0 */
 +static const struct samsung_pin_bank_data exynos7_pin_banks6[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpr4", 0x00),
 +};
 +
 +/* pin banks of exynos7 pin-controller - FSYS1 */
 +static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = {
 +      EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpr0", 0x00),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04),
 +      EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr2", 0x08),
 +      EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c),
 +};
 +
 +const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
 +      {
 +              /* pin-controller instance 0 Alive data */
 +              .pin_banks      = exynos7_pin_banks0,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks0),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +              .eint_wkup_init = exynos_eint_wkup_init,
 +      }, {
 +              /* pin-controller instance 1 BUS0 data */
 +              .pin_banks      = exynos7_pin_banks1,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks1),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 2 NFC data */
 +              .pin_banks      = exynos7_pin_banks2,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks2),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 3 TOUCH data */
 +              .pin_banks      = exynos7_pin_banks3,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks3),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 4 FF data */
 +              .pin_banks      = exynos7_pin_banks4,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks4),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 5 ESE data */
 +              .pin_banks      = exynos7_pin_banks5,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks5),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 6 FSYS0 data */
 +              .pin_banks      = exynos7_pin_banks6,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks6),
 +              .eint_gpio_init = exynos_eint_gpio_init,
 +      }, {
 +              /* pin-controller instance 7 FSYS1 data */
 +              .pin_banks      = exynos7_pin_banks7,
 +              .nr_banks       = ARRAY_SIZE(exynos7_pin_banks7),
 +              .eint_gpio_init = exynos_eint_gpio_init,
        },
  };
@@@ -66,7 -66,7 +66,7 @@@ __devm_gpiod_get_index_optional(struct 
                              unsigned int index, enum gpiod_flags flags);
  void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
  
- int gpiod_get_direction(const struct gpio_desc *desc);
+ int gpiod_get_direction(struct gpio_desc *desc);
  int gpiod_direction_input(struct gpio_desc *desc);
  int gpiod_direction_output(struct gpio_desc *desc, int value);
  int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
  /* Value get/set from non-sleeping context */
  int gpiod_get_value(const struct gpio_desc *desc);
  void gpiod_set_value(struct gpio_desc *desc, int value);
+ void gpiod_set_array(unsigned int array_size,
+                    struct gpio_desc **desc_array, int *value_array);
  int gpiod_get_raw_value(const struct gpio_desc *desc);
  void gpiod_set_raw_value(struct gpio_desc *desc, int value);
+ void gpiod_set_raw_array(unsigned int array_size,
+                        struct gpio_desc **desc_array, int *value_array);
  
  /* Value get/set from sleeping context */
  int gpiod_get_value_cansleep(const struct gpio_desc *desc);
  void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
+ void gpiod_set_array_cansleep(unsigned int array_size,
+                             struct gpio_desc **desc_array,
+                             int *value_array);
  int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
  void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
+ void gpiod_set_raw_array_cansleep(unsigned int array_size,
+                                 struct gpio_desc **desc_array,
+                                 int *value_array);
  
  int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
  
@@@ -94,13 -104,6 +104,13 @@@ int gpiod_to_irq(const struct gpio_des
  struct gpio_desc *gpio_to_desc(unsigned gpio);
  int desc_to_gpio(const struct gpio_desc *desc);
  
 +/* Child properties interface */
 +struct fwnode_handle;
 +
 +struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
 +                                       const char *propname);
 +struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
 +                                          struct fwnode_handle *child);
  #else /* CONFIG_GPIOLIB */
  
  static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
@@@ -217,6 -220,13 +227,13 @@@ static inline void gpiod_set_value(stru
        /* GPIO can never have been requested */
        WARN_ON(1);
  }
+ static inline void gpiod_set_array(unsigned int array_size,
+                                  struct gpio_desc **desc_array,
+                                  int *value_array)
+ {
+       /* GPIO can never have been requested */
+       WARN_ON(1);
+ }
  static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
  {
        /* GPIO can never have been requested */
@@@ -228,6 -238,13 +245,13 @@@ static inline void gpiod_set_raw_value(
        /* GPIO can never have been requested */
        WARN_ON(1);
  }
+ static inline void gpiod_set_raw_array(unsigned int array_size,
+                                      struct gpio_desc **desc_array,
+                                      int *value_array)
+ {
+       /* GPIO can never have been requested */
+       WARN_ON(1);
+ }
  
  static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
  {
@@@ -240,6 -257,13 +264,13 @@@ static inline void gpiod_set_value_cans
        /* GPIO can never have been requested */
        WARN_ON(1);
  }
+ static inline void gpiod_set_array_cansleep(unsigned int array_size,
+                                           struct gpio_desc **desc_array,
+                                           int *value_array)
+ {
+       /* GPIO can never have been requested */
+       WARN_ON(1);
+ }
  static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
  {
        /* GPIO can never have been requested */
@@@ -252,6 -276,13 +283,13 @@@ static inline void gpiod_set_raw_value_
        /* GPIO can never have been requested */
        WARN_ON(1);
  }
+ static inline void gpiod_set_raw_array_cansleep(unsigned int array_size,
+                                               struct gpio_desc **desc_array,
+                                               int *value_array)
+ {
+       /* GPIO can never have been requested */
+       WARN_ON(1);
+ }
  
  static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
  {