Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Feb 2013 17:35:29 +0000 (09:35 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Feb 2013 17:35:29 +0000 (09:35 -0800)
Pull GPIO changes from Grant Likely:
 "This branch contains the usual set of individual driver improvements
  and bug fixes, as well as updates to the core code.  The more notable
  changes include:

   - Internally add new API for referencing GPIOs by gpio_desc instead
     of number.  Eventually this will become a public API

   - ACPI GPIO binding support"

* tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux: (33 commits)
  arm64: select ARCH_WANT_OPTIONAL_GPIOLIB
  gpio: em: Use irq_domain_add_simple() to fix runtime error
  gpio: using common order: let 'static const' instead of 'const static'
  gpio/vt8500: memory cleanup missing
  gpiolib: Fix locking on gpio debugfs files
  gpiolib: let gpio_chip reference its descriptors
  gpiolib: use descriptors internally
  gpiolib: use gpio_chips list in gpiochip_find_base
  gpiolib: use gpio_chips list in sysfs ops
  gpiolib: use gpio_chips list in gpiochip_find
  gpiolib: use gpio_chips list in gpiolib_sysfs_init
  gpiolib: link all gpio_chips using a list
  gpio/langwell: cleanup driver
  gpio/langwell: Add Cloverview ids to pci device table
  gpio/lynxpoint: add chipset gpio driver.
  gpiolib: add missing braces in gpio_direction_show
  gpiolib-acpi: Fix error checks in interrupt requesting
  gpio: mpc8xxx: don't set IRQ_TYPE_NONE when creating irq mapping
  gpiolib: remove gpiochip_reserve()
  arm: pxa: tosa: do not use gpiochip_reserve()
  ...

20 files changed:
arch/arm/mach-pxa/tosa.c
arch/arm64/Kconfig
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-em.c
drivers/gpio/gpio-langwell.c
drivers/gpio/gpio-lynxpoint.c [new file with mode: 0644]
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-twl4030.c
drivers/gpio/gpio-vt8500.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
include/asm-generic/gpio.h
include/linux/acpi_gpio.h
include/linux/gpio.h

index 9e7998d..3d91d2e 100644 (file)
@@ -927,8 +927,6 @@ static void tosa_restart(char mode, const char *cmd)
 
 static void __init tosa_init(void)
 {
-       int dummy;
-
        pxa2xx_mfp_config(ARRAY_AND_SIZE(tosa_pin_config));
 
        pxa_set_ffuart_info(NULL);
@@ -947,10 +945,6 @@ static void __init tosa_init(void)
        /* enable batt_fault */
        PMCR = 0x01;
 
-       dummy = gpiochip_reserve(TOSA_SCOOP_GPIO_BASE, 12);
-       dummy = gpiochip_reserve(TOSA_SCOOP_JC_GPIO_BASE, 12);
-       dummy = gpiochip_reserve(TOSA_TC6393XB_GPIO_BASE, 16);
-
        pxa_set_mci_info(&tosa_mci_platform_data);
        pxa_set_ficp_info(&tosa_ficp_platform_data);
        pxa_set_i2c_info(NULL);
index f532ce5..fd70a68 100644 (file)
@@ -1,6 +1,7 @@
 config ARM64
        def_bool y
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+       select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select ARCH_WANT_FRAME_POINTERS
        select ARM_AMBA
@@ -93,7 +94,7 @@ config IOMMU_HELPER
        def_bool SWIOTLB
 
 config GENERIC_GPIO
-       def_bool y
+       bool
 
 source "init/Kconfig"
 
index 74e17f1..93aaadf 100644 (file)
@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB
          Selecting this from the architecture code will cause the gpiolib
          code to always get built in.
 
+config GPIO_DEVRES
+       def_bool y
+       depends on HAS_IOMEM
 
 
 menuconfig GPIOLIB
@@ -298,6 +301,14 @@ config GPIO_GE_FPGA
          and write pin state) for GPIO implemented in a number of GE single
          board computers.
 
+config GPIO_LYNXPOINT
+       bool "Intel Lynxpoint GPIO support"
+       depends on ACPI
+       select IRQ_DOMAIN
+       help
+         driver for GPIO functionality on Intel Lynxpoint PCH chipset
+         Requires ACPI device enumeration code to set up a platform device.
+
 comment "I2C GPIO expanders:"
 
 config GPIO_ARIZONA
index 6dbcba2..22e07bc 100644 (file)
@@ -2,7 +2,8 @@
 
 ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
 
-obj-$(CONFIG_GPIOLIB)          += gpiolib.o devres.o
+obj-$(CONFIG_GPIO_DEVRES)      += devres.o
+obj-$(CONFIG_GPIOLIB)          += gpiolib.o
 obj-$(CONFIG_OF_GPIO)          += gpiolib-of.o
 obj-$(CONFIG_GPIO_ACPI)                += gpiolib-acpi.o
 
@@ -30,6 +31,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)   += gpio-janz-ttl.o
 obj-$(CONFIG_ARCH_KS8695)      += gpio-ks8695.o
 obj-$(CONFIG_GPIO_LANGWELL)    += gpio-langwell.o
 obj-$(CONFIG_ARCH_LPC32XX)     += gpio-lpc32xx.o
+obj-$(CONFIG_GPIO_LYNXPOINT)   += gpio-lynxpoint.o
 obj-$(CONFIG_GPIO_MAX730X)     += gpio-max730x.o
 obj-$(CONFIG_GPIO_MAX7300)     += gpio-max7300.o
 obj-$(CONFIG_GPIO_MAX7301)     += gpio-max7301.o
index bdc8302..deca78f 100644 (file)
@@ -299,8 +299,9 @@ static int em_gio_probe(struct platform_device *pdev)
        irq_chip->irq_set_type = em_gio_irq_set_type;
        irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
 
-       p->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
+       p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
                                              pdata->number_of_pins,
+                                             pdata->irq_base,
                                              &em_gio_irq_domain_ops, p);
        if (!p->irq_domain) {
                ret = -ENXIO;
index e77b2b3..634c3d3 100644 (file)
@@ -71,10 +71,12 @@ struct lnw_gpio {
        struct irq_domain               *domain;
 };
 
+#define to_lnw_priv(chip)      container_of(chip, struct lnw_gpio, chip)
+
 static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
                        enum GPIO_REG reg_type)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       struct lnw_gpio *lnw = to_lnw_priv(chip);
        unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 32;
        void __iomem *ptr;
@@ -86,7 +88,7 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
 static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
                                   enum GPIO_REG reg_type)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       struct lnw_gpio *lnw = to_lnw_priv(chip);
        unsigned nreg = chip->ngpio / 32;
        u8 reg = offset / 16;
        void __iomem *ptr;
@@ -130,7 +132,7 @@ static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
 static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       struct lnw_gpio *lnw = to_lnw_priv(chip);
        void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        u32 value;
        unsigned long flags;
@@ -153,7 +155,7 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int lnw_gpio_direction_output(struct gpio_chip *chip,
                        unsigned offset, int value)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       struct lnw_gpio *lnw = to_lnw_priv(chip);
        void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
        unsigned long flags;
 
@@ -176,7 +178,7 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
 
 static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       struct lnw_gpio *lnw = to_lnw_priv(chip);
        return irq_create_mapping(lnw->domain, offset);
 }
 
@@ -234,6 +236,8 @@ static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = {   /* pin number */
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), .driver_data = 96 },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), .driver_data = 96 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
@@ -299,17 +303,6 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
        .xlate = irq_domain_xlate_twocell,
 };
 
-#ifdef CONFIG_PM
-static int lnw_gpio_runtime_resume(struct device *dev)
-{
-       return 0;
-}
-
-static int lnw_gpio_runtime_suspend(struct device *dev)
-{
-       return 0;
-}
-
 static int lnw_gpio_runtime_idle(struct device *dev)
 {
        int err = pm_schedule_suspend(dev, 500);
@@ -320,16 +313,8 @@ static int lnw_gpio_runtime_idle(struct device *dev)
        return -EBUSY;
 }
 
-#else
-#define lnw_gpio_runtime_suspend       NULL
-#define lnw_gpio_runtime_resume                NULL
-#define lnw_gpio_runtime_idle          NULL
-#endif
-
 static const struct dev_pm_ops lnw_gpio_pm_ops = {
-       .runtime_suspend = lnw_gpio_runtime_suspend,
-       .runtime_resume = lnw_gpio_runtime_resume,
-       .runtime_idle = lnw_gpio_runtime_idle,
+       SET_RUNTIME_PM_OPS(NULL, NULL, lnw_gpio_runtime_idle)
 };
 
 static int lnw_gpio_probe(struct pci_dev *pdev,
@@ -349,7 +334,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        retval = pci_request_regions(pdev, "langwell_gpio");
        if (retval) {
                dev_err(&pdev->dev, "error requesting resources\n");
-               goto err2;
+               goto err_pci_req_region;
        }
        /* get the gpio_base from bar1 */
        start = pci_resource_start(pdev, 1);
@@ -358,7 +343,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        if (!base) {
                dev_err(&pdev->dev, "error mapping bar1\n");
                retval = -EFAULT;
-               goto err3;
+               goto err_ioremap;
        }
        gpio_base = *((u32 *)base + 1);
        /* release the IO mapping, since we already get the info from bar1 */
@@ -370,21 +355,21 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        if (!base) {
                dev_err(&pdev->dev, "error mapping bar0\n");
                retval = -EFAULT;
-               goto err3;
+               goto err_ioremap;
        }
 
-       lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL);
+       lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL);
        if (!lnw) {
                dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
                retval = -ENOMEM;
-               goto err3;
+               goto err_ioremap;
        }
 
        lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
                                            &lnw_gpio_irq_ops, lnw);
        if (!lnw->domain) {
                retval = -ENOMEM;
-               goto err3;
+               goto err_ioremap;
        }
 
        lnw->reg_base = base;
@@ -403,7 +388,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
        retval = gpiochip_add(&lnw->chip);
        if (retval) {
                dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
-               goto err3;
+               goto err_ioremap;
        }
 
        lnw_irq_init_hw(lnw);
@@ -418,9 +403,9 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
 
        return 0;
 
-err3:
+err_ioremap:
        pci_release_regions(pdev);
