Merge tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Oct 2014 18:58:15 +0000 (14:58 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Oct 2014 18:58:15 +0000 (14:58 -0400)
Pull GPIO changes from Linus Walleij:
 "This is the bulk of GPIO changes for the v3.18 development cycle:

   - Increase the default ARCH_NR_GPIO from 256 to 512.  This was done
     to avoid having a custom <asm/gpio.h> header for the x86
     architecture - GPIO is custom and complicated enough as it is
     already! We want to move to a radix to store the descriptors going
     forward, and finally get rid of this fixed array size altogether.

   - Endgame patching of the gpio_remove() semantics initiated by
     Abdoulaye Berthe.  It is not accepted by the system that the
     removal of a GPIO chip fails during eg reboot or shutdown, and
     therefore the return value has now painfully been refactored away.
     For special cases like GPIO expanders on a hot-pluggable bus like
     USB, we may later add some gpiochip_try_remove() call, but for the
     cases we have now, return values are moot.

   - Some incremental refactoring of the gpiolib core and ACPI GPIO
     library for more descriptor usage.

   - Refactor the chained IRQ handler set-up method to handle also
     threaded, nested interrupts and set up the parent IRQ correctly.
     Switch STMPE and TC3589x drivers to use this registration method.

   - Add a .irq_not_threaded flag to the struct gpio_chip, so that also
     GPIO expanders that block but are still not using threaded IRQ
     handlers.

   - New drivers for the ARM64 X-Gene SoC GPIO controller.

   - The syscon GPIO driver has been improved to handle the "DSP GPIO"
     found on the TI Keystone 2 SoC:s.

   - ADNP driver switched to use gpiolib irqchip helpers.

   - Refactor the DWAPB driver to support being instantiated from and
     MFD cell (platform device).

   - Incremental feature improvement in the Zynq, MCP23S08, DWAPB, OMAP,
     Xilinx and Crystalcove drivers.

   - Various minor fixes"

* tag 'gpio-v3.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (52 commits)
  gpio: pch: Build context save/restore only for PM
  pinctrl: abx500: get rid of unused variable
  gpio: ks8695: fix 'else should follow close brace '}''
  gpio: stmpe: add verbose debug code
  gpio: stmpe: fix up interrupt enable logic
  gpio: staticize xway_stp_init()
  gpio: handle also nested irqchips in the chained handler set-up
  gpio: set parent irq on chained handlers
  gpiolib: irqchip: use irq_find_mapping while removing irqchip
  gpio: crystalcove: support virtual GPIO
  pinctrl: bcm281xx: make Kconfig dependency more strict
  gpio: kona: enable only on BCM_MOBILE or for compile testing
  gpio, bcm-kona, LLVMLinux: Remove use of __initconst
  gpio: Fix ngpio in gpio-xilinx driver
  gpio: dwapb: fix pointer to integer cast
  gpio: xgene: Remove unneeded #ifdef CONFIG_OF guard
  gpio: xgene: Remove unneeded forward declation for struct xgene_gpio
  gpio: xgene: Fix missing spin_lock_init()
  gpio: ks8695: fix switch case indentation
  gpiolib: add irq_not_threaded flag to gpio_chip
  ...

65 files changed:
Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-pca953x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-xgene.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
Documentation/gpio/driver.txt
arch/arm/common/scoop.c
arch/mips/txx9/generic/setup.c
arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
arch/sh/boards/mach-x3proto/gpio.c
drivers/bcma/driver_gpio.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-adnp.c
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-crystalcove.c
drivers/gpio/gpio-cs5535.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-ks8695.c
drivers/gpio/gpio-mcp23s08.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-stp-xway.c
drivers/gpio/gpio-syscon.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-xgene.c [new file with mode: 0644]
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/hid/hid-cp2112.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/keyboard/adp5589-keys.c
drivers/input/touchscreen/ad7879.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-tca6507.c
drivers/media/dvb-frontends/cxd2820r_core.c
drivers/mfd/asic3.c
drivers/mfd/htc-i2cpld.c
drivers/mfd/sm501.c
drivers/mfd/tc6393xb.c
drivers/mfd/ucb1x00-core.c
drivers/pinctrl/Kconfig
drivers/pinctrl/nomadik/pinctrl-abx500.c
drivers/pinctrl/nomadik/pinctrl-nomadik.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/samsung/pinctrl-exynos5440.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sirf/pinctrl-sirf.c
drivers/platform/x86/intel_pmic_gpio.c
drivers/ssb/driver_gpio.c
drivers/staging/vme/devices/vme_pio2_gpio.c
drivers/tty/serial/max310x.c
drivers/tty/serial/sc16is7xx.c
drivers/video/fbdev/via/via-gpio.c
include/asm-generic/gpio.h
include/linux/gpio/driver.h
include/linux/platform_data/gpio-dwapb.h [new file with mode: 0644]
include/linux/spi/mcp23s08.h
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8996.c

