Merge tag 'gpio-v4.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Jul 2017 19:40:27 +0000 (12:40 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Jul 2017 19:40:27 +0000 (12:40 -0700)
Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.13 series.

  Some administrativa:

  I have a slew of 8250 serial patches and the new IOT2040 serial+GPIO
  driver coming in through this tree, along with a whole bunch of Exar
  8250 fixes. These are ACKed by Greg and also hit drivers/platform/*
  where they are ACKed by Andy Shevchenko.

  Speaking about drivers/platform/* there is also a bunch of ACPI stuff
  coming through that route, again ACKed by Andy.

  The MCP23S08 changes are coming in here as well. You already have the
  commits in your tree, so this is just a result of sharing an immutable
  branch between pin control and GPIO.

  Core:
   - Export add/remove for lookup tables so that modules can export GPIO
     descriptor tables.
   - Handle GPIO sleep states: it is now possible to flag that a GPIO
     line may loose its state during suspend/resume of the system to
     save power. This is used in the Wolfson Micro Arizona driver.
   - ACPI-based GPIO was tightened up a lot around the edges.
   - Use bitmap_fill() to speed up a loop.

  New drivers:
   - Exar XRA1403 SPI-based GPIO.
   - MVEBU driver now supports Armada 7K and 8K.
   - LP87565 PMIC GPIO.
   - Renesas R-CAR R8A7743 (RZ/G1M).
   - The new IOT2040 8250 serial/GPIO also comes in through this
     changeset.

  Substantial driver changes:
   - Seriously fix the Exar 8250 GPIO portions to work.
   - The MCP23S08 was moved out to a pin control driver.
   - Convert MEVEBU to use regmap for register access.
   - Drop Vulcan support from the Broadcom driver.
   - Serious cleanup and improvement of the mockup driver, giving us a
     better test coverage.

  Misc:
   - Lots of janitorial clean up.
   - A bunch of documentation fixes"

* tag 'gpio-v4.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (70 commits)
  serial: exar: Add support for IOT2040 device
  gpio-exar/8250-exar: Make set of exported GPIOs configurable
  platform: Accept const properties
  serial: exar: Factor out platform hooks
  gpio-exar/8250-exar: Rearrange gpiochip parenthood
  gpio: exar: Fix iomap request
  gpio-exar/8250-exar: Do not even instantiate a GPIO device for Commtech cards
  serial: uapi: Add support for bus termination
  gpio: rcar: Add R8A7743 (RZ/G1M) support
  gpio: gpio-wcove: Fix GPIO control register offset calculation
  gpio: lp87565: Add support for GPIO
  gpio: dwapb: fix missing first irq for edgeboth irq type
  MAINTAINERS: Take maintainership for GPIO ACPI support
  gpio: exar: Fix reading of directions and values
  gpio: exar: Allocate resources on behalf of the platform device
  gpio-exar/8250-exar: Fix passing in of parent PCI device
  gpio: mockup: use devm_kcalloc() where applicable
  gpio: mockup: add myself as author
  gpio: mockup: improve the error message
  gpio: mockup: don't return magic numbers from probe()
  ...

52 files changed:
Documentation/acpi/gpio-properties.txt
Documentation/devicetree/bindings/gpio/gpio.txt
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
MAINTAINERS
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/stargate2.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/mips/ath79/mach-pb44.c
drivers/base/platform.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-adp5588.c
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-exar.c
drivers/gpio/gpio-lp87565.c [new file with mode: 0644]
drivers/gpio/gpio-max732x.c
drivers/gpio/gpio-merrifield.c
drivers/gpio/gpio-ml-ioh.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-pcf857x.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-sta2x11.c
drivers/gpio/gpio-wcove.c
drivers/gpio/gpio-xra1403.c [new file with mode: 0644]
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/input/keyboard/adp5588-keys.c
drivers/pnp/pnpacpi/rsparser.c
drivers/tty/serial/8250/8250_exar.c
include/dt-bindings/gpio/gpio.h
include/linux/acpi.h
include/linux/gpio/driver.h
include/linux/gpio/machine.h
include/linux/i2c/adp5588.h [deleted file]
include/linux/i2c/max732x.h [deleted file]
include/linux/i2c/pcf857x.h [deleted file]
include/linux/of_gpio.h
include/linux/platform_data/adp5588.h [new file with mode: 0644]
include/linux/platform_data/max732x.h [new file with mode: 0644]
include/linux/platform_data/pcf857x.h [new file with mode: 0644]
include/linux/platform_device.h

index 2aff034..88c65cb 100644 (file)
@@ -156,3 +156,68 @@ pointed to by its first argument.  That should be done in the driver's .probe()
 routine.  On removal, the driver should unregister its GPIO mapping table by
 calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
 table was previously registered.
+
+Using the _CRS fallback
+-----------------------
+
+If a device does not have _DSD or the driver does not create ACPI GPIO
+mapping, the Linux GPIO framework refuses to return any GPIOs. This is
+because the driver does not know what it actually gets. For example if we
+have a device like below:
+
+  Device (BTH)
+  {
+      Name (_HID, ...)
+
+      Name (_CRS, ResourceTemplate () {
+          GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
+                  "\\_SB.GPO0", 0, ResourceConsumer) {15}
+          GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone,
+                  "\\_SB.GPO0", 0, ResourceConsumer) {27}
+      })
+  }
+
+The driver might expect to get the right GPIO when it does:
+
+  desc = gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+
+but since there is no way to know the mapping between "reset" and
+the GpioIo() in _CRS desc will hold ERR_PTR(-ENOENT).
+
+The driver author can solve this by passing the mapping explictly
+(the recommended way and documented in the above chapter).
+
+The ACPI GPIO mapping tables should not contaminate drivers that are not
+knowing about which exact device they are servicing on. It implies that
+the ACPI GPIO mapping tables are hardly linked to ACPI ID and certain
+objects, as listed in the above chapter, of the device in question.
+
+Getting GPIO descriptor
+-----------------------
+
+There are two main approaches to get GPIO resource from ACPI:
+       desc = gpiod_get(dev, connection_id, flags);
+       desc = gpiod_get_index(dev, connection_id, index, flags);
+
+We may consider two different cases here, i.e. when connection ID is
+provided and otherwise.
+
+Case 1:
+       desc = gpiod_get(dev, "non-null-connection-id", flags);
+       desc = gpiod_get_index(dev, "non-null-connection-id", index, flags);
+
+Case 2:
+       desc = gpiod_get(dev, NULL, flags);
+       desc = gpiod_get_index(dev, NULL, index, flags);
+
+Case 1 assumes that corresponding ACPI device description must have
+defined device properties and will prevent to getting any GPIO resources
+otherwise.
+
+Case 2 explicitly tells GPIO core to look for resources in _CRS.
+
+Be aware that gpiod_get_index() in cases 1 and 2, assuming that there
+are two versions of ACPI device description provided and no mapping is
+present in the driver, will return different resources. That's why a
+certain driver has to handle them carefully as explained in previous
+chapter.
index 84ede03..802402f 100644 (file)
@@ -74,11 +74,14 @@ GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
 Optional standard bitfield specifiers for the last cell:
 
 - Bit 0: 0 means active high, 1 means active low
-- Bit 1: 1 means single-ended wiring, see:
+- Bit 1: 0 mean push-pull wiring, see:
+           https://en.wikipedia.org/wiki/Push-pull_output
+         1 means single-ended wiring, see:
            https://en.wikipedia.org/wiki/Single-ended_triode
-          When used with active-low, this means open drain/collector, see:
+- Bit 2: 0 means open-source, 1 means open drain, see:
            https://en.wikipedia.org/wiki/Open_collector
-          When used with active-high, this means open source/emitter
+- Bit 3: 0 means the output should be maintained during sleep/low-power mode
+         1 means the output state can be lost during sleep/low-power mode
 
 1.1) GPIO specifier best practices
 ----------------------------------
@@ -282,8 +285,8 @@ Example 1:
        };
 
 Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
-pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's
-pins 50..59.
+pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's
+pins 50..69.
 
 Example 2:
 
index 7c1ab3b..6826a37 100644 (file)
@@ -3,6 +3,7 @@
 Required Properties:
 
   - compatible: should contain one of the following.
+    - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
     - "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller.
     - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
     - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
index 101af87..cb79977 100644 (file)
@@ -5747,6 +5747,15 @@ F:       include/asm-generic/gpio.h
 F:     include/uapi/linux/gpio.h
 F:     tools/gpio/
 
+GPIO ACPI SUPPORT
+M:     Mika Westerberg <mika.westerberg@linux.intel.com>
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+L:     linux-gpio@vger.kernel.org
+L:     linux-acpi@vger.kernel.org
+S:     Maintained
+F:     Documentation/acpi/gpio-properties.txt
+F:     drivers/gpio/gpiolib-acpi.c
+
 GRE DEMULTIPLEXER DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
 L:     netdev@vger.kernel.org
@@ -12026,6 +12035,13 @@ S:     Maintained
 F:     drivers/media/platform/davinci/
 F:     include/media/davinci/
 
+TI DAVINCI SERIES GPIO DRIVER
+M:     Keerthy <j-keerthy@ti.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/gpio-davinci.txt
+F:     drivers/gpio/gpio-davinci.c
+
 TI AM437X VPFE DRIVER
 M:     "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -14338,6 +14354,14 @@ L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/char/xillybus/
 
+XRA1403 GPIO EXPANDER
+M:     Nandor Han <nandor.han@ge.com>
+M:     Semi Malinen <semi.malinen@ge.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-xra1403.c
+F:     Documentation/devicetree/bindings/gpio/gpio-xra1403.txt
+
 XTENSA XTFPGA PLATFORM SUPPORT
 M:     Max Filippov <jcmvbkbc@gmail.com>
 L:     linux-xtensa@linux-xtensa.org
index 5807562..f673cd7 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 #include <linux/platform_data/at24.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
index 20f1874..70e00db 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 #include <linux/platform_data/at24.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 055e947..1d76e74 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/at24.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 
 #include <media/i2c/tvp514x.h>
 #include <media/i2c/adv7343.h>
index d452a49..1467c1d 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/types.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/physmap.h>
index 051c554..fae38fd 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/i2c.h>
 #include <linux/leds.h>
 #include <linux/mfd/da903x.h>
-#include <linux/i2c/max732x.h>
+#include <linux/platform_data/max732x.h>
 #include <linux/i2c/pxa-i2c.h>
 
 #include <asm/types.h>
index 7b6610e..2d45d18 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/mtd/partitions.h>
 
 #include <linux/i2c/pxa-i2c.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 #include <linux/platform_data/at24.h>
 #include <linux/smc91x.h>
 #include <linux/gpio.h>
index eaec7b4..24985e6 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/usb/isp1362.h>
 #endif
 #include <linux/i2c.h>
-#include <linux/i2c/adp5588.h>
+#include <linux/platform_data/adp5588.h>
 #include <linux/etherdevice.h>
 #include <linux/ata_platform.h>
 #include <linux/irq.h>
index 67b980d..be78298 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 
 #include "machtypes.h"
 #include "dev-gpio-buttons.h"
index 97332d0..d1bd992 100644 (file)
@@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_data);
  * platform device is released.
  */
 int platform_device_add_properties(struct platform_device *pdev,
-                                  struct property_entry *properties)
+                                  const struct property_entry *properties)
 {
        return device_add_properties(&pdev->dev, properties);
 }
index 395c85d..f235eae 100644 (file)
@@ -337,9 +337,10 @@ config GPIO_MPC8XXX
 
 config GPIO_MVEBU
        def_bool y
-       depends on PLAT_ORION
+       depends on PLAT_ORION || ARCH_MVEBU
        depends on OF_GPIO
        select GENERIC_IRQ_CHIP
+       select REGMAP_MMIO
 
 config GPIO_MXC
        def_bool y
@@ -515,12 +516,13 @@ config GPIO_XILINX
 
 config GPIO_XLP
        tristate "Netlogic XLP GPIO support"
-       depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || ARCH_THUNDER2 || COMPILE_TEST)
+       depends on OF_GPIO && (CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST)
        select GPIOLIB_IRQCHIP
        help
          This driver provides support for GPIO interface on Netlogic XLP MIPS64
          SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX,
-         XLP9XX and XLP5XX.
+         XLP9XX and XLP5XX. The same GPIO controller block is also present in
+         Cavium's ThunderX2 CN99XX SoCs.
 
          If unsure, say N.
 
@@ -963,6 +965,16 @@ config GPIO_LP873X
          This driver can also be built as a module. If so, the module will be
           called gpio-lp873x.
 
+config GPIO_LP87565
+       tristate "TI LP87565 GPIO"
+       depends on MFD_TI_LP87565
+       help
+         This driver supports the GPIO on TI Lp873565 PMICs. 3 GPIOs are present
+         on LP87565 PMICs.
+
+         This driver can also be built as a module. If so, the module will be
+         called gpio-lp87565.
+
 config GPIO_MAX77620
        tristate "GPIO support for PMIC MAX77620 and MAX20024"
        depends on MFD_MAX77620
@@ -1236,6 +1248,12 @@ config GPIO_PISOSR
          GPIO driver for SPI compatible parallel-in/serial-out shift
          registers. These are input only devices.
 
+config GPIO_XRA1403
+       tristate "EXAR XRA1403 16-bit GPIO expander"
+       select REGMAP_SPI
+       help
+         GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander.
+
 endmenu
 
 menu "USB GPIO expanders"
index 845f990..a9fda6c 100644 (file)
@@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_LP3943)     += gpio-lp3943.o
 obj-$(CONFIG_GPIO_LPC18XX)     += gpio-lpc18xx.o
 obj-$(CONFIG_ARCH_LPC32XX)     += gpio-lpc32xx.o
 obj-$(CONFIG_GPIO_LP873X)      += gpio-lp873x.o
+obj-$(CONFIG_GPIO_LP87565)     += gpio-lp87565.o
 obj-$(CONFIG_GPIO_LYNXPOINT)   += gpio-lynxpoint.o
 obj-$(CONFIG_GPIO_MAX730X)     += gpio-max730x.o
 obj-$(CONFIG_GPIO_MAX7300)     += gpio-max7300.o
@@ -141,6 +142,7 @@ obj-$(CONFIG_GPIO_XGENE)    += gpio-xgene.o
 obj-$(CONFIG_GPIO_XGENE_SB)    += gpio-xgene-sb.o
 obj-$(CONFIG_GPIO_XILINX)      += gpio-xilinx.o
 obj-$(CONFIG_GPIO_XLP)         += gpio-xlp.o
+obj-$(CONFIG_GPIO_XRA1403)     += gpio-xra1403.o
 obj-$(CONFIG_GPIO_XTENSA)      += gpio-xtensa.o
 obj-$(CONFIG_GPIO_ZEVIO)       += gpio-zevio.o
 obj-$(CONFIG_GPIO_ZYNQ)                += gpio-zynq.o
index c0f718b..e717f8d 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
-#include <linux/i2c/adp5588.h>
+#include <linux/platform_data/adp5588.h>
 
 #define DRV_NAME       "adp5588-gpio"
 
index cd23fd7..d4e6ba0 100644 (file)
@@ -33,9 +33,23 @@ static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
        struct arizona *arizona = arizona_gpio->arizona;
+       bool persistent = gpiochip_line_is_persistent(chip, offset);
+       bool change;
+       int ret;
 
-       return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
-                                 ARIZONA_GPN_DIR, ARIZONA_GPN_DIR);
+       ret = regmap_update_bits_check(arizona->regmap,
+                                      ARIZONA_GPIO1_CTRL + offset,
+                                      ARIZONA_GPN_DIR, ARIZONA_GPN_DIR,
+                                      &change);
+       if (ret < 0)
+               return ret;
+
+       if (change && persistent) {
+               pm_runtime_mark_last_busy(chip->parent);
+               pm_runtime_put_autosuspend(chip->parent);
+       }
+
+       return 0;
 }
 
 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -85,6 +99,21 @@ static int arizona_gpio_direction_out(struct gpio_chip *chip,
 {
        struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
        struct arizona *arizona = arizona_gpio->arizona;
+       bool persistent = gpiochip_line_is_persistent(chip, offset);
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_GPIO1_CTRL + offset, &val);
+       if (ret < 0)
+               return ret;
+
+       if ((val & ARIZONA_GPN_DIR) && persistent) {
+               ret = pm_runtime_get_sync(chip->parent);
+               if (ret < 0) {
+                       dev_err(chip->parent, "Failed to resume: %d\n", ret);
+                       return ret;
+               }
+       }
 
        if (value)
                value = ARIZONA_GPN_LVL;
@@ -158,6 +187,8 @@ static int arizona_gpio_probe(struct platform_device *pdev)
        else
                arizona_gpio->gpio_chip.base = -1;
 
+       pm_runtime_enable(&pdev->dev);
+
        ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip,
                                     arizona_gpio);
        if (ret < 0) {
index ac17357..65cb359 100644 (file)
@@ -437,6 +437,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
 {
        unsigned        gpio, bank;
        int             irq;
+       int             ret;
        struct clk      *clk;
        u32             binten = 0;
        unsigned        ngpio, bank_irq;
@@ -480,12 +481,15 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
                       PTR_ERR(clk));
                return PTR_ERR(clk);
        }