-err2:
+err_pci_req_region:
        pci_disable_device(pdev);
        return retval;
 }
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
new file mode 100644 (file)
index 0000000..3472b05
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * GPIO controller driver for Intel Lynxpoint PCH chipset>
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/irqdomain.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* LynxPoint chipset has support for 94 gpio pins */
+
+#define LP_NUM_GPIO    94
+
+/* Bitmapped register offsets */
+#define LP_ACPI_OWNED  0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */
+#define LP_GC          0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */
+#define LP_INT_STAT    0x80
+#define LP_INT_ENABLE  0x90
+
+/* Each pin has two 32 bit config registers, starting at 0x100 */
+#define LP_CONFIG1     0x100
+#define LP_CONFIG2     0x104
+
+/* LP_CONFIG1 reg bits */
+#define OUT_LVL_BIT    BIT(31)
+#define IN_LVL_BIT     BIT(30)
+#define TRIG_SEL_BIT   BIT(4) /* 0: Edge, 1: Level */
+#define INT_INV_BIT    BIT(3) /* Invert interrupt triggering */
+#define DIR_BIT                BIT(2) /* 0: Output, 1: Input */
+#define USE_SEL_BIT    BIT(0) /* 0: Native, 1: GPIO */
+
+/* LP_CONFIG2 reg bits */
+#define GPINDIS_BIT    BIT(2) /* disable input sensing */
+#define GPIWP_BIT      (BIT(0) | BIT(1)) /* weak pull options */
+
+struct lp_gpio {
+       struct gpio_chip        chip;
+       struct irq_domain       *domain;
+       struct platform_device  *pdev;
+       spinlock_t              lock;
+       unsigned long           reg_base;
+};
+
+/*
+ * Lynxpoint gpios are controlled through both bitmapped registers and
+ * per gpio specific registers. The bitmapped registers are in chunks of
+ * 3 x 32bit registers to cover all 94 gpios
+ *
+ * per gpio specific registers consist of two 32bit registers per gpio
+ * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of
+ * 188 config registes.
+ *
+ * A simplified view of the register layout look like this:
+ *
+ * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31  (bitmapped registers)
+ * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63
+ * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94
+ * ...
+ * LP_INT_ENABLE[31:0] ...
+ * LP_INT_ENABLE[63:31] ...
+ * LP_INT_ENABLE[94:64] ...
+ * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers)
+ * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0
+ * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1
+ * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1
+ * LP2_CONFIG1 (gpio 2) ...
+ * LP2_CONFIG2 (gpio 2) ...
+ * ...
+ * LP94_CONFIG1 (gpio 94) ...
+ * LP94_CONFIG2 (gpio 94) ...
+ */
+
+static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
+                                int reg)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       int reg_offset;
+
+       if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
+               /* per gpio specific config registers */
+               reg_offset = offset * 8;
+       else
+               /* bitmapped registers */
+               reg_offset = (offset / 32) * 4;
+
+       return lg->reg_base + reg + reg_offset;
+}
+
+static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+       unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
+       unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED);
+
+       pm_runtime_get(&lg->pdev->dev); /* should we put if failed */
+
+       /* Fail if BIOS reserved pin for ACPI use */
+       if (!(inl(acpi_use) & BIT(offset % 32))) {
+               dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset);
+               return -EBUSY;
+       }
+       /* Fail if pin is in alternate function mode (not GPIO mode) */
+       if (!(inl(reg) & USE_SEL_BIT))
+               return -ENODEV;
+
+       /* enable input sensing */
+       outl(inl(conf2) & ~GPINDIS_BIT, conf2);
+
+
+       return 0;
+}
+
+static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
+
+       /* disable input sensing */
+       outl(inl(conf2) | GPINDIS_BIT, conf2);
+
+       pm_runtime_put(&lg->pdev->dev);
+}
+
+static int lp_irq_type(struct irq_data *d, unsigned type)
+{
+       struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+       u32 hwirq = irqd_to_hwirq(d);
+       unsigned long flags;
+       u32 value;
+       unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1);
+
+       if (hwirq >= lg->chip.ngpio)
+               return -EINVAL;
+
+       spin_lock_irqsave(&lg->lock, flags);
+       value = inl(reg);
+
+       /* set both TRIG_SEL and INV bits to 0 for rising edge */
+       if (type & IRQ_TYPE_EDGE_RISING)
+               value &= ~(TRIG_SEL_BIT | INT_INV_BIT);
+
+       /* TRIG_SEL bit 0, INV bit 1 for falling edge */
+       if (type & IRQ_TYPE_EDGE_FALLING)
+               value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT;
+
+       /* TRIG_SEL bit 1, INV bit 0 for level low */
+       if (type & IRQ_TYPE_LEVEL_LOW)
+               value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT;
+
+       /* TRIG_SEL bit 1, INV bit 1 for level high */
+       if (type & IRQ_TYPE_LEVEL_HIGH)
+               value |= TRIG_SEL_BIT | INT_INV_BIT;
+
+       outl(value, reg);
+       spin_unlock_irqrestore(&lg->lock, flags);
+
+       return 0;
+}
+
+static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+       return inl(reg) & IN_LVL_BIT;
+}
+
+static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+       unsigned long flags;
+
+       spin_lock_irqsave(&lg->lock, flags);
+
+       if (value)
+               outl(inl(reg) | OUT_LVL_BIT, reg);
+       else
+               outl(inl(reg) & ~OUT_LVL_BIT, reg);
+
+       spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+       unsigned long flags;
+
+       spin_lock_irqsave(&lg->lock, flags);
+       outl(inl(reg) | DIR_BIT, reg);
+       spin_unlock_irqrestore(&lg->lock, flags);
+
+       return 0;
+}
+
+static int lp_gpio_direction_output(struct gpio_chip *chip,
+                                     unsigned offset, int value)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+       unsigned long flags;
+
+       lp_gpio_set(chip, offset, value);
+
+       spin_lock_irqsave(&lg->lock, flags);
+       outl(inl(reg) & ~DIR_BIT, reg);
+       spin_unlock_irqrestore(&lg->lock, flags);
+
+       return 0;
+}
+
+static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+       return irq_create_mapping(lg->domain, offset);
+}
+
+static void lp_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+       struct irq_data *data = irq_desc_get_irq_data(desc);
+       struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
+       struct irq_chip *chip = irq_data_get_irq_chip(data);
+       u32 base, pin, mask;
+       unsigned long reg, pending;
+       unsigned virq;
+
+       /* check from GPIO controller which pin triggered the interrupt */
+       for (base = 0; base < lg->chip.ngpio; base += 32) {
+               reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+
+               while ((pending = inl(reg))) {
+                       pin = __ffs(pending);
+                       mask = BIT(pin);
+                       /* Clear before handling so we don't lose an edge */
+                       outl(mask, reg);
+                       virq = irq_find_mapping(lg->domain, base + pin);
+                       generic_handle_irq(virq);
+               }
+       }
+       chip->irq_eoi(data);
+}
+
+static void lp_irq_unmask(struct irq_data *d)
+{
+}
+
+static void lp_irq_mask(struct irq_data *d)
+{
+}
+
+static void lp_irq_enable(struct irq_data *d)
+{
+       struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+       u32 hwirq = irqd_to_hwirq(d);
+       unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
+       unsigned long flags;
+
+       spin_lock_irqsave(&lg->lock, flags);
+       outl(inl(reg) | BIT(hwirq % 32), reg);
+       spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static void lp_irq_disable(struct irq_data *d)
+{
+       struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+       u32 hwirq = irqd_to_hwirq(d);
+       unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
+       unsigned long flags;
+
+       spin_lock_irqsave(&lg->lock, flags);
+       outl(inl(reg) & ~BIT(hwirq % 32), reg);
+       spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static struct irq_chip lp_irqchip = {
+       .name = "LP-GPIO",
+       .irq_mask = lp_irq_mask,
+       .irq_unmask = lp_irq_unmask,
+       .irq_enable = lp_irq_enable,
+       .irq_disable = lp_irq_disable,
+       .irq_set_type = lp_irq_type,
+       .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void lp_gpio_irq_init_hw(struct lp_gpio *lg)
+{
+       unsigned long reg;
+       unsigned base;
+
+       for (base = 0; base < lg->chip.ngpio; base += 32) {
+               /* disable gpio pin interrupts */
+               reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
+               outl(0, reg);
+               /* Clear interrupt status register */
+               reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+               outl(0xffffffff, reg);
+       }
+}
+
+static int lp_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+                           irq_hw_number_t hw)
+{
+       struct lp_gpio *lg = d->host_data;
+
+       irq_set_chip_and_handler_name(virq, &lp_irqchip, handle_simple_irq,
+                                     "demux");
+       irq_set_chip_data(virq, lg);
+       irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+       return 0;
+}
+
+static const struct irq_domain_ops lp_gpio_irq_ops = {
+       .map = lp_gpio_irq_map,
+};
+
+static int lp_gpio_probe(struct platform_device *pdev)
+{
+       struct lp_gpio *lg;
+       struct gpio_chip *gc;
+       struct resource *io_rc, *irq_rc;
+       struct device *dev = &pdev->dev;
+       unsigned long reg_len;
+       unsigned hwirq;
+       int ret = -ENODEV;
+
+       lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL);
+       if (!lg) {
+               dev_err(dev, "can't allocate lp_gpio chip data\n");
+               return -ENOMEM;
+       }
+
+       lg->pdev = pdev;
+       platform_set_drvdata(pdev, lg);
+
+       io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+       if (!io_rc) {
+               dev_err(dev, "missing IO resources\n");
+               return -EINVAL;
+       }
+
+       lg->reg_base = io_rc->start;
+       reg_len = resource_size(io_rc);
+
+       if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) {
+               dev_err(dev, "failed requesting IO region 0x%x\n",
+                       (unsigned int)lg->reg_base);
+               return -EBUSY;
+       }
+
+       spin_lock_init(&lg->lock);
+
+       gc = &lg->chip;
+       gc->label = dev_name(dev);
+       gc->owner = THIS_MODULE;
+       gc->request = lp_gpio_request;
+       gc->free = lp_gpio_free;
+       gc->direction_input = lp_gpio_direction_input;
+       gc->direction_output = lp_gpio_direction_output;
+       gc->get = lp_gpio_get;
+       gc->set = lp_gpio_set;
+       gc->base = -1;
+       gc->ngpio = LP_NUM_GPIO;
+       gc->can_sleep = 0;
+       gc->dev = dev;
+
+       /* set up interrupts  */
+       if (irq_rc && irq_rc->start) {
+               hwirq = irq_rc->start;
+               gc->to_irq = lp_gpio_to_irq;
+
+               lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO,
+                                                  &lp_gpio_irq_ops, lg);
+               if (!lg->domain)
+                       return -ENXIO;
+
+               lp_gpio_irq_init_hw(lg);
+
+               irq_set_handler_data(hwirq, lg);
+               irq_set_chained_handler(hwirq, lp_gpio_irq_handler);
+       }
+
+       ret = gpiochip_add(gc);
+       if (ret) {
+               dev_err(dev, "failed adding lp-gpio chip\n");
+               return ret;
+       }
+       pm_runtime_enable(dev);
+
+       return 0;
+}
+
+static int lp_gpio_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int lp_gpio_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops lp_gpio_pm_ops = {
+       .runtime_suspend = lp_gpio_runtime_suspend,
+       .runtime_resume = lp_gpio_runtime_resume,
+};
+
+static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
+       { "INT33C7", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
+
+static int lp_gpio_remove(struct platform_device *pdev)
+{
+       struct lp_gpio *lg = platform_get_drvdata(pdev);
+       int err;
+       err = gpiochip_remove(&lg->chip);
+       if (err)
+               dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver lp_gpio_driver = {
+       .probe          = lp_gpio_probe,
+       .remove         = lp_gpio_remove,
+       .driver         = {
+               .name   = "lp_gpio",
+               .owner  = THIS_MODULE,
+               .pm     = &lp_gpio_pm_ops,
+               .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match),
+       },
+};
+
+static int __init lp_gpio_init(void)
+{
+       return platform_driver_register(&lp_gpio_driver);
+}
+
+subsys_initcall(lp_gpio_init);
index 9ae29cc..a0b33a2 100644 (file)
@@ -292,7 +292,6 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
 
        irq_set_chip_data(virq, h->host_data);
        irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
-       irq_set_irq_type(virq, IRQ_TYPE_NONE);
 
        return 0;
 }
index 45d97c4..25000b0 100644 (file)
@@ -66,6 +66,7 @@ struct mxs_gpio_port {
        struct irq_domain *domain;
        struct bgpio_chip bgc;
        enum mxs_gpio_id devid;
+       u32 both_edges;
 };
 
 static inline int is_imx23_gpio(struct mxs_gpio_port *port)
@@ -82,13 +83,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
 
 static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
 {
+       u32 val;
        u32 pin_mask = 1 << d->hwirq;
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct mxs_gpio_port *port = gc->private;
        void __iomem *pin_addr;
        int edge;
 
+       port->both_edges &= ~pin_mask;
        switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               val = gpio_get_value(port->bgc.gc.base + d->hwirq);
+               if (val)
+                       edge = GPIO_INT_FALL_EDGE;
+               else
+                       edge = GPIO_INT_RISE_EDGE;
+               port->both_edges |= pin_mask;
+               break;
        case IRQ_TYPE_EDGE_RISING:
                edge = GPIO_INT_RISE_EDGE;
                break;
@@ -125,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
        return 0;
 }
 
+static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio)
+{
+       u32 bit, val, edge;
+       void __iomem *pin_addr;
+
+       bit = 1 << gpio;
+
+       pin_addr = port->base + PINCTRL_IRQPOL(port);
+       val = readl(pin_addr);
+       edge = val & bit;
+
+       if (edge)
+               writel(bit, pin_addr + MXS_CLR);
+       else
+               writel(bit, pin_addr + MXS_SET);
+}
+
 /* MXS has one interrupt *per* gpio port */
 static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
 {
@@ -138,6 +166,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
 
        while (irq_stat != 0) {
                int irqoffset = fls(irq_stat) - 1;
+               if (port->both_edges & (1 << irqoffset))
+                       mxs_flip_edge(port, irqoffset);
+
                generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
                irq_stat &= ~(1 << irqoffset);
        }
index f1fbedb..159f5c5 100644 (file)
@@ -1476,19 +1476,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
        .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
 };
 
-const static struct omap_gpio_platform_data omap2_pdata = {
+static const struct omap_gpio_platform_data omap2_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = false,
 };
 
-const static struct omap_gpio_platform_data omap3_pdata = {
+static const struct omap_gpio_platform_data omap3_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
 };
 
-const static struct omap_gpio_platform_data omap4_pdata = {
+static const struct omap_gpio_platform_data omap4_pdata = {
        .regs = &omap4_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
index cc102d2..2405946 100644 (file)
@@ -46,6 +46,7 @@
 #define PCA957X_TYPE           0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
+       { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
        { "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
        { "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
        { "pca9536", 4  | PCA953X_TYPE, },
@@ -71,19 +72,23 @@ static const struct i2c_device_id pca953x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+
 struct pca953x_chip {
        unsigned gpio_start;
-       u32 reg_output;
-       u32 reg_direction;
+       u8 reg_output[MAX_BANK];
+       u8 reg_direction[MAX_BANK];
        struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
        struct mutex irq_lock;
-       u32 irq_mask;
-       u32 irq_stat;
-       u32 irq_trig_raise;
-       u32 irq_trig_fall;
-       int      irq_base;
+       u8 irq_mask[MAX_BANK];
+       u8 irq_stat[MAX_BANK];
+       u8 irq_trig_raise[MAX_BANK];
+       u8 irq_trig_fall[MAX_BANK];
        struct irq_domain *domain;
 #endif
 
@@ -93,33 +98,69 @@ struct pca953x_chip {
        int     chip_type;
 };
 
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+                               int off)
+{
+       int ret;
+       int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+       int offset = off / BANK_SZ;
+
+       ret = i2c_smbus_read_byte_data(chip->client,
+                               (reg << bank_shift) + offset);
+       *val = ret;
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed reading register\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
+                               int off)
+{
+       int ret = 0;
+       int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+       int offset = off / BANK_SZ;
+
+       ret = i2c_smbus_write_byte_data(chip->client,
+                                       (reg << bank_shift) + offset, val);
+
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "failed writing register\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
        int ret = 0;
 
        if (chip->gpio_chip.ngpio <= 8)
-               ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-       else if (chip->gpio_chip.ngpio == 24) {
-               cpu_to_le32s(&val);
+               ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
+       else if (chip->gpio_chip.ngpio >= 24) {
+               int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
                ret = i2c_smbus_write_i2c_block_data(chip->client,
-                                               (reg << 2) | REG_ADDR_AI,
-                                               3,
-                                               (u8 *) &val);
+                                       (reg << bank_shift) | REG_ADDR_AI,
+                                       NBANK(chip), val);
        }
        else {
                switch (chip->chip_type) {
                case PCA953X_TYPE:
                        ret = i2c_smbus_write_word_data(chip->client,
-                                                       reg << 1, val);
+                                                       reg << 1, (u16) *val);
                        break;
                case PCA957X_TYPE:
                        ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
-                                                       val & 0xff);
+                                                       val[0]);
                        if (ret < 0)
                                break;
                        ret = i2c_smbus_write_byte_data(chip->client,
                                                        (reg << 1) + 1,
-                                                       (val & 0xff00) >> 8);
+                                                       val[1]);
                        break;
                }
        }
@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
        return 0;
 }
 
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
        int ret;
 
        if (chip->gpio_chip.ngpio <= 8) {
                ret = i2c_smbus_read_byte_data(chip->client, reg);
                *val = ret;
-       }
-       else if (chip->gpio_chip.ngpio == 24) {
-               *val = 0;
+       } else if (chip->gpio_chip.ngpio >= 24) {
+               int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
                ret = i2c_smbus_read_i2c_block_data(chip->client,
-                                               (reg << 2) | REG_ADDR_AI,
-                                               3,
-                                               (u8 *) val);
-               le32_to_cpus(val);
+                                       (reg << bank_shift) | REG_ADDR_AI,
+                                       NBANK(chip), val);
        } else {
                ret = i2c_smbus_read_word_data(chip->client, reg << 1);
-               *val = ret;
+               val[0] = (u16)ret & 0xFF;
+               val[1] = (u16)ret >> 8;
        }