diff --git a/Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt b/Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt
new file mode 100644 (file)
index 0000000..6c7e6c7
--- /dev/null
@@ -0,0 +1,39 @@
+Keystone 2 DSP GPIO controller bindings
+
+HOST OS userland running on ARM can send interrupts to DSP cores using
+the DSP GPIO controller IP. It provides 28 IRQ signals per each DSP core.
+This is one of the component used by the IPC mechanism used on Keystone SOCs.
+
+For example TCI6638K2K SoC has 8 DSP GPIO controllers:
+ - 8 for C66x CorePacx CPUs 0-7
+
+Keystone 2 DSP GPIO controller has specific features:
+- each GPIO can be configured only as output pin;
+- setting GPIO value to 1 causes IRQ generation on target DSP core;
+- reading pin value returns 0 - if IRQ was handled or 1 - IRQ is still
+  pending.
+
+Required Properties:
+- compatible: should be "ti,keystone-dsp-gpio"
+- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to
+  access device state control registers and the offset of device's specific
+  registers within device state control registers range.
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Should be 2.
+
+Please refer to gpio.txt in this directory for details of the common GPIO
+bindings used by client devices.
+
+Example:
+       dspgpio0: keystone_dsp_gpio@02620240 {
+               compatible = "ti,keystone-dsp-gpio";
+               ti,syscon-dev = <&devctrl 0x240>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+
+       dsp0: dsp0 {
+               compatible = "linux,rproc-user";
+               ...
+               kick-gpio = <&dspgpio0 27>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt b/Documentation/devicetree/bindings/gpio/gpio-pca953x.txt
new file mode 100644 (file)
index 0000000..b9a42f2
--- /dev/null
@@ -0,0 +1,39 @@
+* NXP PCA953x I2C GPIO multiplexer
+
+Required properties:
+ - compatible: Has to contain one of the following:
+       nxp,pca9505
+       nxp,pca9534
+       nxp,pca9535
+       nxp,pca9536
+       nxp,pca9537
+       nxp,pca9538
+       nxp,pca9539
+       nxp,pca9554
+       nxp,pca9555
+       nxp,pca9556
+       nxp,pca9557
+       nxp,pca9574
+       nxp,pca9575
+       nxp,pca9698
+       maxim,max7310
+       maxim,max7312
+       maxim,max7313
+       maxim,max7315
+       ti,pca6107
+       ti,tca6408
+       ti,tca6416
+       ti,tca6424
+       exar,xra1202
+
+Example:
+
+
+       gpio@20 {
+               compatible = "nxp,pca9505";
+               reg = <0x20>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_pca9505>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xgene.txt b/Documentation/devicetree/bindings/gpio/gpio-xgene.txt
new file mode 100644 (file)
index 0000000..86dbb05
--- /dev/null
@@ -0,0 +1,22 @@
+APM X-Gene SoC GPIO controller bindings
+
+This is a gpio controller that is part of the flash controller.
+This gpio controller controls a total of 48 gpios.
+
+Required properties:
+- compatible: "apm,xgene-gpio" for X-Gene GPIO controller
+- reg: Physical base address and size of the controller's registers
+- #gpio-cells: Should be two.
+       - first cell is the pin number
+       - second cell is used to specify the gpio polarity:
+               0 = active high
+               1 = active low
+- gpio-controller: Marks the device node as a GPIO controller.
+
+Example:
+       gpio0: gpio0@1701c000 {
+               compatible = "apm,xgene-gpio";
+               reg = <0x0 0x1701c000 0x0 0x40>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
index 6641626..b2afdb2 100644 (file)
@@ -19,7 +19,7 @@ Required properties:
 - gpio-controller : Marks the device node as a gpio controller.
 - #gpio-cells : Should be one.  It is the pin number.
 
-Example:
+Example for a MMP platform:
 
        gpio: gpio@d4019000 {
                compatible = "marvell,mmp-gpio";
@@ -32,6 +32,19 @@ Example:
                #interrupt-cells = <1>;
       };
 
+Example for a PXA3xx platform:
+
+       gpio: gpio@40e00000 {
+               compatible = "intel,pxa3xx-gpio";
+               reg = <0x40e00000 0x10000>;
+               interrupt-names = "gpio0", "gpio1", "gpio_mux";
+               interrupts = <8 9 10>;
+               gpio-controller;
+               #gpio-cells = <0x2>;
+               interrupt-controller;
+               #interrupt-cells = <0x2>;
+       };
+
 * Marvell Orion GPIO Controller
 
 Required properties:
index 18790c2..31e0b5d 100644 (file)
@@ -124,7 +124,8 @@ symbol:
 * gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
   gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
   data. (Notice handler data, since the irqchip data is likely used by the
-  parent irqchip!) This is for the chained type of chip.
+  parent irqchip!) This is for the chained type of chip. This is also used
+  to set up a nested irqchip if NULL is passed as handler.
 
 To use the helpers please keep the following in mind:
 
@@ -178,7 +179,8 @@ does not help since it pins the module to the kernel forever (it calls
 try_module_get()). A GPIO driver can use the following functions instead
 to request and free descriptors without being pinned to the kernel forever.
 
-       int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
+       struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
+                                                   const char *label)
 
        void gpiochip_free_own_desc(struct gpio_desc *desc)
 
index a20fa80..45f4c21 100644 (file)
@@ -243,18 +243,12 @@ err_ioremap:
 static int scoop_remove(struct platform_device *pdev)
 {
        struct scoop_dev *sdev = platform_get_drvdata(pdev);
-       int ret;
 
        if (!sdev)
                return -EINVAL;
 
-       if (sdev->gpio.base != -1) {
-               ret = gpiochip_remove(&sdev->gpio);
-               if (ret) {
-                       dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
-                       return ret;
-               }
-       }
+       if (sdev->gpio.base != -1)
+               gpiochip_remove(&sdev->gpio);
 
        platform_set_drvdata(pdev, NULL);
        iounmap(sdev->base);
index 9ff200a..2791b86 100644 (file)
@@ -789,11 +789,11 @@ void __init txx9_iocled_init(unsigned long baseaddr,
        if (platform_device_add(pdev))
                goto out_pdev;
        return;
+
 out_pdev:
        platform_device_put(pdev);
 out_gpio:
-       if (gpiochip_remove(&iocled->chip))
-               return;
+       gpiochip_remove(&iocled->chip);
 out_unmap:
        iounmap(iocled->mmioaddr);
 out_free:
index e238b6a..7399702 100644 (file)
@@ -141,7 +141,8 @@ static int mcu_gpiochip_add(struct mcu *mcu)
 
 static int mcu_gpiochip_remove(struct mcu *mcu)
 {
-       return gpiochip_remove(&mcu->gc);
+       gpiochip_remove(&mcu->gc);
+       return 0;
 }
 
 static int mcu_probe(struct i2c_client *client, const struct i2c_device_id *id)
index 3ea65e9..f035a7a 100644 (file)
@@ -128,10 +128,8 @@ int __init x3proto_gpio_setup(void)
        return 0;
 
 err_irq:
-       ret = gpiochip_remove(&x3proto_gpio_chip);
-       if (unlikely(ret))
-               pr_err("Failed deregistering GPIO\n");
-
+       gpiochip_remove(&x3proto_gpio_chip);
+       ret = 0;
 err_gpio:
        synchronize_irq(ilsel);
 
index 57ce5fe..706b9ae 100644 (file)
@@ -255,5 +255,6 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
 int bcma_gpio_unregister(struct bcma_drv_cc *cc)
 {
        bcma_gpio_irq_domain_exit(cc);
-       return gpiochip_remove(&cc->gpio);
+       gpiochip_remove(&cc->gpio);
+       return 0;
 }
index 9de1515..0959ca9 100644 (file)
@@ -136,7 +136,6 @@ config GPIO_DWAPB
        tristate "Synopsys DesignWare APB GPIO driver"
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
-       depends on OF_GPIO
        help
          Say Y or M here to build support for the Synopsys DesignWare APB
          GPIO block.
@@ -334,6 +333,15 @@ config GPIO_TZ1090_PDC
        help
          Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
 
+config GPIO_XGENE
+       bool "APM X-Gene GPIO controller support"
+       depends on ARM64 && OF_GPIO
+       help
+         This driver is to support the GPIO block within the APM X-Gene SoC
+         platform's generic flash controller. The GPIO pins are muxed with
+         the generic flash controller's address and data pins. Say yes
+         here to enable the GFC GPIO functionality.
+
 config GPIO_XILINX
        bool "Xilinx GPIO support"
        depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
@@ -681,6 +689,7 @@ config GPIO_ADP5588_IRQ
 config GPIO_ADNP
        tristate "Avionic Design N-bit GPIO expander"
        depends on I2C && OF_GPIO
+       select GPIOLIB_IRQCHIP
        help
          This option enables support for N GPIOs found on Avionic Design
          I2C GPIO expanders. The register space will be extended by powers
@@ -796,7 +805,6 @@ config GPIO_MAX7301
 
 config GPIO_MCP23S08
        tristate "Microchip MCP23xxx I/O expander"
-       depends on OF_GPIO
        depends on (SPI_MASTER && !I2C) || I2C
        help
          SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
@@ -880,7 +888,7 @@ config GPIO_MSIC
 
 config GPIO_BCM_KONA
        bool "Broadcom Kona GPIO"
-       depends on OF_GPIO
+       depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
        help
          Turn on GPIO support for Broadcom "Kona" chips.
 
index 5d024e3..e5d346c 100644 (file)
@@ -101,6 +101,7 @@ obj-$(CONFIG_GPIO_VX855)    += gpio-vx855.o
 obj-$(CONFIG_GPIO_WM831X)      += gpio-wm831x.o
 obj-$(CONFIG_GPIO_WM8350)      += gpio-wm8350.o
 obj-$(CONFIG_GPIO_WM8994)      += gpio-wm8994.o
+obj-$(CONFIG_GPIO_XGENE)       += gpio-xgene.o
 obj-$(CONFIG_GPIO_XILINX)      += gpio-xilinx.o
 obj-$(CONFIG_GPIO_XTENSA)      += gpio-xtensa.o
 obj-$(CONFIG_GPIO_ZEVIO)       += gpio-zevio.o
index 416b220..d3d0a90 100644 (file)
@@ -6,10 +6,9 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
-#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/of_irq.h>
 #include <linux/seq_file.h>
@@ -27,8 +26,6 @@ struct adnp {
        unsigned int reg_shift;
 
        struct mutex i2c_lock;
-
-       struct irq_domain *domain;
        struct mutex irq_lock;
 
        u8 *irq_enable;
@@ -253,6 +250,7 @@ static void adnp_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
 {
        struct gpio_chip *chip = &adnp->gpio;
+       int err;
 
        adnp->reg_shift = get_count_order(num_gpios) - 3;
 
@@ -272,6 +270,10 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
        chip->of_node = chip->dev->of_node;
        chip->owner = THIS_MODULE;
 
+       err = gpiochip_add(chip);
+       if (err)
+               return err;
+
        return 0;
 }
 
@@ -326,7 +328,8 @@ static irqreturn_t adnp_irq(int irq, void *data)
 
                for_each_set_bit(bit, &pending, 8) {
                        unsigned int child_irq;
-                       child_irq = irq_find_mapping(adnp->domain, base + bit);
+                       child_irq = irq_find_mapping(adnp->gpio.irqdomain,
+                                                    base + bit);
                        handle_nested_irq(child_irq);
                }
        }
@@ -334,35 +337,32 @@ static irqreturn_t adnp_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int adnp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       struct adnp *adnp = to_adnp(chip);
-       return irq_create_mapping(adnp->domain, offset);
-}
-
-static void adnp_irq_mask(struct irq_data *data)
+static void adnp_irq_mask(struct irq_data *d)
 {
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
-       unsigned int reg = data->hwirq >> adnp->reg_shift;
-       unsigned int pos = data->hwirq & 7;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct adnp *adnp = to_adnp(gc);
+       unsigned int reg = d->hwirq >> adnp->reg_shift;
+       unsigned int pos = d->hwirq & 7;
 
        adnp->irq_enable[reg] &= ~BIT(pos);
 }
 
-static void adnp_irq_unmask(struct irq_data *data)
+static void adnp_irq_unmask(struct irq_data *d)
 {
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
-       unsigned int reg = data->hwirq >> adnp->reg_shift;
-       unsigned int pos = data->hwirq & 7;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct adnp *adnp = to_adnp(gc);
+       unsigned int reg = d->hwirq >> adnp->reg_shift;
+       unsigned int pos = d->hwirq & 7;
 
        adnp->irq_enable[reg] |= BIT(pos);
 }
 
-static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
+static int adnp_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
-       unsigned int reg = data->hwirq >> adnp->reg_shift;
-       unsigned int pos = data->hwirq & 7;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct adnp *adnp = to_adnp(gc);
+       unsigned int reg = d->hwirq >> adnp->reg_shift;
+       unsigned int pos = d->hwirq & 7;
 
        if (type & IRQ_TYPE_EDGE_RISING)
                adnp->irq_rise[reg] |= BIT(pos);
@@ -387,16 +387,18 @@ static int adnp_irq_set_type(struct irq_data *data, unsigned int type)
        return 0;
 }
 
-static void adnp_irq_bus_lock(struct irq_data *data)
+static void adnp_irq_bus_lock(struct irq_data *d)
 {
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct adnp *adnp = to_adnp(gc);
 
        mutex_lock(&adnp->irq_lock);
 }
 
-static void adnp_irq_bus_unlock(struct irq_data *data)
+static void adnp_irq_bus_unlock(struct irq_data *d)
 {
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct adnp *adnp = to_adnp(gc);
        unsigned int num_regs = 1 << adnp->reg_shift, i;
 
        mutex_lock(&adnp->i2c_lock);
@@ -408,26 +410,6 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
        mutex_unlock(&adnp->irq_lock);
 }
 
-static int adnp_irq_reqres(struct irq_data *data)
-{
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
-
-       if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
-               dev_err(adnp->gpio.dev,
-                       "unable to lock HW IRQ %lu for IRQ\n",
-                       data->hwirq);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static void adnp_irq_relres(struct irq_data *data)
-{
-       struct adnp *adnp = irq_data_get_irq_chip_data(data);
-
-       gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
-}
-
 static struct irq_chip adnp_irq_chip = {
        .name = "gpio-adnp",
        .irq_mask = adnp_irq_mask,
@@ -435,29 +417,6 @@ static struct irq_chip adnp_irq_chip = {
        .irq_set_type = adnp_irq_set_type,
        .irq_bus_lock = adnp_irq_bus_lock,
        .irq_bus_sync_unlock = adnp_irq_bus_unlock,
-       .irq_request_resources = adnp_irq_reqres,
-       .irq_release_resources = adnp_irq_relres,
-};
-
-static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
-                       irq_hw_number_t hwirq)
-{
-       irq_set_chip_data(irq, domain->host_data);
-       irq_set_chip(irq, &adnp_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 adnp_irq_domain_ops = {
-       .map = adnp_irq_map,
-       .xlate = irq_domain_xlate_twocell,
 };
 
 static int adnp_irq_setup(struct adnp *adnp)
@@ -503,35 +462,28 @@ static int adnp_irq_setup(struct adnp *adnp)
                adnp->irq_enable[i] = 0x00;
        }
 
-       adnp->domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
-                                            &adnp_irq_domain_ops, adnp);
-
-       err = request_threaded_irq(adnp->client->irq, NULL, adnp_irq,
-                                  IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                  dev_name(chip->dev), adnp);
+       err = devm_request_threaded_irq(chip->dev, adnp->client->irq,
+                                       NULL, adnp_irq,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       dev_name(chip->dev), adnp);
        if (err != 0) {
                dev_err(chip->dev, "can't request IRQ#%d: %d\n",
                        adnp->client->irq, err);
                return err;
        }
 
-       chip->to_irq = adnp_gpio_to_irq;
-       return 0;
-}
-
-static void adnp_irq_teardown(struct adnp *adnp)
-{
-       unsigned int irq, i;
-
-       free_irq(adnp->client->irq, adnp);
-
-       for (i = 0; i < adnp->gpio.ngpio; i++) {
-               irq = irq_find_mapping(adnp->domain, i);
-               if (irq > 0)
-                       irq_dispose_mapping(irq);
+       err = gpiochip_irqchip_add(chip,
+                                  &adnp_irq_chip,
+                                  0,
+                                  handle_simple_irq,
+                                  IRQ_TYPE_NONE);
+       if (err) {
+               dev_err(chip->dev,
+                       "could not connect irqchip to gpiochip\n");
+               return err;
        }
 
-       irq_domain_remove(adnp->domain);
+       return 0;
 }
 
 static int adnp_i2c_probe(struct i2c_client *client,
@@ -558,38 +510,25 @@ static int adnp_i2c_probe(struct i2c_client *client,
        adnp->client = client;
 
        err = adnp_gpio_setup(adnp, num_gpios);
-       if (err < 0)
+       if (err)
                return err;
 
        if (of_find_property(np, "interrupt-controller", NULL)) {
                err = adnp_irq_setup(adnp);
-               if (err < 0)
-                       goto teardown;
+               if (err)
+                       return err;
        }
 
-       err = gpiochip_add(&adnp->gpio);
-       if (err < 0)
-               goto teardown;
-
        i2c_set_clientdata(client, adnp);
-       return 0;
 
-teardown:
-       if (of_find_property(np, "interrupt-controller", NULL))
-               adnp_irq_teardown(adnp);
-
-       return err;
+       return 0;
 }
 
 static int adnp_i2c_remove(struct i2c_client *client)
 {
        struct adnp *adnp = i2c_get_clientdata(client);
-       struct device_node *np = client->dev.of_node;
 
        gpiochip_remove(&adnp->gpio);
-       if (of_find_property(np, "interrupt-controller", NULL))
-               adnp_irq_teardown(adnp);
-
        return 0;
 }
 
index 3f6b33c..de0801e 100644 (file)
@@ -496,7 +496,7 @@ static struct irq_chip bcm_gpio_irq_chip = {
        .irq_release_resources = bcm_kona_gpio_irq_relres,
 };
 
-static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
+static struct of_device_id const bcm_kona_gpio_of_match[] = {
        { .compatible = "brcm,kona-gpio" },
        {}
 };
index 934462f..bbfe7f5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mfd/intel_soc_pmic.h>
 
 #define CRYSTALCOVE_GPIO_NUM   16
+#define CRYSTALCOVE_VGPIO_NUM  94
 
 #define UPDATE_IRQ_TYPE                BIT(0)
 #define UPDATE_IRQ_MASK                BIT(1)
@@ -130,6 +131,9 @@ static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
 {
        struct crystalcove_gpio *cg = to_cg(chip);
 
+       if (gpio > CRYSTALCOVE_VGPIO_NUM)
+               return 0;
+
        return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
                            CTLO_INPUT_SET);
 }
@@ -139,6 +143,9 @@ static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
 {
        struct crystalcove_gpio *cg = to_cg(chip);
 
+       if (gpio > CRYSTALCOVE_VGPIO_NUM)
+               return 0;
+
        return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
                            CTLO_OUTPUT_SET | value);
 }
@@ -149,6 +156,9 @@ static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
        int ret;
        unsigned int val;
 
+       if (gpio > CRYSTALCOVE_VGPIO_NUM)
+               return 0;
+
        ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
        if (ret)
                return ret;
@@ -161,6 +171,9 @@ static void crystalcove_gpio_set(struct gpio_chip *chip,
 {
        struct crystalcove_gpio *cg = to_cg(chip);
 
+       if (gpio > CRYSTALCOVE_VGPIO_NUM)
+               return;
+
        if (value)
                regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
        else
@@ -256,7 +269,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
 
        pending = p0 | p1 << 8;
 
-       for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
+       for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
                if (pending & BIT(gpio)) {
                        virq = irq_find_mapping(cg->chip.irqdomain, gpio);
                        generic_handle_irq(virq);
@@ -273,7 +286,7 @@ static void crystalcove_gpio_dbg_show(struct seq_file *s,
        int gpio, offset;
        unsigned int ctlo, ctli, mirqs0, mirqsx, irq;
 
-       for (gpio = 0; gpio < cg->chip.ngpio; gpio++) {
+       for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
                regmap_read(cg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
                regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &ctli);
                regmap_read(cg->regmap, gpio < 8 ? MGPIO0IRQS0 : MGPIO1IRQS0,
@@ -320,7 +333,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
        cg->chip.get = crystalcove_gpio_get;
        cg->chip.set = crystalcove_gpio_set;
        cg->chip.base = -1;
-       cg->chip.ngpio = CRYSTALCOVE_GPIO_NUM;
+       cg->chip.ngpio = CRYSTALCOVE_VGPIO_NUM;
        cg->chip.can_sleep = true;
        cg->chip.dev = dev;
        cg->chip.dbg_show = crystalcove_gpio_dbg_show;
@@ -346,7 +359,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
        return 0;
 
 out_remove_gpio:
-       WARN_ON(gpiochip_remove(&cg->chip));
+       gpiochip_remove(&cg->chip);
        return retval;
 }
 
@@ -354,14 +367,11 @@ static int crystalcove_gpio_remove(struct platform_device *pdev)
 {
        struct crystalcove_gpio *cg = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
-       int err;
-
-       err = gpiochip_remove(&cg->chip);
 
+       gpiochip_remove(&cg->chip);
        if (irq >= 0)
                free_irq(irq, cg);
-
-       return err;
+       return 0;
 }
 
 static struct platform_driver crystalcove_gpio_driver = {
index 92ec58f..668127f 100644 (file)
@@ -201,7 +201,8 @@ EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event);
 
 static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
 {
-       struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
+       struct cs5535_gpio_chip *chip =
+               container_of(c, struct cs5535_gpio_chip, chip);
        unsigned long flags;
 
        spin_lock_irqsave(&chip->lock, flags);
@@ -241,7 +242,8 @@ static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 
 static int chip_direction_input(struct gpio_chip *c, unsigned offset)
 {
-       struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
+       struct cs5535_gpio_chip *chip =
+               container_of(c, struct cs5535_gpio_chip, chip);
        unsigned long flags;
 
        spin_lock_irqsave(&chip->lock, flags);
@@ -254,7 +256,8 @@ static int chip_direction_input(struct gpio_chip *c, unsigned offset)
 
 static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
 {
-       struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
+       struct cs5535_gpio_chip *chip =
+               container_of(c, struct cs5535_gpio_chip, chip);
        unsigned long flags;
 
        spin_lock_irqsave(&chip->lock, flags);
index d6618a6..b43cd84 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
+#include <linux/platform_data/gpio-dwapb.h>
+#include <linux/slab.h>
 
 #define GPIO_SWPORTA_DR                0x00
 #define GPIO_SWPORTA_DDR       0x04
@@ -35,6 +37,7 @@
 #define GPIO_INTTYPE_LEVEL     0x38
 #define GPIO_INT_POLARITY      0x3c
 #define GPIO_INTSTATUS         0x40
+#define GPIO_PORTA_DEBOUNCE    0x48
 #define GPIO_PORTA_EOI         0x4c
 #define GPIO_EXT_PORTA         0x50
 #define GPIO_EXT_PORTB         0x54
 
 struct dwapb_gpio;
 
+#ifdef CONFIG_PM_SLEEP
+/* Store GPIO context across system-wide suspend/resume transitions */
+struct dwapb_context {
+       u32 data;
+       u32 dir;
+       u32 ext;
+       u32 int_en;
+       u32 int_mask;
+       u32 int_type;
+       u32 int_pol;
+       u32 int_deb;
+};
+#endif
+
 struct dwapb_gpio_port {
        struct bgpio_chip       bgc;
        bool                    is_registered;
        struct dwapb_gpio       *gpio;
+#ifdef CONFIG_PM_SLEEP
+       struct dwapb_context    *ctx;
+#endif
+       unsigned int            idx;
 };
 
 struct dwapb_gpio {
@@ -62,11 +83,33 @@ struct dwapb_gpio {
        struct irq_domain       *domain;
 };
 
+static inline struct dwapb_gpio_port *
+to_dwapb_gpio_port(struct bgpio_chip *bgc)
+{
+       return container_of(bgc, struct dwapb_gpio_port, bgc);
+}
+
+static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
+{
+       struct bgpio_chip *bgc  = &gpio->ports[0].bgc;
+       void __iomem *reg_base  = gpio->regs;
+
+       return bgc->read_reg(reg_base + offset);
+}
+
+static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
+                              u32 val)
+{
+       struct bgpio_chip *bgc  = &gpio->ports[0].bgc;
+       void __iomem *reg_base  = gpio->regs;
+
+       bgc->write_reg(reg_base + offset, val);
+}
+
 static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
        struct bgpio_chip *bgc = to_bgpio_chip(gc);
-       struct dwapb_gpio_port *port = container_of(bgc, struct
-                                                   dwapb_gpio_port, bgc);
+       struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
        struct dwapb_gpio *gpio = port->gpio;
 
        return irq_find_mapping(gpio->domain, offset);
@@ -74,21 +117,20 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 
 static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
 {
-       u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
+       u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
 
        if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
                v &= ~BIT(offs);
        else
                v |= BIT(offs);
 
-       writel(v, gpio->regs + GPIO_INT_POLARITY);
+       dwapb_write(gpio, GPIO_INT_POLARITY, v);
 }
 
-static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
+static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
 {
-       struct dwapb_gpio *gpio = irq_get_handler_data(irq);
-       struct irq_chip *chip = irq_desc_get_chip(desc);
        u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
+       u32 ret = irq_status;
 
        while (irq_status) {
                int hwirq = fls(irq_status) - 1;
@@ -102,6 +144,16 @@ static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
                        dwapb_toggle_trigger(gpio, hwirq);
        }
 
+       return ret;
+}
+
+static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
+{
+       struct dwapb_gpio *gpio = irq_get_handler_data(irq);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+
+       dwapb_do_irq(gpio);
+
        if (chip->irq_eoi)
                chip->irq_eoi(irq_desc_get_irq_data(desc));
 }
@@ -115,9 +167,9 @@ static void dwapb_irq_enable(struct irq_data *d)
        u32 val;
 
        spin_lock_irqsave(&bgc->lock, flags);
-       val = readl(gpio->regs + GPIO_INTEN);
+       val = dwapb_read(gpio, GPIO_INTEN);
        val |= BIT(d->hwirq);
-       writel(val, gpio->regs + GPIO_INTEN);
+       dwapb_write(gpio, GPIO_INTEN, val);
        spin_unlock_irqrestore(&bgc->lock, flags);
 }
 
@@ -130,9 +182,9 @@ static void dwapb_irq_disable(struct irq_data *d)
        u32 val;
 
        spin_lock_irqsave(&bgc->lock, flags);
-       val = readl(gpio->regs + GPIO_INTEN);
+       val = dwapb_read(gpio, GPIO_INTEN);
        val &= ~BIT(d->hwirq);
-       writel(val, gpio->regs + GPIO_INTEN);
+       dwapb_write(gpio, GPIO_INTEN, val);
        spin_unlock_irqrestore(&bgc->lock, flags);
 }
 
@@ -172,8 +224,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
                return -EINVAL;
 
        spin_lock_irqsave(&bgc->lock, flags);
-       level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
-       polarity = readl(gpio->regs + GPIO_INT_POLARITY);
+       level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
+       polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
 
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
@@ -200,29 +252,55 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
 
        irq_setup_alt_chip(d, type);
 
-       writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
-       writel(polarity, gpio->regs + GPIO_INT_POLARITY);
+       dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
+       dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
+       return 0;
+}
+
+static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
+                                  unsigned offset, unsigned debounce)
+{
+       struct bgpio_chip *bgc = to_bgpio_chip(gc);
+       struct dwapb_gpio_port *port = to_dwapb_gpio_port(bgc);
+       struct dwapb_gpio *gpio = port->gpio;
+       unsigned long flags, val_deb;
+       unsigned long mask = bgc->pin2mask(bgc, offset);
+
+       spin_lock_irqsave(&bgc->lock, flags);
+
+       val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
+       if (debounce)
+               dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb | mask);
+       else
+               dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb & ~mask);
+
        spin_unlock_irqrestore(&bgc->lock, flags);
 
        return 0;
 }
 
+static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
+{
+       u32 worked;
+       struct dwapb_gpio *gpio = dev_id;
+
+       worked = dwapb_do_irq(gpio);
+
+       return worked ? IRQ_HANDLED : IRQ_NONE;
+}
+
 static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
-                                struct dwapb_gpio_port *port)
+                                struct dwapb_gpio_port *port,
+                                struct dwapb_port_property *pp)
 {
        struct gpio_chip *gc = &port->bgc.gc;
-       struct device_node *node =  gc->of_node;
-       struct irq_chip_generic *irq_gc;
+       struct device_node *node = pp->node;
+       struct irq_chip_generic *irq_gc = NULL;
        unsigned int hwirq, ngpio = gc->ngpio;
        struct irq_chip_type *ct;
-       int err, irq, i;
-
-       irq = irq_of_parse_and_map(node, 0);
-       if (!irq) {
-               dev_warn(gpio->dev, "no irq for bank %s\n",
-                       port->bgc.gc.of_node->full_name);
-               return;
-       }
+       int err, i;
 
        gpio->domain = irq_domain_add_linear(node, ngpio,
                                             &irq_generic_chip_ops, gpio);
@@ -269,8 +347,24 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
        irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
        irq_gc->chip_types[1].handler = handle_edge_irq;
 
-       irq_set_chained_handler(irq, dwapb_irq_handler);
-       irq_set_handler_data(irq, gpio);
+       if (!pp->irq_shared) {
+               irq_set_chained_handler(pp->irq, dwapb_irq_handler);
+               irq_set_handler_data(pp->irq, gpio);
+       } else {
+               /*
+                * Request a shared IRQ since where MFD would have devices
+                * using the same irq pin
+                */
+               err = devm_request_irq(gpio->dev, pp->irq,
+                                      dwapb_irq_handler_mfd,
+                                      IRQF_SHARED, "gpio-dwapb-mfd", gpio);
+               if (err) {
+                       dev_err(gpio->dev, "error requesting IRQ\n");
+                       irq_domain_remove(gpio->domain);
+                       gpio->domain = NULL;
+                       return;
+               }
+       }
 
        for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
                irq_create_mapping(gpio->domain, hwirq);
@@ -296,57 +390,53 @@ static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
 }
 
 static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
-                              struct device_node *port_np,
+                              struct dwapb_port_property *pp,
                               unsigned int offs)
 {
        struct dwapb_gpio_port *port;
-       u32 port_idx, ngpio;
        void __iomem *dat, *set, *dirout;
        int err;
 
-       if (of_property_read_u32(port_np, "reg", &port_idx) ||
-               port_idx >= DWAPB_MAX_PORTS) {
-               dev_err(gpio->dev, "missing/invalid port index for %s\n",
-                       port_np->full_name);
-               return -EINVAL;
-       }
-
        port = &gpio->ports[offs];
        port->gpio = gpio;
+       port->idx = pp->idx;
 
-       if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
-               dev_info(gpio->dev, "failed to get number of gpios for %s\n",
-                        port_np->full_name);
-               ngpio = 32;
-       }
+#ifdef CONFIG_PM_SLEEP
+       port->ctx = devm_kzalloc(gpio->dev, sizeof(*port->ctx), GFP_KERNEL);
+       if (!port->ctx)
+               return -ENOMEM;
+#endif
 
-       dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
-       set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
+       dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE);
+       set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE);
        dirout = gpio->regs + GPIO_SWPORTA_DDR +