-       clk_prepare_enable(clk);
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
 
        if (!pdata->gpio_unbanked) {
                irq = devm_irq_alloc_descs(dev, -1, 0, ngpio, 0);
                if (irq < 0) {
                        dev_err(dev, "Couldn't allocate IRQ numbers\n");
+                       clk_disable_unprepare(clk);
                        return irq;
                }
 
@@ -494,6 +498,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
                                                        chips);
                if (!irq_domain) {
                        dev_err(dev, "Couldn't register an IRQ domain\n");
+                       clk_disable_unprepare(clk);
                        return -ENODEV;
                }
        }
@@ -562,8 +567,10 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
                                       sizeof(struct
                                              davinci_gpio_irq_data),
                                              GFP_KERNEL);
-               if (!irqdata)
+               if (!irqdata) {
+                       clk_disable_unprepare(clk);
                        return -ENOMEM;
+               }
 
                irqdata->regs = g;
                irqdata->bank_num = bank;
index f051c45..c07ada9 100644 (file)
@@ -288,7 +288,8 @@ static int dwapb_irq_set_type(struct irq_data *d, u32 type)
        irq_setup_alt_chip(d, type);
 
        dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
-       dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
+       if (type != IRQ_TYPE_EDGE_BOTH)
+               dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
        spin_unlock_irqrestore(&gc->bgpio_lock, flags);
 
        return 0;
index 0810767..fb8d304 100644 (file)
@@ -31,6 +31,7 @@ struct exar_gpio_chip {
        int index;
        void __iomem *regs;
        char name[20];
+       unsigned int first_pin;
 };
 
 static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
@@ -51,11 +52,12 @@ static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
 static int exar_set_direction(struct gpio_chip *chip, int direction,
                              unsigned int offset)
 {
-       unsigned int bank = offset / 8;
-       unsigned int addr;
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
+               EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
 
-       addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
-       exar_update(chip, addr, direction, offset % 8);
+       exar_update(chip, addr, direction, bit);
        return 0;
 }
 
@@ -68,41 +70,38 @@ static int exar_get(struct gpio_chip *chip, unsigned int reg)
        value = readb(exar_gpio->regs + reg);
        mutex_unlock(&exar_gpio->lock);
 
-       return !!value;
+       return value;
 }
 
 static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
 {
-       unsigned int bank = offset / 8;
-       unsigned int addr;
-       int val;
-
-       addr = bank ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
-       val = exar_get(chip, addr) >> (offset % 8);
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
+               EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
 
-       return !!val;
+       return !!(exar_get(chip, addr) & BIT(bit));
 }
 
 static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
 {
-       unsigned int bank = offset / 8;
-       unsigned int addr;
-       int val;
-
-       addr = bank ? EXAR_OFFSET_MPIOLVL_LO : EXAR_OFFSET_MPIOLVL_HI;
-       val = exar_get(chip, addr) >> (offset % 8);
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
+               EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
 
-       return !!val;
+       return !!(exar_get(chip, addr) & BIT(bit));
 }
 
 static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
                           int value)
 {
-       unsigned int bank = offset / 8;
-       unsigned int addr;
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
+               EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
 
-       addr = bank ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
-       exar_update(chip, addr, value, offset % 8);
+       exar_update(chip, addr, value, bit);
 }
 
 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
@@ -119,27 +118,30 @@ static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
 
 static int gpio_exar_probe(struct platform_device *pdev)
 {
-       struct pci_dev *pcidev = platform_get_drvdata(pdev);
+       struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
        struct exar_gpio_chip *exar_gpio;
+       u32 first_pin, ngpios;
        void __iomem *p;
        int index, ret;
 
-       if (pcidev->vendor != PCI_VENDOR_ID_EXAR)
-               return -ENODEV;
-
        /*
-        * Map the pci device to get the register addresses.
-        * We will need to read and write those registers to control
-        * the GPIO pins.
-        * Using managed functions will save us from unmaping on exit.
-        * As the device is enabled using managed functions by the
-        * UART driver we can also use managed functions here.
+        * The UART driver must have mapped region 0 prior to registering this
+        * device - use it.
         */
-       p = pcim_iomap(pcidev, 0, 0);
+       p = pcim_iomap_table(pcidev)[0];
        if (!p)
                return -ENOMEM;
 
-       exar_gpio = devm_kzalloc(&pcidev->dev, sizeof(*exar_gpio), GFP_KERNEL);
+       ret = device_property_read_u32(&pdev->dev, "linux,first-pin",
+                                      &first_pin);
+       if (ret)
+               return ret;
+
+       ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios);
+       if (ret)
+               return ret;
+
+       exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
        if (!exar_gpio)
                return -ENOMEM;
 
@@ -149,18 +151,19 @@ static int gpio_exar_probe(struct platform_device *pdev)
 
        sprintf(exar_gpio->name, "exar_gpio%d", index);
        exar_gpio->gpio_chip.label = exar_gpio->name;
-       exar_gpio->gpio_chip.parent = &pcidev->dev;
+       exar_gpio->gpio_chip.parent = &pdev->dev;
        exar_gpio->gpio_chip.direction_output = exar_direction_output;
        exar_gpio->gpio_chip.direction_input = exar_direction_input;
        exar_gpio->gpio_chip.get_direction = exar_get_direction;
        exar_gpio->gpio_chip.get = exar_get_value;
        exar_gpio->gpio_chip.set = exar_set_value;
        exar_gpio->gpio_chip.base = -1;
-       exar_gpio->gpio_chip.ngpio = 16;
+       exar_gpio->gpio_chip.ngpio = ngpios;
        exar_gpio->regs = p;
        exar_gpio->index = index;
+       exar_gpio->first_pin = first_pin;
 
-       ret = devm_gpiochip_add_data(&pcidev->dev,
+       ret = devm_gpiochip_add_data(&pdev->dev,
                                     &exar_gpio->gpio_chip, exar_gpio);
        if (ret)
                goto err_destroy;
diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c
new file mode 100644 (file)
index 0000000..6313c50
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ *     Keerthy <j-keerthy@ti.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 "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.
+ *
+ * Based on the LP873X driver
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/lp87565.h>
+
+struct lp87565_gpio {
+       struct gpio_chip chip;
+       struct regmap *map;
+};
+
+static int lp87565_gpio_get_direction(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(chip);
+       int ret, val;
+
+       ret = regmap_read(gpio->map, LP87565_REG_GPIO_CONFIG, &val);
+       if (ret < 0)
+               return ret;
+
+       return !(val & BIT(offset));
+}
+
+static int lp87565_gpio_direction_input(struct gpio_chip *chip,
+                                       unsigned int offset)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(chip);
+
+       return regmap_update_bits(gpio->map,
+                                 LP87565_REG_GPIO_CONFIG,
+                                 BIT(offset), 0);
+}
+
+static int lp87565_gpio_direction_output(struct gpio_chip *chip,
+                                        unsigned int offset, int value)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(chip);
+
+       return regmap_update_bits(gpio->map,
+                                 LP87565_REG_GPIO_CONFIG,
+                                 BIT(offset), !value ? BIT(offset) : 0);
+}
+
+static int lp87565_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(chip);
+       int ret, val;
+
+       ret = regmap_read(gpio->map, LP87565_REG_GPIO_IN, &val);
+       if (ret < 0)
+               return ret;
+
+       return !!(val & BIT(offset));
+}
+
+static void lp87565_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                            int value)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(chip);
+
+       regmap_update_bits(gpio->map, LP87565_REG_GPIO_OUT,
+                          BIT(offset), value ? BIT(offset) : 0);
+}
+
+static int lp87565_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(gc);
+       int ret;
+
+       switch (offset) {
+       case 0:
+       case 1:
+       case 2:
+               /*
+                * MUX can program the pin to be in EN1/2/3 pin mode
+                * Or GPIO1/2/3 mode.
+                * Setup the GPIO*_SEL MUX to GPIO mode
+                */
+               ret = regmap_update_bits(gpio->map,
+                                        LP87565_REG_PIN_FUNCTION,
+                                        BIT(offset), BIT(offset));
+               if (ret)
+                       return ret;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int lp87565_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+                                  unsigned long config)
+{
+       struct lp87565_gpio *gpio = gpiochip_get_data(gc);
+
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+               return regmap_update_bits(gpio->map,
+                                         LP87565_REG_GPIO_CONFIG,
+                                         BIT(offset +
+                                             __ffs(LP87565_GOIO1_OD)),
+                                         BIT(offset +
+                                             __ffs(LP87565_GOIO1_OD)));
+       case PIN_CONFIG_DRIVE_PUSH_PULL:
+               return regmap_update_bits(gpio->map,
+                                         LP87565_REG_GPIO_CONFIG,
+                                         BIT(offset +
+                                             __ffs(LP87565_GOIO1_OD)), 0);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static const struct gpio_chip template_chip = {
+       .label                  = "lp87565-gpio",
+       .owner                  = THIS_MODULE,
+       .request                = lp87565_gpio_request,
+       .get_direction          = lp87565_gpio_get_direction,
+       .direction_input        = lp87565_gpio_direction_input,
+       .direction_output       = lp87565_gpio_direction_output,
+       .get                    = lp87565_gpio_get,
+       .set                    = lp87565_gpio_set,
+       .set_config             = lp87565_gpio_set_config,
+       .base                   = -1,
+       .ngpio                  = 3,
+       .can_sleep              = true,
+};
+
+static int lp87565_gpio_probe(struct platform_device *pdev)
+{
+       struct lp87565_gpio *gpio;
+       struct lp87565 *lp87565;
+       int ret;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       lp87565 = dev_get_drvdata(pdev->dev.parent);
+       gpio->chip = template_chip;
+       gpio->chip.parent = lp87565->dev;
+       gpio->map = lp87565->regmap;
+
+       ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct platform_device_id lp87565_gpio_id_table[] = {
+       { "lp87565-q1-gpio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, lp87565_gpio_id_table);
+
+static struct platform_driver lp87565_gpio_driver = {
+       .driver = {
+               .name = "lp87565-gpio",
+       },
+       .probe = lp87565_gpio_probe,
+       .id_table = lp87565_gpio_id_table,
+};
+module_platform_driver(lp87565_gpio_driver);
+
+MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("LP87565 GPIO driver");
+MODULE_LICENSE("GPL v2");
index 4ea4c6a..7f4d26c 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
-#include <linux/i2c/max732x.h>
+#include <linux/platform_data/max732x.h>
 #include <linux/of.h>
 
 
index 9dbdc36..ec85602 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/bitops.h>
 #include <linux/gpio/driver.h>
-#include <linux/gpio.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index 78896a8..74fdce0 100644 (file)
@@ -385,14 +385,18 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
        return ret;
 }
 
-static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
-                               unsigned int irq_start, unsigned int num)
+static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
+                                      unsigned int irq_start,
+                                      unsigned int num)
 {
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
 
        gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base,
                                    handle_simple_irq);
+       if (!gc)
+               return -ENOMEM;
+
        gc->private = chip;
        ct = gc->chip_types;
 
@@ -404,6 +408,8 @@ static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
 
        irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
                               IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+
+       return 0;
 }
 
 static int ioh_gpio_probe(struct pci_dev *pdev,
@@ -468,7 +474,11 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
                        goto err_gpiochip_add;
                }
                chip->irq_base = irq_base;
-               ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]);
+
+               ret = ioh_gpio_alloc_generic_chip(chip,
+                                                 irq_base, num_ports[j]);
+               if (ret)
+                       goto err_gpiochip_add;
        }
 
        chip = chip_save;
index c6dadac..a6565e1 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2014  Kamlakant Patel <kamlakant.patel@broadcom.com>
  * Copyright (C) 2015-2016  Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
+ * Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
 
 #define GPIO_MOCKUP_NAME       "gpio-mockup"
 #define        GPIO_MOCKUP_MAX_GC      10