-
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed reading register\n");
                return ret;
@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
        struct pca953x_chip *chip;
-       uint reg_val;
+       u8 reg_val;
        int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
        mutex_lock(&chip->i2c_lock);
-       reg_val = chip->reg_direction | (1u << off);
+       reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
 
        switch (chip->chip_type) {
        case PCA953X_TYPE:
@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
                offset = PCA957X_CFG;
                break;
        }
-       ret = pca953x_write_reg(chip, offset, reg_val);
+       ret = pca953x_write_single(chip, offset, reg_val, off);
        if (ret)
                goto exit;
 
-       chip->reg_direction = reg_val;
+       chip->reg_direction[off / BANK_SZ] = reg_val;
        ret = 0;
 exit:
        mutex_unlock(&chip->i2c_lock);
@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
                unsigned off, int val)
 {
        struct pca953x_chip *chip;
-       uint reg_val;
+       u8 reg_val;
        int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
        mutex_lock(&chip->i2c_lock);
        /* set output level */
        if (val)
-               reg_val = chip->reg_output | (1u << off);
+               reg_val = chip->reg_output[off / BANK_SZ]
+                       | (1u << (off % BANK_SZ));
        else
-               reg_val = chip->reg_output & ~(1u << off);
+               reg_val = chip->reg_output[off / BANK_SZ]
+                       & ~(1u << (off % BANK_SZ));
 
        switch (chip->chip_type) {
        case PCA953X_TYPE:
@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
                offset = PCA957X_OUT;
                break;
        }
-       ret = pca953x_write_reg(chip, offset, reg_val);
+       ret = pca953x_write_single(chip, offset, reg_val, off);
        if (ret)
                goto exit;
 
-       chip->reg_output = reg_val;
+       chip->reg_output[off / BANK_SZ] = reg_val;
 
        /* then direction */
-       reg_val = chip->reg_direction & ~(1u << off);
+       reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
        switch (chip->chip_type) {
        case PCA953X_TYPE:
                offset = PCA953X_DIRECTION;
@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
                offset = PCA957X_CFG;
                break;
        }
-       ret = pca953x_write_reg(chip, offset, reg_val);
+       ret = pca953x_write_single(chip, offset, reg_val, off);
        if (ret)
                goto exit;
 
-       chip->reg_direction = reg_val;
+       chip->reg_direction[off / BANK_SZ] = reg_val;
        ret = 0;
 exit:
        mutex_unlock(&chip->i2c_lock);
@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
                offset = PCA957X_IN;
                break;
        }
-       ret = pca953x_read_reg(chip, offset, &reg_val);
+       ret = pca953x_read_single(chip, offset, &reg_val, off);
        mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
                /* NOTE:  diagnostic already emitted; that's all we should
@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
        struct pca953x_chip *chip;
-       u32 reg_val;
+       u8 reg_val;
        int ret, offset = 0;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
        mutex_lock(&chip->i2c_lock);
        if (val)
-               reg_val = chip->reg_output | (1u << off);
+               reg_val = chip->reg_output[off / BANK_SZ]
+                       | (1u << (off % BANK_SZ));
        else
-               reg_val = chip->reg_output & ~(1u << off);
+               reg_val = chip->reg_output[off / BANK_SZ]
+                       & ~(1u << (off % BANK_SZ));
 
        switch (chip->chip_type) {
        case PCA953X_TYPE:
@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
                offset = PCA957X_OUT;
                break;
        }
-       ret = pca953x_write_reg(chip, offset, reg_val);
+       ret = pca953x_write_single(chip, offset, reg_val, off);
        if (ret)
                goto exit;
 
-       chip->reg_output = reg_val;
+       chip->reg_output[off / BANK_SZ] = reg_val;
 exit:
        mutex_unlock(&chip->i2c_lock);
 }
@@ -328,21 +371,21 @@ static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
        struct pca953x_chip *chip;
 
        chip = container_of(gc, struct pca953x_chip, gpio_chip);
-       return chip->irq_base + off;
+       return irq_create_mapping(chip->domain, off);
 }
 
 static void pca953x_irq_mask(struct irq_data *d)
 {
        struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-       chip->irq_mask &= ~(1 << d->hwirq);
+       chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
 {
        struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-       chip->irq_mask |= 1 << d->hwirq;
+       chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_bus_lock(struct irq_data *d)
@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
 static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
        struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-       u32 new_irqs;
-       u32 level;
+       u8 new_irqs;
+       int level, i;
 
        /* Look for any newly setup interrupt */
-       new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
-       new_irqs &= ~chip->reg_direction;
-
-       while (new_irqs) {
-               level = __ffs(new_irqs);
-               pca953x_gpio_direction_input(&chip->gpio_chip, level);
-               new_irqs &= ~(1 << level);
+       for (i = 0; i < NBANK(chip); i++) {
+               new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
+               new_irqs &= ~chip->reg_direction[i];
+
+               while (new_irqs) {
+                       level = __ffs(new_irqs);
+                       pca953x_gpio_direction_input(&chip->gpio_chip,
+                                                       level + (BANK_SZ * i));
+                       new_irqs &= ~(1 << level);
+               }
        }
 
        mutex_unlock(&chip->irq_lock);
@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 {
        struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-       u32 mask = 1 << d->hwirq;
+       int bank_nb = d->hwirq / BANK_SZ;
+       u8 mask = 1 << (d->hwirq % BANK_SZ);
 
        if (!(type & IRQ_TYPE_EDGE_BOTH)) {
                dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
        }
 
        if (type & IRQ_TYPE_EDGE_FALLING)
-               chip->irq_trig_fall |= mask;
+               chip->irq_trig_fall[bank_nb] |= mask;
        else
-               chip->irq_trig_fall &= ~mask;
+               chip->irq_trig_fall[bank_nb] &= ~mask;
 
        if (type & IRQ_TYPE_EDGE_RISING)
-               chip->irq_trig_raise |= mask;
+               chip->irq_trig_raise[bank_nb] |= mask;
        else
-               chip->irq_trig_raise &= ~mask;
+               chip->irq_trig_raise[bank_nb] &= ~mask;
 
        return 0;
 }
@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
        .irq_set_type           = pca953x_irq_set_type,
 };
 
-static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 {
-       u32 cur_stat;
-       u32 old_stat;
-       u32 pending;
-       u32 trigger;
-       int ret, offset = 0;
+       u8 cur_stat[MAX_BANK];
+       u8 old_stat[MAX_BANK];
+       u8 pendings = 0;
+       u8 trigger[MAX_BANK], triggers = 0;
+       int ret, i, offset = 0;
 
        switch (chip->chip_type) {
        case PCA953X_TYPE:
@@ -420,60 +467,88 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
                offset = PCA957X_IN;
                break;
        }
-       ret = pca953x_read_reg(chip, offset, &cur_stat);
+       ret = pca953x_read_regs(chip, offset, cur_stat);
        if (ret)
                return 0;
 
        /* Remove output pins from the equation */
-       cur_stat &= chip->reg_direction;
+       for (i = 0; i < NBANK(chip); i++)
+               cur_stat[i] &= chip->reg_direction[i];
+
+       memcpy(old_stat, chip->irq_stat, NBANK(chip));
 
-       old_stat = chip->irq_stat;
-       trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+       for (i = 0; i < NBANK(chip); i++) {
+               trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
+               triggers += trigger[i];
+       }
 
-       if (!trigger)
+       if (!triggers)
                return 0;
 
-       chip->irq_stat = cur_stat;
+       memcpy(chip->irq_stat, cur_stat, NBANK(chip));
 
-       pending = (old_stat & chip->irq_trig_fall) |
-                 (cur_stat & chip->irq_trig_raise);
-       pending &= trigger;
+       for (i = 0; i < NBANK(chip); i++) {
+               pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
+                       (cur_stat[i] & chip->irq_trig_raise[i]);
+               pending[i] &= trigger[i];
+               pendings += pending[i];
+       }
 
-       return pending;
+       return pendings;
 }
 
 static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 {
        struct pca953x_chip *chip = devid;
-       u32 pending;
-       u32 level;
-
-       pending = pca953x_irq_pending(chip);
+       u8 pending[MAX_BANK];
+       u8 level;
+       int i;
 
-       if (!pending)
+       if (!pca953x_irq_pending(chip, pending))
                return IRQ_HANDLED;
 
-       do {
-               level = __ffs(pending);
-               handle_nested_irq(irq_find_mapping(chip->domain, level));
-
-               pending &= ~(1 << level);
-       } while (pending);
+       for (i = 0; i < NBANK(chip); i++) {
+               while (pending[i]) {
+                       level = __ffs(pending[i]);
+                       handle_nested_irq(irq_find_mapping(chip->domain,
+                                                       level + (BANK_SZ * i)));
+                       pending[i] &= ~(1 << level);
+               }
+       }
 
        return IRQ_HANDLED;
 }
 