-               (port_idx * GPIO_SWPORT_DDR_SIZE);
+               (pp->idx * GPIO_SWPORT_DDR_SIZE);
 
        err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
                         NULL, false);
        if (err) {
                dev_err(gpio->dev, "failed to init gpio chip for %s\n",
-                       port_np->full_name);
+                       pp->name);
                return err;
        }
 
-       port->bgc.gc.ngpio = ngpio;
-       port->bgc.gc.of_node = port_np;
+#ifdef CONFIG_OF_GPIO
+       port->bgc.gc.of_node = pp->node;
+#endif
+       port->bgc.gc.ngpio = pp->ngpio;
+       port->bgc.gc.base = pp->gpio_base;
 
-       /*
-        * Only port A can provide interrupts in all configurations of the IP.
-        */
-       if (port_idx == 0 &&
-           of_property_read_bool(port_np, "interrupt-controller"))
-               dwapb_configure_irqs(gpio, port);
+       /* Only port A support debounce */
+       if (pp->idx == 0)
+               port->bgc.gc.set_debounce = dwapb_gpio_set_debounce;
+
+       if (pp->irq)
+               dwapb_configure_irqs(gpio, port, pp);
 
        err = gpiochip_add(&port->bgc.gc);
        if (err)
                dev_err(gpio->dev, "failed to register gpiochip for %s\n",
-                       port_np->full_name);
+                       pp->name);
        else
                port->is_registered = true;
 
@@ -362,25 +452,116 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
                        gpiochip_remove(&gpio->ports[m].bgc.gc);
 }
 
+static struct dwapb_platform_data *
+dwapb_gpio_get_pdata_of(struct device *dev)
+{
+       struct device_node *node, *port_np;
+       struct dwapb_platform_data *pdata;
+       struct dwapb_port_property *pp;
+       int nports;
+       int i;
+
+       node = dev->of_node;
+       if (!IS_ENABLED(CONFIG_OF_GPIO) || !node)
+               return ERR_PTR(-ENODEV);
+
+       nports = of_get_child_count(node);
+       if (nports == 0)
+               return ERR_PTR(-ENODEV);
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL);
+       if (!pdata->properties) {
+               kfree(pdata);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       pdata->nports = nports;
+
+       i = 0;
+       for_each_child_of_node(node, port_np) {
+               pp = &pdata->properties[i++];
+               pp->node = port_np;
+
+               if (of_property_read_u32(port_np, "reg", &pp->idx) ||
+                   pp->idx >= DWAPB_MAX_PORTS) {
+                       dev_err(dev, "missing/invalid port index for %s\n",
+                               port_np->full_name);
+                       kfree(pdata->properties);
+                       kfree(pdata);
+                       return ERR_PTR(-EINVAL);
+               }
+
+               if (of_property_read_u32(port_np, "snps,nr-gpios",
+                                        &pp->ngpio)) {
+                       dev_info(dev, "failed to get number of gpios for %s\n",
+                                port_np->full_name);
+                       pp->ngpio = 32;
+               }
+
+               /*
+                * Only port A can provide interrupts in all configurations of
+                * the IP.
+                */
+               if (pp->idx == 0 &&
+                   of_property_read_bool(port_np, "interrupt-controller")) {
+                       pp->irq = irq_of_parse_and_map(port_np, 0);
+                       if (!pp->irq) {
+                               dev_warn(dev, "no irq for bank %s\n",
+                                        port_np->full_name);
+                       }
+               }
+
+               pp->irq_shared  = false;
+               pp->gpio_base   = -1;
+               pp->name        = port_np->full_name;
+       }
+
+       return pdata;
+}
+
+static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata)
+{
+       if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata)
+               return;
+
+       kfree(pdata->properties);
+       kfree(pdata);
+}
+
 static int dwapb_gpio_probe(struct platform_device *pdev)
 {
+       unsigned int i;
        struct resource *res;
        struct dwapb_gpio *gpio;
-       struct device_node *np;
        int err;
-       unsigned int offs = 0;
+       struct device *dev = &pdev->dev;
+       struct dwapb_platform_data *pdata = dev_get_platdata(dev);
+       bool is_pdata_alloc = !pdata;
+
+       if (is_pdata_alloc) {
+               pdata = dwapb_gpio_get_pdata_of(dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
+       }
 
-       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
-       if (!gpio)
-               return -ENOMEM;
-       gpio->dev = &pdev->dev;
+       if (!pdata->nports) {
+               err = -ENODEV;
+               goto out_err;
+       }
 
-       gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
-       if (!gpio->nr_ports) {
-               err = -EINVAL;
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio) {
+               err = -ENOMEM;
                goto out_err;
        }
-       gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
+       gpio->dev = &pdev->dev;
+       gpio->nr_ports = pdata->nports;
+
+       gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports,
                                   sizeof(*gpio->ports), GFP_KERNEL);
        if (!gpio->ports) {
                err = -ENOMEM;
@@ -394,20 +575,23 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
                goto out_err;
        }
 
-       for_each_child_of_node(pdev->dev.of_node, np) {
-               err = dwapb_gpio_add_port(gpio, np, offs++);
+       for (i = 0; i < gpio->nr_ports; i++) {
+               err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
                if (err)
                        goto out_unregister;
        }
        platform_set_drvdata(pdev, gpio);
 
-       return 0;
+       goto out_err;
 
 out_unregister:
        dwapb_gpio_unregister(gpio);
        dwapb_irq_teardown(gpio);
 
 out_err:
+       if (is_pdata_alloc)
+               dwapb_free_pdata_of(pdata);
+
        return err;
 }
 
@@ -427,10 +611,100 @@ static const struct of_device_id dwapb_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, dwapb_of_match);
 