+/*
+ * We're storing two values per chip: the GPIO base and the number
+ * of GPIO lines.
+ */
+#define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2)
 
 enum {
-       DIR_IN = 0,
-       DIR_OUT,
+       GPIO_MOCKUP_DIR_OUT = 0,
+       GPIO_MOCKUP_DIR_IN = 1,
 };
 
 /*
@@ -41,6 +47,7 @@ enum {
 struct gpio_mockup_line_status {
        int dir;
        bool value;
+       bool irq_enabled;
 };
 
 struct gpio_mockup_irq_context {
@@ -61,7 +68,7 @@ struct gpio_mockup_dbgfs_private {
        int offset;
 };
 
-static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_GC << 1];
+static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
 static int gpio_mockup_params_nr;
 module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
 
@@ -93,7 +100,7 @@ static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset,
        struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
 
        gpio_mockup_set(gc, offset, value);
-       chip->lines[offset].dir = DIR_OUT;
+       chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT;
 
        return 0;
 }
@@ -102,7 +109,7 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
 {
        struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
 
-       chip->lines[offset].dir = DIR_IN;
+       chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN;
 
        return 0;
 }
@@ -121,7 +128,7 @@ static int gpio_mockup_name_lines(struct device *dev,
        char **names;
        int i;
 
-       names = devm_kzalloc(dev, sizeof(char *) * gc->ngpio, GFP_KERNEL);
+       names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL);
        if (!names)
                return -ENOMEM;
 
@@ -142,12 +149,21 @@ static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
        return chip->irq_base + offset;
 }
 
-/*
- * While we should generally support irqmask and irqunmask, this driver is
- * for testing purposes only so we don't care.
- */
-static void gpio_mockup_irqmask(struct irq_data *d) { }
-static void gpio_mockup_irqunmask(struct irq_data *d) { }
+static void gpio_mockup_irqmask(struct irq_data *data)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+       chip->lines[data->irq - gc->irq_base].irq_enabled = false;
+}
+
+static void gpio_mockup_irqunmask(struct irq_data *data)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+       chip->lines[data->irq - gc->irq_base].irq_enabled = true;
+}
 
 static struct irq_chip gpio_mockup_irqchip = {
        .name           = GPIO_MOCKUP_NAME,
@@ -178,6 +194,7 @@ static int gpio_mockup_irqchip_setup(struct device *dev,
 
        for (i = 0; i < gc->ngpio; i++) {
                irq_set_chip(irq_base + i, gc->irqchip);
+               irq_set_chip_data(irq_base + i, gc);
                irq_set_handler(irq_base + i, &handle_simple_irq);
                irq_modify_status(irq_base + i,
                                  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
@@ -197,8 +214,13 @@ static ssize_t gpio_mockup_event_write(struct file *file,
        struct seq_file *sfile;
        struct gpio_desc *desc;
        struct gpio_chip *gc;
-       int val;
-       char buf;
+       int rv, val;
+
+       rv = kstrtoint_from_user(usr_buf, size, 0, &val);
+       if (rv)
+               return rv;
+       if (val != 0 && val != 1)
+               return -EINVAL;
 
        sfile = file->private_data;
        priv = sfile->private;
@@ -206,19 +228,11 @@ static ssize_t gpio_mockup_event_write(struct file *file,
        chip = priv->chip;
        gc = &chip->gc;
 
-       if (copy_from_user(&buf, usr_buf, 1))
-               return -EFAULT;
-
-       if (buf == '0')
-               val = 0;
-       else if (buf == '1')
-               val = 1;
-       else
-               return -EINVAL;
-
-       gpiod_set_value_cansleep(desc, val);
-       priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
-       irq_work_queue(&priv->chip->irq_ctx.work);
+       if (chip->lines[priv->offset].irq_enabled) {
+               gpiod_set_value_cansleep(desc, val);
+               priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
+               irq_work_queue(&priv->chip->irq_ctx.work);
+       }
 
        return size;
 }
@@ -294,8 +308,8 @@ static int gpio_mockup_add(struct device *dev,
        gc->get_direction = gpio_mockup_get_direction;
        gc->to_irq = gpio_mockup_to_irq;
 
-       chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio,
-                                  GFP_KERNEL);
+       chip->lines = devm_kcalloc(dev, gc->ngpio,
+                                  sizeof(*chip->lines), GFP_KERNEL);
        if (!chip->lines)
                return -ENOMEM;
 
@@ -321,23 +335,24 @@ static int gpio_mockup_add(struct device *dev,
 
 static int gpio_mockup_probe(struct platform_device *pdev)
 {
-       struct gpio_mockup_chip *chips;
+       int ret, i, base, ngpio, num_chips;
        struct device *dev = &pdev->dev;
-       int ret, i, base, ngpio;
+       struct gpio_mockup_chip *chips;
        char *chip_name;
 
-       if (gpio_mockup_params_nr < 2)
+       if (gpio_mockup_params_nr < 2 || (gpio_mockup_params_nr % 2))
                return -EINVAL;
 
-       chips = devm_kzalloc(dev,
-                            sizeof(*chips) * (gpio_mockup_params_nr >> 1),
-                            GFP_KERNEL);
+       /* Each chip is described by two values. */
+       num_chips = gpio_mockup_params_nr / 2;
+
+       chips = devm_kcalloc(dev, num_chips, sizeof(*chips), GFP_KERNEL);
        if (!chips)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, chips);
 
-       for (i = 0; i < gpio_mockup_params_nr >> 1; i++) {
+       for (i = 0; i < num_chips; i++) {
                base = gpio_mockup_ranges[i * 2];
 
                if (base == -1)
@@ -355,18 +370,16 @@ static int gpio_mockup_probe(struct platform_device *pdev)
                        ret = gpio_mockup_add(dev, &chips[i],
                                              chip_name, base, ngpio);
                } else {
-                       ret = -1;
+                       ret = -EINVAL;
                }
 
                if (ret) {
-                       dev_err(dev, "gpio<%d..%d> add failed\n",
-                               base, base < 0 ? ngpio : base + ngpio);
+                       dev_err(dev,
+                               "adding gpiochip failed: %d (base: %d, ngpio: %d)\n",
+                               ret, base, base < 0 ? ngpio : base + ngpio);
 
                        return ret;
                }
-
-               dev_info(dev, "gpio<%d..%d> add successful!",
-                        base, base + ngpio);
        }
 
        return 0;
@@ -420,5 +433,6 @@ module_exit(mock_device_exit);
 
 MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
 MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
+MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
 MODULE_DESCRIPTION("GPIO Testing driver");
 MODULE_LICENSE("GPL v2");
index c83ea68..e338c37 100644 (file)
  *   interrupts.
  */
 
+#include <linux/bitops.h>
+#include <linux/clk.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
 #include <linux/irq.h>
-#include <linux/slab.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
-#include <linux/io.h>
-#include <linux/of_irq.h>
+#include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
-#include <linux/pwm.h>
-#include <linux/clk.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/consumer.h>
-#include <linux/irqchip/chained_irq.h>
 #include <linux/platform_device.h>
-#include <linux/bitops.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
 
 #include "gpiolib.h"
 
@@ -87,6 +89,7 @@
 #define MVEBU_GPIO_SOC_VARIANT_ORION   0x1
 #define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2
 #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3
+#define MVEBU_GPIO_SOC_VARIANT_A8K     0x4
 
 #define MVEBU_MAX_GPIO_PER_BANK                32
 
@@ -106,9 +109,9 @@ struct mvebu_pwm {
 
 struct mvebu_gpio_chip {
        struct gpio_chip   chip;
-       spinlock_t         lock;
-       void __iomem      *membase;
-       void __iomem      *percpu_membase;
+       struct regmap     *regs;
+       u32                offset;
+       struct regmap     *percpu_regs;
        int                irqbase;
        struct irq_domain *domain;
        int                soc_variant;
@@ -130,92 +133,152 @@ struct mvebu_gpio_chip {
  * Functions returning addresses of individual registers for a given
  * GPIO controller.
  */
-static void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
-{
-       return mvchip->membase + GPIO_OUT_OFF;
-}
 
-static void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
+static void mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip,
+                        struct regmap **map, unsigned int *offset)
 {
-       return mvchip->membase + GPIO_BLINK_EN_OFF;
-}
+       int cpu;
 
-static void __iomem *mvebu_gpioreg_blink_counter_select(struct mvebu_gpio_chip
-                                                       *mvchip)
-{
-       return mvchip->membase + GPIO_BLINK_CNT_SELECT_OFF;
+       switch (mvchip->soc_variant) {
+       case MVEBU_GPIO_SOC_VARIANT_ORION:
+       case MVEBU_GPIO_SOC_VARIANT_MV78200:
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               *map = mvchip->regs;
+               *offset = GPIO_EDGE_CAUSE_OFF + mvchip->offset;
+               break;
+       case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
+               cpu = smp_processor_id();
+               *map = mvchip->percpu_regs;
+               *offset = GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
+               break;
+       default:
+               BUG();
+       }
 }
 
-static void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
+static u32
+mvebu_gpio_read_edge_cause(struct mvebu_gpio_chip *mvchip)
 {
-       return mvchip->membase + GPIO_IO_CONF_OFF;
-}
+       struct regmap *map;
+       unsigned int offset;
+       u32 val;
 
-static void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip)
-{
-       return mvchip->membase + GPIO_IN_POL_OFF;
+       mvebu_gpioreg_edge_cause(mvchip, &map, &offset);
+       regmap_read(map, offset, &val);
+
+       return val;
 }
 
-static void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
+static void
+mvebu_gpio_write_edge_cause(struct mvebu_gpio_chip *mvchip, u32 val)
 {
-       return mvchip->membase + GPIO_DATA_IN_OFF;
+       struct regmap *map;
+       unsigned int offset;
+
+       mvebu_gpioreg_edge_cause(mvchip, &map, &offset);
+       regmap_write(map, offset, val);
 }
 
-static void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
+static inline void
+mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip,
+                       struct regmap **map, unsigned int *offset)
 {
        int cpu;
 
        switch (mvchip->soc_variant) {
        case MVEBU_GPIO_SOC_VARIANT_ORION:
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               *map = mvchip->regs;
+               *offset = GPIO_EDGE_MASK_OFF + mvchip->offset;
+               break;
        case MVEBU_GPIO_SOC_VARIANT_MV78200:
-               return mvchip->membase + GPIO_EDGE_CAUSE_OFF;
+               cpu = smp_processor_id();
+               *map = mvchip->regs;
+               *offset = GPIO_EDGE_MASK_MV78200_OFF(cpu);
+               break;
        case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
                cpu = smp_processor_id();
-               return mvchip->percpu_membase +
-                       GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
+               *map = mvchip->percpu_regs;
+               *offset = GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
+               break;
        default:
                BUG();
        }
 }
 
-static void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
+static u32
+mvebu_gpio_read_edge_mask(struct mvebu_gpio_chip *mvchip)
 {
-       int cpu;
+       struct regmap *map;
+       unsigned int offset;
+       u32 val;
 
-       switch (mvchip->soc_variant) {
-       case MVEBU_GPIO_SOC_VARIANT_ORION:
-               return mvchip->membase + GPIO_EDGE_MASK_OFF;
-       case MVEBU_GPIO_SOC_VARIANT_MV78200:
-               cpu = smp_processor_id();
-               return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu);
-       case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
-               cpu = smp_processor_id();
-               return mvchip->percpu_membase +
-                       GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
-       default:
-               BUG();
-       }
+       mvebu_gpioreg_edge_mask(mvchip, &map, &offset);
+       regmap_read(map, offset, &val);
+
+       return val;
 }
 
-static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
+static void
+mvebu_gpio_write_edge_mask(struct mvebu_gpio_chip *mvchip, u32 val)
+{
+       struct regmap *map;
+       unsigned int offset;
+
+       mvebu_gpioreg_edge_mask(mvchip, &map, &offset);
+       regmap_write(map, offset, val);
+}
+
+static void
+mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip,
+                        struct regmap **map, unsigned int *offset)
 {
        int cpu;
 
        switch (mvchip->soc_variant) {
        case MVEBU_GPIO_SOC_VARIANT_ORION:
-               return mvchip->membase + GPIO_LEVEL_MASK_OFF;
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               *map = mvchip->regs;
+               *offset = GPIO_LEVEL_MASK_OFF + mvchip->offset;
+               break;
        case MVEBU_GPIO_SOC_VARIANT_MV78200:
                cpu = smp_processor_id();
-               return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu);
+               *map = mvchip->regs;
+               *offset = GPIO_LEVEL_MASK_MV78200_OFF(cpu);
+               break;
        case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
                cpu = smp_processor_id();
-               return mvchip->percpu_membase +
-                       GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
+               *map = mvchip->percpu_regs;
+               *offset = GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
+               break;
        default:
                BUG();
        }
 }
 
+static u32
+mvebu_gpio_read_level_mask(struct mvebu_gpio_chip *mvchip)
+{
+       struct regmap *map;
+       unsigned int offset;
+       u32 val;
+
+       mvebu_gpioreg_level_mask(mvchip, &map, &offset);
+       regmap_read(map, offset, &val);
+
+       return val;
+}
+
+static void
+mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
+{
+       struct regmap *map;
+       unsigned int offset;
+
+       mvebu_gpioreg_level_mask(mvchip, &map, &offset);
+       regmap_write(map, offset, val);
+}
+
 /*
  * Functions returning addresses of individual registers for a given
  * PWM controller.
@@ -236,17 +299,9 @@ static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
 static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
 {
        struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
-       unsigned long flags;
-       u32 u;
 
-       spin_lock_irqsave(&mvchip->lock, flags);
-       u = readl_relaxed(mvebu_gpioreg_out(mvchip));
-       if (value)
-               u |= BIT(pin);
-       else
-               u &= ~BIT(pin);
-       writel_relaxed(u, mvebu_gpioreg_out(mvchip));
-       spin_unlock_irqrestore(&mvchip->lock, flags);
+       regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
+                          BIT(pin), value ? BIT(pin) : 0);
 }
 
 static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin)
@@ -254,11 +309,18 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin)
        struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
        u32 u;
 
-       if (readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin)) {
-               u = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) ^
-                       readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+       regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u);
+
+       if (u & BIT(pin)) {
+               u32 data_in, in_pol;
+
+               regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset,
+                           &data_in);
+               regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
+                           &in_pol);
+               u = data_in ^ in_pol;
        } else {
-               u = readl_relaxed(mvebu_gpioreg_out(mvchip));
+               regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &u);
        }
 
        return (u >> pin) & 1;
@@ -268,25 +330,15 @@ static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin,
                             int value)
 {
        struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
-       unsigned long flags;
-       u32 u;
 
-       spin_lock_irqsave(&mvchip->lock, flags);
-       u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
-       if (value)
-               u |= BIT(pin);
-       else
-               u &= ~BIT(pin);
-       writel_relaxed(u, mvebu_gpioreg_blink(mvchip));
-       spin_unlock_irqrestore(&mvchip->lock, flags);
+       regmap_update_bits(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
+                          BIT(pin), value ? BIT(pin) : 0);
 }
 
 static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
 {
        struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
-       unsigned long flags;
        int ret;
-       u32 u;
 
        /*
         * Check with the pinctrl driver whether this pin is usable as
@@ -296,11 +348,8 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
        if (ret)
                return ret;
 
-       spin_lock_irqsave(&mvchip->lock, flags);
-       u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
-       u |= BIT(pin);
-       writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
-       spin_unlock_irqrestore(&mvchip->lock, flags);
+       regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
+                          BIT(pin), BIT(pin));
 
        return 0;
 }
@@ -309,9 +358,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
                                       int value)
 {
        struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
-       unsigned long flags;
        int ret;
-       u32 u;
 
        /*
         * Check with the pinctrl driver whether this pin is usable as
@@ -324,11 +371,8 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
        mvebu_gpio_blink(chip, pin, 0);
        mvebu_gpio_set(chip, pin, value);
 
-       spin_lock_irqsave(&mvchip->lock, flags);
-       u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
-       u &= ~BIT(pin);
-       writel_relaxed(u, mvebu_gpioreg_io_conf(mvchip));
-       spin_unlock_irqrestore(&mvchip->lock, flags);
+       regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
+                          BIT(pin), 0);
 
        return 0;
 }
@@ -350,7 +394,7 @@ static void mvebu_gpio_irq_ack(struct irq_data *d)
        u32 mask = d->mask;
 
        irq_gc_lock(gc);
-       writel_relaxed(~mask, mvebu_gpioreg_edge_cause(mvchip));
+       mvebu_gpio_write_edge_cause(mvchip, ~mask);
        irq_gc_unlock(gc);
 }
 
@@ -363,8 +407,7 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
 
        irq_gc_lock(gc);
        ct->mask_cache_priv &= ~mask;
-
-       writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
+       mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
        irq_gc_unlock(gc);
 }
 
@@ -377,7 +420,7 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
 
        irq_gc_lock(gc);
        ct->mask_cache_priv |= mask;
-       writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
+       mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
        irq_gc_unlock(gc);
 }
 
@@ -390,7 +433,7 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d)
 
        irq_gc_lock(gc);
        ct->mask_cache_priv &= ~mask;
-       writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
+       mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
        irq_gc_unlock(gc);
 }
 
@@ -403,7 +446,7 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
 
        irq_gc_lock(gc);
        ct->mask_cache_priv |= mask;
-       writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
+       mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
        irq_gc_unlock(gc);
 }
 
@@ -443,8 +486,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
        pin = d->hwirq;
 
-       u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & BIT(pin);
-       if (!u)
+       regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u);
+       if ((u & BIT(pin)) == 0)
                return -EINVAL;
 
        type &= IRQ_TYPE_SENSE_MASK;
@@ -462,31 +505,35 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
        case IRQ_TYPE_LEVEL_HIGH:
-               u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
-               u &= ~BIT(pin);
-               writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+               regmap_update_bits(mvchip->regs,
+                                  GPIO_IN_POL_OFF + mvchip->offset,
+                                  BIT(pin), 0);
                break;
        case IRQ_TYPE_EDGE_FALLING:
        case IRQ_TYPE_LEVEL_LOW:
-               u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
-               u |= BIT(pin);
-               writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+               regmap_update_bits(mvchip->regs,
+                                  GPIO_IN_POL_OFF + mvchip->offset,
+                                  BIT(pin), BIT(pin));
                break;
        case IRQ_TYPE_EDGE_BOTH: {
-               u32 v;
+               u32 data_in, in_pol, val;
 
-               v = readl_relaxed(mvebu_gpioreg_in_pol(mvchip)) ^
-                       readl_relaxed(mvebu_gpioreg_data_in(mvchip));
+               regmap_read(mvchip->regs,
+                           GPIO_IN_POL_OFF + mvchip->offset, &in_pol);
+               regmap_read(mvchip->regs,
+                           GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
 
                /*
                 * set initial polarity based on current input level
                 */
-               u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
-               if (v & BIT(pin))
-                       u |= BIT(pin);          /* falling */
+               if ((data_in ^ in_pol) & BIT(pin))
+                       val = BIT(pin); /* falling */
                else
-                       u &= ~BIT(pin);         /* rising */
-               writel_relaxed(u, mvebu_gpioreg_in_pol(mvchip));
+                       val = 0; /* raising */
+
+               regmap_update_bits(mvchip->regs,
+                                  GPIO_IN_POL_OFF + mvchip->offset,
+                                  BIT(pin), val);
                break;
        }
        }
@@ -497,7 +544,7 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
 {
        struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       u32 cause, type;
+       u32 cause, type, data_in, level_mask, edge_cause, edge_mask;
        int i;
 
        if (mvchip == NULL)
@@ -505,10 +552,12 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
 
        chained_irq_enter(chip, desc);
 
-       cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
-               readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
-       cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
-               readl_relaxed(mvebu_gpioreg_edge_mask(mvchip));
+       regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
+       level_mask = mvebu_gpio_read_level_mask(mvchip);
+       edge_cause = mvebu_gpio_read_edge_cause(mvchip);
+       edge_mask  = mvebu_gpio_read_edge_mask(mvchip);
+
+       cause = (data_in ^ level_mask) | (edge_cause & edge_mask);
 
        for (i = 0; i < mvchip->chip.ngpio; i++) {
                int irq;
@@ -523,9 +572,13 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
                        /* Swap polarity (race with GPIO line) */
                        u32 polarity;
 
-                       polarity = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+                       regmap_read(mvchip->regs,
+                                   GPIO_IN_POL_OFF + mvchip->offset,
+                                   &polarity);
                        polarity ^= BIT(i);
-                       writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
+                       regmap_write(mvchip->regs,
+                                    GPIO_IN_POL_OFF + mvchip->offset,
+                                    polarity);
                }
 
                generic_handle_irq(irq);
@@ -628,7 +681,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
                        state->period = 1;
        }
 
-       u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
+       regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
        if (u)
                state->enabled = true;
        else
@@ -691,8 +744,8 @@ static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
 {
        struct mvebu_pwm *mvpwm = mvchip->mvpwm;
 
-       mvpwm->blink_select =
-               readl_relaxed(mvebu_gpioreg_blink_counter_select(mvchip));
+       regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
+                   &mvpwm->blink_select);
        mvpwm->blink_on_duration =
                readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
        mvpwm->blink_off_duration =
@@ -703,8 +756,8 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
 {
        struct mvebu_pwm *mvpwm = mvchip->mvpwm;
 
-       writel_relaxed(mvpwm->blink_select,
-                      mvebu_gpioreg_blink_counter_select(mvchip));
+       regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
+                    mvpwm->blink_select);
        writel_relaxed(mvpwm->blink_on_duration,
                       mvebu_pwmreg_blink_on_duration(mvpwm));
        writel_relaxed(mvpwm->blink_off_duration,
@@ -747,7 +800,8 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
                set = U32_MAX;
        else
                return -EINVAL;
-       writel_relaxed(set, mvebu_gpioreg_blink_counter_select(mvchip));
+       regmap_write(mvchip->regs,
+                    GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
 
        mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
        if (!mvpwm)
@@ -790,14 +844,14 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
        u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
        int i;
 
-       out     = readl_relaxed(mvebu_gpioreg_out(mvchip));
-       io_conf = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
-       blink   = readl_relaxed(mvebu_gpioreg_blink(mvchip));
-       in_pol  = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
-       data_in = readl_relaxed(mvebu_gpioreg_data_in(mvchip));
-       cause   = readl_relaxed(mvebu_gpioreg_edge_cause(mvchip));
-       edg_msk = readl_relaxed(mvebu_gpioreg_edge_mask(mvchip));
-       lvl_msk = readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
+       regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out);
+       regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &io_conf);
+       regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &blink);
+       regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, &in_pol);
+       regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
+       cause   = mvebu_gpio_read_edge_cause(mvchip);
+       edg_msk = mvebu_gpio_read_edge_mask(mvchip);
+       lvl_msk = mvebu_gpio_read_level_mask(mvchip);
 
        for (i = 0; i < chip->ngpio; i++) {
                const char *label;
@@ -855,6 +909,10 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
                .compatible = "marvell,armada-370-gpio",
                .data       = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
        },