+static int pca953x_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+                      irq_hw_number_t hwirq)
+{
+       irq_clear_status_flags(irq, IRQ_NOREQUEST);
+       irq_set_chip_data(irq, d->host_data);
+       irq_set_chip(irq, &pca953x_irq_chip);
+       irq_set_nested_thread(irq, true);
+#ifdef CONFIG_ARM
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       irq_set_noprobe(irq);
+#endif
+
+       return 0;
+}
+
+static const struct irq_domain_ops pca953x_irq_simple_ops = {
+       .map = pca953x_gpio_irq_map,
+       .xlate = irq_domain_xlate_twocell,
+};
+
 static int pca953x_irq_setup(struct pca953x_chip *chip,
                             const struct i2c_device_id *id,
                             int irq_base)
 {
        struct i2c_client *client = chip->client;
-       int ret, offset = 0;
-       u32 temporary;
+       int ret, i, offset = 0;
 
        if (irq_base != -1
                        && (id->driver_data & PCA_INT)) {
-               int lvl;
 
                switch (chip->chip_type) {
                case PCA953X_TYPE:
@@ -483,49 +558,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                        offset = PCA957X_IN;
                        break;
                }
-               ret = pca953x_read_reg(chip, offset, &temporary);
-               chip->irq_stat = temporary;
+               ret = pca953x_read_regs(chip, offset, chip->irq_stat);
                if (ret)
-                       goto out_failed;
+                       return ret;
 
                /*
                 * There is no way to know which GPIO line generated the
                 * interrupt.  We have to rely on the previous read for
                 * this purpose.
                 */
-               chip->irq_stat &= chip->reg_direction;
+               for (i = 0; i < NBANK(chip); i++)
+                       chip->irq_stat[i] &= chip->reg_direction[i];
                mutex_init(&chip->irq_lock);
 
-               chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
-               if (chip->irq_base < 0)
-                       goto out_failed;
-
-               chip->domain = irq_domain_add_legacy(client->dev.of_node,
+               chip->domain = irq_domain_add_simple(client->dev.of_node,
                                                chip->gpio_chip.ngpio,
-                                               chip->irq_base,
-                                               0,
-                                               &irq_domain_simple_ops,
+                                               irq_base,
+                                               &pca953x_irq_simple_ops,
                                                NULL);
-               if (!chip->domain) {
-                       ret = -ENODEV;
-                       goto out_irqdesc_free;
-               }
+               if (!chip->domain)
+                       return -ENODEV;
 
-               for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
-                       int irq = lvl + chip->irq_base;
-
-                       irq_clear_status_flags(irq, IRQ_NOREQUEST);
-                       irq_set_chip_data(irq, chip);
-                       irq_set_chip(irq, &pca953x_irq_chip);
-                       irq_set_nested_thread(irq, true);
-#ifdef CONFIG_ARM
-                       set_irq_flags(irq, IRQF_VALID);
-#else
-                       irq_set_noprobe(irq);
-#endif
-               }
-
-               ret = request_threaded_irq(client->irq,
+               ret = devm_request_threaded_irq(&client->dev,
+                                       client->irq,
                                           NULL,
                                           pca953x_irq_handler,
                                           IRQF_TRIGGER_LOW | IRQF_ONESHOT,
@@ -533,28 +588,15 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                if (ret) {
                        dev_err(&client->dev, "failed to request irq %d\n",
                                client->irq);
-                       goto out_irqdesc_free;
+                       return ret;
                }
 
                chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
        }
 
        return 0;
-
-out_irqdesc_free:
-       irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
-out_failed:
-       chip->irq_base = -1;
-       return ret;
 }
 
-static void pca953x_irq_teardown(struct pca953x_chip *chip)
-{
-       if (chip->irq_base != -1) {
-               irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
-               free_irq(chip->client->irq, chip);
-       }
-}
 #else /* CONFIG_GPIO_PCA953X_IRQ */
 static int pca953x_irq_setup(struct pca953x_chip *chip,
                             const struct i2c_device_id *id,
@@ -567,10 +609,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 
        return 0;
 }
-
-static void pca953x_irq_teardown(struct pca953x_chip *chip)
-{
-}
 #endif
 
 /*
@@ -619,18 +657,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 {
        int ret;
+       u8 val[MAX_BANK];
 
-       ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+       ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
        if (ret)
                goto out;
 
-       ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
-                              &chip->reg_direction);
+       ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
+                              chip->reg_direction);
        if (ret)
                goto out;
 
        /* set platform specific polarity inversion */
-       ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+       if (invert)
+               memset(val, 0xFF, NBANK(chip));
+       else
+               memset(val, 0, NBANK(chip));
+
+       ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
 out:
        return ret;
 }
@@ -638,28 +682,36 @@ out:
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
        int ret;
-       u32 val = 0;
+       u8 val[MAX_BANK];
 
        /* Let every port in proper state, that could save power */
-       pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
-       pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
-       pca953x_write_reg(chip, PCA957X_OUT, 0x0);
-
-       ret = pca953x_read_reg(chip, PCA957X_IN, &val);
+       memset(val, 0, NBANK(chip));
+       pca953x_write_regs(chip, PCA957X_PUPD, val);
+       memset(val, 0xFF, NBANK(chip));
+       pca953x_write_regs(chip, PCA957X_CFG, val);
+       memset(val, 0, NBANK(chip));
+       pca953x_write_regs(chip, PCA957X_OUT, val);
+
+       ret = pca953x_read_regs(chip, PCA957X_IN, val);
        if (ret)
                goto out;
-       ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+       ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
        if (ret)
                goto out;
-       ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+       ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
        if (ret)
                goto out;
 
        /* set platform specific polarity inversion */
-       pca953x_write_reg(chip, PCA957X_INVRT, invert);
+       if (invert)
+               memset(val, 0xFF, NBANK(chip));
+       else
+               memset(val, 0, NBANK(chip));
+       pca953x_write_regs(chip, PCA957X_INVRT, val);
 
        /* To enable register 6, 7 to controll pull up and pull down */
-       pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+       memset(val, 0x02, NBANK(chip));
+       pca953x_write_regs(chip, PCA957X_BKEN, val);
 
        return 0;
 out:
@@ -675,7 +727,8 @@ static int pca953x_probe(struct i2c_client *client,
        int ret;
        u32 invert = 0;
 
-       chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+       chip = devm_kzalloc(&client->dev,
+                       sizeof(struct pca953x_chip), GFP_KERNEL);
        if (chip == NULL)
                return -ENOMEM;
 
@@ -710,15 +763,15 @@ static int pca953x_probe(struct i2c_client *client,
        else
                ret = device_pca957x_init(chip, invert);
        if (ret)
-               goto out_failed;
+               return ret;
 
        ret = pca953x_irq_setup(chip, id, irq_base);
        if (ret)
-               goto out_failed;
+               return ret;
 
        ret = gpiochip_add(&chip->gpio_chip);
        if (ret)
-               goto out_failed_irq;
+               return ret;
 
        if (pdata && pdata->setup) {
                ret = pdata->setup(client, chip->gpio_chip.base,
@@ -729,12 +782,6 @@ static int pca953x_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, chip);
        return 0;
-
-out_failed_irq:
-       pca953x_irq_teardown(chip);
-out_failed:
-       kfree(chip);
-       return ret;
 }
 
 static int pca953x_remove(struct i2c_client *client)
@@ -760,12 +807,11 @@ static int pca953x_remove(struct i2c_client *client)
                return ret;
        }
 
-       pca953x_irq_teardown(chip);
-       kfree(chip);
        return 0;
 }
 
 static const struct of_device_id pca953x_dt_ids[] = {
+       { .compatible = "nxp,pca9505", },
        { .compatible = "nxp,pca9534", },
        { .compatible = "nxp,pca9535", },
        { .compatible = "nxp,pca9536", },
index c1720de..b820869 100644 (file)
@@ -365,7 +365,7 @@ static int __init pl061_gpio_init(void)
 {
        return amba_driver_register(&pl061_gpio_driver);
 }
-subsys_initcall(pl061_gpio_init);
+module_init(pl061_gpio_init);
 
 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
 MODULE_DESCRIPTION("PL061 GPIO driver");
index 8325f58..9cc108d 100644 (file)
@@ -642,12 +642,7 @@ static struct platform_driver pxa_gpio_driver = {
                .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
        },
 };
-
-static int __init pxa_gpio_init(void)
-{
-       return platform_driver_register(&pxa_gpio_driver);
-}
-postcore_initcall(pxa_gpio_init);
+module_platform_driver(pxa_gpio_driver);
 
 #ifdef CONFIG_PM
 static int pxa_gpio_suspend(void)
index 9572aa1..4d330e3 100644 (file)
@@ -37,7 +37,6 @@
 
 #include <linux/i2c/twl.h>
 
-
 /*
  * The GPIO "subchip" supports 18 GPIOs which can be configured as
  * inputs or outputs, with pullups or pulldowns on each pin.  Each
  * There are also two LED pins used sometimes as output-only GPIOs.
  */
 
-
-static struct gpio_chip twl_gpiochip;
-static int twl4030_gpio_base;
-static int twl4030_gpio_irq_base;
-
 /* genirq interfaces are not available to modules */
 #ifdef MODULE
 #define is_module()    true
@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base;
 /* Mask for GPIO registers when aggregated into a 32-bit integer */
 #define GPIO_32_MASK                   0x0003ffff
 
-/* Data structures */
-static DEFINE_MUTEX(gpio_lock);
+struct gpio_twl4030_priv {
+       struct gpio_chip gpio_chip;
+       struct mutex mutex;
+       int irq_base;
 
-/* store usage of each GPIO. - each bit represents one GPIO */
-static unsigned int gpio_usage_count;
+       /* Bitfields for state caching */
+       unsigned int usage_count;
+       unsigned int direction;
+       unsigned int out_state;
+};
 
 /*----------------------------------------------------------------------*/
 
+static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip)
+{
+       return container_of(chip, struct gpio_twl4030_priv, gpio_chip);
+}
+
 /*
  * To configure TWL4030 GPIO module registers
  */
@@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address)
 
 /*----------------------------------------------------------------------*/
 
-static u8 cached_leden;                /* protected by gpio_lock */
+static u8 cached_leden;
 
 /* The LED lines are open drain outputs ... a FET pulls to GND, so an
  * external pullup is needed.  We could also expose the integrated PWM
@@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value)
        if (led)
                mask <<= 1;
 
-       mutex_lock(&gpio_lock);
        if (value)
                cached_leden &= ~mask;
        else
                cached_leden |= mask;
        status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
                                  TWL4030_LED_LEDEN_REG);
-       mutex_unlock(&gpio_lock);
 }
 
 static int twl4030_set_gpio_direction(int gpio, int is_input)
@@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
        u8 base = REG_GPIODATADIR1 + d_bnk;
        int ret = 0;
 
-       mutex_lock(&gpio_lock);
        ret = gpio_twl4030_read(base);
        if (ret >= 0) {
                if (is_input)
@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
 
                ret = gpio_twl4030_write(base, reg);
        }
-       mutex_unlock(&gpio_lock);
        return ret;
 }
 
@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio)
        u8 base = 0;
        int ret = 0;
 
-       if (unlikely((gpio >= TWL4030_GPIO_MAX)
-               || !(gpio_usage_count & BIT(gpio))))
-               return -EPERM;
-
        base = REG_GPIODATAIN1 + d_bnk;
        ret = gpio_twl4030_read(base);
        if (ret > 0)
@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio)
 
 static int twl_request(struct gpio_chip *chip, unsigned offset)
 {
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
        int status = 0;
 
-       mutex_lock(&gpio_lock);
+       mutex_lock(&priv->mutex);
 
        /* Support the two LED outputs as output-only GPIOs. */
        if (offset >= TWL4030_GPIO_MAX) {
@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
        }
 
        /* on first use, turn GPIO module "on" */
-       if (!gpio_usage_count) {
+       if (!priv->usage_count) {
                struct twl4030_gpio_platform_data *pdata;
                u8 value = MASK_GPIO_CTRL_GPIO_ON;
 
@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
                status = gpio_twl4030_write(REG_GPIO_CTRL, value);
        }
 
+done:
        if (!status)
-               gpio_usage_count |= (0x1 << offset);
+               priv->usage_count |= BIT(offset);
 
-done:
-       mutex_unlock(&gpio_lock);
+       mutex_unlock(&priv->mutex);
        return status;
 }
 
 static void twl_free(struct gpio_chip *chip, unsigned offset)
 {
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+       mutex_lock(&priv->mutex);
        if (offset >= TWL4030_GPIO_MAX) {
                twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
-               return;
+               goto out;
        }
 
-       mutex_lock(&gpio_lock);
-
-       gpio_usage_count &= ~BIT(offset);
+       priv->usage_count &= ~BIT(offset);
 
        /* on last use, switch off GPIO module */
-       if (!gpio_usage_count)
+       if (!priv->usage_count)
                gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
 
-       mutex_unlock(&gpio_lock);
+out:
+       mutex_unlock(&priv->mutex);
 }
 
 static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
 {
-       return (offset < TWL4030_GPIO_MAX)
-               ? twl4030_set_gpio_direction(offset, 1)
-               : -EINVAL;
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+       int ret;
+
+       mutex_lock(&priv->mutex);
+       if (offset < TWL4030_GPIO_MAX)
+               ret = twl4030_set_gpio_direction(offset, 1);
+       else
+               ret = -EINVAL;
+
+       if (!ret)
+               priv->direction &= ~BIT(offset);
+
+       mutex_unlock(&priv->mutex);
+
+       return ret;
 }
 
 static int twl_get(struct gpio_chip *chip, unsigned offset)
 {
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+       int ret;
        int status = 0;
 
-       if (offset < TWL4030_GPIO_MAX)
-               status = twl4030_get_gpio_datain(offset);
-       else if (offset == TWL4030_GPIO_MAX)
-               status = cached_leden & LEDEN_LEDAON;
+       mutex_lock(&priv->mutex);
+       if (!(priv->usage_count & BIT(offset))) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       if (priv->direction & BIT(offset))
+               status = priv->out_state & BIT(offset);
        else
-               status = cached_leden & LEDEN_LEDBON;
-       return (status < 0) ? 0 : status;
+               status = twl4030_get_gpio_datain(offset);
+
+       ret = (status <= 0) ? 0 : 1;
+out:
+       mutex_unlock(&priv->mutex);
+       return ret;
 }
 
-static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-       if (offset < TWL4030_GPIO_MAX) {
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+       mutex_lock(&priv->mutex);
+       if (offset < TWL4030_GPIO_MAX)
                twl4030_set_gpio_dataout(offset, value);
-               return twl4030_set_gpio_direction(offset, 0);
-       } else {
+       else
                twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
-               return 0;
-       }
+
+       if (value)
+               priv->out_state |= BIT(offset);
+       else
+               priv->out_state &= ~BIT(offset);
+
+       mutex_unlock(&priv->mutex);
 }
 
-static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
 {
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+       mutex_lock(&priv->mutex);
        if (offset < TWL4030_GPIO_MAX)
                twl4030_set_gpio_dataout(offset, value);
-       else
-               twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
+
+       priv->direction |= BIT(offset);
+       mutex_unlock(&priv->mutex);
+
+       twl_set(chip, offset, value);
+
+       return 0;
 }
 
 static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-       return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX))
-               ? (twl4030_gpio_irq_base + offset)
+       struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+       return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
+               ? (priv->irq_base + offset)
                : -EINVAL;
 }
 