+#ifdef CONFIG_PM_SLEEP
+static int dwapb_gpio_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+       struct bgpio_chip *bgc  = &gpio->ports[0].bgc;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&bgc->lock, flags);
+       for (i = 0; i < gpio->nr_ports; i++) {
+               unsigned int offset;
+               unsigned int idx = gpio->ports[i].idx;
+               struct dwapb_context *ctx = gpio->ports[i].ctx;
+
+               BUG_ON(!ctx);
+
+               offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
+               ctx->dir = dwapb_read(gpio, offset);
+
+               offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
+               ctx->data = dwapb_read(gpio, offset);
+
+               offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
+               ctx->ext = dwapb_read(gpio, offset);
+
+               /* Only port A can provide interrupts */
+               if (idx == 0) {
+                       ctx->int_mask   = dwapb_read(gpio, GPIO_INTMASK);
+                       ctx->int_en     = dwapb_read(gpio, GPIO_INTEN);
+                       ctx->int_pol    = dwapb_read(gpio, GPIO_INT_POLARITY);
+                       ctx->int_type   = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
+                       ctx->int_deb    = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
+
+                       /* Mask out interrupts */
+                       dwapb_write(gpio, GPIO_INTMASK, 0xffffffff);
+               }
+       }
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
+       return 0;
+}
+
+static int dwapb_gpio_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+       struct bgpio_chip *bgc  = &gpio->ports[0].bgc;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&bgc->lock, flags);
+       for (i = 0; i < gpio->nr_ports; i++) {
+               unsigned int offset;
+               unsigned int idx = gpio->ports[i].idx;
+               struct dwapb_context *ctx = gpio->ports[i].ctx;
+
+               BUG_ON(!ctx);
+
+               offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
+               dwapb_write(gpio, offset, ctx->data);
+
+               offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
+               dwapb_write(gpio, offset, ctx->dir);
+
+               offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
+               dwapb_write(gpio, offset, ctx->ext);
+
+               /* Only port A can provide interrupts */
+               if (idx == 0) {
+                       dwapb_write(gpio, GPIO_INTTYPE_LEVEL, ctx->int_type);
+                       dwapb_write(gpio, GPIO_INT_POLARITY, ctx->int_pol);
+                       dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, ctx->int_deb);
+                       dwapb_write(gpio, GPIO_INTEN, ctx->int_en);
+                       dwapb_write(gpio, GPIO_INTMASK, ctx->int_mask);
+
+                       /* Clear out spurious interrupts */
+                       dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
+               }
+       }
+       spin_unlock_irqrestore(&bgc->lock, flags);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
+                        dwapb_gpio_resume);
+
 static struct platform_driver dwapb_gpio_driver = {
        .driver         = {
                .name   = "gpio-dwapb",
                .owner  = THIS_MODULE,
+               .pm     = &dwapb_gpio_pm_ops,
                .of_match_table = of_match_ptr(dwapb_of_match),
        },
        .probe          = dwapb_gpio_probe,
index 464a83d..cc09b23 100644 (file)
@@ -265,29 +265,27 @@ static int ks8695_gpio_show(struct seq_file *s, void *unused)
                                seq_printf(s, "EXT%i ", i);
 
                                switch ((ctrl & intmask[i]) >> (4 * i)) {
-                                       case IOPC_TM_LOW:
-                                               seq_printf(s, "(Low)");         break;
-                                       case IOPC_TM_HIGH:
-                                               seq_printf(s, "(High)");        break;
-                                       case IOPC_TM_RISING:
-                                               seq_printf(s, "(Rising)");      break;
-                                       case IOPC_TM_FALLING:
-                                               seq_printf(s, "(Falling)");     break;
-                                       case IOPC_TM_EDGE:
-                                               seq_printf(s, "(Edges)");       break;
+                               case IOPC_TM_LOW:
+                                       seq_printf(s, "(Low)");         break;
+                               case IOPC_TM_HIGH:
+                                       seq_printf(s, "(High)");        break;
+                               case IOPC_TM_RISING:
+                                       seq_printf(s, "(Rising)");      break;
+                               case IOPC_TM_FALLING:
+                                       seq_printf(s, "(Falling)");     break;
+                               case IOPC_TM_EDGE:
+                                       seq_printf(s, "(Edges)");       break;
                                }
-                       }
-                       else
+                       } else
                                seq_printf(s, "GPIO\t");
-               }
-               else if (i <= KS8695_GPIO_5) {
+               } else if (i <= KS8695_GPIO_5) {
                        if (ctrl & enable[i])
                                seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
                        else
                                seq_printf(s, "GPIO\t");
-               }
-               else
+               } else {
                        seq_printf(s, "GPIO\t");
+               }
 
                seq_printf(s, "\t");
 
index 6f183d9..8488e2f 100644 (file)
@@ -479,7 +479,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
 
        mutex_init(&mcp->irq_lock);
 
-       mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
+       mcp->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->ngpio,
                                                &irq_domain_simple_ops, mcp);
        if (!mcp->irq_domain)
                return -ENODEV;
@@ -581,7 +581,7 @@ done:
 
 static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
                              void *data, unsigned addr, unsigned type,
-                             unsigned base, unsigned pullups)
+                             struct mcp23s08_platform_data *pdata, int cs)
 {
        int status;
        bool mirror = false;
@@ -635,7 +635,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
                return -EINVAL;
        }
 
-       mcp->chip.base = base;
+       mcp->chip.base = pdata->base;
        mcp->chip.can_sleep = true;
        mcp->chip.dev = dev;
        mcp->chip.owner = THIS_MODULE;
@@ -648,11 +648,9 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
        if (status < 0)
                goto fail;
 
-       mcp->irq_controller = of_property_read_bool(mcp->chip.of_node,
-                                               "interrupt-controller");
+       mcp->irq_controller = pdata->irq_controller;
        if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
-               mirror = of_property_read_bool(mcp->chip.of_node,
-                                               "microchip,irq-mirror");
+               mirror = pdata->mirror;
 
        if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
                /* mcp23s17 has IOCON twice, make sure they are in sync */
@@ -668,7 +666,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
        }
 
        /* configure ~100K pullups */
-       status = mcp->ops->write(mcp, MCP_GPPU, pullups);
+       status = mcp->ops->write(mcp, MCP_GPPU, pdata->chip[cs].pullups);
        if (status < 0)
                goto fail;
 
@@ -768,25 +766,29 @@ MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
 static int mcp230xx_probe(struct i2c_client *client,
                                    const struct i2c_device_id *id)
 {
-       struct mcp23s08_platform_data *pdata;
+       struct mcp23s08_platform_data *pdata, local_pdata;
        struct mcp23s08 *mcp;
-       int status, base, pullups;
+       int status;
        const struct of_device_id *match;
 
        match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
                                        &client->dev);
-       pdata = dev_get_platdata(&client->dev);
-       if (match || !pdata) {
-               base = -1;
-               pullups = 0;
+       if (match) {
+               pdata = &local_pdata;
+               pdata->base = -1;
+               pdata->chip[0].pullups = 0;
+               pdata->irq_controller = of_property_read_bool(
+                                       client->dev.of_node,
+                                       "interrupt-controller");
+               pdata->mirror = of_property_read_bool(client->dev.of_node,
+                                                     "microchip,irq-mirror");
                client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
        } else {
-               if (!gpio_is_valid(pdata->base)) {
+               pdata = dev_get_platdata(&client->dev);
+               if (!pdata || !gpio_is_valid(pdata->base)) {
                        dev_dbg(&client->dev, "invalid platform data\n");
                        return -EINVAL;
                }
-               base = pdata->base;
-               pullups = pdata->chip[0].pullups;
        }
 
        mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
@@ -795,7 +797,7 @@ static int mcp230xx_probe(struct i2c_client *client,
 
        mcp->irq = client->irq;
        status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
-                                   id->driver_data, base, pullups);
+                                   id->driver_data, pdata, 0);
        if (status)
                goto fail;
 
@@ -863,14 +865,12 @@ static void mcp23s08_i2c_exit(void) { }
 
 static int mcp23s08_probe(struct spi_device *spi)
 {
-       struct mcp23s08_platform_data   *pdata;
+       struct mcp23s08_platform_data   *pdata, local_pdata;
        unsigned                        addr;
        int                             chips = 0;
        struct mcp23s08_driver_data     *data;
        int                             status, type;
-       unsigned                        base = -1,
-                                       ngpio = 0,
-                                       pullups[ARRAY_SIZE(pdata->chip)];
+       unsigned                        ngpio = 0;
        const struct                    of_device_id *match;
        u32                             spi_present_mask = 0;
 
@@ -893,11 +893,18 @@ static int mcp23s08_probe(struct spi_device *spi)
                        return -ENODEV;
                }
 
+               pdata = &local_pdata;
+               pdata->base = -1;
                for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
-                       pullups[addr] = 0;
+                       pdata->chip[addr].pullups = 0;
                        if (spi_present_mask & (1 << addr))
                                chips++;
                }
+               pdata->irq_controller = of_property_read_bool(
+                                       spi->dev.of_node,
+                                       "interrupt-controller");
+               pdata->mirror = of_property_read_bool(spi->dev.of_node,
+                                                     "microchip,irq-mirror");
        } else {
                type = spi_get_device_id(spi)->driver_data;
                pdata = dev_get_platdata(&spi->dev);
@@ -917,10 +924,7 @@ static int mcp23s08_probe(struct spi_device *spi)
                                return -EINVAL;
                        }
                        spi_present_mask |= 1 << addr;
-                       pullups[addr] = pdata->chip[addr].pullups;
                }
-
-               base = pdata->base;
        }
 
        if (!chips)
@@ -938,13 +942,13 @@ static int mcp23s08_probe(struct spi_device *spi)
                chips--;
                data->mcp[addr] = &data->chip[chips];
                status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
-                                           0x40 | (addr << 1), type, base,
-                                           pullups[addr]);
+                                           0x40 | (addr << 1), type, pdata,
+                                           addr);
                if (status < 0)
                        goto fail;
 
-               if (base != -1)
-                       base += (type == MCP_TYPE_S17) ? 16 : 8;
+               if (pdata->base != -1)
+                       pdata->base += (type == MCP_TYPE_S17) ? 16 : 8;
                ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
        }
        data->ngpio = ngpio;
index 1749321..415682f 100644 (file)
@@ -857,16 +857,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
        spin_unlock_irqrestore(&bank->lock, flags);
 }
 
-static struct irq_chip gpio_irq_chip = {
-       .name           = "GPIO",
-       .irq_shutdown   = omap_gpio_irq_shutdown,
-       .irq_ack        = omap_gpio_ack_irq,
-       .irq_mask       = omap_gpio_mask_irq,
-       .irq_unmask     = omap_gpio_unmask_irq,
-       .irq_set_type   = omap_gpio_irq_type,
-       .irq_set_wake   = omap_gpio_wake_enable,
-};
-
 /*---------------------------------------------------------------------*/
 
 static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -1088,7 +1078,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
                               IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
-static int omap_gpio_chip_init(struct gpio_bank *bank)
+static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 {
        int j;
        static int gpio;
@@ -1137,17 +1127,17 @@ static int omap_gpio_chip_init(struct gpio_bank *bank)
        }
 #endif
 
-       ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
+       ret = gpiochip_irqchip_add(&bank->chip, irqc,
                                   irq_base, omap_gpio_irq_handler,
                                   IRQ_TYPE_NONE);
 
        if (ret) {
                dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
-               ret = gpiochip_remove(&bank->chip);
+               gpiochip_remove(&bank->chip);
                return -ENODEV;
        }
 
-       gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
+       gpiochip_set_chained_irqchip(&bank->chip, irqc,
                                     bank->irq, omap_gpio_irq_handler);
 
        for (j = 0; j < bank->width; j++) {
@@ -1172,6 +1162,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
        const struct omap_gpio_platform_data *pdata;
        struct resource *res;
        struct gpio_bank *bank;
+       struct irq_chip *irqc;
        int ret;
 
        match = of_match_device(of_match_ptr(omap_gpio_match), dev);
@@ -1186,6 +1177,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
+       if (!irqc)
+               return -ENOMEM;
+
+       irqc->irq_shutdown = omap_gpio_irq_shutdown,
+       irqc->irq_ack = omap_gpio_ack_irq,
+       irqc->irq_mask = omap_gpio_mask_irq,
+       irqc->irq_unmask = omap_gpio_unmask_irq,
+       irqc->irq_set_type = omap_gpio_irq_type,
+       irqc->irq_set_wake = omap_gpio_wake_enable,
+       irqc->name = dev_name(&pdev->dev);
+
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (unlikely(!res)) {
                dev_err(dev, "Invalid IRQ resource\n");
@@ -1241,7 +1244,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 
        omap_gpio_mod_init(bank);
 
-       ret = omap_gpio_chip_init(bank);
+       ret = omap_gpio_chip_init(bank, irqc);
        if (ret)
                return ret;
 
index f9961ee..e2da64a 100644 (file)
@@ -520,7 +520,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
        struct i2c_client *client = chip->client;
        int ret, i, offset = 0;
 
-       if (irq_base != -1
+       if (client->irq && irq_base != -1
                        && (id->driver_data & PCA_INT)) {
 
                switch (chip->chip_type) {
@@ -586,50 +586,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 }
 #endif
 
-/*
- * Handlers for alternative sources of platform_data
- */
-#ifdef CONFIG_OF_GPIO
-/*
- * Translate OpenFirmware node properties into platform_data
- * WARNING: This is DEPRECATED and will be removed eventually!
- */
-static void
-pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
-{
-       struct device_node *node;
-       const __be32 *val;
-       int size;
-
-       *gpio_base = -1;
-
-       node = client->dev.of_node;
-       if (node == NULL)
-               return;
-
-       val = of_get_property(node, "linux,gpio-base", &size);
-       WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
-       if (val) {
-               if (size != sizeof(*val))
-                       dev_warn(&client->dev, "%s: wrong linux,gpio-base\n",
-                                node->full_name);
-               else
-                       *gpio_base = be32_to_cpup(val);
-       }
-
-       val = of_get_property(node, "polarity", NULL);
-       WARN(val, "%s: device-tree property 'polarity' is deprecated!", __func__);
-       if (val)
-               *invert = *val;
-}
-#else
-static void
-pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
-{
-       *gpio_base = -1;
-}
-#endif
-
 static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 {
        int ret;
@@ -704,12 +660,8 @@ static int pca953x_probe(struct i2c_client *client,
                invert = pdata->invert;
                chip->names = pdata->names;
        } else {
-               pca953x_get_alt_pdata(client, &chip->gpio_start, &invert);
-#ifdef CONFIG_OF_GPIO
-               /* If I2C node has no interrupts property, disable GPIO interrupts */
-               if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
-                       irq_base = -1;
-#endif
+               chip->gpio_start = -1;
+               irq_base = 0;
        }
 
        chip->client = client;
index e0ac549..2d9a950 100644 (file)
@@ -171,6 +171,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
        return 0;
 }
 
+#ifdef CONFIG_PM
 /*
  * Save register configuration and disable interrupts.
  */
@@ -206,6 +207,7 @@ static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
                iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
                          &chip->reg->gpio_use_sel);
 }
+#endif
 
 static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
 {
index 3810da4..7c288ba 100644 (file)
@@ -1309,56 +1309,6 @@ samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin)
 }
 EXPORT_SYMBOL(s3c_gpio_getpull);
 
-#ifdef CONFIG_S5P_GPIO_DRVSTR
-s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin)
-{
-       struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
-       unsigned int off;
-       void __iomem *reg;
-       int shift;
-       u32 drvstr;
-
-       if (!chip)
-               return -EINVAL;
-
-       off = pin - chip->chip.base;
-       shift = off * 2;
-       reg = chip->base + 0x0C;
-
-       drvstr = __raw_readl(reg);
-       drvstr = drvstr >> shift;
-       drvstr &= 0x3;
-
-       return (__force s5p_gpio_drvstr_t)drvstr;
-}
-EXPORT_SYMBOL(s5p_gpio_get_drvstr);
-
-int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr)
-{
-       struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin);
-       unsigned int off;
-       void __iomem *reg;
-       int shift;
-       u32 tmp;
-
-       if (!chip)
-               return -EINVAL;
-
-       off = pin - chip->chip.base;
-       shift = off * 2;
-       reg = chip->base + 0x0C;
-
-       tmp = __raw_readl(reg);
-       tmp &= ~(0x3 << shift);
-       tmp |= drvstr << shift;
-
-       __raw_writel(tmp, reg);
-
-       return 0;
-}
-EXPORT_SYMBOL(s5p_gpio_set_drvstr);
-#endif /* CONFIG_S5P_GPIO_DRVSTR */
-
 #ifdef CONFIG_PLAT_S3C24XX
 unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
 {
index 845025a..85c5b19 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/mfd/stmpe.h>
+#include <linux/seq_file.h>
 
 /*
  * These registers are modified under the irq bus lock and cached to avoid
@@ -127,19 +128,19 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        int regoffset = offset / 8;
        int mask = 1 << (offset % 8);
 
-       if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
+       if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
                return -EINVAL;
 
        /* STMPE801 doesn't have RE and FE registers */
        if (stmpe_gpio->stmpe->partnum == STMPE801)
                return 0;
 
-       if (type == IRQ_TYPE_EDGE_RISING)
+       if (type & IRQ_TYPE_EDGE_RISING)
                stmpe_gpio->regs[REG_RE][regoffset] |= mask;
        else
                stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
 
-       if (type == IRQ_TYPE_EDGE_FALLING)
+       if (type & IRQ_TYPE_EDGE_FALLING)
                stmpe_gpio->regs[REG_FE][regoffset] |= mask;
        else
                stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
@@ -211,6 +212,77 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
        stmpe_gpio->regs[REG_IE][regoffset] |= mask;
 }
 