+       {
+               .compatible = "marvell,armada-8k-gpio",
+               .data       = (void *) MVEBU_GPIO_SOC_VARIANT_A8K,
+       },
        {
                /* sentinel */
        },
@@ -865,36 +923,41 @@ static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
        struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
        int i;
 
-       mvchip->out_reg = readl(mvebu_gpioreg_out(mvchip));
-       mvchip->io_conf_reg = readl(mvebu_gpioreg_io_conf(mvchip));
-       mvchip->blink_en_reg = readl(mvebu_gpioreg_blink(mvchip));
-       mvchip->in_pol_reg = readl(mvebu_gpioreg_in_pol(mvchip));
+       regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
+                   &mvchip->out_reg);
+       regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
+                   &mvchip->io_conf_reg);
+       regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
+                   &mvchip->blink_en_reg);
+       regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
+                   &mvchip->in_pol_reg);
 
        switch (mvchip->soc_variant) {
        case MVEBU_GPIO_SOC_VARIANT_ORION:
-               mvchip->edge_mask_regs[0] =
-                       readl(mvchip->membase + GPIO_EDGE_MASK_OFF);
-               mvchip->level_mask_regs[0] =
-                       readl(mvchip->membase + GPIO_LEVEL_MASK_OFF);
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
+                           &mvchip->edge_mask_regs[0]);
+               regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
+                           &mvchip->level_mask_regs[0]);
                break;
        case MVEBU_GPIO_SOC_VARIANT_MV78200:
                for (i = 0; i < 2; i++) {
-                       mvchip->edge_mask_regs[i] =
-                               readl(mvchip->membase +
-                                     GPIO_EDGE_MASK_MV78200_OFF(i));
-                       mvchip->level_mask_regs[i] =
-                               readl(mvchip->membase +
-                                     GPIO_LEVEL_MASK_MV78200_OFF(i));
+                       regmap_read(mvchip->regs,
+                                   GPIO_EDGE_MASK_MV78200_OFF(i),
+                                   &mvchip->edge_mask_regs[i]);
+                       regmap_read(mvchip->regs,
+                                   GPIO_LEVEL_MASK_MV78200_OFF(i),
+                                   &mvchip->level_mask_regs[i]);
                }
                break;
        case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
                for (i = 0; i < 4; i++) {
-                       mvchip->edge_mask_regs[i] =
-                               readl(mvchip->membase +
-                                     GPIO_EDGE_MASK_ARMADAXP_OFF(i));
-                       mvchip->level_mask_regs[i] =
-                               readl(mvchip->membase +
-                                     GPIO_LEVEL_MASK_ARMADAXP_OFF(i));
+                       regmap_read(mvchip->regs,
+                                   GPIO_EDGE_MASK_ARMADAXP_OFF(i),
+                                   &mvchip->edge_mask_regs[i]);
+                       regmap_read(mvchip->regs,
+                                   GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
+                                   &mvchip->level_mask_regs[i]);
                }
                break;
        default:
@@ -912,35 +975,41 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
        struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
        int i;
 
-       writel(mvchip->out_reg, mvebu_gpioreg_out(mvchip));
-       writel(mvchip->io_conf_reg, mvebu_gpioreg_io_conf(mvchip));
-       writel(mvchip->blink_en_reg, mvebu_gpioreg_blink(mvchip));
-       writel(mvchip->in_pol_reg, mvebu_gpioreg_in_pol(mvchip));
+       regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
+                    mvchip->out_reg);
+       regmap_write(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
+                    mvchip->io_conf_reg);
+       regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
+                    mvchip->blink_en_reg);
+       regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
+                    mvchip->in_pol_reg);
 
        switch (mvchip->soc_variant) {
        case MVEBU_GPIO_SOC_VARIANT_ORION:
-               writel(mvchip->edge_mask_regs[0],
-                      mvchip->membase + GPIO_EDGE_MASK_OFF);
-               writel(mvchip->level_mask_regs[0],
-                      mvchip->membase + GPIO_LEVEL_MASK_OFF);
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
+                            mvchip->edge_mask_regs[0]);
+               regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
+                            mvchip->level_mask_regs[0]);
                break;
        case MVEBU_GPIO_SOC_VARIANT_MV78200:
                for (i = 0; i < 2; i++) {
-                       writel(mvchip->edge_mask_regs[i],
-                              mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(i));
-                       writel(mvchip->level_mask_regs[i],
-                              mvchip->membase +
-                              GPIO_LEVEL_MASK_MV78200_OFF(i));
+                       regmap_write(mvchip->regs,
+                                    GPIO_EDGE_MASK_MV78200_OFF(i),
+                                    mvchip->edge_mask_regs[i]);
+                       regmap_write(mvchip->regs,
+                                    GPIO_LEVEL_MASK_MV78200_OFF(i),
+                                    mvchip->level_mask_regs[i]);
                }
                break;
        case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
                for (i = 0; i < 4; i++) {
-                       writel(mvchip->edge_mask_regs[i],
-                              mvchip->membase +
-                              GPIO_EDGE_MASK_ARMADAXP_OFF(i));
-                       writel(mvchip->level_mask_regs[i],
-                              mvchip->membase +
-                              GPIO_LEVEL_MASK_ARMADAXP_OFF(i));
+                       regmap_write(mvchip->regs,
+                                    GPIO_EDGE_MASK_ARMADAXP_OFF(i),
+                                    mvchip->edge_mask_regs[i]);
+                       regmap_write(mvchip->regs,
+                                    GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
+                                    mvchip->level_mask_regs[i]);
                }
                break;
        default:
@@ -953,12 +1022,73 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
        return 0;
 }
 
+static const struct regmap_config mvebu_gpio_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+};
+
+static int mvebu_gpio_probe_raw(struct platform_device *pdev,
+                               struct mvebu_gpio_chip *mvchip)
+{
+       struct resource *res;
+       void __iomem *base;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       mvchip->regs = devm_regmap_init_mmio(&pdev->dev, base,
+                                            &mvebu_gpio_regmap_config);
+       if (IS_ERR(mvchip->regs))
+               return PTR_ERR(mvchip->regs);
+
+       /*
+        * For the legacy SoCs, the regmap directly maps to the GPIO
+        * registers, so no offset is needed.
+        */
+       mvchip->offset = 0;
+
+       /*
+        * The Armada XP has a second range of registers for the
+        * per-CPU registers
+        */
+       if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               base = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(base))
+                       return PTR_ERR(base);
+
+               mvchip->percpu_regs =
+                       devm_regmap_init_mmio(&pdev->dev, base,
+                                             &mvebu_gpio_regmap_config);
+               if (IS_ERR(mvchip->percpu_regs))
+                       return PTR_ERR(mvchip->percpu_regs);
+       }
+
+       return 0;
+}
+
+static int mvebu_gpio_probe_syscon(struct platform_device *pdev,
+                                  struct mvebu_gpio_chip *mvchip)
+{
+       mvchip->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);
+       if (IS_ERR(mvchip->regs))
+               return PTR_ERR(mvchip->regs);
+
+       if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int mvebu_gpio_probe(struct platform_device *pdev)
 {
        struct mvebu_gpio_chip *mvchip;
        const struct of_device_id *match;
        struct device_node *np = pdev->dev.of_node;
-       struct resource *res;
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
        unsigned int ngpios;
@@ -1016,53 +1146,47 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
        mvchip->chip.of_node = np;
        mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
 
-       spin_lock_init(&mvchip->lock);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mvchip->membase = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mvchip->membase))
-               return PTR_ERR(mvchip->membase);
+       if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K)
+               err = mvebu_gpio_probe_syscon(pdev, mvchip);
+       else
+               err = mvebu_gpio_probe_raw(pdev, mvchip);
 
-       /*
-        * The Armada XP has a second range of registers for the
-        * per-CPU registers
-        */
-       if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
-                                                              res);
-               if (IS_ERR(mvchip->percpu_membase))
-                       return PTR_ERR(mvchip->percpu_membase);
-       }
+       if (err)
+               return err;
 
        /*
         * Mask and clear GPIO interrupts.
         */
        switch (soc_variant) {
        case MVEBU_GPIO_SOC_VARIANT_ORION:
-               writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
-               writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
-               writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF);
+       case MVEBU_GPIO_SOC_VARIANT_A8K:
+               regmap_write(mvchip->regs,
+                            GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0);
+               regmap_write(mvchip->regs,
+                            GPIO_EDGE_MASK_OFF + mvchip->offset, 0);
+               regmap_write(mvchip->regs,
+                            GPIO_LEVEL_MASK_OFF + mvchip->offset, 0);
                break;
        case MVEBU_GPIO_SOC_VARIANT_MV78200:
-               writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
+               regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
                for (cpu = 0; cpu < 2; cpu++) {
-                       writel_relaxed(0, mvchip->membase +
-                                      GPIO_EDGE_MASK_MV78200_OFF(cpu));
-                       writel_relaxed(0, mvchip->membase +
-                                      GPIO_LEVEL_MASK_MV78200_OFF(cpu));
+                       regmap_write(mvchip->regs,
+                                    GPIO_EDGE_MASK_MV78200_OFF(cpu), 0);
+                       regmap_write(mvchip->regs,
+                                    GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0);
                }
                break;
        case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
-               writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
-               writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
-               writel_relaxed(0, mvchip->membase + GPIO_LEVEL_MASK_OFF);
+               regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
+               regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0);
+               regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0);
                for (cpu = 0; cpu < 4; cpu++) {
-                       writel_relaxed(0, mvchip->percpu_membase +
-                                      GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu));
-                       writel_relaxed(0, mvchip->percpu_membase +
-                                      GPIO_EDGE_MASK_ARMADAXP_OFF(cpu));
-                       writel_relaxed(0, mvchip->percpu_membase +
-                                      GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu));
+                       regmap_write(mvchip->percpu_regs,
+                                    GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0);
+                       regmap_write(mvchip->percpu_regs,
+                                    GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0);
+                       regmap_write(mvchip->percpu_regs,
+                                    GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0);
                }
                break;
        default:
index 8ddf930..a4fd78b 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <linux/gpio.h>
 #include <linux/i2c.h>
-#include <linux/i2c/pcf857x.h>
+#include <linux/platform_data/pcf857x.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
index 71bc6da..f6600f8 100644 (file)
@@ -331,14 +331,18 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
        return ret;
 }
 
-static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
-                               unsigned int irq_start, unsigned int num)
+static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
+                                      unsigned int irq_start,
+                                      unsigned int num)
 {
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
 
        gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base,
                                    handle_simple_irq);
+       if (!gc)
+               return -ENOMEM;
+
        gc->private = chip;
        ct = gc->chip_types;
 
@@ -349,6 +353,8 @@ static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
 
        irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
                               IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+
+       return 0;
 }
 
 static int pch_gpio_probe(struct pci_dev *pdev,
@@ -425,7 +431,10 @@ static int pch_gpio_probe(struct pci_dev *pdev,
                goto err_request_irq;
        }
 
-       pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
+       ret = pch_gpio_alloc_generic_chip(chip, irq_base,
+                                         gpio_pins[chip->ioh]);
+       if (ret)
+               goto err_request_irq;
 
 end:
        return 0;
index 31ad288..4a1536a 100644 (file)
@@ -344,6 +344,10 @@ static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
 
 static const struct of_device_id gpio_rcar_of_table[] = {
        {
+               .compatible = "renesas,gpio-r8a7743",
+               /* RZ/G1 GPIO is identical to R-Car Gen2. */
+               .data = &gpio_rcar_info_gen2,
+       }, {
                .compatible = "renesas,gpio-r8a7790",
                .data = &gpio_rcar_info_gen2,
        }, {
index 39df062..9e70516 100644 (file)
@@ -320,13 +320,16 @@ static irqreturn_t gsta_gpio_handler(int irq, void *dev_id)
        return ret;
 }
 
-static void gsta_alloc_irq_chip(struct gsta_gpio *chip)
+static int gsta_alloc_irq_chip(struct gsta_gpio *chip)
 {
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
 
        gc = irq_alloc_generic_chip(KBUILD_MODNAME, 1, chip->irq_base,
                                     chip->reg_base, handle_simple_irq);
+       if (!gc)
+               return -ENOMEM;
+
        gc->private = chip;
        ct = gc->chip_types;
 
@@ -350,6 +353,8 @@ static void gsta_alloc_irq_chip(struct gsta_gpio *chip)
                }
                gc->irq_cnt = i - gc->irq_base;
        }
+
+       return 0;
 }
 
 /* The platform device used here is instantiated by the MFD device */
@@ -400,7 +405,10 @@ static int gsta_probe(struct platform_device *dev)
                return err;
        }
        chip->irq_base = err;
-       gsta_alloc_irq_chip(chip);
+
+       err = gsta_alloc_irq_chip(chip);
+       if (err)
+               return err;
 
        err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler,
                               IRQF_SHARED, KBUILD_MODNAME, chip);
index 7b1bc20..37c103e 100644 (file)
@@ -108,19 +108,14 @@ struct wcove_gpio {
 static inline unsigned int to_reg(int gpio, enum ctrl_register reg_type)
 {
        unsigned int reg;
-       int bank;
 
-       if (gpio < BANK0_NR_PINS)
-               bank = 0;
-       else if (gpio < BANK0_NR_PINS + BANK1_NR_PINS)
-               bank = 1;
-       else
-               bank = 2;
+       if (gpio >= WCOVE_GPIO_NUM)
+               return -EOPNOTSUPP;
 
        if (reg_type == CTRL_IN)
-               reg = GPIO_IN_CTRL_BASE + bank;
+               reg = GPIO_IN_CTRL_BASE + gpio;
        else
-               reg = GPIO_OUT_CTRL_BASE + bank;
+               reg = GPIO_OUT_CTRL_BASE + gpio;
 
        return reg;
 }
@@ -145,7 +140,10 @@ static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
 
 static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio)
 {
-       unsigned int reg = to_reg(gpio, CTRL_IN);
+       int reg = to_reg(gpio, CTRL_IN);
+
+       if (reg < 0)
+               return;
 
        regmap_update_bits(wg->regmap, reg, CTLI_INTCNT_BE, wg->intcnt);
 }