-static struct gpio_chip twl_gpiochip = {
+static struct gpio_chip template_chip = {
        .label                  = "twl4030",
        .owner                  = THIS_MODULE,
        .request                = twl_request,
@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
 {
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
        struct device_node *node = pdev->dev.of_node;
+       struct gpio_twl4030_priv *priv;
        int ret, irq_base;
 
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
        /* maybe setup IRQs */
        if (is_module()) {
                dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       twl4030_gpio_irq_base = irq_base;
+       priv->irq_base = irq_base;
 
 no_irqs:
-       twl_gpiochip.base = -1;
-       twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
-       twl_gpiochip.dev = &pdev->dev;
+       priv->gpio_chip = template_chip;
+       priv->gpio_chip.base = -1;
+       priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
+       priv->gpio_chip.dev = &pdev->dev;
+
+       mutex_init(&priv->mutex);
 
        if (node)
                pdata = of_gpio_twl4030(&pdev->dev);
@@ -481,23 +528,23 @@ no_irqs:
         * is (still) clear if use_leds is set.
         */
        if (pdata->use_leds)
-               twl_gpiochip.ngpio += 2;
+               priv->gpio_chip.ngpio += 2;
 
-       ret = gpiochip_add(&twl_gpiochip);
+       ret = gpiochip_add(&priv->gpio_chip);
        if (ret < 0) {
                dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
-               twl_gpiochip.ngpio = 0;
+               priv->gpio_chip.ngpio = 0;
                gpio_twl4030_remove(pdev);
                goto out;
        }
 
-       twl4030_gpio_base = twl_gpiochip.base;
+       platform_set_drvdata(pdev, priv);
 
        if (pdata && pdata->setup) {
                int status;
 
-               status = pdata->setup(&pdev->dev,
-                               twl4030_gpio_base, TWL4030_GPIO_MAX);
+               status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
+                                     TWL4030_GPIO_MAX);
                if (status)
                        dev_dbg(&pdev->dev, "setup --> %d\n", status);
        }
@@ -510,18 +557,19 @@ out:
 static int gpio_twl4030_remove(struct platform_device *pdev)
 {
        struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
        int status;
 
        if (pdata && pdata->teardown) {
-               status = pdata->teardown(&pdev->dev,
-                               twl4030_gpio_base, TWL4030_GPIO_MAX);
+               status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
+                                        TWL4030_GPIO_MAX);
                if (status) {
                        dev_dbg(&pdev->dev, "teardown --> %d\n", status);
                        return status;
                }
        }
 
-       status = gpiochip_remove(&twl_gpiochip);
+       status = gpiochip_remove(&priv->gpio_chip);
        if (status < 0)
                return status;
 
index b53320a..81683ca 100644 (file)
@@ -73,19 +73,20 @@ struct vt8500_gpio_data {
 static struct vt8500_gpio_data vt8500_data = {
        .num_banks      = 7,
        .banks  = {
+               VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
                VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
                VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
                VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
                VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
                VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
                VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
-               VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
        },
 };
 
 static struct vt8500_gpio_data wm8505_data = {
        .num_banks      = 10,
        .banks  = {
+               VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
                VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
                VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
                VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
@@ -95,7 +96,6 @@ static struct vt8500_gpio_data wm8505_data = {
                VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
                VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
                VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
-               VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
                VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
        },
 };
@@ -127,6 +127,12 @@ struct vt8500_gpio_chip {
        void __iomem    *base;
 };
 
+struct vt8500_data {
+       struct vt8500_gpio_chip *chip;
+       void __iomem *iobase;
+       int num_banks;
+};
+
 
 #define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
 
@@ -224,19 +230,32 @@ static int vt8500_of_xlate(struct gpio_chip *gc,
 static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
                                const struct vt8500_gpio_data *data)
 {
+       struct vt8500_data *priv;
        struct vt8500_gpio_chip *vtchip;
        struct gpio_chip *chip;
        int i;
        int pin_cnt = 0;
 
-       vtchip = devm_kzalloc(&pdev->dev,
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct vt8500_data), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       priv->chip = devm_kzalloc(&pdev->dev,
                        sizeof(struct vt8500_gpio_chip) * data->num_banks,
                        GFP_KERNEL);
-       if (!vtchip) {
-               pr_err("%s: failed to allocate chip memory\n", __func__);
+       if (!priv->chip) {
+               dev_err(&pdev->dev, "failed to allocate chip memory\n");
                return -ENOMEM;
        }
 
+       priv->iobase = base;
+       priv->num_banks = data->num_banks;
+       platform_set_drvdata(pdev, priv);
+
+       vtchip = priv->chip;
+
        for (i = 0; i < data->num_banks; i++) {
                vtchip[i].base = base;
                vtchip[i].regs = &data->banks[i];
@@ -273,36 +292,54 @@ static struct of_device_id vt8500_gpio_dt_ids[] = {
 
 static int vt8500_gpio_probe(struct platform_device *pdev)
 {
+       int ret;
        void __iomem *gpio_base;
-       struct device_node *np;
+       struct resource *res;
        const struct of_device_id *of_id =
                                of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
 
        if (!of_id) {
-               dev_err(&pdev->dev, "Failed to find gpio controller\n");
+               dev_err(&pdev->dev, "No matching driver data\n");
                return -ENODEV;
        }
 
-       np = pdev->dev.of_node;
-       if (!np) {
-               dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
-               return -EFAULT;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get IO resource\n");
+               return -ENODEV;
        }
 
-       gpio_base = of_iomap(np, 0);
+       gpio_base = devm_request_and_ioremap(&pdev->dev, res);
        if (!gpio_base) {
                dev_err(&pdev->dev, "Unable to map GPIO registers\n");
-               of_node_put(np);
                return -ENOMEM;
        }
 
-       vt8500_add_chips(pdev, gpio_base, of_id->data);
+       ret = vt8500_add_chips(pdev, gpio_base, of_id->data);
+
+       return ret;
+}
+
+static int vt8500_gpio_remove(struct platform_device *pdev)
+{
+       int i;
+       int ret;
+       struct vt8500_data *priv = platform_get_drvdata(pdev);
+       struct vt8500_gpio_chip *vtchip = priv->chip;
+
+       for (i = 0; i < priv->num_banks; i++) {
+               ret = gpiochip_remove(&vtchip[i].chip);
+               if (ret)
+                       dev_warn(&pdev->dev, "gpiochip_remove returned %d\n",
+                                ret);
+       }
 
        return 0;
 }
 
 static struct platform_driver vt8500_gpio_driver = {
        .probe          = vt8500_gpio_probe,
+       .remove         = vt8500_gpio_remove,
        .driver         = {
                .name   = "vt8500-gpio",
                .owner  = THIS_MODULE,
index cbad6e9..a063eb0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/export.h>
 #include <linux/acpi_gpio.h>
 #include <linux/acpi.h>
+#include <linux/interrupt.h>
 
 static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
 {
@@ -52,3 +53,89 @@ int acpi_get_gpio(char *path, int pin)
        return chip->base + pin;
 }
 EXPORT_SYMBOL_GPL(acpi_get_gpio);
+
+
+static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
+{
+       acpi_handle handle = data;
+
+       acpi_evaluate_object(handle, NULL, NULL, NULL);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
+ * @chip:      gpio chip
+ *
+ * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
+ * handled by ACPI event methods which need to be called from the GPIO
+ * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
+ * gpio pins have acpi event methods and assigns interrupt handlers that calls
+ * the acpi event methods for those pins.
+ *
+ * Interrupts are automatically freed on driver detach
+ */
+
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
+{
+       struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
+       struct acpi_resource *res;
+       acpi_handle handle, ev_handle;
+       acpi_status status;
+       unsigned int pin;
+       int irq, ret;
+       char ev_name[5];
+
+       if (!chip->dev || !chip->to_irq)
+               return;
+
+       handle = ACPI_HANDLE(chip->dev);
+       if (!handle)
+               return;
+
+       status = acpi_get_event_resources(handle, &buf);
+       if (ACPI_FAILURE(status))
+               return;
+
+       /* If a gpio interrupt has an acpi event handler method, then
+        * set up an interrupt handler that calls the acpi event handler
+        */
+
+       for (res = buf.pointer;
+            res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
+            res = ACPI_NEXT_RESOURCE(res)) {
+
+               if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
+                   res->data.gpio.connection_type !=
+                   ACPI_RESOURCE_GPIO_TYPE_INT)
+                       continue;
+
+               pin = res->data.gpio.pin_table[0];
+               if (pin > chip->ngpio)
+                       continue;
+
+               sprintf(ev_name, "_%c%02X",
+               res->data.gpio.triggering ? 'E' : 'L', pin);
+
+               status = acpi_get_handle(handle, ev_name, &ev_handle);
+               if (ACPI_FAILURE(status))
+                       continue;
+
+               irq = chip->to_irq(chip, pin);
+               if (irq < 0)
+                       continue;
+
+               /* Assume BIOS sets the triggering, so no flags */
+               ret = devm_request_threaded_irq(chip->dev, irq, NULL,
+                                         acpi_gpio_irq_handler,
+                                         0,
+                                         "GPIO-signaled-ACPI-event",
+                                         ev_handle);
+               if (ret)
+                       dev_err(chip->dev,
+                               "Failed to request IRQ %d ACPI event handler\n",
+                               irq);
+       }
+}
+EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
index 5359ca7..4828fe7 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/spinlock.h>
+#include <linux/list.h>
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/debugfs.h>
@@ -52,14 +53,13 @@ struct gpio_desc {
 /* flag symbols are bit numbers */
 #define FLAG_REQUESTED 0
 #define FLAG_IS_OUT    1
-#define FLAG_RESERVED  2
-#define FLAG_EXPORT    3       /* protected by sysfs_lock */
-#define FLAG_SYSFS     4       /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 5       /* trigger on falling edge */
-#define FLAG_TRIG_RISE 6       /* trigger on rising edge */
-#define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
-#define FLAG_OPEN_DRAIN        8       /* Gpio is open drain type */
-#define FLAG_OPEN_SOURCE 9     /* Gpio is open source type */
+#define FLAG_EXPORT    2       /* protected by sysfs_lock */
+#define FLAG_SYSFS     3       /* exported via /sys/class/gpio/control */
+#define FLAG_TRIG_FALL 4       /* trigger on falling edge */
+#define FLAG_TRIG_RISE 5       /* trigger on rising edge */
+#define FLAG_ACTIVE_LOW        6       /* sysfs value has active low */
+#define FLAG_OPEN_DRAIN        7       /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 8     /* Gpio is open source type */
 
 #define ID_SHIFT       16      /* add new flags before this one */
 
@@ -72,10 +72,36 @@ struct gpio_desc {
 };
 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
 
+#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
+
+static LIST_HEAD(gpio_chips);
+
 #ifdef CONFIG_GPIO_SYSFS
 static DEFINE_IDR(dirent_idr);
 #endif
 
+/*
+ * Internal gpiod_* API using descriptors instead of the integer namespace.
+ * Most of this should eventually go public.
+ */
+static int gpiod_request(struct gpio_desc *desc, const char *label);
+static void gpiod_free(struct gpio_desc *desc);
+static int gpiod_direction_input(struct gpio_desc *desc);
+static int gpiod_direction_output(struct gpio_desc *desc, int value);
+static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
+static int gpiod_get_value_cansleep(struct gpio_desc *desc);
+static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
+static int gpiod_get_value(struct gpio_desc *desc);
+static void gpiod_set_value(struct gpio_desc *desc, int value);
+static int gpiod_cansleep(struct gpio_desc *desc);
+static int gpiod_to_irq(struct gpio_desc *desc);
+static int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+static int gpiod_export_link(struct device *dev, const char *name,
+                            struct gpio_desc *desc);
+static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value);
+static void gpiod_unexport(struct gpio_desc *desc);
+
+
 static inline void desc_set_label(struct gpio_desc *d, const char *label)
 {
 #ifdef CONFIG_DEBUG_FS
@@ -83,6 +109,36 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
 #endif
 }
 
+/*
+ * Return the GPIO number of the passed descriptor relative to its chip
+ */
+static int gpio_chip_hwgpio(const struct gpio_desc *desc)
+{
+       return desc - &desc->chip->desc[0];
+}
+
+/**
+ * Convert a GPIO number to its descriptor
+ */
+static struct gpio_desc *gpio_to_desc(unsigned gpio)
+{
+       if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
+               return NULL;
+       else
+               return &gpio_desc[gpio];
+}
+
+/**
+ * Convert a GPIO descriptor to the integer namespace.
+ * This should disappear in the future but is needed since we still
+ * use GPIO numbers for error messages and sysfs nodes
+ */
+static int desc_to_gpio(const struct gpio_desc *desc)
+{
+       return desc->chip->base + gpio_chip_hwgpio(desc);
+}
+
+
 /* Warn when drivers omit gpio_request() calls -- legal but ill-advised
  * when setting direction, and otherwise illegal.  Until board setup code
  * and drivers use explicit requests everywhere (which won't happen when
@@ -94,10 +150,10 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
  * only "legal" in the sense that (old) code using it won't break yet,
  * but instead only triggers a WARN() stack dump.
  */
-static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
+static int gpio_ensure_requested(struct gpio_desc *desc)
 {
        const struct gpio_chip *chip = desc->chip;
-       const int gpio = chip->base + offset;
+       const int gpio = desc_to_gpio(desc);
 
        if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
                        "autorequest GPIO-%d\n", gpio)) {
@@ -116,95 +172,54 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 }
 
 /* caller holds gpio_lock *OR* gpio is marked as requested */
+static struct gpio_chip *gpiod_to_chip(struct gpio_desc *desc)
+{
+       return desc->chip;
+}
+
 struct gpio_chip *gpio_to_chip(unsigned gpio)
 {
-       return gpio_desc[gpio].chip;
+       return gpiod_to_chip(gpio_to_desc(gpio));
 }
 
 /* dynamic allocation of GPIOs, e.g. on a hotplugged device */
 static int gpiochip_find_base(int ngpio)
 {
-       int i;
-       int spare = 0;
-       int base = -ENOSPC;
-
-       for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
-               struct gpio_desc *desc = &gpio_desc[i];
-               struct gpio_chip *chip = desc->chip;
+       struct gpio_chip *chip;
+       int base = ARCH_NR_GPIOS - ngpio;
 
-               if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
-                       spare++;
-                       if (spare == ngpio) {
-                               base = i;
-                               break;
-                       }
-               } else {
-                       spare = 0;
-                       if (chip)
-                               i -= chip->ngpio - 1;
-               }
+       list_for_each_entry_reverse(chip, &gpio_chips, list) {
+               /* found a free space? */
+               if (chip->base + chip->ngpio <= base)
+                       break;
+               else
+                       /* nope, check the space right before the chip */
+                       base = chip->base - ngpio;
        }
 
-       if (gpio_is_valid(base))
+       if (gpio_is_valid(base)) {
                pr_debug("%s: found new base at %d\n", __func__, base);
-       return base;
-}
-
-/**
- * gpiochip_reserve() - reserve range of gpios to use with platform code only
- * @start: starting gpio number
- * @ngpio: number of gpios to reserve
- * Context: platform init, potentially before irqs or kmalloc will work
- *
- * Returns a negative errno if any gpio within the range is already reserved
- * or registered, else returns zero as a success code.  Use this function
- * to mark a range of gpios as unavailable for dynamic gpio number allocation,
- * for example because its driver support is not yet loaded.
- */
-int __init gpiochip_reserve(int start, int ngpio)
-{
-       int ret = 0;
-       unsigned long flags;
-       int i;
-
-       if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
-               return -EINVAL;
-
-       spin_lock_irqsave(&gpio_lock, flags);
-
-       for (i = start; i < start + ngpio; i++) {
-               struct gpio_desc *desc = &gpio_desc[i];
-
-               if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
-                       ret = -EBUSY;
-                       goto err;
-               }
-
-               set_bit(FLAG_RESERVED, &desc->flags);
+               return base;
+       } else {
+               pr_err("%s: cannot find free range\n", __func__);
+               return -ENOSPC;
        }
-
-       pr_debug("%s: reserved gpios from %d to %d\n",
-                __func__, start, start + ngpio - 1);
-err:
-       spin_unlock_irqrestore(&gpio_lock, flags);
-
-       return ret;
 }
 
 /* caller ensures gpio is valid and requested, chip->get_direction may sleep  */
-static int gpio_get_direction(unsigned gpio)
+static int gpiod_get_direction(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
+       unsigned                offset;
        int                     status = -EINVAL;
 
-       chip = gpio_to_chip(gpio);
-       gpio -= chip->base;
+       chip = gpiod_to_chip(desc);
+       offset = gpio_chip_hwgpio(desc);
 
        if (!chip->get_direction)
                return status;
 
-       status = chip->get_direction(chip, gpio);
+       status = chip->get_direction(chip, offset);
        if (status > 0) {
                /* GPIOF_DIR_IN, or other positive */
                status = 1;
@@ -248,19 +263,19 @@ static DEFINE_MUTEX(sysfs_lock);
 static ssize_t gpio_direction_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
 
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
+       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
                status = -EIO;
-       else
-               gpio_get_direction(gpio);
+       } else {
+               gpiod_get_direction(desc);
                status = sprintf(buf, "%s\n",
                        test_bit(FLAG_IS_OUT, &desc->flags)
                                ? "out" : "in");
+       }
 
        mutex_unlock(&sysfs_lock);
        return status;
@@ -269,8 +284,7 @@ static ssize_t gpio_direction_show(struct device *dev,
 static ssize_t gpio_direction_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -278,11 +292,11 @@ static ssize_t gpio_direction_store(struct device *dev,
        if (!test_bit(FLAG_EXPORT, &desc->flags))
                status = -EIO;
        else if (sysfs_streq(buf, "high"))
-               status = gpio_direction_output(gpio, 1);
+               status = gpiod_direction_output(desc, 1);
        else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
-               status = gpio_direction_output(gpio, 0);
+               status = gpiod_direction_output(desc, 0);
        else if (sysfs_streq(buf, "in"))
-               status = gpio_direction_input(gpio);
+               status = gpiod_direction_input(desc);
        else
                status = -EINVAL;
 
@@ -296,8 +310,7 @@ static /* const */ DEVICE_ATTR(direction, 0644,
 static ssize_t gpio_value_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -307,7 +320,7 @@ static ssize_t gpio_value_show(struct device *dev,
        } else {
                int value;
 
-               value = !!gpio_get_value_cansleep(gpio);
+               value = !!gpiod_get_value_cansleep(desc);
                if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                        value = !value;
 
@@ -321,8 +334,7 @@ static ssize_t gpio_value_show(struct device *dev,
 static ssize_t gpio_value_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
-       const struct gpio_desc  *desc = dev_get_drvdata(dev);
-       unsigned                gpio = desc - gpio_desc;
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
        ssize_t                 status;
 
        mutex_lock(&sysfs_lock);
@@ -338,7 +350,7 @@ static ssize_t gpio_value_store(struct device *dev,
                if (status == 0) {
                        if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                                value = !value;
-                       gpio_set_value_cansleep(gpio, value != 0);
+                       gpiod_set_value_cansleep(desc, value != 0);
                        status = size;
                }
        }
@@ -368,7 +380,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
        if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
                return 0;
 
-       irq = gpio_to_irq(desc - gpio_desc);
+       irq = gpiod_to_irq(desc);
        if (irq < 0)
                return -EIO;
 
@@ -638,29 +650,32 @@ static ssize_t export_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t len)
 {
-       long    gpio;
-       int     status;
+       long                    gpio;
+       struct gpio_desc        *desc;
+       int                     status;
 
        status = strict_strtol(buf, 0, &gpio);
        if (status < 0)
                goto done;
 
+       desc = gpio_to_desc(gpio);
+
        /* No extra locking here; FLAG_SYSFS just signifies that the
         * request and export were done by on behalf of userspace, so
         * they may be undone on its behalf too.
         */
 
-       status = gpio_request(gpio, "sysfs");
+       status = gpiod_request(desc, "sysfs");
        if (status < 0) {
                if (status == -EPROBE_DEFER)
                        status = -ENODEV;
                goto done;
        }
-       status = gpio_export(gpio, true);
+       status = gpiod_export(desc, true);
        if (status < 0)
-               gpio_free(gpio);
+               gpiod_free(desc);
        else
-               set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags);
+               set_bit(FLAG_SYSFS, &desc->flags);
 
 done:
        if (status)
@@ -672,8 +687,9 @@ static ssize_t unexport_store(struct class *class,
                                struct class_attribute *attr,
                                const char *buf, size_t len)
 {
-       long    gpio;
-       int     status;
+       long                    gpio;
+       struct gpio_desc        *desc;
+       int                     status;
 
        status = strict_strtol(buf, 0, &gpio);
        if (status < 0)
@@ -681,17 +697,18 @@ static ssize_t unexport_store(struct class *class,
 
        status = -EINVAL;
 
+       desc = gpio_to_desc(gpio);
        /* reject bogus commands (gpio_unexport ignores them) */
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto done;
 
        /* No extra locking here; FLAG_SYSFS just signifies that the
         * request and export were done by on behalf of userspace, so
         * they may be undone on its behalf too.
         */
-       if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) {
+       if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
                status = 0;
-               gpio_free(gpio);
+               gpiod_free(desc);
        }
 done:
        if (status)
@@ -728,13 +745,13 @@ static struct class gpio_class = {
  *
  * Returns zero on success, else an error.
  */
-int gpio_export(unsigned gpio, bool direction_may_change)
+static int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
 {
        unsigned long           flags;
-       struct gpio_desc        *desc;
        int                     status;
        const char              *ioname = NULL;
        struct device           *dev;
+       int                     offset;
 
        /* can't export until sysfs is available ... */
        if (!gpio_class.p) {
@@ -742,20 +759,19 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                return -ENOENT;
        }
 
-       if (!gpio_is_valid(gpio)) {
-               pr_debug("%s: gpio %d is not valid\n", __func__, gpio);
+       if (!desc) {
+               pr_debug("%s: invalid gpio descriptor\n", __func__);
                return -EINVAL;
        }
 
        mutex_lock(&sysfs_lock);
 
        spin_lock_irqsave(&gpio_lock, flags);
-       desc = &gpio_desc[gpio];
        if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
             test_bit(FLAG_EXPORT, &desc->flags)) {
                spin_unlock_irqrestore(&gpio_lock, flags);
                pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n",
-                               __func__, gpio,
+                               __func__, desc_to_gpio(desc),
                                test_bit(FLAG_REQUESTED, &desc->flags),
                                test_bit(FLAG_EXPORT, &desc->flags));
                status = -EPERM;
@@ -766,11 +782,13 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                direction_may_change = false;
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
-               ioname = desc->chip->names[gpio - desc->chip->base];
+       offset = gpio_chip_hwgpio(desc);
+       if (desc->chip->names && desc->chip->names[offset])
+               ioname = desc->chip->names[offset];
 
        dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                           desc, ioname ? ioname : "gpio%u", gpio);
+                           desc, ioname ? ioname : "gpio%u",
+                           desc_to_gpio(desc));
        if (IS_ERR(dev)) {
                status = PTR_ERR(dev);
                goto fail_unlock;
@@ -786,7 +804,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                        goto fail_unregister_device;
        }
 
-       if (gpio_to_irq(gpio) >= 0 && (direction_may_change ||
+       if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
                                       !test_bit(FLAG_IS_OUT, &desc->flags))) {
                status = device_create_file(dev, &dev_attr_edge);
                if (status)
@@ -801,9 +819,15 @@ fail_unregister_device:
        device_unregister(dev);
 fail_unlock:
        mutex_unlock(&sysfs_lock);
-       pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+       pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
+                status);
        return status;
 }
+
+int gpio_export(unsigned gpio, bool direction_may_change)
+{
+       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+}
 EXPORT_SYMBOL_GPL(gpio_export);
 
 static int match_export(struct device *dev, const void *data)
@@ -822,18 +846,16 @@ static int match_export(struct device *dev, const void *data)
  *
  * Returns zero on success, else an error.
  */
-int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
+static int gpiod_export_link(struct device *dev, const char *name,
+                            struct gpio_desc *desc)
 {
-       struct gpio_desc        *desc;
        int                     status = -EINVAL;
 
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto done;
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                struct device *tdev;
 
@@ -850,12 +872,17 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
 
 done:
        if (status)
-               pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+               pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
+                        status);
 
        return status;
 }
-EXPORT_SYMBOL_GPL(gpio_export_link);
 
+int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
+{
+       return gpiod_export_link(dev, name, gpio_to_desc(gpio));
+}
+EXPORT_SYMBOL_GPL(gpio_export_link);
 
 /**
  * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value
@@ -869,19 +896,16 @@ EXPORT_SYMBOL_GPL(gpio_export_link);
  *
  * Returns zero on success, else an error.
  */
-int gpio_sysfs_set_active_low(unsigned gpio, int value)
+static int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
 {
-       struct gpio_desc        *desc;
        struct device           *dev = NULL;
        int                     status = -EINVAL;
 
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto done;
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
                if (dev == NULL) {
@@ -897,10 +921,16 @@ unlock:
 
 done:
        if (status)
-               pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+               pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
+                        status);
 
        return status;
 }
+
+int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+       return gpiod_sysfs_set_active_low(gpio_to_desc(gpio), value);
+}
 EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
 
 /**
@@ -909,21 +939,18 @@ EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
  *
  * This is implicit on gpio_free().
  */
-void gpio_unexport(unsigned gpio)
+static void gpiod_unexport(struct gpio_desc *desc)
 {
-       struct gpio_desc        *desc;
        int                     status = 0;
        struct device           *dev = NULL;
 
-       if (!gpio_is_valid(gpio)) {
+       if (!desc) {
                status = -EINVAL;
                goto done;
        }
 
        mutex_lock(&sysfs_lock);
 
-       desc = &gpio_desc[gpio];
-
        if (test_bit(FLAG_EXPORT, &desc->flags)) {
 
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
@@ -935,13 +962,20 @@ void gpio_unexport(unsigned gpio)
        }
 
        mutex_unlock(&sysfs_lock);
+
        if (dev) {
                device_unregister(dev);
                put_device(dev);
        }
 done:
        if (status)
-               pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+               pr_debug("%s: gpio%d status %d\n", __func__, desc_to_gpio(desc),
+                        status);
+}
+
+void gpio_unexport(unsigned gpio)
+{
+       gpiod_unexport(gpio_to_desc(gpio));
 }
 EXPORT_SYMBOL_GPL(gpio_unexport);
 
@@ -975,9 +1009,9 @@ static int gpiochip_export(struct gpio_chip *chip)
                unsigned        gpio;
 
                spin_lock_irqsave(&gpio_lock, flags);
-               gpio = chip->base;
-               while (gpio_desc[gpio].chip == chip)
-                       gpio_desc[gpio++].chip = NULL;
+               gpio = 0;
+               while (gpio < chip->ngpio)
+                       chip->desc[gpio++].chip = NULL;
                spin_unlock_irqrestore(&gpio_lock, flags);
 
                pr_debug("%s: chip %s status %d\n", __func__,
@@ -1012,7 +1046,7 @@ static int __init gpiolib_sysfs_init(void)
 {
        int             status;
        unsigned long   flags;
-       unsigned        gpio;
+       struct gpio_chip *chip;
 
        status = class_register(&gpio_class);
        if (status < 0)
@@ -1025,10 +1059,7 @@ static int __init gpiolib_sysfs_init(void)
         * registered, and so arch_initcall() can always gpio_export().
         */
        spin_lock_irqsave(&gpio_lock, flags);
-       for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
-               struct gpio_chip        *chip;
-
-               chip = gpio_desc[gpio].chip;
+       list_for_each_entry(chip, &gpio_chips, list) {
                if (!chip || chip->exported)
                        continue;
 
@@ -1053,8 +1084,66 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
 {
 }
 
+static inline int gpiod_export(struct gpio_desc *desc,
+                              bool direction_may_change)
+{
+       return -ENOSYS;
+}
+
+static inline int gpiod_export_link(struct device *dev, const char *name,
+                                   struct gpio_desc *desc)
+{
+       return -ENOSYS;
+}
+
+static inline int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
+{
+       return -ENOSYS;
+}
+
+static inline void gpiod_unexport(struct gpio_desc *desc)
+{
+}
+
 #endif /* CONFIG_GPIO_SYSFS */
 
+/*
+ * Add a new chip to the global chips list, keeping the list of chips sorted
+ * by base order.
+ *
+ * Return -EBUSY if the new chip overlaps with some other chip's integer
+ * space.
+ */
+static int gpiochip_add_to_list(struct gpio_chip *chip)
+{
+       struct list_head *pos = &gpio_chips;
+       struct gpio_chip *_chip;
+       int err = 0;
+
+       /* find where to insert our chip */
+       list_for_each(pos, &gpio_chips) {
+               _chip = list_entry(pos, struct gpio_chip, list);
+               /* shall we insert before _chip? */
+               if (_chip->base >= chip->base + chip->ngpio)
+                       break;
+       }
+
+       /* are we stepping on the chip right before? */
+       if (pos != &gpio_chips && pos->prev != &gpio_chips) {
+               _chip = list_entry(pos->prev, struct gpio_chip, list);
+               if (_chip->base + _chip->ngpio > chip->base) {
+                       dev_err(chip->dev,
+                              "GPIO integer space overlap, cannot add chip\n");
+                       err = -EBUSY;
+               }
+       }
+
+       if (!err)
+               list_add_tail(&chip->list, pos);
+
+       return err;
+}
+
 /**
  * gpiochip_add() - register a gpio_chip
  * @chip: the chip to register, with chip->base initialized
@@ -1096,16 +1185,14 @@ int gpiochip_add(struct gpio_chip *chip)
                chip->base = base;
        }
 
-       /* these GPIO numbers must not be managed by another gpio_chip */
-       for (id = base; id < base + chip->ngpio; id++) {
-               if (gpio_desc[id].chip != NULL) {
-                       status = -EBUSY;
-                       break;
-               }
-       }
+       status = gpiochip_add_to_list(chip);
+
        if (status == 0) {
-               for (id = base; id < base + chip->ngpio; id++) {
-                       gpio_desc[id].chip = chip;
+               chip->desc = &gpio_desc[chip->base];
+
+               for (id = 0; id < chip->ngpio; id++) {
+                       struct gpio_desc *desc = &chip->desc[id];
+                       desc->chip = chip;
 
                        /* REVISIT:  most hardware initializes GPIOs as
                         * inputs (often with pullups enabled) so power
@@ -1114,7 +1201,7 @@ int gpiochip_add(struct gpio_chip *chip)
                         * and in case chip->get_direction is not set,
                         * we may expose the wrong direction in sysfs.
                         */
-                       gpio_desc[id].flags = !chip->direction_input
+                       desc->flags = !chip->direction_input
                                ? (1 << FLAG_IS_OUT)
                                : 0;
                }
@@ -1167,15 +1254,17 @@ int gpiochip_remove(struct gpio_chip *chip)
        gpiochip_remove_pin_ranges(chip);
        of_gpiochip_remove(chip);
 
-       for (id = chip->base; id < chip->base + chip->ngpio; id++) {
-               if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
+       for (id = 0; id < chip->ngpio; id++) {
+               if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
                        status = -EBUSY;
                        break;
                }
        }
        if (status == 0) {
-               for (id = chip->base; id < chip->base + chip->ngpio; id++)
-                       gpio_desc[id].chip = NULL;
+               for (id = 0; id < chip->ngpio; id++)
+                       chip->desc[id].chip = NULL;
+
+               list_del(&chip->list);
        }
 
        spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1202,20 +1291,17 @@ struct gpio_chip *gpiochip_find(void *data,
                                int (*match)(struct gpio_chip *chip,
                                             void *data))
 {
-       struct gpio_chip *chip = NULL;
+       struct gpio_chip *chip;
        unsigned long flags;
-       int i;
 
        spin_lock_irqsave(&gpio_lock, flags);
-       for (i = 0; i < ARCH_NR_GPIOS; i++) {
-               if (!gpio_desc[i].chip)
-                       continue;
-
-               if (match(gpio_desc[i].chip, data)) {
-                       chip = gpio_desc[i].chip;
+       list_for_each_entry(chip, &gpio_chips, list)
+               if (match(chip, data))
                        break;
-               }
-       }
+
+       /* No match? */
+       if (&chip->list == &gpio_chips)
+               chip = NULL;
        spin_unlock_irqrestore(&gpio_lock, flags);
 
        return chip;
@@ -1297,20 +1383,18 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
  * on each other, and help provide better diagnostics in debugfs.
  * They're called even less than the "set direction" calls.
  */
-int gpio_request(unsigned gpio, const char *label)
+static int gpiod_request(struct gpio_desc *desc, const char *label)
 {
-       struct gpio_desc        *desc;
        struct gpio_chip        *chip;
        int                     status = -EPROBE_DEFER;
        unsigned long           flags;
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio)) {
+       if (!desc) {
                status = -EINVAL;
                goto done;
        }
-       desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip == NULL)
                goto done;
@@ -1334,7 +1418,7 @@ int gpio_request(unsigned gpio, const char *label)
        if (chip->request) {
                /* chip->request may sleep */
                spin_unlock_irqrestore(&gpio_lock, flags);
-               status = chip->request(chip, gpio - chip->base);
+               status = chip->request(chip, gpio_chip_hwgpio(desc));
                spin_lock_irqsave(&gpio_lock, flags);
 
                if (status < 0) {
@@ -1347,42 +1431,46 @@ int gpio_request(unsigned gpio, const char *label)
        if (chip->get_direction) {
                /* chip->get_direction may sleep */
                spin_unlock_irqrestore(&gpio_lock, flags);
-               gpio_get_direction(gpio);
+               gpiod_get_direction(desc);
                spin_lock_irqsave(&gpio_lock, flags);
        }
 done:
        if (status)
-               pr_debug("gpio_request: gpio-%d (%s) status %d\n",
-                       gpio, label ? : "?", status);
+               pr_debug("_gpio_request: gpio-%d (%s) status %d\n",
+                        desc ? desc_to_gpio(desc) : -1,
+                        label ? : "?", status);
        spin_unlock_irqrestore(&gpio_lock, flags);
        return status;
 }
+
+int gpio_request(unsigned gpio, const char *label)
+{
+       return gpiod_request(gpio_to_desc(gpio), label);
+}
 EXPORT_SYMBOL_GPL(gpio_request);
 
-void gpio_free(unsigned gpio)
+static void gpiod_free(struct gpio_desc *desc)
 {
        unsigned long           flags;
-       struct gpio_desc        *desc;
        struct gpio_chip        *chip;
 
        might_sleep();
 
-       if (!gpio_is_valid(gpio)) {
+       if (!desc) {
                WARN_ON(extra_checks);
                return;
        }
 
-       gpio_unexport(gpio);
+       gpiod_unexport(desc);
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       desc = &gpio_desc[gpio];
        chip = desc->chip;
        if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
                if (chip->free) {
                        spin_unlock_irqrestore(&gpio_lock, flags);
                        might_sleep_if(chip->can_sleep);
-                       chip->free(chip, gpio - chip->base);
+                       chip->free(chip, gpio_chip_hwgpio(desc));
                        spin_lock_irqsave(&gpio_lock, flags);
                }
                desc_set_label(desc, NULL);
@@ -1396,6 +1484,11 @@ void gpio_free(unsigned gpio)
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 }
+
+void gpio_free(unsigned gpio)
+{
+       gpiod_free(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(gpio_free);
 
 /**
@@ -1406,29 +1499,32 @@ EXPORT_SYMBOL_GPL(gpio_free);
  */
 int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
 {
+       struct gpio_desc *desc;
        int err;
 
-       err = gpio_request(gpio, label);
+       desc = gpio_to_desc(gpio);
+
+       err = gpiod_request(desc, label);
        if (err)
                return err;
 
        if (flags & GPIOF_OPEN_DRAIN)
-               set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+               set_bit(FLAG_OPEN_DRAIN, &desc->flags);
 
        if (flags & GPIOF_OPEN_SOURCE)
-               set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+               set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 
        if (flags & GPIOF_DIR_IN)
-               err = gpio_direction_input(gpio);
+               err = gpiod_direction_input(desc);
        else
-               err = gpio_direction_output(gpio,
+               err = gpiod_direction_output(desc,
                                (flags & GPIOF_INIT_HIGH) ? 1 : 0);
 
        if (err)
                goto free_gpio;
 
        if (flags & GPIOF_EXPORT) {
-               err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE);
+               err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
                if (err)
                        goto free_gpio;
        }
@@ -1436,7 +1532,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
        return 0;
 
  free_gpio:
-       gpio_free(gpio);
+       gpiod_free(desc);
        return err;
 }
 EXPORT_SYMBOL_GPL(gpio_request_one);
@@ -1491,14 +1587,17 @@ EXPORT_SYMBOL_GPL(gpio_free_array);
  */
 const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
 {
-       unsigned gpio = chip->base + offset;
+       struct gpio_desc *desc;
 
-       if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
+       if (!GPIO_OFFSET_VALID(chip, offset))
                return NULL;
-       if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
+
+       desc = &chip->desc[offset];
+
+       if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
                return NULL;
 #ifdef CONFIG_DEBUG_FS
-       return gpio_desc[gpio].label;
+       return desc->label;
 #else
        return "?";
 #endif
@@ -1515,24 +1614,21 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
  * rely on gpio_request() having been called beforehand.
  */
 
-int gpio_direction_input(unsigned gpio)
+static int gpiod_direction_input(struct gpio_desc *desc)
 {
        unsigned long           flags;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int                     offset;
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto fail;
        chip = desc->chip;
        if (!chip || !chip->get || !chip->direction_input)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1542,11 +1638,12 @@ int gpio_direction_input(unsigned gpio)
 
        might_sleep_if(chip->can_sleep);
 
+       offset = gpio_chip_hwgpio(desc);
        if (status) {
-               status = chip->request(chip, gpio);
+               status = chip->request(chip, offset);
                if (status < 0) {
                        pr_debug("GPIO-%d: chip request fail, %d\n",
-                               chip->base + gpio, status);
+                               desc_to_gpio(desc), status);
                        /* and it's not available to anyone else ...
                         * gpio_request() is the fully clean solution.
                         */
@@ -1554,48 +1651,54 @@ int gpio_direction_input(unsigned gpio)
                }
        }
 
-       status = chip->direction_input(chip, gpio);
+       status = chip->direction_input(chip, offset);
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
-       trace_gpio_direction(chip->base + gpio, 1, status);
+       trace_gpio_direction(desc_to_gpio(desc), 1, status);
 lose:
        return status;
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
+       if (status) {
+               int gpio = -1;
+               if (desc)
+                       gpio = desc_to_gpio(desc);
                pr_debug("%s: gpio-%d status %d\n",
                        __func__, gpio, status);
+       }
        return status;
 }
+
+int gpio_direction_input(unsigned gpio)
+{
+       return gpiod_direction_input(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(gpio_direction_input);
 
-int gpio_direction_output(unsigned gpio, int value)
+static int gpiod_direction_output(struct gpio_desc *desc, int value)
 {
        unsigned long           flags;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int offset;
 
        /* Open drain pin should not be driven to 1 */
        if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
-               return gpio_direction_input(gpio);
+               return gpiod_direction_input(desc);
 
        /* Open source pin should not be driven to 0 */
        if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
-               return gpio_direction_input(gpio);
+               return gpiod_direction_input(desc);
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto fail;
        chip = desc->chip;
        if (!chip || !chip->set || !chip->direction_output)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1605,11 +1708,12 @@ int gpio_direction_output(unsigned gpio, int value)
 
        might_sleep_if(chip->can_sleep);
 
+       offset = gpio_chip_hwgpio(desc);
        if (status) {
-               status = chip->request(chip, gpio);
+               status = chip->request(chip, offset);
                if (status < 0) {
                        pr_debug("GPIO-%d: chip request fail, %d\n",
-                               chip->base + gpio, status);
+                               desc_to_gpio(desc), status);
                        /* and it's not available to anyone else ...
                         * gpio_request() is the fully clean solution.
                         */
@@ -1617,20 +1721,29 @@ int gpio_direction_output(unsigned gpio, int value)
                }
        }
 
-       status = chip->direction_output(chip, gpio, value);
+       status = chip->direction_output(chip, offset, value);
        if (status == 0)
                set_bit(FLAG_IS_OUT, &desc->flags);
-       trace_gpio_value(chip->base + gpio, 0, value);
-       trace_gpio_direction(chip->base + gpio, 0, status);
+       trace_gpio_value(desc_to_gpio(desc), 0, value);
+       trace_gpio_direction(desc_to_gpio(desc), 0, status);
 lose:
        return status;
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
+       if (status) {
+               int gpio = -1;
+               if (desc)
+                       gpio = desc_to_gpio(desc);
                pr_debug("%s: gpio-%d status %d\n",
                        __func__, gpio, status);
+       }
        return status;
 }
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+       return gpiod_direction_output(gpio_to_desc(gpio), value);
+}
 EXPORT_SYMBOL_GPL(gpio_direction_output);
 
 /**
@@ -1638,24 +1751,22 @@ EXPORT_SYMBOL_GPL(gpio_direction_output);
  * @gpio: the gpio to set debounce time
  * @debounce: debounce time is microseconds
  */
-int gpio_set_debounce(unsigned gpio, unsigned debounce)
+static int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
        unsigned long           flags;
        struct gpio_chip        *chip;
-       struct gpio_desc        *desc = &gpio_desc[gpio];
        int                     status = -EINVAL;
+       int                     offset;
 
        spin_lock_irqsave(&gpio_lock, flags);
 
-       if (!gpio_is_valid(gpio))
+       if (!desc)
                goto fail;
        chip = desc->chip;
        if (!chip || !chip->set || !chip->set_debounce)
                goto fail;
-       gpio -= chip->base;
-       if (gpio >= chip->ngpio)
-               goto fail;
-       status = gpio_ensure_requested(desc, gpio);
+
+       status = gpio_ensure_requested(desc);
        if (status < 0)
                goto fail;
 
@@ -1665,16 +1776,26 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
 
        might_sleep_if(chip->can_sleep);
 
-       return chip->set_debounce(chip, gpio, debounce);
+       offset = gpio_chip_hwgpio(desc);
+       return chip->set_debounce(chip, offset, debounce);
 
 fail:
        spin_unlock_irqrestore(&gpio_lock, flags);
-       if (status)
+       if (status) {
+               int gpio = -1;
+               if (desc)
+                       gpio = desc_to_gpio(desc);
                pr_debug("%s: gpio-%d status %d\n",
                        __func__, gpio, status);
+       }
 
        return status;
 }
+
+int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+       return gpiod_set_debounce(gpio_to_desc(gpio), debounce);
+}
 EXPORT_SYMBOL_GPL(gpio_set_debounce);
 
 /* I/O calls are only valid after configuration completed; the relevant
@@ -1708,18 +1829,25 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
  * It returns the zero or nonzero value provided by the associated
  * gpio_chip.get() method; or zero if no such method is provided.
  */
-int __gpio_get_value(unsigned gpio)
+static int gpiod_get_value(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
        int value;
+       int offset;
 
-       chip = gpio_to_chip(gpio);
+       chip = desc->chip;
+       offset = gpio_chip_hwgpio(desc);
        /* Should be using gpio_get_value_cansleep() */
        WARN_ON(chip->can_sleep);
-       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
-       trace_gpio_value(gpio, 1, value);
+       value = chip->get ? chip->get(chip, offset) : 0;
+       trace_gpio_value(desc_to_gpio(desc), 1, value);
        return value;
 }
+
+int __gpio_get_value(unsigned gpio)
+{
+       return gpiod_get_value(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(__gpio_get_value);
 
 /*
@@ -1728,23 +1856,25 @@ EXPORT_SYMBOL_GPL(__gpio_get_value);
  * @chip: Gpio chip.
  * @value: Non-zero for setting it HIGH otherise it will set to LOW.
  */
-static void _gpio_set_open_drain_value(unsigned gpio,
-                       struct gpio_chip *chip, int value)
+static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
 {
        int err = 0;
+       struct gpio_chip *chip = desc->chip;
+       int offset = gpio_chip_hwgpio(desc);
+
        if (value) {
-               err = chip->direction_input(chip, gpio - chip->base);
+               err = chip->direction_input(chip, offset);
                if (!err)
-                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       clear_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_output(chip, gpio - chip->base, 0);
+               err = chip->direction_output(chip, offset, 0);
                if (!err)
-                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       set_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(gpio, value, err);
+       trace_gpio_direction(desc_to_gpio(desc), value, err);
        if (err < 0)
                pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
-                                       __func__, gpio, err);
+                                       __func__, desc_to_gpio(desc), err);
 }
 
 /*
@@ -1753,26 +1883,27 @@ static void _gpio_set_open_drain_value(unsigned gpio,
  * @chip: Gpio chip.
  * @value: Non-zero for setting it HIGH otherise it will set to LOW.
  */
-static void _gpio_set_open_source_value(unsigned gpio,
-                       struct gpio_chip *chip, int value)
+static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
 {
        int err = 0;
+       struct gpio_chip *chip = desc->chip;
+       int offset = gpio_chip_hwgpio(desc);
+
        if (value) {
-               err = chip->direction_output(chip, gpio - chip->base, 1);
+               err = chip->direction_output(chip, offset, 1);
                if (!err)
-                       set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       set_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_input(chip, gpio - chip->base);
+               err = chip->direction_input(chip, offset);
                if (!err)
-                       clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+                       clear_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(gpio, !value, err);
+       trace_gpio_direction(desc_to_gpio(desc), !value, err);
        if (err < 0)
                pr_err("%s: Error in set_value for open source gpio%d err %d\n",
-                                       __func__, gpio, err);
+                                       __func__, desc_to_gpio(desc), err);
 }
 
-
 /**
  * __gpio_set_value() - assign a gpio's value
  * @gpio: gpio whose value will be assigned
@@ -1782,20 +1913,25 @@ static void _gpio_set_open_source_value(unsigned gpio,
  * This is used directly or indirectly to implement gpio_set_value().
  * It invokes the associated gpio_chip.set() method.
  */
-void __gpio_set_value(unsigned gpio, int value)
+static void gpiod_set_value(struct gpio_desc *desc, int value)
 {
        struct gpio_chip        *chip;
 
-       chip = gpio_to_chip(gpio);
+       chip = desc->chip;
        /* Should be using gpio_set_value_cansleep() */
        WARN_ON(chip->can_sleep);
-       trace_gpio_value(gpio, 0, value);
-       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
-               _gpio_set_open_drain_value(gpio, chip, value);
-       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
-               _gpio_set_open_source_value(gpio, chip, value);
+       trace_gpio_value(desc_to_gpio(desc), 0, value);
+       if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+               _gpio_set_open_drain_value(desc, value);
+       else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+               _gpio_set_open_source_value(desc, value);
        else
-               chip->set(chip, gpio - chip->base, value);
+               chip->set(chip, gpio_chip_hwgpio(desc), value);
+}
+
+void __gpio_set_value(unsigned gpio, int value)
+{
+       return gpiod_set_value(gpio_to_desc(gpio), value);
 }
 EXPORT_SYMBOL_GPL(__gpio_set_value);
 
@@ -1807,14 +1943,15 @@ EXPORT_SYMBOL_GPL(__gpio_set_value);
  * This is used directly or indirectly to implement gpio_cansleep().  It
  * returns nonzero if access reading or writing the GPIO value can sleep.
  */
-int __gpio_cansleep(unsigned gpio)
+static int gpiod_cansleep(struct gpio_desc *desc)
 {
-       struct gpio_chip        *chip;
-
        /* only call this on GPIOs that are valid! */
-       chip = gpio_to_chip(gpio);
+       return desc->chip->can_sleep;
+}
 
-       return chip->can_sleep;
+int __gpio_cansleep(unsigned gpio)
+{
+       return gpiod_cansleep(gpio_to_desc(gpio));
 }
 EXPORT_SYMBOL_GPL(__gpio_cansleep);
 
@@ -1827,50 +1964,67 @@ EXPORT_SYMBOL_GPL(__gpio_cansleep);
  * It returns the number of the IRQ signaled by this (input) GPIO,
  * or a negative errno.
  */
-int __gpio_to_irq(unsigned gpio)
+static int gpiod_to_irq(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
+       int                     offset;
 
-       chip = gpio_to_chip(gpio);
-       return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+       chip = desc->chip;
+       offset = gpio_chip_hwgpio(desc);
+       return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
 }
-EXPORT_SYMBOL_GPL(__gpio_to_irq);
 
+int __gpio_to_irq(unsigned gpio)
+{
+       return gpiod_to_irq(gpio_to_desc(gpio));
+}
+EXPORT_SYMBOL_GPL(__gpio_to_irq);
 
 
 /* There's no value in making it easy to inline GPIO calls that may sleep.
  * Common examples include ones connected to I2C or SPI chips.
  */
 
-int gpio_get_value_cansleep(unsigned gpio)
+static int gpiod_get_value_cansleep(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
        int value;
+       int offset;
 
        might_sleep_if(extra_checks);
-       chip = gpio_to_chip(gpio);
-       value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
-       trace_gpio_value(gpio, 1, value);
+       chip = desc->chip;
+       offset = gpio_chip_hwgpio(desc);
+       value = chip->get ? chip->get(chip, offset) : 0;
+       trace_gpio_value(desc_to_gpio(desc), 1, value);
        return value;
 }
+
+int gpio_get_value_cansleep(unsigned gpio)
+{
+       return gpiod_get_value_cansleep(gpio_to_desc(gpio));
+}
 EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
 
-void gpio_set_value_cansleep(unsigned gpio, int value)
+static void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 {
        struct gpio_chip        *chip;
 
        might_sleep_if(extra_checks);
-       chip = gpio_to_chip(gpio);
-       trace_gpio_value(gpio, 0, value);
-       if (test_bit(FLAG_OPEN_DRAIN,  &gpio_desc[gpio].flags))
-               _gpio_set_open_drain_value(gpio, chip, value);
-       else if (test_bit(FLAG_OPEN_SOURCE,  &gpio_desc[gpio].flags))
-               _gpio_set_open_source_value(gpio, chip, value);
+       chip = desc->chip;
+       trace_gpio_value(desc_to_gpio(desc), 0, value);
+       if (test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
+               _gpio_set_open_drain_value(desc, value);
+       else if (test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
+               _gpio_set_open_source_value(desc, value);
        else
-               chip->set(chip, gpio - chip->base, value);
+               chip->set(chip, gpio_chip_hwgpio(desc), value);
 }
-EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 
+void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+       return gpiod_set_value_cansleep(gpio_to_desc(gpio), value);
+}
+EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -1878,14 +2032,14 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        unsigned                i;
        unsigned                gpio = chip->base;
-       struct gpio_desc        *gdesc = &gpio_desc[gpio];
+       struct gpio_desc        *gdesc = &chip->desc[0];
        int                     is_out;
 
        for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
                if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
                        continue;
 
-               gpio_get_direction(gpio);
+               gpiod_get_direction(gdesc);
                is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
                seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
                        gpio, gdesc->label,
@@ -1899,46 +2053,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 
 static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_chip *chip = NULL;
-       unsigned int gpio;
-       void *ret = NULL;
-       loff_t index = 0;
-
-       /* REVISIT this isn't locked against gpio_chip removal ... */
+       loff_t index = *pos;
 
-       for (gpio = 0; gpio_is_valid(gpio); gpio++) {
-               if (gpio_desc[gpio].chip == chip)
-                       continue;
-
-               chip = gpio_desc[gpio].chip;
-               if (!chip)
-                       continue;
+       s->private = "";
 
-               if (index++ >= *pos) {
-                       ret = chip;
-                       break;
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_for_each_entry(chip, &gpio_chips, list)
+               if (index-- == 0) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       return chip;
                }
-       }
-
-       s->private = "";
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
-       return ret;
+       return NULL;
 }
 
 static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_chip *chip = v;
-       unsigned int gpio;
        void *ret = NULL;
 
-       /* skip GPIOs provided by the current chip */
-       for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
-               chip = gpio_desc[gpio].chip;
-               if (chip) {
-                       ret = chip;
-                       break;
-               }
-       }
+       spin_lock_irqsave(&gpio_lock, flags);
+       if (list_is_last(&chip->list, &gpio_chips))
+               ret = NULL;
+       else
+               ret = list_entry(chip->list.next, struct gpio_chip, list);
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
        s->private = "\n";
        ++*pos;
index 20ca766..bde6469 100644 (file)
@@ -47,12 +47,14 @@ struct gpio;
 struct seq_file;
 struct module;
 struct device_node;
+struct gpio_desc;
 
 /**
  * struct gpio_chip - abstract a GPIO controller
  * @label: for diagnostics
  * @dev: optional device providing the GPIOs
  * @owner: helps prevent removal of modules exporting active GPIOs
+ * @list: links gpio_chips together for traversal
  * @request: optional hook for chip-specific activation, such as
  *     enabling module power and clock; may sleep
  * @free: optional hook for chip-specific deactivation, such as
@@ -75,6 +77,7 @@ struct device_node;
  *     negative during registration, requests dynamic ID allocation.
  * @ngpio: the number of GPIOs handled by this controller; the last GPIO
  *     handled is (base + ngpio - 1).
+ * @desc: array of ngpio descriptors. Private.
  * @can_sleep: flag must be set iff get()/set() methods sleep, as they
  *     must while accessing GPIO expander chips over I2C or SPI
  * @names: if set, must be an array of strings to use as alternative
@@ -98,6 +101,7 @@ struct gpio_chip {
        const char              *label;
        struct device           *dev;
        struct module           *owner;
+       struct list_head        list;
 
        int                     (*request)(struct gpio_chip *chip,
                                                unsigned offset);
@@ -124,6 +128,7 @@ struct gpio_chip {
                                                struct gpio_chip *chip);
        int                     base;
        u16                     ngpio;
+       struct gpio_desc        *desc;
        const char              *const *names;
        unsigned                can_sleep:1;
        unsigned                exported:1;
@@ -152,7 +157,6 @@ struct gpio_chip {
 extern const char *gpiochip_is_requested(struct gpio_chip *chip,
                        unsigned offset);
 extern struct gpio_chip *gpio_to_chip(unsigned gpio);
-extern int __must_check gpiochip_reserve(int start, int ngpio);
 
 /* add/remove chips */
 extern int gpiochip_add(struct gpio_chip *chip);
@@ -192,12 +196,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe
 extern int gpio_request_array(const struct gpio *array, size_t num);
 extern void gpio_free_array(const struct gpio *array, size_t num);
 
-/* bindings for managed devices that want to request gpios */
-int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
-int devm_gpio_request_one(struct device *dev, unsigned gpio,
-                         unsigned long flags, const char *label);
-void devm_gpio_free(struct device *dev, unsigned int gpio);
-
 #ifdef CONFIG_GPIO_SYSFS
 
 /*
@@ -212,6 +210,43 @@ extern void gpio_unexport(unsigned gpio);
 
 #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 gpio_offset, unsigned int pin_offset,
+                          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 gpio_offset, unsigned int pin_offset,
+                      unsigned int npins)
+{
+       return 0;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+}
+
+#endif /* CONFIG_PINCTRL */
+
 #else  /* !CONFIG_GPIOLIB */
 
 static inline bool gpio_is_valid(int number)
@@ -270,41 +305,4 @@ static inline void gpio_unexport(unsigned gpio)
 }
 #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 gpio_offset, unsigned int pin_offset,
-                          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 gpio_offset, unsigned int pin_offset,
-                      unsigned int npins)
-{
-       return 0;
-}
-
-static inline void
-gpiochip_remove_pin_ranges(struct gpio_chip *chip)
-{
-}
-
-#endif /* CONFIG_PINCTRL */
-
 #endif /* _ASM_GENERIC_GPIO_H */
index 91615a3..b76ebd0 100644 (file)
@@ -2,10 +2,12 @@
 #define _LINUX_ACPI_GPIO_H_
 
 #include <linux/errno.h>
+#include <linux/gpio.h>
 
 #ifdef CONFIG_GPIO_ACPI
 
 int acpi_get_gpio(char *path, int pin);
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
 
 #else /* CONFIG_GPIO_ACPI */
 
@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
        return -ENODEV;
 }
 
+static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
+
 #endif /* CONFIG_GPIO_ACPI */
 
 #endif /* _LINUX_ACPI_GPIO_H_ */
index bfe6656..f6c7ae3 100644 (file)
@@ -94,24 +94,12 @@ static inline int gpio_request(unsigned gpio, const char *label)
        return -ENOSYS;
 }
 
-static inline int devm_gpio_request(struct device *dev, unsigned gpio,
-                                   const char *label)
-{
-       return -ENOSYS;
-}
-
 static inline int gpio_request_one(unsigned gpio,
                                        unsigned long flags, const char *label)
 {
        return -ENOSYS;
 }
 
-static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
-                                       unsigned long flags, const char *label)
-{
-       return -ENOSYS;
-}
-
 static inline int gpio_request_array(const struct gpio *array, size_t num)
 {
        return -ENOSYS;
@@ -125,14 +113,6 @@ static inline void gpio_free(unsigned gpio)
        WARN_ON(1);
 }
 
-static inline void devm_gpio_free(struct device *dev, unsigned gpio)
-{
-       might_sleep();
-
-       /* GPIO can never have been requested */
-       WARN_ON(1);
-}
-
 static inline void gpio_free_array(const struct gpio *array, size_t num)
 {
        might_sleep();
@@ -248,4 +228,12 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip)
 
 #endif /* ! CONFIG_GENERIC_GPIO */
 
+struct device;
+
+/* bindings for managed devices that want to request gpios */
+int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
+int devm_gpio_request_one(struct device *dev, unsigned gpio,
+                         unsigned long flags, const char *label);
+void devm_gpio_free(struct device *dev, unsigned int gpio);
+
 #endif /* __LINUX_GPIO_H */