+static void stmpe_dbg_show_one(struct seq_file *s,
+                              struct gpio_chip *gc,
+                              unsigned offset, unsigned gpio)
+{
+       struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc);
+       struct stmpe *stmpe = stmpe_gpio->stmpe;
+       const char *label = gpiochip_is_requested(gc, offset);
+       int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
+       bool val = !!stmpe_gpio_get(gc, offset);
+       u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+       u8 mask = 1 << (offset % 8);
+       int ret;
+       u8 dir;
+
+       ret = stmpe_reg_read(stmpe, dir_reg);
+       if (ret < 0)
+               return;
+       dir = !!(ret & mask);
+
+       if (dir) {
+               seq_printf(s, " gpio-%-3d (%-20.20s) out %s",
+                          gpio, label ?: "(none)",
+                          val ? "hi" : "lo");
+       } else {
+               u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8);
+               u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8);
+               u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8);
+               u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8);
+               bool edge_det;
+               bool rise;
+               bool fall;
+               bool irqen;
+
+               ret = stmpe_reg_read(stmpe, edge_det_reg);
+               if (ret < 0)
+                       return;
+               edge_det = !!(ret & mask);
+               ret = stmpe_reg_read(stmpe, rise_reg);
+               if (ret < 0)
+                       return;
+               rise = !!(ret & mask);
+               ret = stmpe_reg_read(stmpe, fall_reg);
+               if (ret < 0)
+                       return;
+               fall = !!(ret & mask);
+               ret = stmpe_reg_read(stmpe, irqen_reg);
+               if (ret < 0)
+                       return;
+               irqen = !!(ret & mask);
+
+               seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s %s%s%s",
+                          gpio, label ?: "(none)",
+                          val ? "hi" : "lo",
+                          edge_det ? "edge-asserted" : "edge-inactive",
+                          irqen ? "IRQ-enabled" : "",
+                          rise ? " rising-edge-detection" : "",
+                          fall ? " falling-edge-detection" : "");
+       }
+}
+
+static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc)
+{
+       unsigned i;
+       unsigned gpio = gc->base;
+
+       for (i = 0; i < gc->ngpio; i++, gpio++) {
+               stmpe_dbg_show_one(s, gc, i, gpio);
+               seq_printf(s, "\n");
+       }
+}
+
 static struct irq_chip stmpe_gpio_irq_chip = {
        .name                   = "stmpe-gpio",
        .irq_bus_lock           = stmpe_gpio_irq_lock,
@@ -293,6 +365,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 #endif
        stmpe_gpio->chip.base = -1;
 
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+                stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
+
        if (pdata)
                stmpe_gpio->norequest_mask = pdata->norequest_mask;
        else if (np)
@@ -308,6 +383,12 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
        if (ret)
                goto out_free;
 
+       ret = gpiochip_add(&stmpe_gpio->chip);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
+               goto out_disable;
+       }
+
        if (irq > 0) {
                ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                stmpe_gpio_irq, IRQF_ONESHOT,
@@ -324,14 +405,13 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(&pdev->dev,
                                "could not connect irqchip to gpiochip\n");
-                       return ret;
+                       goto out_disable;
                }
-       }
 
-       ret = gpiochip_add(&stmpe_gpio->chip);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
-               goto out_disable;
+               gpiochip_set_chained_irqchip(&stmpe_gpio->chip,
+                                            &stmpe_gpio_irq_chip,
+                                            irq,
+                                            NULL);
        }
 
        if (pdata && pdata->setup)
@@ -343,6 +423,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 
 out_disable:
        stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
+       gpiochip_remove(&stmpe_gpio->chip);
 out_free:
        kfree(stmpe_gpio);
        return ret;
index 04882a9..7e359b7 100644 (file)
@@ -292,7 +292,7 @@ static struct platform_driver xway_stp_driver = {
        },
 };
 
-int __init xway_stp_init(void)
+static int __init xway_stp_init(void)
 {
        return platform_driver_register(&xway_stp_driver);
 }
index 30884fb..e82fde4 100644 (file)
@@ -37,6 +37,8 @@
  * dat_bit_offset:     Offset (in bits) to the first GPIO bit.
  * dir_bit_offset:     Optional offset (in bits) to the first bit to switch
  *                     GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
+ * set:                HW specific callback to assigns output value
+ *                     for signal "offset"
  */
 
 struct syscon_gpio_data {
@@ -45,12 +47,16 @@ struct syscon_gpio_data {
        unsigned int    bit_count;
        unsigned int    dat_bit_offset;
        unsigned int    dir_bit_offset;
+       void            (*set)(struct gpio_chip *chip,
+                              unsigned offset, int value);
 };
 
 struct syscon_gpio_priv {
        struct gpio_chip                chip;
        struct regmap                   *syscon;
        const struct syscon_gpio_data   *data;
+       u32                             dreg_offset;
+       u32                             dir_reg_offset;
 };
 
 static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
@@ -61,9 +67,11 @@ static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
 static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
-       unsigned int val, offs = priv->data->dat_bit_offset + offset;
+       unsigned int val, offs;
        int ret;
 
+       offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
+
        ret = regmap_read(priv->syscon,
                          (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
        if (ret)
@@ -75,7 +83,9 @@ static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
 static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
 {
        struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
-       unsigned int offs = priv->data->dat_bit_offset + offset;
+       unsigned int offs;
+
+       offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
 
        regmap_update_bits(priv->syscon,
                           (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -88,7 +98,10 @@ static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
        struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 
        if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
-               unsigned int offs = priv->data->dir_bit_offset + offset;
+               unsigned int offs;
+
+               offs = priv->dir_reg_offset +
+                      priv->data->dir_bit_offset + offset;
 
                regmap_update_bits(priv->syscon,
                                   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -103,7 +116,10 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
        struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
 
        if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
-               unsigned int offs = priv->data->dir_bit_offset + offset;
+               unsigned int offs;
+
+               offs = priv->dir_reg_offset +
+                      priv->data->dir_bit_offset + offset;
 
                regmap_update_bits(priv->syscon,
                                   (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
@@ -111,7 +127,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
                                   BIT(offs % SYSCON_REG_BITS));
        }
 
-       syscon_gpio_set(chip, offset, val);
+       priv->data->set(chip, offset, val);
 
        return 0;
 }
@@ -124,11 +140,46 @@ static const struct syscon_gpio_data clps711x_mctrl_gpio = {
        .dat_bit_offset = 0x40 * 8 + 8,
 };
 
+#define KEYSTONE_LOCK_BIT BIT(0)
+
+static void keystone_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+       struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+       unsigned int offs;
+       int ret;
+
+       offs = priv->dreg_offset + priv->data->dat_bit_offset + offset;
+
+       if (!val)
+               return;
+
+       ret = regmap_update_bits(
+                       priv->syscon,
+                       (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+                       BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT,
+                       BIT(offs % SYSCON_REG_BITS) | KEYSTONE_LOCK_BIT);
+       if (ret < 0)
+               dev_err(chip->dev, "gpio write failed ret(%d)\n", ret);
+}
+
+static const struct syscon_gpio_data keystone_dsp_gpio = {
+       /* ARM Keystone 2 */
+       .compatible     = NULL,
+       .flags          = GPIO_SYSCON_FEAT_OUT,
+       .bit_count      = 28,
+       .dat_bit_offset = 4,
+       .set            = keystone_gpio_set,
+};
+
 static const struct of_device_id syscon_gpio_ids[] = {
        {
                .compatible     = "cirrus,clps711x-mctrl-gpio",
                .data           = &clps711x_mctrl_gpio,
        },
+       {
+               .compatible     = "ti,keystone-dsp-gpio",
+               .data           = &keystone_dsp_gpio,
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
@@ -138,6 +189,8 @@ static int syscon_gpio_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
        struct syscon_gpio_priv *priv;
+       struct device_node *np = dev->of_node;
+       int ret;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -145,10 +198,31 @@ static int syscon_gpio_probe(struct platform_device *pdev)
 
        priv->data = of_id->data;
 
-       priv->syscon =
-               syscon_regmap_lookup_by_compatible(priv->data->compatible);
-       if (IS_ERR(priv->syscon))
-               return PTR_ERR(priv->syscon);
+       if (priv->data->compatible) {
+               priv->syscon = syscon_regmap_lookup_by_compatible(
+                                       priv->data->compatible);
+               if (IS_ERR(priv->syscon))
+                       return PTR_ERR(priv->syscon);
+       } else {
+               priv->syscon =
+                       syscon_regmap_lookup_by_phandle(np, "gpio,syscon-dev");
+               if (IS_ERR(priv->syscon))
+                       return PTR_ERR(priv->syscon);
+
+               ret = of_property_read_u32_index(np, "gpio,syscon-dev", 1,
+                                                &priv->dreg_offset);
+               if (ret)
+                       dev_err(dev, "can't read the data register offset!\n");
+
+               priv->dreg_offset <<= 3;
+
+               ret = of_property_read_u32_index(np, "gpio,syscon-dev", 2,
+                                                &priv->dir_reg_offset);
+               if (ret)
+                       dev_err(dev, "can't read the dir register offset!\n");
+
+               priv->dir_reg_offset <<= 3;
+       }
 
        priv->chip.dev = dev;
        priv->chip.owner = THIS_MODULE;
@@ -159,7 +233,7 @@ static int syscon_gpio_probe(struct platform_device *pdev)
        if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
                priv->chip.direction_input = syscon_gpio_dir_in;
        if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
-               priv->chip.set = syscon_gpio_set;
+               priv->chip.set = priv->data->set ? : syscon_gpio_set;
                priv->chip.direction_output = syscon_gpio_dir_out;
        }
 
index 7324869..ae0f646 100644 (file)
@@ -300,6 +300,11 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
                return ret;
        }
 
+       gpiochip_set_chained_irqchip(&tc3589x_gpio->chip,
+                                    &tc3589x_gpio_irq_chip,
+                                    irq,
+                                    NULL);
+
        if (pdata && pdata->setup)
                pdata->setup(tc3589x, tc3589x_gpio->chip.base);
 
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
new file mode 100644 (file)
index 0000000..7d48922
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * AppliedMicro X-Gene SoC GPIO Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/driver.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#define GPIO_SET_DR_OFFSET     0x0C
+#define GPIO_DATA_OFFSET       0x14
+#define GPIO_BANK_STRIDE       0x0C
+
+#define XGENE_GPIOS_PER_BANK   16
+#define XGENE_MAX_GPIO_BANKS   3
+#define XGENE_MAX_GPIOS                (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
+
+#define GPIO_BIT_OFFSET(x)     (x % XGENE_GPIOS_PER_BANK)
+#define GPIO_BANK_OFFSET(x)    ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
+
+struct xgene_gpio {
+       struct gpio_chip        chip;
+       void __iomem            *base;
+       spinlock_t              lock;
+#ifdef CONFIG_PM
+       u32                     set_dr_val[XGENE_MAX_GPIO_BANKS];
+#endif
+};
+
+static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip)
+{
+       return container_of(chip, struct xgene_gpio, chip);
+}
+
+static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct xgene_gpio *chip = to_xgene_gpio(gc);
+       unsigned long bank_offset;
+       u32 bit_offset;
+
+       bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
+       bit_offset = GPIO_BIT_OFFSET(offset);
+       return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
+}
+
+static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct xgene_gpio *chip = to_xgene_gpio(gc);
+       unsigned long bank_offset;
+       u32 setval, bit_offset;
+
+       bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
+       bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
+
+       setval = ioread32(chip->base + bank_offset);
+       if (val)
+               setval |= BIT(bit_offset);
+       else
+               setval &= ~BIT(bit_offset);
+       iowrite32(setval, chip->base + bank_offset);
+}
+
+static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct xgene_gpio *chip = to_xgene_gpio(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       __xgene_gpio_set(gc, offset, val);
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
+{
+       struct xgene_gpio *chip = to_xgene_gpio(gc);
+       unsigned long flags, bank_offset;
+       u32 dirval, bit_offset;
+
+       bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
+       bit_offset = GPIO_BIT_OFFSET(offset);
+
+       spin_lock_irqsave(&chip->lock, flags);
+
+       dirval = ioread32(chip->base + bank_offset);
+       dirval |= BIT(bit_offset);
+       iowrite32(dirval, chip->base + bank_offset);
+
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+static int xgene_gpio_dir_out(struct gpio_chip *gc,
+                                       unsigned int offset, int val)
+{
+       struct xgene_gpio *chip = to_xgene_gpio(gc);
+       unsigned long flags, bank_offset;
+       u32 dirval, bit_offset;
+
+       bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
+       bit_offset = GPIO_BIT_OFFSET(offset);
+
+       spin_lock_irqsave(&chip->lock, flags);
+
+       dirval = ioread32(chip->base + bank_offset);
+       dirval &= ~BIT(bit_offset);
+       iowrite32(dirval, chip->base + bank_offset);
+       __xgene_gpio_set(gc, offset, val);
+
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int xgene_gpio_suspend(struct device *dev)
+{
+       struct xgene_gpio *gpio = dev_get_drvdata(dev);
+       unsigned long bank_offset;
+       unsigned int bank;
+
+       for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
+               bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
+               gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
+       }
+       return 0;
+}
+
+static int xgene_gpio_resume(struct device *dev)
+{
+       struct xgene_gpio *gpio = dev_get_drvdata(dev);
+       unsigned long bank_offset;
+       unsigned int bank;
+
+       for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
+               bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
+               iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
+       }
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
+#define XGENE_GPIO_PM_OPS      (&xgene_gpio_pm)
+#else
+#define XGENE_GPIO_PM_OPS      NULL
+#endif
+
+static int xgene_gpio_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct xgene_gpio *gpio;
+       int err = 0;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
+                                                       resource_size(res));
+       if (!gpio->base) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       gpio->chip.ngpio = XGENE_MAX_GPIOS;
+
+       spin_lock_init(&gpio->lock);
+       gpio->chip.dev = &pdev->dev;
+       gpio->chip.direction_input = xgene_gpio_dir_in;
+       gpio->chip.direction_output = xgene_gpio_dir_out;
+       gpio->chip.get = xgene_gpio_get;
+       gpio->chip.set = xgene_gpio_set;
+       gpio->chip.label = dev_name(&pdev->dev);
+       gpio->chip.base = -1;
+
+       platform_set_drvdata(pdev, gpio);
+
+       err = gpiochip_add(&gpio->chip);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "failed to register gpiochip.\n");
+               goto err;
+       }
+
+       dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
+       return 0;
+err:
+       dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
+       return err;
+}
+
+static int xgene_gpio_remove(struct platform_device *pdev)
+{
+       struct xgene_gpio *gpio = platform_get_drvdata(pdev);
+
+       gpiochip_remove(&gpio->chip);
+       return 0;
+}
+
+static const struct of_device_id xgene_gpio_of_match[] = {
+       { .compatible = "apm,xgene-gpio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
+
+static struct platform_driver xgene_gpio_driver = {
+       .driver = {
+               .name = "xgene-gpio",
+               .owner = THIS_MODULE,
+               .of_match_table = xgene_gpio_of_match,
+               .pm     = XGENE_GPIO_PM_OPS,
+       },
+       .probe = xgene_gpio_probe,
+       .remove = xgene_gpio_remove,
+};
+
+module_platform_driver(xgene_gpio_driver);
+
+MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
+MODULE_DESCRIPTION("APM X-Gene GPIO driver");
+MODULE_LICENSE("GPL");
index 1248186..ba18b06 100644 (file)
@@ -197,6 +197,7 @@ static int xgpio_of_probe(struct device_node *np)
        struct xgpio_instance *chip;
        int status = 0;
        const u32 *tree_info;
+       u32 ngpio;
 
        chip = kzalloc(sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -211,12 +212,13 @@ static int xgpio_of_probe(struct device_node *np)
        /* Update GPIO direction shadow register with default value */
        of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
 
-       /* By default assume full GPIO controller */
-       chip->mmchip.gc.ngpio = 32;
-
-       /* Check device node and parent device node for device width */
-       of_property_read_u32(np, "xlnx,gpio-width",
-                             (u32 *)&chip->mmchip.gc.ngpio);
+       /*
+        * Check device node and parent device node for device width
+        * and assume default width of 32
+        */
+       if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio))
+               ngpio = 32;
+       chip->mmchip.gc.ngpio = (u16)ngpio;
 
        spin_lock_init(&chip->gpio_lock);
 
@@ -258,12 +260,13 @@ static int xgpio_of_probe(struct device_node *np)
                /* Update GPIO direction shadow register with default value */
                of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
 
-               /* By default assume full GPIO controller */
-               chip->mmchip.gc.ngpio = 32;
-
-               /* Check device node and parent device node for device width */
-               of_property_read_u32(np, "xlnx,gpio2-width",
-                                    (u32 *)&chip->mmchip.gc.ngpio);
+               /*
+                * Check device node and parent device node for device width
+                * and assume default width of 32
+                */
+               if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio))
+                       ngpio = 32;
+               chip->mmchip.gc.ngpio = (u16)ngpio;
 
                spin_lock_init(&chip->gpio_lock);
 