@@ -153,27 +151,36 @@ static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio)
 static int wcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int reg = to_reg(gpio, CTRL_OUT);
+
+       if (reg < 0)
+               return 0;
 
-       return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT),
-                           CTLO_INPUT_SET);
+       return regmap_write(wg->regmap, reg, CTLO_INPUT_SET);
 }
 
 static int wcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio,
                                    int value)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int reg = to_reg(gpio, CTRL_OUT);
 
-       return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT),
-                           CTLO_OUTPUT_SET | value);
+       if (reg < 0)
+               return 0;
+
+       return regmap_write(wg->regmap, reg, CTLO_OUTPUT_SET | value);
 }
 
 static int wcove_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
        unsigned int val;
-       int ret;
+       int ret, reg = to_reg(gpio, CTRL_OUT);
+
+       if (reg < 0)
+               return 0;
 
-       ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &val);
+       ret = regmap_read(wg->regmap, reg, &val);
        if (ret)
                return ret;
 
@@ -184,9 +191,12 @@ static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
        unsigned int val;
-       int ret;
+       int ret, reg = to_reg(gpio, CTRL_IN);
+
+       if (reg < 0)
+               return 0;
 
-       ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &val);
+       ret = regmap_read(wg->regmap, reg, &val);
        if (ret)
                return ret;
 
@@ -197,25 +207,33 @@ static void wcove_gpio_set(struct gpio_chip *chip,
                                 unsigned int gpio, int value)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int reg = to_reg(gpio, CTRL_OUT);
+
+       if (reg < 0)
+               return;
 
        if (value)
-               regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
+               regmap_update_bits(wg->regmap, reg, 1, 1);
        else
-               regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
+               regmap_update_bits(wg->regmap, reg, 1, 0);
 }
 
 static int wcove_gpio_set_config(struct gpio_chip *chip, unsigned int gpio,
                                 unsigned long config)
 {
        struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int reg = to_reg(gpio, CTRL_OUT);
+
+       if (reg < 0)
+               return 0;
 
        switch (pinconf_to_config_param(config)) {
        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
-               return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
-                                               CTLO_DRV_MASK, CTLO_DRV_OD);
+               return regmap_update_bits(wg->regmap, reg, CTLO_DRV_MASK,
+                                         CTLO_DRV_OD);
        case PIN_CONFIG_DRIVE_PUSH_PULL:
-               return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
-                                               CTLO_DRV_MASK, CTLO_DRV_CMOS);
+               return regmap_update_bits(wg->regmap, reg, CTLO_DRV_MASK,
+                                         CTLO_DRV_CMOS);
        default:
                break;
        }
@@ -228,6 +246,9 @@ static int wcove_irq_type(struct irq_data *data, unsigned int type)
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct wcove_gpio *wg = gpiochip_get_data(chip);
 
+       if (data->hwirq >= WCOVE_GPIO_NUM)
+               return 0;
+
        switch (type) {
        case IRQ_TYPE_NONE:
                wg->intcnt = CTLI_INTCNT_DIS;
@@ -278,6 +299,9 @@ static void wcove_irq_unmask(struct irq_data *data)
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct wcove_gpio *wg = gpiochip_get_data(chip);
 
+       if (data->hwirq >= WCOVE_GPIO_NUM)
+               return;
+
        wg->set_irq_mask = false;
        wg->update |= UPDATE_IRQ_MASK;
 }
@@ -287,6 +311,9 @@ static void wcove_irq_mask(struct irq_data *data)
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct wcove_gpio *wg = gpiochip_get_data(chip);
 
+       if (data->hwirq >= WCOVE_GPIO_NUM)
+               return;
+
        wg->set_irq_mask = true;
        wg->update |= UPDATE_IRQ_MASK;
 }
diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c
new file mode 100644 (file)
index 0000000..0230e4b
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * GPIO driver for EXAR XRA1403 16-bit GPIO expander
+ *
+ * Copyright (c) 2017, General Electric Company
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/seq_file.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+
+/* XRA1403 registers */
+#define XRA_GSR   0x00 /* GPIO State */
+#define XRA_OCR   0x02 /* Output Control */
+#define XRA_PIR   0x04 /* Input Polarity Inversion */
+#define XRA_GCR   0x06 /* GPIO Configuration */
+#define XRA_PUR   0x08 /* Input Internal Pull-up Resistor Enable/Disable */
+#define XRA_IER   0x0A /* Input Interrupt Enable */
+#define XRA_TSCR  0x0C /* Output Three-State Control */
+#define XRA_ISR   0x0E /* Input Interrupt Status */
+#define XRA_REIR  0x10 /* Input Rising Edge Interrupt Enable */
+#define XRA_FEIR  0x12 /* Input Falling Edge Interrupt Enable */
+#define XRA_IFR   0x14 /* Input Filter Enable/Disable */
+
+struct xra1403 {
+       struct gpio_chip  chip;
+       struct regmap     *regmap;
+};
+
+static const struct regmap_config xra1403_regmap_cfg = {
+               .reg_bits = 7,
+               .pad_bits = 1,
+               .val_bits = 8,
+
+               .max_register = XRA_IFR | 0x01,
+};
+
+static unsigned int to_reg(unsigned int reg, unsigned int offset)
+{
+       return reg + (offset > 7);
+}
+
+static int xra1403_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+       struct xra1403 *xra = gpiochip_get_data(chip);
+
+       return regmap_update_bits(xra->regmap, to_reg(XRA_GCR, offset),
+                       BIT(offset % 8), BIT(offset % 8));
+}
+
+static int xra1403_direction_output(struct gpio_chip *chip, unsigned int offset,
+                                   int value)
+{
+       int ret;
+       struct xra1403 *xra = gpiochip_get_data(chip);
+
+       ret = regmap_update_bits(xra->regmap, to_reg(XRA_GCR, offset),
+                       BIT(offset % 8), 0);
+       if (ret)
+               return ret;
+
+       ret = regmap_update_bits(xra->regmap, to_reg(XRA_OCR, offset),
+                       BIT(offset % 8), value ? BIT(offset % 8) : 0);
+
+       return ret;
+}
+
+static int xra1403_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+       int ret;
+       unsigned int val;
+       struct xra1403 *xra = gpiochip_get_data(chip);
+
+       ret = regmap_read(xra->regmap, to_reg(XRA_GCR, offset), &val);
+       if (ret)
+               return ret;
+
+       return !!(val & BIT(offset % 8));
+}
+
+static int xra1403_get(struct gpio_chip *chip, unsigned int offset)
+{
+       int ret;
+       unsigned int val;
+       struct xra1403 *xra = gpiochip_get_data(chip);
+
+       ret = regmap_read(xra->regmap, to_reg(XRA_GSR, offset), &val);
+       if (ret)
+               return ret;
+
+       return !!(val & BIT(offset % 8));
+}
+
+static void xra1403_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+       int ret;
+       struct xra1403 *xra = gpiochip_get_data(chip);
+
+       ret = regmap_update_bits(xra->regmap, to_reg(XRA_OCR, offset),
+                       BIT(offset % 8), value ? BIT(offset % 8) : 0);
+       if (ret)
+               dev_err(chip->parent, "Failed to set pin: %d, ret: %d\n",
+                               offset, ret);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+       int reg;
+       struct xra1403 *xra = gpiochip_get_data(chip);
+       int value[xra1403_regmap_cfg.max_register];
+       int i;
+       unsigned int gcr;
+       unsigned int gsr;
+
+       seq_puts(s, "xra reg:");
+       for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++)
+               seq_printf(s, " %2.2x", reg);
+       seq_puts(s, "\n  value:");
+       for (reg = 0; reg < xra1403_regmap_cfg.max_register; reg++) {
+               regmap_read(xra->regmap, reg, &value[reg]);
+               seq_printf(s, " %2.2x", value[reg]);
+       }
+       seq_puts(s, "\n");
+
+       gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR];
+       gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR];
+       for (i = 0; i < chip->ngpio; i++) {
+               const char *label = gpiochip_is_requested(chip, i);
+
+               if (!label)
+                       continue;
+
+               seq_printf(s, " gpio-%-3d (%-12s) %s %s\n",
+                          chip->base + i, label,
+                          (gcr & BIT(i)) ? "in" : "out",
+                          (gsr & BIT(i)) ? "hi" : "lo");
+       }
+}
+#else
+#define xra1403_dbg_show NULL
+#endif
+
+static int xra1403_probe(struct spi_device *spi)
+{
+       struct xra1403 *xra;
+       struct gpio_desc *reset_gpio;
+       int ret;
+
+       xra = devm_kzalloc(&spi->dev, sizeof(*xra), GFP_KERNEL);
+       if (!xra)
+               return -ENOMEM;
+
+       /* bring the chip out of reset if reset pin is provided*/
+       reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
+       if (IS_ERR(reset_gpio))
+               dev_warn(&spi->dev, "Could not get reset-gpios\n");
+
+       xra->chip.direction_input = xra1403_direction_input;
+       xra->chip.direction_output = xra1403_direction_output;
+       xra->chip.get_direction = xra1403_get_direction;
+       xra->chip.get = xra1403_get;
+       xra->chip.set = xra1403_set;
+
+       xra->chip.dbg_show = xra1403_dbg_show;
+
+       xra->chip.ngpio = 16;
+       xra->chip.label = "xra1403";
+
+       xra->chip.base = -1;
+       xra->chip.can_sleep = true;
+       xra->chip.parent = &spi->dev;
+       xra->chip.owner = THIS_MODULE;
+
+       xra->regmap = devm_regmap_init_spi(spi, &xra1403_regmap_cfg);
+       if (IS_ERR(xra->regmap)) {
+               ret = PTR_ERR(xra->regmap);
+               dev_err(&spi->dev, "Failed to allocate regmap: %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
+       if (ret < 0) {
+               dev_err(&spi->dev, "Unable to register gpiochip\n");
+               return ret;
+       }
+
+       spi_set_drvdata(spi, xra);
+
+       return 0;
+}
+
+static const struct spi_device_id xra1403_ids[] = {
+       { "xra1403" },
+       {},
+};
+MODULE_DEVICE_TABLE(spi, xra1403_ids);
+
+static const struct of_device_id xra1403_spi_of_match[] = {
+       { .compatible = "exar,xra1403" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xra1403_spi_of_match);
+
+static struct spi_driver xra1403_driver = {
+       .probe    = xra1403_probe,
+       .id_table = xra1403_ids,
+       .driver   = {
+               .name           = "xra1403",
+               .of_match_table = of_match_ptr(xra1403_spi_of_match),
+       },
+};
+
+module_spi_driver(xra1403_driver);
+
+MODULE_AUTHOR("Nandor Han <nandor.han@ge.com>");
+MODULE_AUTHOR("Semi Malinen <semi.malinen@ge.com>");
+MODULE_DESCRIPTION("GPIO expander driver for EXAR XRA1403");
+MODULE_LICENSE("GPL v2");
index 6b4d10d..df08514 100644 (file)
@@ -96,8 +96,8 @@
 /* GPIO upper 16 bit mask */
 #define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
 
-/* For GPIO quirks */
-#define ZYNQ_GPIO_QUIRK_FOO    BIT(0)
+/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */
+#define ZYNQ_GPIO_QUIRK_IS_ZYNQ        BIT(0)
 
 /**
  * struct zynq_gpio - gpio device private data structure
@@ -135,6 +135,17 @@ struct zynq_platform_data {
 static struct irq_chip zynq_gpio_level_irqchip;
 static struct irq_chip zynq_gpio_edge_irqchip;
 
+/**
+ * zynq_gpio_is_zynq - test if HW is zynq or zynqmp
+ * @gpio:      Pointer to driver data struct
+ *
+ * Return: 0 if zynqmp, 1 if zynq.
+ */
+static int zynq_gpio_is_zynq(struct zynq_gpio *gpio)
+{
+       return !!(gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_IS_ZYNQ);
+}
+
 /**
  * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
  * for a given pin in the GPIO device
@@ -242,18 +253,16 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
 static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
 {
        u32 reg;
-       bool is_zynq_gpio;
        unsigned int bank_num, bank_pin_num;
        struct zynq_gpio *gpio = gpiochip_get_data(chip);
 
-       is_zynq_gpio = gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_FOO;
        zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
 
        /*
         * On zynq bank 0 pins 7 and 8 are special and cannot be used
         * as inputs.
         */
-       if (is_zynq_gpio && bank_num == 0 &&
+       if (zynq_gpio_is_zynq(gpio) && bank_num == 0 &&
                (bank_pin_num == 7 || bank_pin_num == 8))
                return -EINVAL;
 
@@ -637,7 +646,7 @@ static const struct zynq_platform_data zynqmp_gpio_def = {
 
 static const struct zynq_platform_data zynq_gpio_def = {
        .label = "zynq_gpio",
-       .quirks = ZYNQ_GPIO_QUIRK_FOO,
+       .quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ,
        .ngpio = ZYNQ_GPIO_NR_GPIOS,
        .max_bank = ZYNQ_GPIO_MAX_BANK,
        .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
@@ -651,9 +660,8 @@ static const struct zynq_platform_data zynq_gpio_def = {
 };
 
 static const struct of_device_id zynq_gpio_of_match[] = {
-       { .compatible = "xlnx,zynq-gpio-1.0", .data = (void *)&zynq_gpio_def },
-       { .compatible = "xlnx,zynqmp-gpio-1.0",
-                                       .data = (void *)&zynqmp_gpio_def },
+       { .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def },
+       { .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
        { /* end of table */ }
 };
 MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
index 8fa5fcd..c9b42dd 100644 (file)
@@ -165,6 +165,23 @@ static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
        /* The address of this function is used as a key. */
 }
 
+bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
+                               struct acpi_resource_gpio **agpio)
+{
+       struct acpi_resource_gpio *gpio;
+
+       if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+               return false;
+
+       gpio = &ares->data.gpio;
+       if (gpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
+               return false;
+
+       *agpio = gpio;
+       return true;
+}
+EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
+
 static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
                                                   void *context)
 {
@@ -178,11 +195,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
        unsigned long irqflags;
        int ret, pin, irq;
 
-       if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
-               return AE_OK;
-
-       agpio = &ares->data.gpio;
-       if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
+       if (!acpi_gpio_get_irq_resource(ares, &agpio))
                return AE_OK;
 
        handle = ACPI_HANDLE(chip->parent);
@@ -423,6 +436,59 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
        return false;
 }
 
+static enum gpiod_flags
+acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
+{
+       bool pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
+
+       switch (agpio->io_restriction) {
+       case ACPI_IO_RESTRICT_INPUT:
+               return GPIOD_IN;
+       case ACPI_IO_RESTRICT_OUTPUT:
+               /*
+                * ACPI GPIO resources don't contain an initial value for the
+                * GPIO. Therefore we deduce that value from the pull field
+                * instead. If the pin is pulled up we assume default to be
+                * high, otherwise low.
+                */
+               return pull_up ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+       default:
+               /*
+                * Assume that the BIOS has configured the direction and pull
+                * accordingly.
+                */
+               return GPIOD_ASIS;
+       }
+}
+
+int
+acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
+{
+       int ret = 0;
+
+       /*
+        * Check if the BIOS has IoRestriction with explicitly set direction
+        * and update @flags accordingly. Otherwise use whatever caller asked
+        * for.
+        */
+       if (update & GPIOD_FLAGS_BIT_DIR_SET) {
+               enum gpiod_flags diff = *flags ^ update;
+
+               /*
+                * Check if caller supplied incompatible GPIO initialization
+                * flags.
+                *
+                * Return %-EINVAL to notify that firmware has different
+                * settings and we are going to use them.
+                */
+               if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) ||
+                   ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL)))
+                       ret = -EINVAL;
+               *flags = update;
+       }
+       return ret;
+}
+
 struct acpi_gpio_lookup {
        struct acpi_gpio_info info;
        int index;
@@ -460,8 +526,11 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
                 * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
                 */
                if (lookup->info.gpioint) {
+                       lookup->info.flags = GPIOD_IN;
                        lookup->info.polarity = agpio->polarity;
                        lookup->info.triggering = agpio->triggering;
+               } else {
+                       lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
                }
 
        }
@@ -588,18 +657,19 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
 struct gpio_desc *acpi_find_gpio(struct device *dev,
                                 const char *con_id,
                                 unsigned int idx,
-                                enum gpiod_flags flags,
+                                enum gpiod_flags *dflags,
                                 enum gpio_lookup_flags *lookupflags)
 {
        struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_gpio_info info;
        struct gpio_desc *desc;
        char propname[32];
+       int err;
        int i;
 
        /* Try first from _DSD */
        for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id && strcmp(con_id, "gpios")) {
+               if (con_id) {
                        snprintf(propname, sizeof(propname), "%s-%s",
                                 con_id, gpio_suffixes[i]);
                } else {
@@ -622,17 +692,21 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
                desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
                if (IS_ERR(desc))
                        return desc;
+       }
 
-               if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) &&
-                   info.gpioint) {
-                       dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
-                       return ERR_PTR(-ENOENT);
-               }
+       if (info.gpioint &&
+           (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) {
+               dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
+               return ERR_PTR(-ENOENT);
        }
 
        if (info.polarity == GPIO_ACTIVE_LOW)
                *lookupflags |= GPIO_ACTIVE_LOW;
 
+       err = acpi_gpio_update_gpiod_flags(dflags, info.flags);
+       if (err)
+               dev_dbg(dev, "Override GPIO initialization flags\n");
+
        return desc;
 }
 
@@ -686,12 +760,16 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
  * used to translate from the GPIO offset in the resource to the Linux IRQ
  * number.
  *
+ * The function is idempotent, though each time it runs it will configure GPIO
+ * pin direction according to the flags in GpioInt resource.
+ *
  * Return: Linux IRQ number (>%0) on success, negative errno on failure.
  */
 int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
 {
        int idx, i;
        unsigned int irq_flags;
+       int ret;
 
        for (i = 0, idx = 0; idx <= index; i++) {
                struct acpi_gpio_info info;
@@ -704,6 +782,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                        return PTR_ERR(desc);
 
                if (info.gpioint && idx++ == index) {
+                       char label[32];
                        int irq;
 
                        if (IS_ERR(desc))
@@ -713,6 +792,11 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                        if (irq < 0)
                                return irq;
 
+                       snprintf(label, sizeof(label), "GpioInt() %d", index);
+                       ret = gpiod_configure_flags(desc, label, 0, info.flags);
+                       if (ret < 0)
+                               return ret;
+
                        irq_flags = acpi_dev_get_irq_type(info.triggering,
                                                          info.polarity);
 
@@ -740,7 +824,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
        struct acpi_resource *ares;
        int pin_index = (int)address;
        acpi_status status;
-       bool pull_up;
        int length;
        int i;
 
@@ -755,7 +838,6 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
        }
 
        agpio = &ares->data.gpio;
-       pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
 
        if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
            function == ACPI_WRITE)) {
@@ -806,35 +888,23 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                }
 
                if (!found) {
-                       desc = gpiochip_request_own_desc(chip, pin,
-                                                        "ACPI:OpRegion");
+                       enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio);
+                       const char *label = "ACPI:OpRegion";
+                       int err;
+
+                       desc = gpiochip_request_own_desc(chip, pin, label);
                        if (IS_ERR(desc)) {
                                status = AE_ERROR;
                                mutex_unlock(&achip->conn_lock);
                                goto out;
                        }
 
-                       switch (agpio->io_restriction) {
-                       case ACPI_IO_RESTRICT_INPUT:
-                               gpiod_direction_input(desc);
-                               break;
-                       case ACPI_IO_RESTRICT_OUTPUT:
-                               /*
-                                * ACPI GPIO resources don't contain an
-                                * initial value for the GPIO. Therefore we
-                                * deduce that value from the pull field
-                                * instead. If the pin is pulled up we
-                                * assume default to be high, otherwise
-                                * low.
-                                */
-                               gpiod_direction_output(desc, pull_up);
-                               break;
-                       default:
-                               /*
-                                * Assume that the BIOS has configured the
-                                * direction and pull accordingly.
-                                */
-                               break;
+                       err = gpiod_configure_flags(desc, label, 0, flags);
+                       if (err < 0) {
+                               status = AE_NOT_CONFIGURED;
+                               gpiochip_free_own_desc(desc);
+                               mutex_unlock(&achip->conn_lock);
+                               goto out;
                        }
 
                        conn = kzalloc(sizeof(*conn), GFP_KERNEL);
@@ -1089,7 +1159,7 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
 
        /* Try first from _DSD */
        for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id && strcmp(con_id, "gpios"))
+               if (con_id)
                        snprintf(propname, sizeof(propname), "%s-%s",
                                 con_id, gpio_suffixes[i]);
                else
@@ -1119,6 +1189,9 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
                struct list_head resource_list;
                unsigned int crs_count = 0;
 
+               if (!acpi_can_fallback_to_crs(adev, con_id))
+                       return count;
+
                INIT_LIST_HEAD(&resource_list);
                acpi_dev_get_resources(adev, &resource_list,
                                       acpi_find_gpio_count, &crs_count);
@@ -1129,45 +1202,11 @@ int acpi_gpio_count(struct device *dev, const char *con_id)
        return count ? count : -ENOENT;
 }
 
-struct acpi_crs_lookup {
-       struct list_head node;
-       struct acpi_device *adev;
-       const char *con_id;
-};
-
-static DEFINE_MUTEX(acpi_crs_lookup_lock);
-static LIST_HEAD(acpi_crs_lookup_list);
-
 bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
 {
-       struct acpi_crs_lookup *l, *lookup = NULL;
-
        /* Never allow fallback if the device has properties */
        if (adev->data.properties || adev->driver_gpios)
                return false;
 
-       mutex_lock(&acpi_crs_lookup_lock);
-
-       list_for_each_entry(l, &acpi_crs_lookup_list, node) {
-               if (l->adev == adev) {
-                       lookup = l;
-                       break;
-               }
-       }
-
-       if (!lookup) {
-               lookup = kmalloc(sizeof(*lookup), GFP_KERNEL);
-               if (lookup) {
-                       lookup->adev = adev;
-                       lookup->con_id = kstrdup(con_id, GFP_KERNEL);
-                       list_add_tail(&lookup->node, &acpi_crs_lookup_list);
-               }
-       }
-
-       mutex_unlock(&acpi_crs_lookup_lock);
-
-       return lookup &&
-               ((!lookup->con_id && !con_id) ||
-                (lookup->con_id && con_id &&
-                 strcmp(lookup->con_id, con_id) == 0));
+       return con_id == NULL;
 }
index b13b7c7..54ce8dc 100644 (file)
@@ -153,6 +153,9 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
                        *flags |= GPIO_OPEN_SOURCE;
        }
 
+       if (of_flags & OF_GPIO_SLEEP_MAY_LOOSE_VALUE)
+               *flags |= GPIO_SLEEP_MAY_LOOSE_VALUE;
+
        return desc;
 }
 
@@ -236,7 +239,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
  *
  * This is only used by of_gpiochip_add to request/set GPIO initial
  * configuration.
- * It retures error if it fails otherwise 0 on success.
+ * It returns error if it fails otherwise 0 on success.
  */
 static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
 {
index a42a1ee..9568708 100644 (file)
@@ -1,4 +1,4 @@
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -1472,8 +1472,6 @@ static struct gpio_chip *find_chip_by_name(const char *name)
 
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
-       int i;
-
        if (!gpiochip->irq_need_valid_mask)
                return 0;
 
@@ -1483,8 +1481,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
                return -ENOMEM;
 
        /* Assume by default all GPIOs are valid */
-       for (i = 0; i < gpiochip->ngpio; i++)
-               set_bit(i, gpiochip->irq_valid_mask);
+       bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio);
 
        return 0;
 }
@@ -2870,6 +2867,16 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset)
 }
 EXPORT_SYMBOL_GPL(gpiochip_line_is_open_source);
 
+bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset)
+{
+       if (offset >= chip->ngpio)
+               return false;
+
+       return !test_bit(FLAG_SLEEP_MAY_LOOSE_VALUE,
+                        &chip->gpiodev->descs[offset].flags);
+}
+EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent);
+
 /**
  * gpiod_get_raw_value_cansleep() - return a gpio's raw value
  * @desc: gpio whose value will be returned
@@ -3009,6 +3016,7 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
 
        mutex_unlock(&gpio_lookup_lock);
 }
+EXPORT_SYMBOL_GPL(gpiod_add_lookup_table);
 
 /**
  * gpiod_remove_lookup_table() - unregister GPIO device consumers
@@ -3022,6 +3030,7 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
 
        mutex_unlock(&gpio_lookup_lock);
 }
+EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
 
 static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
@@ -3213,7 +3222,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
  * requested function and/or index, or another IS_ERR() code if an error
  * occurred while trying to acquire the GPIO.
  */
-static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
+int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags)
 {
        int status;
@@ -3224,6 +3233,8 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                set_bit(FLAG_OPEN_DRAIN, &desc->flags);
        if (lflags & GPIO_OPEN_SOURCE)
                set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+       if (lflags & GPIO_SLEEP_MAY_LOOSE_VALUE)
+               set_bit(FLAG_SLEEP_MAY_LOOSE_VALUE, &desc->flags);
 
        /* No particular flag request, return here... */
        if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
@@ -3273,7 +3284,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
                        desc = of_find_gpio(dev, con_id, idx, &lookupflags);
                } else if (ACPI_COMPANION(dev)) {
                        dev_dbg(dev, "using ACPI for GPIO lookup\n");
-                       desc = acpi_find_gpio(dev, con_id, idx, flags, &lookupflags);
+                       desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
                }
        }
 
@@ -3354,8 +3365,12 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                struct acpi_gpio_info info;
 
                desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
-               if (!IS_ERR(desc))
+               if (!IS_ERR(desc)) {
                        active_low = info.polarity == GPIO_ACTIVE_LOW;
+                       ret = acpi_gpio_update_gpiod_flags(&dflags, info.flags);
+                       if (ret)
+                               pr_debug("Override GPIO initialization flags\n");
+               }
        }
 
        if (IS_ERR(desc))
index 2495b7e..a8be286 100644 (file)
@@ -75,11 +75,13 @@ struct gpio_device {
 
 /**
  * struct acpi_gpio_info - ACPI GPIO specific information
+ * @flags: GPIO initialization flags
  * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
  * @polarity: interrupt polarity as provided by ACPI
  * @triggering: triggering type as provided by ACPI
  */
 struct acpi_gpio_info {
+       enum gpiod_flags flags;
        bool gpioint;
        int polarity;
        int triggering;
@@ -121,10 +123,13 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
 void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
 void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
 
+int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
+                                enum gpiod_flags update);
+
 struct gpio_desc *acpi_find_gpio(struct device *dev,
                                 const char *con_id,
                                 unsigned int idx,
-                                enum gpiod_flags flags,
+                                enum gpiod_flags *dflags,
                                 enum gpio_lookup_flags *lookupflags);
 struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
                                      const char *propname, int index,
@@ -143,9 +148,15 @@ acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
 static inline void
 acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
 
+static inline int
+acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
+{
+       return 0;
+}
+
 static inline struct gpio_desc *
 acpi_find_gpio(struct device *dev, const char *con_id,
-              unsigned int idx, enum gpiod_flags flags,
+              unsigned int idx, enum gpiod_flags *dflags,
               enum gpio_lookup_flags *lookupflags)
 {
        return ERR_PTR(-ENOENT);
@@ -190,6 +201,7 @@ struct gpio_desc {
 #define FLAG_OPEN_SOURCE 8     /* Gpio is open source type */
 #define FLAG_USED_AS_IRQ 9     /* GPIO is connected to an IRQ */
 #define FLAG_IS_HOGGED 11      /* GPIO is hogged */
+#define FLAG_SLEEP_MAY_LOOSE_VALUE 12  /* GPIO may loose value in sleep */
 
        /* Connection label */
        const char              *label;
@@ -199,6 +211,8 @@ struct gpio_desc {
 
 int gpiod_request(struct gpio_desc *desc, const char *label);
 void gpiod_free(struct gpio_desc *desc);
+int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
+               unsigned long lflags, enum gpiod_flags dflags);
 int gpiod_hog(struct gpio_desc *desc, const char *name,
                unsigned long lflags, enum gpiod_flags dflags);
 
index 53fe9a3..f9d273c 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/gpio.h>
 #include <linux/slab.h>
 
-#include <linux/i2c/adp5588.h>
+#include <linux/platform_data/adp5588.h>
 
 /* Key Event Register xy */
 #define KEY_EV_PRESSED         (1 << 7)
index 4b717c6..43d8ed5 100644 (file)
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/kernel.h>
 #include <linux/acpi.h>
@@ -149,8 +145,8 @@ static int vendor_resource_matches(struct pnp_dev *dev,
            uuid_len == sizeof(match->data) &&
            memcmp(uuid, match->data, uuid_len) == 0) {
                if (expected_len && expected_len != actual_len) {
-                       dev_err(&dev->dev, "wrong vendor descriptor size; "
-                               "expected %d, found %d bytes\n",
+                       dev_err(&dev->dev,
+                               "wrong vendor descriptor size; expected %d, found %d bytes\n",
                                expected_len, actual_len);
                        return 0;
                }
@@ -180,6 +176,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        struct pnp_dev *dev = data;
        struct acpi_resource_dma *dma;
        struct acpi_resource_vendor_typed *vendor_typed;
+       struct acpi_resource_gpio *gpio;
        struct resource_win win = {{0}, 0};
        struct resource *r = &win.res;
        int i, flags;
@@ -203,13 +200,27 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
                         * one interrupt, we won't be able to re-encode it.
                         */
                        if (pnp_can_write(dev)) {
-                               dev_warn(&dev->dev, "multiple interrupts in "
-                                        "_CRS descriptor; configuration can't "
-                                        "be changed\n");
+                               dev_warn(&dev->dev,
+                                        "multiple interrupts in _CRS descriptor; configuration can't be changed\n");
                                dev->capabilities &= ~PNP_WRITE;
                        }
                }
                return AE_OK;
+       } else if (acpi_gpio_get_irq_resource(res, &gpio)) {
+               /*
+                * If the resource is GpioInt() type then extract the IRQ
+                * from GPIO resource and fill it into IRQ resource type.
+                */
+               i = acpi_dev_gpio_irq_get(dev->data, 0);
+               if (i >= 0) {
+                       flags = acpi_dev_irq_flags(gpio->triggering,
+                                                  gpio->polarity,
+                                                  gpio->sharable);
+               } else {
+                       flags = IORESOURCE_DISABLED;
+               }
+               pnp_add_irq_resource(dev, i, flags);
+               return AE_OK;
        } else if (r->flags & IORESOURCE_DISABLED) {
                pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
                return AE_OK;
@@ -331,8 +342,8 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
                        if (p->interrupts[i] < PNP_IRQ_NR)
                                __set_bit(p->interrupts[i], map.bits);
                        else
-                               dev_err(&dev->dev, "ignoring IRQ %d option "
-                                       "(too large for %d entry bitmap)\n",
+                               dev_err(&dev->dev,
+                                       "ignoring IRQ %d option (too large for %d entry bitmap)\n",
                                        p->interrupts[i], PNP_IRQ_NR);
                }
        }
@@ -933,8 +944,9 @@ int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
                case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
                case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
                default:        /* other type */
-                       dev_warn(&dev->dev, "can't encode unknown resource "
-                                "type %d\n", resource->type);
+                       dev_warn(&dev->dev,
+                                "can't encode unknown resource type %d\n",
+                                resource->type);
                        return -EINVAL;
                }
                resource++;
index a309bcf..b5c98e5 100644 (file)
@@ -9,10 +9,13 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License.
  */
+#include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/property.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
 #include <linux/slab.h>
 #define UART_EXAR_MPIOSEL_15_8 0x99    /* MPIOSEL[15:8] */
 #define UART_EXAR_MPIOOD_15_8  0x9a    /* MPIOOD[15:8] */
 
+#define UART_EXAR_RS485_DLY(x) ((x) << 4)
+
+/*
+ * IOT2040 MPIO wiring semantics:
+ *
+ * MPIO                Port    Function
+ * ----                ----    --------
+ * 0           2       Mode bit 0
+ * 1           2       Mode bit 1
+ * 2           2       Terminate bus
+ * 3           -       <reserved>
+ * 4           3       Mode bit 0
+ * 5           3       Mode bit 1
+ * 6           3       Terminate bus
+ * 7           -       <reserved>
+ * 8           2       Enable
+ * 9           3       Enable
+ * 10          -       Red LED
+ * 11..15      -       <unused>
+ */
+
+/* IOT2040 MPIOs 0..7 */
+#define IOT2040_UART_MODE_RS232                0x01
+#define IOT2040_UART_MODE_RS485                0x02
+#define IOT2040_UART_MODE_RS422                0x03
+#define IOT2040_UART_TERMINATE_BUS     0x04
+
+#define IOT2040_UART1_MASK             0x0f
+#define IOT2040_UART2_SHIFT            4
+
+#define IOT2040_UARTS_DEFAULT_MODE     0x11    /* both RS232 */
+#define IOT2040_UARTS_GPIO_LO_MODE     0x88    /* reserved pins as input */
+
+/* IOT2040 MPIOs 8..15 */
+#define IOT2040_UARTS_ENABLE           0x03
+#define IOT2040_UARTS_GPIO_HI_MODE     0xF8    /* enable & LED as outputs */
+
 struct exar8250;
 
+struct exar8250_platform {
+       int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
+       int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
+};
+
 /**
  * struct exar8250_board - board information
  * @num_ports: number of serial ports
@@ -194,7 +239,8 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
 }
 
 static void *
-xr17v35x_register_gpio(struct pci_dev *pcidev)
+__xr17v35x_register_gpio(struct pci_dev *pcidev,
+                        const struct property_entry *properties)
 {
        struct platform_device *pdev;
 
@@ -202,8 +248,11 @@ xr17v35x_register_gpio(struct pci_dev *pcidev)
        if (!pdev)
                return NULL;
 
-       platform_set_drvdata(pdev, pcidev);
-       if (platform_device_add(pdev) < 0) {
+       pdev->dev.parent = &pcidev->dev;
+       ACPI_COMPANION_SET(&pdev->dev, ACPI_COMPANION(&pcidev->dev));
+
+       if (platform_device_add_properties(pdev, properties) < 0 ||
+           platform_device_add(pdev) < 0) {
                platform_device_put(pdev);
                return NULL;
        }
@@ -211,17 +260,131 @@ xr17v35x_register_gpio(struct pci_dev *pcidev)
        return pdev;
 }
 
+static const struct property_entry exar_gpio_properties[] = {
+       PROPERTY_ENTRY_U32("linux,first-pin", 0),
+       PROPERTY_ENTRY_U32("ngpios", 16),
+       { }
+};
+
+static int xr17v35x_register_gpio(struct pci_dev *pcidev,
+                                 struct uart_8250_port *port)
+{
+       if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
+               port->port.private_data =
+                       __xr17v35x_register_gpio(pcidev, exar_gpio_properties);
+
+       return 0;
+}
+
+static const struct exar8250_platform exar8250_default_platform = {
+       .register_gpio = xr17v35x_register_gpio,
+};
+
+static int iot2040_rs485_config(struct uart_port *port,
+                               struct serial_rs485 *rs485)
+{
+       bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
+       u8 __iomem *p = port->membase;
+       u8 mask = IOT2040_UART1_MASK;
+       u8 mode, value;
+
+       if (is_rs485) {
+               if (rs485->flags & SER_RS485_RX_DURING_TX)
+                       mode = IOT2040_UART_MODE_RS422;
+               else
+                       mode = IOT2040_UART_MODE_RS485;
+
+               if (rs485->flags & SER_RS485_TERMINATE_BUS)
+                       mode |= IOT2040_UART_TERMINATE_BUS;
+       } else {
+               mode = IOT2040_UART_MODE_RS232;
+       }
+
+       if (port->line == 3) {
+               mask <<= IOT2040_UART2_SHIFT;
+               mode <<= IOT2040_UART2_SHIFT;
+       }
+
+       value = readb(p + UART_EXAR_MPIOLVL_7_0);
+       value &= ~mask;
+       value |= mode;
+       writeb(value, p + UART_EXAR_MPIOLVL_7_0);
+
+       value = readb(p + UART_EXAR_FCTR);
+       if (is_rs485)
+               value |= UART_FCTR_EXAR_485;
+       else
+               value &= ~UART_FCTR_EXAR_485;
+       writeb(value, p + UART_EXAR_FCTR);
+
+       if (is_rs485)
+               writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
+
+       port->rs485 = *rs485;
+
+       return 0;
+}
+
+static const struct property_entry iot2040_gpio_properties[] = {
+       PROPERTY_ENTRY_U32("linux,first-pin", 10),
+       PROPERTY_ENTRY_U32("ngpios", 1),
+       { }
+};
+
+static int iot2040_register_gpio(struct pci_dev *pcidev,
+                             struct uart_8250_port *port)
+{
+       u8 __iomem *p = port->port.membase;
+
+       writeb(IOT2040_UARTS_DEFAULT_MODE, p + UART_EXAR_MPIOLVL_7_0);
+       writeb(IOT2040_UARTS_GPIO_LO_MODE, p + UART_EXAR_MPIOSEL_7_0);
+       writeb(IOT2040_UARTS_ENABLE, p + UART_EXAR_MPIOLVL_15_8);
+       writeb(IOT2040_UARTS_GPIO_HI_MODE, p + UART_EXAR_MPIOSEL_15_8);
+
+       port->port.private_data =
+               __xr17v35x_register_gpio(pcidev, iot2040_gpio_properties);
+
+       return 0;
+}
+
+static const struct exar8250_platform iot2040_platform = {
+       .rs485_config = iot2040_rs485_config,
+       .register_gpio = iot2040_register_gpio,
+};
+
+static const struct dmi_system_id exar_platforms[] = {
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+                       DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+                                       "6ES7647-0AA00-1YA2"),
+               },
+               .driver_data = (void *)&iot2040_platform,
+       },
+       {}
+};
+
 static int
 pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
                   struct uart_8250_port *port, int idx)
 {
        const struct exar8250_board *board = priv->board;
+       const struct exar8250_platform *platform;
+       const struct dmi_system_id *dmi_match;
        unsigned int offset = idx * 0x400;
        unsigned int baud = 7812500;
        u8 __iomem *p;
        int ret;
 
+       dmi_match = dmi_first_match(exar_platforms);
+       if (dmi_match)
+               platform = dmi_match->driver_data;
+       else
+               platform = &exar8250_default_platform;
+
        port->port.uartclk = baud * 16;
+       port->port.rs485_config = platform->rs485_config;
+
        /*
         * Setup the uart clock for the devices on expansion slot to
         * half the clock speed of the main chip (which is 125MHz)
@@ -244,10 +407,10 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
                /* Setup Multipurpose Input/Output pins. */
                setup_gpio(pcidev, p);
 
-               port->port.private_data = xr17v35x_register_gpio(pcidev);
+               ret = platform->register_gpio(pcidev, port);
        }
 
-       return 0;
+       return ret;
 }
 
 static void pci_xr17v35x_exit(struct pci_dev *pcidev)