index 31ad5df..74cd480 100644 (file)
  * @chip:      instance of the gpio_chip
  * @base_addr: base address of the GPIO device
  * @clk:       clock resource for this controller
+ * @irq:       interrupt for the GPIO device
  */
 struct zynq_gpio {
        struct gpio_chip chip;
        void __iomem *base_addr;
        struct clk *clk;
+       int irq;
 };
 
 static struct irq_chip zynq_gpio_level_irqchip;
 static struct irq_chip zynq_gpio_edge_irqchip;
-
 /**
  * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
  * for a given pin in the GPIO device
@@ -138,6 +139,13 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
        }
 }
 
+static const unsigned int zynq_gpio_bank_offset[] = {
+       ZYNQ_GPIO_BANK0_PIN_MIN,
+       ZYNQ_GPIO_BANK1_PIN_MIN,
+       ZYNQ_GPIO_BANK2_PIN_MIN,
+       ZYNQ_GPIO_BANK3_PIN_MIN,
+};
+
 /**
  * zynq_gpio_get_value - Get the state of the specified pin of GPIO device
  * @chip:      gpio_chip instance to be worked on
@@ -427,10 +435,9 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
 
 static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
 {
-       if (on)
-               zynq_gpio_irq_unmask(data);
-       else
-               zynq_gpio_irq_mask(data);
+       struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data);
+
+       irq_set_irq_wake(gpio->irq, on);
 
        return 0;
 }
@@ -444,7 +451,8 @@ static struct irq_chip zynq_gpio_level_irqchip = {
        .irq_unmask     = zynq_gpio_irq_unmask,
        .irq_set_type   = zynq_gpio_set_irq_type,
        .irq_set_wake   = zynq_gpio_set_wake,
-       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
+       .flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
+                         IRQCHIP_MASK_ON_SUSPEND,
 };
 
 static struct irq_chip zynq_gpio_edge_irqchip = {
@@ -455,8 +463,28 @@ static struct irq_chip zynq_gpio_edge_irqchip = {
        .irq_unmask     = zynq_gpio_irq_unmask,
        .irq_set_type   = zynq_gpio_set_irq_type,
        .irq_set_wake   = zynq_gpio_set_wake,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND,
 };
 
+static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
+                                     unsigned int bank_num,
+                                     unsigned long pending)
+{
+       unsigned int bank_offset = zynq_gpio_bank_offset[bank_num];
+       struct irq_domain *irqdomain = gpio->chip.irqdomain;
+       int offset;
+
+       if (!pending)
+               return;
+
+       for_each_set_bit(offset, &pending, 32) {
+               unsigned int gpio_irq;
+
+               gpio_irq = irq_find_mapping(irqdomain, offset + bank_offset);
+               generic_handle_irq(gpio_irq);
+       }
+}
+
 /**
  * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
  * @irq:       irq number of the gpio bank where interrupt has occurred
@@ -482,18 +510,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
                                        ZYNQ_GPIO_INTSTS_OFFSET(bank_num));
                int_enb = readl_relaxed(gpio->base_addr +
                                        ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
-               int_sts &= ~int_enb;
-               if (int_sts) {
-                       int offset;
-                       unsigned long pending = int_sts;
-
-                       for_each_set_bit(offset, &pending, 32) {
-                               unsigned int gpio_irq =
-                                       irq_find_mapping(gpio->chip.irqdomain,
-                                                       offset);
-                               generic_handle_irq(gpio_irq);
-                       }
-               }
+               zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb);
        }
 
        chained_irq_exit(irqchip, desc);
@@ -501,7 +518,11 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc)
 
 static int __maybe_unused zynq_gpio_suspend(struct device *dev)
 {
-       if (!device_may_wakeup(dev))
+       struct platform_device *pdev = to_platform_device(dev);
+       int irq = platform_get_irq(pdev, 0);
+       struct irq_data *data = irq_get_irq_data(irq);
+
+       if (!irqd_is_wakeup_set(data))
                return pm_runtime_force_suspend(dev);
 
        return 0;
@@ -509,7 +530,11 @@ static int __maybe_unused zynq_gpio_suspend(struct device *dev)
 
 static int __maybe_unused zynq_gpio_resume(struct device *dev)
 {
-       if (!device_may_wakeup(dev))
+       struct platform_device *pdev = to_platform_device(dev);
+       int irq = platform_get_irq(pdev, 0);
+       struct irq_data *data = irq_get_irq_data(irq);
+
+       if (!irqd_is_wakeup_set(data))
                return pm_runtime_force_resume(dev);
 
        return 0;
@@ -570,7 +595,7 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
  */
 static int zynq_gpio_probe(struct platform_device *pdev)
 {
-       int ret, bank_num, irq;
+       int ret, bank_num;
        struct zynq_gpio *gpio;
        struct gpio_chip *chip;
        struct resource *res;
@@ -586,10 +611,10 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        if (IS_ERR(gpio->base_addr))
                return PTR_ERR(gpio->base_addr);
 
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
+       gpio->irq = platform_get_irq(pdev, 0);
+       if (gpio->irq < 0) {
                dev_err(&pdev->dev, "invalid IRQ\n");
-               return irq;
+               return gpio->irq;
        }
 
        /* configure the gpio chip */
@@ -637,19 +662,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
                goto err_rm_gpiochip;
        }
 
-       gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, irq,
+       gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
                                     zynq_gpio_irqhandler);
 
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
-       device_set_wakeup_capable(&pdev->dev, 1);
-
        return 0;
 
 err_rm_gpiochip:
-       if (gpiochip_remove(chip))
-               dev_err(&pdev->dev, "Failed to remove gpio chip\n");
+       gpiochip_remove(chip);
 err_disable_clk:
        clk_disable_unprepare(gpio->clk);
 
@@ -664,16 +686,10 @@ err_disable_clk:
  */
 static int zynq_gpio_remove(struct platform_device *pdev)
 {
-       int ret;
        struct zynq_gpio *gpio = platform_get_drvdata(pdev);
 
        pm_runtime_get_sync(&pdev->dev);
-
-       ret = gpiochip_remove(&gpio->chip);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to remove gpio chip\n");
-               return ret;
-       }
+       gpiochip_remove(&gpio->chip);
        clk_disable_unprepare(gpio->clk);
        device_set_wakeup_capable(&pdev->dev, 0);
        return 0;
@@ -688,7 +704,6 @@ MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
 static struct platform_driver zynq_gpio_driver = {
        .driver = {
                .name = DRIVER_NAME,
-               .owner = THIS_MODULE,
                .pm = &zynq_gpio_dev_pm_ops,
                .of_match_table = zynq_gpio_of_match,
        },
index 687476f..05c6275 100644 (file)
@@ -25,10 +25,12 @@ struct acpi_gpio_event {
        acpi_handle handle;
        unsigned int pin;
        unsigned int irq;
+       struct gpio_desc *desc;
 };
 
 struct acpi_gpio_connection {
        struct list_head node;
+       unsigned int pin;
        struct gpio_desc *desc;
 };
 
@@ -143,14 +145,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        if (!handler)
                return AE_BAD_PARAMETER;
 
-       desc = gpiochip_get_desc(chip, pin);
+       desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
        if (IS_ERR(desc)) {
-               dev_err(chip->dev, "Failed to get GPIO descriptor\n");
-               return AE_ERROR;
-       }
-
-       ret = gpiochip_request_own_desc(desc, "ACPI:Event");
-       if (ret) {
                dev_err(chip->dev, "Failed to request GPIO\n");
                return AE_ERROR;
        }
@@ -197,6 +193,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        event->handle = evt_handle;
        event->irq = irq;
        event->pin = pin;
+       event->desc = desc;
 
        ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
                                   "ACPI:Event", event);
@@ -280,7 +277,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
                struct gpio_desc *desc;
 
                free_irq(event->irq, event);
-               desc = gpiochip_get_desc(chip, event->pin);
+               desc = event->desc;
                if (WARN_ON(IS_ERR(desc)))
                        continue;
                gpio_unlock_as_irq(chip, event->pin);
@@ -409,26 +406,20 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                struct gpio_desc *desc;
                bool found;
 