index b4f54da..c507458 100644 (file)
@@ -28,4 +28,8 @@
 #define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN)
 #define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_SOURCE)
 
+/* Bit 3 express GPIO suspend/resume persistence */
+#define GPIO_SLEEP_MAINTAIN_VALUE 0
+#define GPIO_SLEEP_MAY_LOOSE_VALUE 8
+
 #endif
index cafdfb8..99f96df 100644 (file)
@@ -964,6 +964,8 @@ int devm_acpi_dev_add_driver_gpios(struct device *dev,
                                   const struct acpi_gpio_mapping *gpios);
 void devm_acpi_dev_remove_driver_gpios(struct device *dev);
 
+bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
+                               struct acpi_resource_gpio **agpio);
 int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
 #else
 static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
@@ -980,6 +982,11 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
 }
 static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
 
+static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
+                                             struct acpi_resource_gpio **agpio)
+{
+       return false;
+}
 static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
 {
        return -ENXIO;
index 3935828..af20369 100644 (file)
@@ -213,6 +213,9 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
 bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset);
 bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);
 
+/* Sleep persistence inquiry for drivers */
+bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
+
 /* get driver data */
 void *gpiochip_get_data(struct gpio_chip *chip);
 
index f738d50..6e76b16 100644 (file)
@@ -9,6 +9,8 @@ enum gpio_lookup_flags {
        GPIO_ACTIVE_LOW = (1 << 0),
        GPIO_OPEN_DRAIN = (1 << 1),
        GPIO_OPEN_SOURCE = (1 << 2),
+       GPIO_SLEEP_MAINTAIN_VALUE = (0 << 3),
+       GPIO_SLEEP_MAY_LOOSE_VALUE = (1 << 3),
 };
 
 /**
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
deleted file mode 100644 (file)
index c215304..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
- *
- * Copyright 2009-2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#ifndef _ADP5588_H
-#define _ADP5588_H
-
-#define DEV_ID 0x00            /* Device ID */
-#define CFG 0x01               /* Configuration Register1 */
-#define INT_STAT 0x02          /* Interrupt Status Register */
-#define KEY_LCK_EC_STAT 0x03   /* Key Lock and Event Counter Register */
-#define Key_EVENTA 0x04                /* Key Event Register A */
-#define Key_EVENTB 0x05                /* Key Event Register B */
-#define Key_EVENTC 0x06                /* Key Event Register C */
-#define Key_EVENTD 0x07                /* Key Event Register D */
-#define Key_EVENTE 0x08                /* Key Event Register E */
-#define Key_EVENTF 0x09                /* Key Event Register F */
-#define Key_EVENTG 0x0A                /* Key Event Register G */
-#define Key_EVENTH 0x0B                /* Key Event Register H */
-#define Key_EVENTI 0x0C                /* Key Event Register I */
-#define Key_EVENTJ 0x0D                /* Key Event Register J */
-#define KP_LCK_TMR 0x0E                /* Keypad Lock1 to Lock2 Timer */
-#define UNLOCK1 0x0F           /* Unlock Key1 */
-#define UNLOCK2 0x10           /* Unlock Key2 */
-#define GPIO_INT_STAT1 0x11    /* GPIO Interrupt Status */
-#define GPIO_INT_STAT2 0x12    /* GPIO Interrupt Status */
-#define GPIO_INT_STAT3 0x13    /* GPIO Interrupt Status */
-#define GPIO_DAT_STAT1 0x14    /* GPIO Data Status, Read twice to clear */
-#define GPIO_DAT_STAT2 0x15    /* GPIO Data Status, Read twice to clear */
-#define GPIO_DAT_STAT3 0x16    /* GPIO Data Status, Read twice to clear */
-#define GPIO_DAT_OUT1 0x17     /* GPIO DATA OUT */
-#define GPIO_DAT_OUT2 0x18     /* GPIO DATA OUT */
-#define GPIO_DAT_OUT3 0x19     /* GPIO DATA OUT */
-#define GPIO_INT_EN1 0x1A      /* GPIO Interrupt Enable */
-#define GPIO_INT_EN2 0x1B      /* GPIO Interrupt Enable */
-#define GPIO_INT_EN3 0x1C      /* GPIO Interrupt Enable */
-#define KP_GPIO1 0x1D          /* Keypad or GPIO Selection */
-#define KP_GPIO2 0x1E          /* Keypad or GPIO Selection */
-#define KP_GPIO3 0x1F          /* Keypad or GPIO Selection */
-#define GPI_EM1 0x20           /* GPI Event Mode 1 */
-#define GPI_EM2 0x21           /* GPI Event Mode 2 */
-#define GPI_EM3 0x22           /* GPI Event Mode 3 */
-#define GPIO_DIR1 0x23         /* GPIO Data Direction */
-#define GPIO_DIR2 0x24         /* GPIO Data Direction */
-#define GPIO_DIR3 0x25         /* GPIO Data Direction */
-#define GPIO_INT_LVL1 0x26     /* GPIO Edge/Level Detect */
-#define GPIO_INT_LVL2 0x27     /* GPIO Edge/Level Detect */
-#define GPIO_INT_LVL3 0x28     /* GPIO Edge/Level Detect */
-#define Debounce_DIS1 0x29     /* Debounce Disable */
-#define Debounce_DIS2 0x2A     /* Debounce Disable */
-#define Debounce_DIS3 0x2B     /* Debounce Disable */
-#define GPIO_PULL1 0x2C                /* GPIO Pull Disable */
-#define GPIO_PULL2 0x2D                /* GPIO Pull Disable */
-#define GPIO_PULL3 0x2E                /* GPIO Pull Disable */
-#define CMP_CFG_STAT 0x30      /* Comparator Configuration and Status Register */
-#define CMP_CONFG_SENS1 0x31   /* Sensor1 Comparator Configuration Register */
-#define CMP_CONFG_SENS2 0x32   /* L2 Light Sensor Reference Level, Output Falling for Sensor 1 */
-#define CMP1_LVL2_TRIP 0x33    /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 1 */
-#define CMP1_LVL2_HYS 0x34     /* L3 Light Sensor Reference Level, Output Falling For Sensor 1 */
-#define CMP1_LVL3_TRIP 0x35    /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 1 */
-#define CMP1_LVL3_HYS 0x36     /* Sensor 2 Comparator Configuration Register */
-#define CMP2_LVL2_TRIP 0x37    /* L2 Light Sensor Reference Level, Output Falling for Sensor 2 */
-#define CMP2_LVL2_HYS 0x38     /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 2 */
-#define CMP2_LVL3_TRIP 0x39    /* L3 Light Sensor Reference Level, Output Falling For Sensor 2 */
-#define CMP2_LVL3_HYS 0x3A     /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 2 */
-#define CMP1_ADC_DAT_R1 0x3B   /* Comparator 1 ADC data Register1 */
-#define CMP1_ADC_DAT_R2 0x3C   /* Comparator 1 ADC data Register2 */
-#define CMP2_ADC_DAT_R1 0x3D   /* Comparator 2 ADC data Register1 */
-#define CMP2_ADC_DAT_R2 0x3E   /* Comparator 2 ADC data Register2 */
-
-#define ADP5588_DEVICE_ID_MASK 0xF
-
- /* Configuration Register1 */
-#define ADP5588_AUTO_INC       (1 << 7)
-#define ADP5588_GPIEM_CFG      (1 << 6)
-#define ADP5588_OVR_FLOW_M     (1 << 5)
-#define ADP5588_INT_CFG                (1 << 4)
-#define ADP5588_OVR_FLOW_IEN   (1 << 3)
-#define ADP5588_K_LCK_IM       (1 << 2)
-#define ADP5588_GPI_IEN                (1 << 1)
-#define ADP5588_KE_IEN         (1 << 0)
-
-/* Interrupt Status Register */
-#define ADP5588_CMP2_INT       (1 << 5)
-#define ADP5588_CMP1_INT       (1 << 4)
-#define ADP5588_OVR_FLOW_INT   (1 << 3)
-#define ADP5588_K_LCK_INT      (1 << 2)
-#define ADP5588_GPI_INT                (1 << 1)
-#define ADP5588_KE_INT         (1 << 0)
-
-/* Key Lock and Event Counter Register */
-#define ADP5588_K_LCK_EN       (1 << 6)
-#define ADP5588_LCK21          0x30
-#define ADP5588_KEC            0xF
-
-#define ADP5588_MAXGPIO                18
-#define ADP5588_BANK(offs)     ((offs) >> 3)
-#define ADP5588_BIT(offs)      (1u << ((offs) & 0x7))
-
-/* Put one of these structures in i2c_board_info platform_data */
-
-#define ADP5588_KEYMAPSIZE     80
-
-#define GPI_PIN_ROW0 97
-#define GPI_PIN_ROW1 98
-#define GPI_PIN_ROW2 99
-#define GPI_PIN_ROW3 100
-#define GPI_PIN_ROW4 101
-#define GPI_PIN_ROW5 102
-#define GPI_PIN_ROW6 103
-#define GPI_PIN_ROW7 104
-#define GPI_PIN_COL0 105
-#define GPI_PIN_COL1 106
-#define GPI_PIN_COL2 107
-#define GPI_PIN_COL3 108
-#define GPI_PIN_COL4 109
-#define GPI_PIN_COL5 110
-#define GPI_PIN_COL6 111
-#define GPI_PIN_COL7 112
-#define GPI_PIN_COL8 113
-#define GPI_PIN_COL9 114
-
-#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
-#define GPI_PIN_ROW_END GPI_PIN_ROW7
-#define GPI_PIN_COL_BASE GPI_PIN_COL0
-#define GPI_PIN_COL_END GPI_PIN_COL9
-
-#define GPI_PIN_BASE GPI_PIN_ROW_BASE
-#define GPI_PIN_END GPI_PIN_COL_END
-
-#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
-
-struct adp5588_gpi_map {
-       unsigned short pin;
-       unsigned short sw_evt;
-};
-
-struct adp5588_kpad_platform_data {
-       int rows;                       /* Number of rows */
-       int cols;                       /* Number of columns */
-       const unsigned short *keymap;   /* Pointer to keymap */
-       unsigned short keymapsize;      /* Keymap size */
-       unsigned repeat:1;              /* Enable key repeat */
-       unsigned en_keylock:1;          /* Enable Key Lock feature */
-       unsigned short unlock_key1;     /* Unlock Key 1 */
-       unsigned short unlock_key2;     /* Unlock Key 2 */
-       const struct adp5588_gpi_map *gpimap;
-       unsigned short gpimapsize;
-       const struct adp5588_gpio_platform_data *gpio_data;
-};
-
-struct i2c_client; /* forward declaration */
-
-struct adp5588_gpio_platform_data {
-       int gpio_start;         /* GPIO Chip base # */
-       const char *const *names;
-       unsigned irq_base;      /* interrupt base # */
-       unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
-       int     (*setup)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-       int     (*teardown)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-       void    *context;
-};
-
-#endif
diff --git a/include/linux/i2c/max732x.h b/include/linux/i2c/max732x.h
deleted file mode 100644 (file)
index c04bac8..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __LINUX_I2C_MAX732X_H
-#define __LINUX_I2C_MAX732X_H
-
-/* platform data for the MAX732x 8/16-bit I/O expander driver */
-
-struct max732x_platform_data {
-       /* number of the first GPIO */
-       unsigned        gpio_base;
-
-       /* interrupt base */
-       int             irq_base;
-
-       void            *context;       /* param to setup/teardown */
-
-       int             (*setup)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-       int             (*teardown)(struct i2c_client *client,
-                               unsigned gpio, unsigned ngpio,
-                               void *context);
-};
-#endif /* __LINUX_I2C_MAX732X_H */
diff --git a/include/linux/i2c/pcf857x.h b/include/linux/i2c/pcf857x.h
deleted file mode 100644 (file)
index 0767a2a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __LINUX_PCF857X_H
-#define __LINUX_PCF857X_H
-
-/**
- * struct pcf857x_platform_data - data to set up pcf857x driver
- * @gpio_base: number of the chip's first GPIO
- * @n_latch: optional bit-inverse of initial register value; if
- *     you leave this initialized to zero the driver will act
- *     like the chip was just reset
- * @setup: optional callback issued once the GPIOs are valid
- * @teardown: optional callback issued before the GPIOs are invalidated
- * @context: optional parameter passed to setup() and teardown()
- *
- * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
- * the i2c_board_info used with the pcf875x driver must provide its
- * platform_data (pointer to one of these structures) with at least
- * the gpio_base value initialized.
- *
- * The @setup callback may be used with the kind of board-specific glue
- * which hands the (now-valid) GPIOs to other drivers, or which puts
- * devices in their initial states using these GPIOs.
- *
- * These GPIO chips are only "quasi-bidirectional"; read the chip specs
- * to understand the behavior.  They don't have separate registers to
- * record which pins are used for input or output, record which output
- * values are driven, or provide access to input values.  That must be
- * inferred by reading the chip's value and knowing the last value written
- * to it.  If you leave n_latch initialized to zero, that last written
- * value is presumed to be all ones (as if the chip were just reset).
- */
-struct pcf857x_platform_data {
-       unsigned        gpio_base;
-       unsigned        n_latch;
-
-       int             (*setup)(struct i2c_client *client,
-                                       int gpio, unsigned ngpio,
-                                       void *context);
-       int             (*teardown)(struct i2c_client *client,
-                                       int gpio, unsigned ngpio,
-                                       void *context);
-       void            *context;
-};
-
-#endif /* __LINUX_PCF857X_H */
index 1e089d5..ca10f43 100644 (file)
@@ -31,6 +31,7 @@ enum of_gpio_flags {
        OF_GPIO_ACTIVE_LOW = 0x1,
        OF_GPIO_SINGLE_ENDED = 0x2,
        OF_GPIO_OPEN_DRAIN = 0x4,
+       OF_GPIO_SLEEP_MAY_LOOSE_VALUE = 0x8,
 };
 
 #ifdef CONFIG_OF_GPIO