-               desc = gpiochip_get_desc(chip, pin);
-               if (IS_ERR(desc)) {
-                       status = AE_ERROR;
-                       goto out;
-               }
-
                mutex_lock(&achip->conn_lock);
 
                found = false;
                list_for_each_entry(conn, &achip->conns, node) {
-                       if (conn->desc == desc) {
+                       if (conn->pin == pin) {
                                found = true;
+                               desc = conn->desc;
                                break;
                        }
                }
                if (!found) {
-                       int ret;
-
-                       ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
-                       if (ret) {
+                       desc = gpiochip_request_own_desc(chip, pin,
+                                                        "ACPI:OpRegion");
+                       if (IS_ERR(desc)) {
                                status = AE_ERROR;
                                mutex_unlock(&achip->conn_lock);
                                goto out;
@@ -465,6 +456,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                                goto out;
                        }
 
+                       conn->pin = pin;
                        conn->desc = desc;
                        list_add_tail(&conn->node, &achip->conns);
                }
index c68d037..e8e98ca 100644 (file)
@@ -308,10 +308,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
  *
  * A gpio_chip with any GPIOs still requested may not be removed.
  */
-int gpiochip_remove(struct gpio_chip *chip)
+void gpiochip_remove(struct gpio_chip *chip)
 {
        unsigned long   flags;
-       int             status = 0;
        unsigned        id;
 
        acpi_gpiochip_remove(chip);
@@ -323,24 +322,15 @@ int gpiochip_remove(struct gpio_chip *chip)
        of_gpiochip_remove(chip);
 
        for (id = 0; id < chip->ngpio; id++) {
-               if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
-                       status = -EBUSY;
-                       break;
-               }
-       }
-       if (status == 0) {
-               for (id = 0; id < chip->ngpio; id++)
-                       chip->desc[id].chip = NULL;
-
-               list_del(&chip->list);
+               if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
+                       dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
        }
+       for (id = 0; id < chip->ngpio; id++)
+               chip->desc[id].chip = NULL;
 
+       list_del(&chip->list);
        spin_unlock_irqrestore(&gpio_lock, flags);
-
-       if (status == 0)
-               gpiochip_unexport(chip);
-
-       return status;
+       gpiochip_unexport(chip);
 }
 EXPORT_SYMBOL_GPL(gpiochip_remove);
 
@@ -395,30 +385,47 @@ static struct gpio_chip *find_chip_by_name(const char *name)
  */
 
 /**
- * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
- * @gpiochip: the gpiochip to add the irqchip to
- * @irqchip: the irqchip to add to the gpiochip
+ * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
+ * @gpiochip: the gpiochip to set the irqchip chain to
+ * @irqchip: the irqchip to chain to the gpiochip
  * @parent_irq: the irq number corresponding to the parent IRQ for this
  * chained irqchip
  * @parent_handler: the parent interrupt handler for the accumulated IRQ
- * coming out of the gpiochip
+ * coming out of the gpiochip. If the interrupt is nested rather than
+ * cascaded, pass NULL in this handler argument
  */
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
                                  struct irq_chip *irqchip,
                                  int parent_irq,
                                  irq_flow_handler_t parent_handler)
 {
-       if (gpiochip->can_sleep) {
-               chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n");
+       unsigned int offset;
+
+       if (!gpiochip->irqdomain) {
+               chip_err(gpiochip, "called %s before setting up irqchip\n",
+                        __func__);
                return;
        }
 
-       /*
-        * The parent irqchip is already using the chip_data for this
-        * irqchip, so our callbacks simply use the handler_data.
-        */
-       irq_set_handler_data(parent_irq, gpiochip);
-       irq_set_chained_handler(parent_irq, parent_handler);
+       if (parent_handler) {
+               if (gpiochip->can_sleep) {
+                       chip_err(gpiochip,
+                                "you cannot have chained interrupts on a "
+                                "chip that may sleep\n");
+                       return;
+               }
+               /*
+                * The parent irqchip is already using the chip_data for this
+                * irqchip, so our callbacks simply use the handler_data.
+                */
+               irq_set_handler_data(parent_irq, gpiochip);
+               irq_set_chained_handler(parent_irq, parent_handler);
+       }
+
+       /* Set the parent IRQ for all affected IRQs */
+       for (offset = 0; offset < gpiochip->ngpio; offset++)
+               irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
+                              parent_irq);
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 
@@ -447,7 +454,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
        irq_set_lockdep_class(irq, &gpiochip_irq_lock_class);
        irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
        /* Chips that can sleep need nested thread handlers */
-       if (chip->can_sleep)
+       if (chip->can_sleep && !chip->irq_not_threaded)
                irq_set_nested_thread(irq, 1);
 #ifdef CONFIG_ARM
        set_irq_flags(irq, IRQF_VALID);
@@ -524,7 +531,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
        /* Remove all IRQ mappings and delete the domain */
        if (gpiochip->irqdomain) {
                for (offset = 0; offset < gpiochip->ngpio; offset++)
-                       irq_dispose_mapping(gpiochip->irq_base + offset);
+                       irq_dispose_mapping(
+                               irq_find_mapping(gpiochip->irqdomain, offset));
                irq_domain_remove(gpiochip->irqdomain);
        }
 
@@ -895,12 +903,22 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
  * allows the GPIO chip module to be unloaded as needed (we assume that the
  * GPIO chip driver handles freeing the GPIOs it has requested).
  */
-int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
+struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
+                                           const char *label)
 {
-       if (!desc || !desc->chip)
-               return -EINVAL;
+       struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
+       int err;
 
-       return __gpiod_request(desc, label);
+       if (IS_ERR(desc)) {
+               chip_err(chip, "failed to get GPIO descriptor\n");
+               return desc;
+       }
+
+       err = __gpiod_request(desc, label);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       return desc;
 }
 EXPORT_SYMBOL_GPL(gpiochip_request_own_desc);
 
@@ -1652,7 +1670,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
         * a result. In that case, use platform lookup as a fallback.
         */
        if (!desc || desc == ERR_PTR(-ENOENT)) {
-               dev_dbg(dev, "using lookup tables for GPIO lookup");
+               dev_dbg(dev, "using lookup tables for GPIO lookup\n");
                desc = gpiod_find(dev, con_id, idx, &lookupflags);
        }
 
index a822db5..3318de6 100644 (file)
@@ -1069,8 +1069,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        return ret;
 
 err_gpiochip_remove:
-       if (gpiochip_remove(&dev->gc) < 0)
-               hid_err(hdev, "error removing gpio chip\n");
+       gpiochip_remove(&dev->gc);
 err_free_i2c:
        i2c_del_adapter(&dev->adap);
 err_free_dev:
@@ -1089,8 +1088,7 @@ static void cp2112_remove(struct hid_device *hdev)
        struct cp2112_device *dev = hid_get_drvdata(hdev);
 
        sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
-       if (gpiochip_remove(&dev->gc))
-               hid_err(hdev, "unable to remove gpio chip\n");
+       gpiochip_remove(&dev->gc);
        i2c_del_adapter(&dev->adap);
        /* i2c_del_adapter has finished removing all i2c devices from our
         * adapter. Well behaved devices should no longer call our cp2112_xfer
index 5ef7fcf..b97ed44 100644 (file)
@@ -251,9 +251,7 @@ static void adp5588_gpio_remove(struct adp5588_kpad *kpad)
                        dev_warn(dev, "teardown failed %d\n", error);
        }
 
-       error = gpiochip_remove(&kpad->gc);
-       if (error)
-               dev_warn(dev, "gpiochip_remove failed %d\n", error);
+       gpiochip_remove(&kpad->gc);
 }
 #else
 static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
index 6329549..a452677 100644 (file)
@@ -567,9 +567,7 @@ static void adp5589_gpio_remove(struct adp5589_kpad *kpad)
                        dev_warn(dev, "teardown failed %d\n", error);
        }
 
-       error = gpiochip_remove(&kpad->gc);
-       if (error)
-               dev_warn(dev, "gpiochip_remove failed %d\n", error);
+       gpiochip_remove(&kpad->gc);
 }
 #else
 static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
index fce5906..1eb9d3c 100644 (file)
@@ -470,14 +470,10 @@ static int ad7879_gpio_add(struct ad7879 *ts,
 static void ad7879_gpio_remove(struct ad7879 *ts)
 {
        const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev);
-       int ret;
 
-       if (pdata->gpio_export) {
-               ret = gpiochip_remove(&ts->gc);
-               if (ret)
-                       dev_err(ts->dev, "failed to remove gpio %d\n",
-                               ts->gc.base);
-       }
+       if (pdata->gpio_export)
+               gpiochip_remove(&ts->gc);
+
 }
 #else
 static inline int ad7879_gpio_add(struct ad7879 *ts,
index 4a0e786..5a6363d 100644 (file)
@@ -319,14 +319,8 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
        }
 
 #ifdef CONFIG_LEDS_PCA9532_GPIO
-       if (data->gpio.dev) {
-               int err = gpiochip_remove(&data->gpio);
-               if (err) {
-                       dev_err(&data->client->dev, "%s failed, %d\n",
-                                               "gpiochip_remove()", err);
-                       return err;
-               }
-       }
+       if (data->gpio.dev)
+               gpiochip_remove(&data->gpio);
 #endif
 
        return 0;
index 3d9e267..20fa8e7 100644 (file)
@@ -667,11 +667,8 @@ static int tca6507_probe_gpios(struct i2c_client *client,
 
 static void tca6507_remove_gpio(struct tca6507_chip *tca)
 {
-       if (tca->gpio.ngpio) {
-               int err = gpiochip_remove(&tca->gpio);
-               dev_err(&tca->client->dev, "%s failed, %d\n",
-                       "gpiochip_remove()", err);
-       }
+       if (tca->gpio.ngpio)
+               gpiochip_remove(&tca->gpio);
 }
 #else /* CONFIG_GPIOLIB */
 static int tca6507_probe_gpios(struct i2c_client *client,
index 03930d5..51ef893 100644 (file)
@@ -584,18 +584,14 @@ static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
 static void cxd2820r_release(struct dvb_frontend *fe)
 {
        struct cxd2820r_priv *priv = fe->demodulator_priv;
-       int uninitialized_var(ret); /* silence compiler warning */
 
        dev_dbg(&priv->i2c->dev, "%s\n", __func__);
 
 #ifdef CONFIG_GPIOLIB
        /* remove GPIOs */
-       if (priv->gpio_chip.label) {
-               ret = gpiochip_remove(&priv->gpio_chip);
-               if (ret)
-                       dev_err(&priv->i2c->dev, "%s: gpiochip_remove() " \
-                                       "failed=%d\n", KBUILD_MODNAME, ret);
-       }
+       if (priv->gpio_chip.label)
+               gpiochip_remove(&priv->gpio_chip);
+
 #endif
        kfree(priv);
        return;
index 9fc4186..977bd3a 100644 (file)
@@ -605,7 +605,8 @@ static int asic3_gpio_remove(struct platform_device *pdev)
 {
        struct asic3 *asic = platform_get_drvdata(pdev);
 
-       return gpiochip_remove(&asic->gpio);
+       gpiochip_remove(&asic->gpio);
+       return 0;
 }
 
 static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
index 6bdb78c..adbbce0 100644 (file)
@@ -481,15 +481,9 @@ static int htcpld_register_chip_gpio(
 
        ret = gpiochip_add(&(chip->chip_in));
        if (ret) {
-               int error;
-
                dev_warn(dev, "Unable to register input GPIOs for 0x%x: %d\n",
                         plat_chip_data->addr, ret);
-
-               error = gpiochip_remove(&(chip->chip_out));
-               if (error)
-                       dev_warn(dev, "Error while trying to unregister gpio chip: %d\n", error);
-
+               gpiochip_remove(&(chip->chip_out));
                return ret;
        }
 
index 81e6d09..02027b7 100644 (file)
@@ -1047,7 +1047,6 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
        struct sm501_gpio *gpio = &sm->gpio;
        resource_size_t iobase = sm->io_res->start + SM501_GPIO;
        int ret;
-       int tmp;
 
        dev_dbg(sm->dev, "registering gpio block %08llx\n",
                (unsigned long long)iobase);
@@ -1086,11 +1085,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
        return 0;
 
  err_low_chip:
-       tmp = gpiochip_remove(&gpio->low.gpio);
-       if (tmp) {
-               dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
-               return ret;
-       }
+       gpiochip_remove(&gpio->low.gpio);
 
  err_mapped:
        iounmap(gpio->regs);
@@ -1105,18 +1100,12 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
 static void sm501_gpio_remove(struct sm501_devdata *sm)
 {
        struct sm501_gpio *gpio = &sm->gpio;
-       int ret;
 
        if (!sm->gpio.registered)
                return;
 
-       ret = gpiochip_remove(&gpio->low.gpio);
-       if (ret)
-               dev_err(sm->dev, "cannot remove low chip, cannot tidy up\n");
-
-       ret = gpiochip_remove(&gpio->high.gpio);
-       if (ret)
-               dev_err(sm->dev, "cannot remove high chip, cannot tidy up\n");
+       gpiochip_remove(&gpio->low.gpio);
+       gpiochip_remove(&gpio->high.gpio);
 
        iounmap(gpio->regs);
        release_resource(gpio->regs_res);
index 11c19e5..4fac16b 100644 (file)
@@ -607,7 +607,7 @@ static int tc6393xb_probe(struct platform_device *dev)
        struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
        struct tc6393xb *tc6393xb;
        struct resource *iomem, *rscr;
-       int ret, temp;
+       int ret;
 
        iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (!iomem)
@@ -714,7 +714,7 @@ err_setup:
 
 err_gpio_add:
        if (tc6393xb->gpio.base != -1)
-               temp = gpiochip_remove(&tc6393xb->gpio);
+               gpiochip_remove(&tc6393xb->gpio);
        tcpd->disable(dev);
 err_enable:
        clk_disable(tc6393xb->clk);
@@ -744,13 +744,8 @@ static int tc6393xb_remove(struct platform_device *dev)
 
        tc6393xb_detach_irq(dev);
 
-       if (tc6393xb->gpio.base != -1) {
-               ret = gpiochip_remove(&tc6393xb->gpio);
-               if (ret) {
-                       dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret);
-                       return ret;
-               }
-       }
+       if (tc6393xb->gpio.base != -1)
+               gpiochip_remove(&tc6393xb->gpio);
 
        ret = tcpd->disable(dev);
        clk_disable(tc6393xb->clk);
index 153d595..58ea9fd 100644 (file)
@@ -621,7 +621,6 @@ static void ucb1x00_remove(struct mcp *mcp)
        struct ucb1x00_plat_data *pdata = mcp->attached_device.platform_data;
        struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
        struct list_head *l, *n;
-       int ret;
 
        mutex_lock(&ucb1x00_mutex);
        list_del(&ucb->node);
@@ -631,11 +630,8 @@ static void ucb1x00_remove(struct mcp *mcp)
        }
        mutex_unlock(&ucb1x00_mutex);
 
-       if (ucb->gpio.base != -1) {
-               ret = gpiochip_remove(&ucb->gpio);
-               if (ret)
-                       dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
-       }
+       if (ucb->gpio.base != -1)
+               gpiochip_remove(&ucb->gpio);
 
        irq_set_chained_handler(ucb->irq, NULL);
        irq_free_descs(ucb->irq_base, 16);
index 64d06b5..c6a66de 100644 (file)
@@ -86,7 +86,7 @@ config PINCTRL_BCM2835
 
 config PINCTRL_BCM281XX
        bool "Broadcom BCM281xx pinctrl driver"
-       depends on OF
+       depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST)
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
index 47f4931..2289728 100644 (file)
@@ -1174,7 +1174,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        struct abx500_pinctrl *pct;
        unsigned int id = -1;
-       int ret, err;
+       int ret;
        int i;
 
        if (!np) {
@@ -1266,10 +1266,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
        return 0;
 
 out_rem_chip:
-       err = gpiochip_remove(&pct->chip);
-       if (err)
-               dev_info(&pdev->dev, "failed to remove gpiochip\n");
-
+       gpiochip_remove(&pct->chip);
        return ret;
 }
 
@@ -1280,15 +1277,8 @@ out_rem_chip:
 static int abx500_gpio_remove(struct platform_device *pdev)
 {
        struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
-       int ret;
-
-       ret = gpiochip_remove(&pct->chip);
-       if (ret < 0) {
-               dev_err(pct->dev, "unable to remove gpiochip: %d\n",
-                       ret);
-               return ret;
-       }
 
+       gpiochip_remove(&pct->chip);
        return 0;
 }
 
index 3c29d91..746db6a 100644 (file)
@@ -1276,7 +1276,7 @@ static int nmk_gpio_probe(struct platform_device *dev)
                                   IRQ_TYPE_EDGE_FALLING);
        if (ret) {
                dev_err(&dev->dev, "could not add irqchip\n");
-               ret = gpiochip_remove(&nmk_chip->chip);
+               gpiochip_remove(&nmk_chip->chip);
                return -ENODEV;
        }
        /* Then register the chain on the parent IRQ */