diff --git a/include/linux/platform_data/adp5588.h b/include/linux/platform_data/adp5588.h
new file mode 100644 (file)
index 0000000..c215304
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Analog Devices ADP5588 I/O Expander and QWERTY Keypad Controller
+ *
+ * Copyright 2009-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADP5588_H
+#define _ADP5588_H
+
+#define DEV_ID 0x00            /* Device ID */
+#define CFG 0x01               /* Configuration Register1 */
+#define INT_STAT 0x02          /* Interrupt Status Register */
+#define KEY_LCK_EC_STAT 0x03   /* Key Lock and Event Counter Register */
+#define Key_EVENTA 0x04                /* Key Event Register A */
+#define Key_EVENTB 0x05                /* Key Event Register B */
+#define Key_EVENTC 0x06                /* Key Event Register C */
+#define Key_EVENTD 0x07                /* Key Event Register D */
+#define Key_EVENTE 0x08                /* Key Event Register E */
+#define Key_EVENTF 0x09                /* Key Event Register F */
+#define Key_EVENTG 0x0A                /* Key Event Register G */
+#define Key_EVENTH 0x0B                /* Key Event Register H */
+#define Key_EVENTI 0x0C                /* Key Event Register I */
+#define Key_EVENTJ 0x0D                /* Key Event Register J */
+#define KP_LCK_TMR 0x0E                /* Keypad Lock1 to Lock2 Timer */
+#define UNLOCK1 0x0F           /* Unlock Key1 */
+#define UNLOCK2 0x10           /* Unlock Key2 */
+#define GPIO_INT_STAT1 0x11    /* GPIO Interrupt Status */
+#define GPIO_INT_STAT2 0x12    /* GPIO Interrupt Status */
+#define GPIO_INT_STAT3 0x13    /* GPIO Interrupt Status */
+#define GPIO_DAT_STAT1 0x14    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT2 0x15    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_STAT3 0x16    /* GPIO Data Status, Read twice to clear */
+#define GPIO_DAT_OUT1 0x17     /* GPIO DATA OUT */
+#define GPIO_DAT_OUT2 0x18     /* GPIO DATA OUT */
+#define GPIO_DAT_OUT3 0x19     /* GPIO DATA OUT */
+#define GPIO_INT_EN1 0x1A      /* GPIO Interrupt Enable */
+#define GPIO_INT_EN2 0x1B      /* GPIO Interrupt Enable */
+#define GPIO_INT_EN3 0x1C      /* GPIO Interrupt Enable */
+#define KP_GPIO1 0x1D          /* Keypad or GPIO Selection */
+#define KP_GPIO2 0x1E          /* Keypad or GPIO Selection */
+#define KP_GPIO3 0x1F          /* Keypad or GPIO Selection */
+#define GPI_EM1 0x20           /* GPI Event Mode 1 */
+#define GPI_EM2 0x21           /* GPI Event Mode 2 */
+#define GPI_EM3 0x22           /* GPI Event Mode 3 */
+#define GPIO_DIR1 0x23         /* GPIO Data Direction */
+#define GPIO_DIR2 0x24         /* GPIO Data Direction */
+#define GPIO_DIR3 0x25         /* GPIO Data Direction */
+#define GPIO_INT_LVL1 0x26     /* GPIO Edge/Level Detect */
+#define GPIO_INT_LVL2 0x27     /* GPIO Edge/Level Detect */
+#define GPIO_INT_LVL3 0x28     /* GPIO Edge/Level Detect */
+#define Debounce_DIS1 0x29     /* Debounce Disable */
+#define Debounce_DIS2 0x2A     /* Debounce Disable */
+#define Debounce_DIS3 0x2B     /* Debounce Disable */
+#define GPIO_PULL1 0x2C                /* GPIO Pull Disable */
+#define GPIO_PULL2 0x2D                /* GPIO Pull Disable */
+#define GPIO_PULL3 0x2E                /* GPIO Pull Disable */
+#define CMP_CFG_STAT 0x30      /* Comparator Configuration and Status Register */
+#define CMP_CONFG_SENS1 0x31   /* Sensor1 Comparator Configuration Register */
+#define CMP_CONFG_SENS2 0x32   /* L2 Light Sensor Reference Level, Output Falling for Sensor 1 */
+#define CMP1_LVL2_TRIP 0x33    /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 1 */
+#define CMP1_LVL2_HYS 0x34     /* L3 Light Sensor Reference Level, Output Falling For Sensor 1 */
+#define CMP1_LVL3_TRIP 0x35    /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 1 */
+#define CMP1_LVL3_HYS 0x36     /* Sensor 2 Comparator Configuration Register */
+#define CMP2_LVL2_TRIP 0x37    /* L2 Light Sensor Reference Level, Output Falling for Sensor 2 */
+#define CMP2_LVL2_HYS 0x38     /* L2 Light Sensor Hysteresis (Active when Output Rising) for Sensor 2 */
+#define CMP2_LVL3_TRIP 0x39    /* L3 Light Sensor Reference Level, Output Falling For Sensor 2 */
+#define CMP2_LVL3_HYS 0x3A     /* L3 Light Sensor Hysteresis (Active when Output Rising) For Sensor 2 */
+#define CMP1_ADC_DAT_R1 0x3B   /* Comparator 1 ADC data Register1 */
+#define CMP1_ADC_DAT_R2 0x3C   /* Comparator 1 ADC data Register2 */
+#define CMP2_ADC_DAT_R1 0x3D   /* Comparator 2 ADC data Register1 */
+#define CMP2_ADC_DAT_R2 0x3E   /* Comparator 2 ADC data Register2 */
+
+#define ADP5588_DEVICE_ID_MASK 0xF
+
+ /* Configuration Register1 */
+#define ADP5588_AUTO_INC       (1 << 7)
+#define ADP5588_GPIEM_CFG      (1 << 6)
+#define ADP5588_OVR_FLOW_M     (1 << 5)
+#define ADP5588_INT_CFG                (1 << 4)
+#define ADP5588_OVR_FLOW_IEN   (1 << 3)
+#define ADP5588_K_LCK_IM       (1 << 2)
+#define ADP5588_GPI_IEN                (1 << 1)
+#define ADP5588_KE_IEN         (1 << 0)
+
+/* Interrupt Status Register */
+#define ADP5588_CMP2_INT       (1 << 5)
+#define ADP5588_CMP1_INT       (1 << 4)
+#define ADP5588_OVR_FLOW_INT   (1 << 3)
+#define ADP5588_K_LCK_INT      (1 << 2)
+#define ADP5588_GPI_INT                (1 << 1)
+#define ADP5588_KE_INT         (1 << 0)
+
+/* Key Lock and Event Counter Register */
+#define ADP5588_K_LCK_EN       (1 << 6)
+#define ADP5588_LCK21          0x30
+#define ADP5588_KEC            0xF
+
+#define ADP5588_MAXGPIO                18
+#define ADP5588_BANK(offs)     ((offs) >> 3)
+#define ADP5588_BIT(offs)      (1u << ((offs) & 0x7))
+
+/* Put one of these structures in i2c_board_info platform_data */
+
+#define ADP5588_KEYMAPSIZE     80
+
+#define GPI_PIN_ROW0 97
+#define GPI_PIN_ROW1 98
+#define GPI_PIN_ROW2 99
+#define GPI_PIN_ROW3 100
+#define GPI_PIN_ROW4 101
+#define GPI_PIN_ROW5 102
+#define GPI_PIN_ROW6 103
+#define GPI_PIN_ROW7 104
+#define GPI_PIN_COL0 105
+#define GPI_PIN_COL1 106
+#define GPI_PIN_COL2 107
+#define GPI_PIN_COL3 108
+#define GPI_PIN_COL4 109
+#define GPI_PIN_COL5 110
+#define GPI_PIN_COL6 111
+#define GPI_PIN_COL7 112
+#define GPI_PIN_COL8 113
+#define GPI_PIN_COL9 114
+
+#define GPI_PIN_ROW_BASE GPI_PIN_ROW0
+#define GPI_PIN_ROW_END GPI_PIN_ROW7
+#define GPI_PIN_COL_BASE GPI_PIN_COL0
+#define GPI_PIN_COL_END GPI_PIN_COL9
+
+#define GPI_PIN_BASE GPI_PIN_ROW_BASE
+#define GPI_PIN_END GPI_PIN_COL_END
+
+#define ADP5588_GPIMAPSIZE_MAX (GPI_PIN_END - GPI_PIN_BASE + 1)
+
+struct adp5588_gpi_map {
+       unsigned short pin;
+       unsigned short sw_evt;
+};
+
+struct adp5588_kpad_platform_data {
+       int rows;                       /* Number of rows */
+       int cols;                       /* Number of columns */
+       const unsigned short *keymap;   /* Pointer to keymap */
+       unsigned short keymapsize;      /* Keymap size */
+       unsigned repeat:1;              /* Enable key repeat */
+       unsigned en_keylock:1;          /* Enable Key Lock feature */
+       unsigned short unlock_key1;     /* Unlock Key 1 */
+       unsigned short unlock_key2;     /* Unlock Key 2 */
+       const struct adp5588_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       const struct adp5588_gpio_platform_data *gpio_data;
+};
+
+struct i2c_client; /* forward declaration */
+
+struct adp5588_gpio_platform_data {
+       int gpio_start;         /* GPIO Chip base # */
+       const char *const *names;
+       unsigned irq_base;      /* interrupt base # */
+       unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
+       int     (*setup)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       int     (*teardown)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       void    *context;
+};
+
+#endif
diff --git a/include/linux/platform_data/max732x.h b/include/linux/platform_data/max732x.h
new file mode 100644 (file)
index 0000000..c04bac8
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __LINUX_I2C_MAX732X_H
+#define __LINUX_I2C_MAX732X_H
+
+/* platform data for the MAX732x 8/16-bit I/O expander driver */
+
+struct max732x_platform_data {
+       /* number of the first GPIO */
+       unsigned        gpio_base;
+
+       /* interrupt base */
+       int             irq_base;
+
+       void            *context;       /* param to setup/teardown */
+
+       int             (*setup)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+       int             (*teardown)(struct i2c_client *client,
+                               unsigned gpio, unsigned ngpio,
+                               void *context);
+};
+#endif /* __LINUX_I2C_MAX732X_H */
diff --git a/include/linux/platform_data/pcf857x.h b/include/linux/platform_data/pcf857x.h
new file mode 100644 (file)
index 0000000..0767a2a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __LINUX_PCF857X_H
+#define __LINUX_PCF857X_H
+
+/**
+ * struct pcf857x_platform_data - data to set up pcf857x driver
+ * @gpio_base: number of the chip's first GPIO
+ * @n_latch: optional bit-inverse of initial register value; if
+ *     you leave this initialized to zero the driver will act
+ *     like the chip was just reset
+ * @setup: optional callback issued once the GPIOs are valid
+ * @teardown: optional callback issued before the GPIOs are invalidated
+ * @context: optional parameter passed to setup() and teardown()
+ *
+ * In addition to the I2C_BOARD_INFO() state appropriate to each chip,
+ * the i2c_board_info used with the pcf875x driver must provide its
+ * platform_data (pointer to one of these structures) with at least
+ * the gpio_base value initialized.
+ *
+ * The @setup callback may be used with the kind of board-specific glue
+ * which hands the (now-valid) GPIOs to other drivers, or which puts
+ * devices in their initial states using these GPIOs.
+ *
+ * These GPIO chips are only "quasi-bidirectional"; read the chip specs
+ * to understand the behavior.  They don't have separate registers to
+ * record which pins are used for input or output, record which output
+ * values are driven, or provide access to input values.  That must be
+ * inferred by reading the chip's value and knowing the last value written
+ * to it.  If you leave n_latch initialized to zero, that last written
+ * value is presumed to be all ones (as if the chip were just reset).
+ */
+struct pcf857x_platform_data {
+       unsigned        gpio_base;
+       unsigned        n_latch;
+
+       int             (*setup)(struct i2c_client *client,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+       int             (*teardown)(struct i2c_client *client,
+                                       int gpio, unsigned ngpio,
+                                       void *context);
+       void            *context;
+};
+
+#endif /* __LINUX_PCF857X_H */
index 98c2a7c..49f634d 100644 (file)
@@ -172,7 +172,7 @@ extern int platform_device_add_resources(struct platform_device *pdev,
 extern int platform_device_add_data(struct platform_device *pdev,
                                    const void *data, size_t size);
 extern int platform_device_add_properties(struct platform_device *pdev,
-                                         struct property_entry *properties);
+                               const struct property_entry *properties);
 extern int platform_device_add(struct platform_device *pdev);
 extern void platform_device_del(struct platform_device *pdev);
 extern void platform_device_put(struct platform_device *pdev);