index d30dddd..e730935 100644 (file)
@@ -936,14 +936,8 @@ EXPORT_SYMBOL(msm_pinctrl_probe);
 int msm_pinctrl_remove(struct platform_device *pdev)
 {
        struct msm_pinctrl *pctrl = platform_get_drvdata(pdev);
-       int ret;
-
-       ret = gpiochip_remove(&pctrl->chip);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to remove gpiochip\n");
-               return ret;
-       }
 
+       gpiochip_remove(&pctrl->chip);
        pinctrl_unregister(pctrl->pctrl);
 
        unregister_restart_handler(&pctrl->restart_nb);
index b995ec2..88acfc0 100644 (file)
@@ -874,11 +874,7 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev,
 static int exynos5440_gpiolib_unregister(struct platform_device *pdev,
                                struct exynos5440_pinctrl_priv_data *priv)
 {
-       int ret = gpiochip_remove(priv->gc);
-       if (ret) {
-               dev_err(&pdev->dev, "gpio chip remove failed\n");
-               return ret;
-       }
+       gpiochip_remove(priv->gc);
        return 0;
 }
 
index 4a47691..2d37c8f 100644 (file)
@@ -946,9 +946,7 @@ static int samsung_gpiolib_register(struct platform_device *pdev,
 
 fail:
        for (--i, --bank; i >= 0; --i, --bank)
-               if (gpiochip_remove(&bank->gpio_chip))
-                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
-                                                       bank->gpio_chip.label);
+               gpiochip_remove(&bank->gpio_chip);
        return ret;
 }
 
@@ -958,16 +956,11 @@ static int samsung_gpiolib_unregister(struct platform_device *pdev,
 {
        struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
        struct samsung_pin_bank *bank = ctrl->pin_banks;
-       int ret = 0;
        int i;
 
-       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank)
-               ret = gpiochip_remove(&bank->gpio_chip);
-
-       if (ret)
-               dev_err(&pdev->dev, "gpio chip remove failed\n");
-
-       return ret;
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+               gpiochip_remove(&bank->gpio_chip);
+       return 0;
 }
 
 static const struct of_device_id samsung_pinctrl_dt_match[];
index b713bd5..4c831fd 100644 (file)
@@ -891,8 +891,7 @@ static int sirfsoc_gpio_probe(struct device_node *np)
 
 out_no_range:
 out_banks:
-       if (gpiochip_remove(&sgpio->chip.gc))
-               dev_err(&pdev->dev, "could not remove gpio chip\n");
+       gpiochip_remove(&sgpio->chip.gc);
 out:
        iounmap(regs);
        return err;
index 40929e4..04fed00 100644 (file)
@@ -301,8 +301,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
        return 0;
 
 fail_request_irq:
-       if (gpiochip_remove(&pg->chip))
-               pr_err("gpiochip_remove failed\n");
+       gpiochip_remove(&pg->chip);
 err:
        iounmap(pg->gpiointr);
 err2:
index ba350d2..f92e266 100644 (file)
@@ -475,7 +475,8 @@ int ssb_gpio_unregister(struct ssb_bus *bus)
 {
        if (ssb_chipco_available(&bus->chipco) ||
            ssb_extif_available(&bus->extif)) {
-               return gpiochip_remove(&bus->gpio);
+               gpiochip_remove(&bus->gpio);
+               return 0;
        } else {
                SSB_WARN_ON(1);
        }
index d8a118d..c64776f 100644 (file)
@@ -221,9 +221,7 @@ void pio2_gpio_exit(struct pio2_card *card)
 {
        const char *label = card->gc.label;
 
-       if (gpiochip_remove(&(card->gc)))
-               dev_err(&card->vdev->dev, "Failed to remove GPIO\n");
-
+       gpiochip_remove(&(card->gc));
        kfree(label);
 }
 
index 82573dc..0041a64 100644 (file)
@@ -1248,7 +1248,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
        mutex_destroy(&s->mutex);
 
 #ifdef CONFIG_GPIOLIB
-       WARN_ON(gpiochip_remove(&s->gpio));
+       gpiochip_remove(&s->gpio);
 
 out_uart:
 #endif
@@ -1263,12 +1263,10 @@ out_clk:
 static int max310x_remove(struct device *dev)
 {
        struct max310x_port *s = dev_get_drvdata(dev);
-       int i, ret = 0;
+       int i;
 
 #ifdef CONFIG_GPIOLIB
-       ret = gpiochip_remove(&s->gpio);
-       if (ret)
-               return ret;
+       gpiochip_remove(&s->gpio);
 #endif
 
        for (i = 0; i < s->uart.nr; i++) {
@@ -1282,7 +1280,7 @@ static int max310x_remove(struct device *dev)
        uart_unregister_driver(&s->uart);
        clk_disable_unprepare(s->clk);
 
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id __maybe_unused max310x_dt_ids[] = {
index 3284c31..6246820 100644 (file)
@@ -1157,7 +1157,7 @@ static int sc16is7xx_probe(struct device *dev,
 
 #ifdef CONFIG_GPIOLIB
        if (devtype->nr_gpio)
-               WARN_ON(gpiochip_remove(&s->gpio));
+               gpiochip_remove(&s->gpio);
 
 out_uart:
 #endif
@@ -1173,14 +1173,11 @@ out_clk:
 static int sc16is7xx_remove(struct device *dev)
 {
        struct sc16is7xx_port *s = dev_get_drvdata(dev);
-       int i, ret = 0;
+       int i;
 
 #ifdef CONFIG_GPIOLIB
-       if (s->devtype->nr_gpio) {
-               ret = gpiochip_remove(&s->gpio);
-               if (ret)
-                       return ret;
-       }
+       if (s->devtype->nr_gpio)
+               gpiochip_remove(&s->gpio);
 #endif
 
        for (i = 0; i < s->uart.nr; i++) {
@@ -1195,7 +1192,7 @@ static int sc16is7xx_remove(struct device *dev)
        if (!IS_ERR(s->clk))
                clk_disable_unprepare(s->clk);
 
-       return ret;
+       return 0;
 }
 
 static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
index e408679..6f433b8 100644 (file)
@@ -270,7 +270,7 @@ static int viafb_gpio_probe(struct platform_device *platdev)
 static int viafb_gpio_remove(struct platform_device *platdev)
 {
        unsigned long flags;
-       int ret = 0, i;
+       int i;
 
 #ifdef CONFIG_PM
        viafb_pm_unregister(&viafb_gpio_pm_hooks);
@@ -280,11 +280,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
         * Get unregistered.
         */
        if (viafb_gpio_config.gpio_chip.ngpio > 0) {
-               ret = gpiochip_remove(&viafb_gpio_config.gpio_chip);
-               if (ret) { /* Somebody still using it? */
-                       printk(KERN_ERR "Viafb: GPIO remove failed\n");
-                       return ret;
-               }
+               gpiochip_remove(&viafb_gpio_config.gpio_chip);
        }
        /*
         * Disable the ports.
@@ -294,7 +290,7 @@ static int viafb_gpio_remove(struct platform_device *platdev)
                viafb_gpio_disable(viafb_gpio_config.active_gpios[i]);
        viafb_gpio_config.gpio_chip.ngpio = 0;
        spin_unlock_irqrestore(&viafb_gpio_config.vdev->reg_lock, flags);
-       return ret;
+       return 0;
 }
 
 static struct platform_driver via_gpio_driver = {
index c1d4105..383ade1 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 #ifndef ARCH_NR_GPIOS
-#define ARCH_NR_GPIOS          256
+#define ARCH_NR_GPIOS          512
 #endif
 
 /*
index c5e41da..249db30 100644 (file)
@@ -56,6 +56,8 @@ struct seq_file;
  *     as the chip access may sleep when e.g. reading out the IRQ status
  *     registers.
  * @exported: flags if the gpiochip is exported for use from sysfs. Private.
+ * @irq_not_threaded: flag must be set if @can_sleep is set but the
+ *     IRQs don't need to be threaded
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -101,6 +103,7 @@ struct gpio_chip {
        struct gpio_desc        *desc;
        const char              *const *names;
        bool                    can_sleep;
+       bool                    irq_not_threaded;
        bool                    exported;
 
 #ifdef CONFIG_GPIOLIB_IRQCHIP
@@ -141,7 +144,7 @@ extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 
 /* add/remove chips */
 extern int gpiochip_add(struct gpio_chip *chip);
-extern int gpiochip_remove(struct gpio_chip *chip);
+extern void gpiochip_remove(struct gpio_chip *chip);
 extern struct gpio_chip *gpiochip_find(void *data,
                              int (*match)(struct gpio_chip *chip, void *data));
 
@@ -166,7 +169,8 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
 
 #endif /* CONFIG_GPIOLIB_IRQCHIP */
 
-int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
+struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
+                                           const char *label);
 void gpiochip_free_own_desc(struct gpio_desc *desc);
 
 #else /* CONFIG_GPIOLIB */
diff --git a/include/linux/platform_data/gpio-dwapb.h b/include/linux/platform_data/gpio-dwapb.h
new file mode 100644 (file)
index 0000000..28702c8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright(c) 2014 Intel Corporation.
+ *
+ * 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.
+ */
+
+#ifndef GPIO_DW_APB_H
+#define GPIO_DW_APB_H
+
+struct dwapb_port_property {
+       struct device_node *node;
+       const char      *name;
+       unsigned int    idx;
+       unsigned int    ngpio;
+       unsigned int    gpio_base;
+       unsigned int    irq;
+       bool            irq_shared;
+};
+
+struct dwapb_platform_data {
+       struct dwapb_port_property *properties;
+       unsigned int nports;
+};
+
+#endif
index 2d676d5..aa07d7b 100644 (file)
@@ -22,4 +22,22 @@ struct mcp23s08_platform_data {
         * base to base+15 (or base+31 for s17 variant).
         */
        unsigned        base;
+       /* Marks the device as a interrupt controller.
+        * NOTE: The interrupt functionality is only supported for i2c
+        * versions of the chips. The spi chips can also do the interrupts,
+        * but this is not supported by the linux driver yet.
+        */
+       bool            irq_controller;
+
+       /* Sets the mirror flag in the IOCON register. Devices
+        * with two interrupt outputs (these are the devices ending with 17 and
+        * those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and
+        * IO 8-15 are bank 2. These chips have two different interrupt outputs:
+        * One for bank 1 and another for bank 2. If irq-mirror is set, both
+        * interrupts are generated regardless of the bank that an input change
+        * occurred on. If it is not set, the interrupt are only generated for
+        * the bank they belong to.
+        * On devices with only one interrupt output this property is useless.
+        */
+       bool            mirror;
 };
index 7bb0d36..a01ad62 100644 (file)
@@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
 static void wm5100_free_gpio(struct i2c_client *i2c)
 {
        struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c);
-       int ret;
 
-       ret = gpiochip_remove(&wm5100->gpio_chip);
-       if (ret != 0)
-               dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret);
+       gpiochip_remove(&wm5100->gpio_chip);
 }
 #else
 static void wm5100_init_gpio(struct i2c_client *i2c)
index aa09848..c038b3e 100644 (file)
@@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
 
 static void wm8903_free_gpio(struct wm8903_priv *wm8903)
 {
-       int ret;
-
-       ret = gpiochip_remove(&wm8903->gpio_chip);
-       if (ret != 0)
-               dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret);
+       gpiochip_remove(&wm8903->gpio_chip);
 }
 #else
 static void wm8903_init_gpio(struct wm8903_priv *wm8903)
index 1098ae3..9077411 100644 (file)
@@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
 static void wm8962_free_gpio(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
-       ret = gpiochip_remove(&wm8962->gpio_chip);
-       if (ret != 0)
-               dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+       gpiochip_remove(&wm8962->gpio_chip);
 }
 #else
 static void wm8962_init_gpio(struct snd_soc_codec *codec)
index f16ff4f..b1dcc11 100644 (file)
@@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
 
 static void wm8996_free_gpio(struct wm8996_priv *wm8996)
 {
-       int ret;
-
-       ret = gpiochip_remove(&wm8996->gpio_chip);
-       if (ret != 0)
-               dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret);
+       gpiochip_remove(&wm8996->gpio_chip);
 }
 #else
 static void wm8996_init_gpio(struct wm8996_priv *wm8996)