Merge tag 'gpio-v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 Oct 2016 18:49:09 +0000 (11:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 Oct 2016 18:49:09 +0000 (11:49 -0700)
Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.9 series:

  Subsystem improvements:

   - do away with the last users of the obsolete Kconfig options
     ARCH_REQUIRE_GPIOLIB and ARCH_WANT_OPTIONAL_GPIOLIB (the latter
     always sounded like an item on a wishlist to Santa Claus to me). We
     can now select GPIOLIB and be done with it, for all archs. After
     some struggle it even work on UM. Not that it has GPIO, but if it
     wants to, it can select the library.

   - continued efforts to make drivers properly either tristate or bool.

   - introduce a warning for drivers assigning default triggers to their
     irqchip lines when probed from device tree, so we find and fix
     these ambigous drivers. It is agreed that in the OF config path,
     the device tree defines trigger characteristics.

   - the same warning, mutatis mutandis, for ACPI-probed GPIO irqchips.

   - we introduce the ability to mark certain IRQ lines as "unusable" as
     they can be taken by BIOS/firmware, unrouted in silicon and
     generally nasty if you use them, and such things. This is put to
     good use in the STMPE driver and also in the Cherryview pin control
     driver.

   - a new "mockup" virtual GPIO device that can be used for testing.
     The plan is to add unit tests under tools/* for exercising this
     device and verify that the kernel code paths are working as they
     should.

   - make memory-mapped I/O-drivers depend on HAS_IOMEM. This was
     implicit all the time, but when people started building UM with
     allyesconfig or allmodconfig it exploded in their face.

   - move some stray bits of device tree and ACPI HW description
     callbacks down into their respective implementation silo. These
     were causing issues when compiling on !HAS_IOMEM as well, so now
     eventually UM compiles the GPIOLIB library if it wants to.

  New drivers:

   - new driver for the Aspeed GPIO front-end companion to the pin
     controller merged through the pin control tree.

   - new driver for the LP873x PMIC GPIO portions.

   - new driver for Technologic Systems' I2C FPGA GPIO such as TS4900,
     TS-7970, TS-7990 and TS-4100.

   - new driver for the Broadcom BCM63xx series including BCM6338 and
     BCM6345.

   - new driver for the Intel WhiskeyCove PMIC GPIO.

   - new driver for the Allwinner AXP209 PMIC GPIO portions.

   - new driver for Diamond Systems 48 line GPIO-MM, another of these
     port-mapped I/O expansion cards.

   - support the STMicroelectronics STMPE1600 variant in the STMPE
     driver.

  Driver improvements:

   - the STMPE driver now supports rising/falling edge detection
     properly for IRQs.

   - the PCA954x will now fetch and enable its VCC regulator properly.

   - major rework of the PCA953x driver with the goal of eventually
     switching it over to use regmap and thus modernize it even more.

   - switch the IOP driver to use the generic MMIO GPIO library.

   - move the ages old HTC EGPIO (extended GPIO) GPIO expander driver
     over to this subsystem from MFD, achieveing some separation of
     concerns"

* tag 'gpio-v4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (81 commits)
  gpio: add missing static inline
  gpio: OF: localize some gpiochip init functions
  gpio: acpi: separation of concerns
  gpio: OF: separation of concerns
  gpio: make memory-mapped drivers depend on HAS_IOMEM
  gpio: stmpe: use BIT() macro
  gpio: stmpe: forbid unused lines to be mapped as IRQs
  mfd/gpio: Move HTC GPIO driver to GPIO subsystem
  gpio: MAINTAINERS: Add an entry for GPIO mockup driver
  gpio/mockup: add virtual gpio device
  gpio: Added zynq specific check for special pins on bank zero
  gpio: axp209: Implement get_direction
  gpio: aspeed: remove redundant return value check
  gpio: loongson1: remove redundant return value check
  ARM: omap2: fix missing include
  gpio: tc3589x: fix up complaints on unsigned
  gpio: tc3589x: add .get_direction() and small cleanup
  gpio: f7188x: use gpiochip_get_data instead of container_of
  gpio: tps65218: use devm_gpiochip_add_data() for gpio registration
  gpio: aspeed: fix return value check in aspeed_gpio_probe()
  ...

86 files changed:
Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-aspeed.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-axp209.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-tps65086.txt [deleted file]
Documentation/devicetree/bindings/gpio/gpio-ts4900.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
Documentation/devicetree/bindings/mfd/stmpe.txt
Documentation/gpio/board.txt
Documentation/gpio/gpio-legacy.txt
Documentation/kernel-parameters.txt
MAINTAINERS
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-sa1100/h3xxx.c
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/blackfin/Kconfig
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-altera.c
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-aspeed.c [new file with mode: 0644]
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-axp209.c [new file with mode: 0644]
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-da9052.c
drivers/gpio/gpio-da9055.c
drivers/gpio/gpio-f7188x.c
drivers/gpio/gpio-gpio-mm.c [new file with mode: 0644]
drivers/gpio/gpio-htc-egpio.c [new file with mode: 0644]
drivers/gpio/gpio-iop.c
drivers/gpio/gpio-it87.c
drivers/gpio/gpio-loongson1.c
drivers/gpio/gpio-lp873x.c [new file with mode: 0644]
drivers/gpio/gpio-lpc18xx.c
drivers/gpio/gpio-lpc32xx.c
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-mockup.c [new file with mode: 0644]
drivers/gpio/gpio-msic.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-palmas.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pisosr.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-sch.c
drivers/gpio/gpio-spear-spics.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-sx150x.c
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-tpic2810.c
drivers/gpio/gpio-tps65086.c
drivers/gpio/gpio-tps65218.c
drivers/gpio/gpio-tps65912.c
drivers/gpio/gpio-ts4800.c
drivers/gpio/gpio-ts4900.c [new file with mode: 0644]
drivers/gpio/gpio-twl4030.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-wcove.c [new file with mode: 0644]
drivers/gpio/gpio-wm831x.c
drivers/gpio/gpio-wm8350.c
drivers/gpio/gpio-wm8994.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/htc-egpio.c [deleted file]
drivers/mfd/lp873x.c [new file with mode: 0644]
drivers/mfd/stmpe-i2c.c
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/regulator/Kconfig
include/linux/gpio/driver.h
include/linux/mfd/htc-egpio.h [deleted file]
include/linux/mfd/lp873x.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/of_gpio.h
include/linux/platform_data/gpio-htc-egpio.h [new file with mode: 0644]
include/linux/platform_data/gpio-lpc32xx.h [deleted file]

diff --git a/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt b/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt
new file mode 100644 (file)
index 0000000..e785314
--- /dev/null
@@ -0,0 +1,46 @@
+Bindings for the Broadcom's brcm,bcm6345-gpio memory-mapped GPIO controllers.
+
+These bindings can be used on any BCM63xx SoC. However, BCM6338 and BCM6345
+are the only ones which don't need a pinctrl driver.
+BCM6338 have 8-bit data and dirout registers, where GPIO state can be read
+and/or written, and the direction changed from input to output.
+BCM6345 have 16-bit data and dirout registers, where GPIO state can be read
+and/or written, and the direction changed from input to output.
+
+Required properties:
+       - compatible: should be "brcm,bcm6345-gpio"
+       - reg-names: must contain
+               "dat" - data register
+               "dirout" - direction (output) register
+       - reg: address + size pairs describing the GPIO register sets;
+               order must correspond with the order of entries in reg-names
+       - #gpio-cells: must be set to 2. The first cell is the pin number and
+                       the second cell is used to specify the gpio polarity:
+                       0 = active high
+                       1 = active low
+       - gpio-controller: Marks the device node as a gpio controller.
+
+Optional properties:
+       - native-endian: use native endian memory.
+
+Examples:
+       - BCM6338:
+       gpio: gpio-controller@fffe0407 {
+               compatible = "brcm,bcm6345-gpio";
+               reg-names = "dirout", "dat";
+               reg = <0xfffe0407 1>, <0xfffe040f 1>;
+
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
+
+       - BCM6345:
+       gpio: gpio-controller@fffe0406 {
+               compatible = "brcm,bcm6345-gpio";
+               reg-names = "dirout", "dat";
+               reg = <0xfffe0406 2>, <0xfffe040a 2>;
+               native-endian;
+
+               #gpio-cells = <2>;
+               gpio-controller;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
new file mode 100644 (file)
index 0000000..393bb2e
--- /dev/null
@@ -0,0 +1,36 @@
+Aspeed GPIO controller Device Tree Bindings
+-------------------------------------------
+
+Required properties:
+- compatible           : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio"
+
+- #gpio-cells          : Should be two
+                         - First cell is the GPIO line number
+                         - Second cell is used to specify optional
+                           parameters (unused)
+
+- reg                  : Address and length of the register set for the device
+- gpio-controller      : Marks the device node as a GPIO controller.
+- interrupts           : Interrupt specifier (see interrupt bindings for
+                         details)
+- interrupt-controller : Mark the GPIO controller as an interrupt-controller
+
+Optional properties:
+
+- interrupt-parent     : The parent interrupt controller, optional if inherited
+
+The gpio and interrupt properties are further described in their respective
+bindings documentation:
+
+- Documentation/devicetree/bindings/gpio/gpio.txt
+- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+  Example:
+       gpio@1e780000 {
+               #gpio-cells = <2>;
+               compatible = "aspeed,ast2400-gpio";
+               gpio-controller;
+               interrupts = <20>;
+               reg = <0x1e780000 0x1000>;
+               interrupt-controller;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
new file mode 100644 (file)
index 0000000..a661130
--- /dev/null
@@ -0,0 +1,30 @@
+AXP209 GPIO controller
+
+This driver follows the usual GPIO bindings found in
+Documentation/devicetree/bindings/gpio/gpio.txt
+
+Required properties:
+- compatible: Should be "x-powers,axp209-gpio"
+- #gpio-cells: Should be two. The first cell is the pin number and the
+  second is the GPIO flags.
+- gpio-controller: Marks the device node as a GPIO controller.
+
+This node must be a subnode of the axp20x PMIC, documented in
+Documentation/devicetree/bindings/mfd/axp20x.txt
+
+Example:
+
+axp209: pmic@34 {
+       compatible = "x-powers,axp209";
+       reg = <0x34>;
+       interrupt-parent = <&nmi_intc>;
+       interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+       interrupt-controller;
+       #interrupt-cells = <1>;
+
+       axp_gpio: gpio {
+               compatible = "x-powers,axp209-gpio";
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt
new file mode 100644 (file)
index 0000000..1afc2de
--- /dev/null
@@ -0,0 +1,16 @@
+TPIC2810 GPIO controller bindings
+
+Required properties:
+ - compatible          : Should be "ti,tpic2810".
+ - reg                 : The I2C address of the device
+ - gpio-controller     : Marks the device node as a GPIO controller.
+ - #gpio-cells         : Should be two. For consumer use see gpio.txt.
+
+Example:
+
+       gpio@60 {
+               compatible = "ti,tpic2810";
+               reg = <0x60>;
+               gpio-controller;
+               #gpio-cells = <2>;
+       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt b/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
deleted file mode 100644 (file)
index ba05107..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-* TPS65086 GPO Controller bindings
-
-Required properties:
- - compatible          : Should be "ti,tps65086-gpio".
- - gpio-controller     : Marks the device node as a GPIO Controller.
- - #gpio-cells         : Should be two. The first cell is the pin number
-                           and the second cell is used to specify flags.
-                           See ../gpio/gpio.txt for possible values.
-
-Example:
-
-       gpio4: gpio {
-               compatible = "ti,tps65086-gpio";
-               gpio-controller;
-               #gpio-cells = <2>;
-       };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt b/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt
new file mode 100644 (file)
index 0000000..3f8e71b
--- /dev/null
@@ -0,0 +1,30 @@
+* Technologic Systems I2C-FPGA's GPIO controller bindings
+
+This bindings describes the GPIO controller for Technologic's FPGA core.
+TS-4900's FPGA encodes the GPIO state on 3 bits, whereas the TS-7970's FPGA
+uses 2 bits: it doesn't use a dedicated input bit.
+
+Required properties:
+- compatible: Should be one of the following
+               "technologic,ts4900-gpio"
+               "technologic,ts7970-gpio"
+- reg: Physical base address of the controller and length
+       of memory mapped region.
+- #gpio-cells: Should be two. The first cell is the pin number.
+- gpio-controller: Marks the device node as a gpio controller.
+
+Optional property:
+- ngpios: Number of GPIOs this controller is instantiated with,
+  the default is 32. See gpio.txt for more details.
+
+Example:
+
+&i2c2 {
+       gpio8: gpio@28 {
+               compatible = "technologic,ts4900-gpio";
+               reg = <0x28>;
+               #gpio-cells = <2>;
+               gpio-controller;
+               ngpios = <32>;
+       };
+};
index 98d1983..c3d0165 100644 (file)
@@ -44,26 +44,3 @@ Example for a PXA3xx platform:
                interrupt-controller;
                #interrupt-cells = <0x2>;
        };
-
-* Marvell Orion GPIO Controller
-
-Required properties:
-- compatible         : Should be "marvell,orion-gpio"
-- reg                : Address and length of the register set for controller.
-- gpio-controller    : So we know this is a gpio controller.
-- ngpio              : How many gpios this controller has.
-- interrupts        : Up to 4 Interrupts for the controller.
-
-Optional properties:
-- mask-offset        : For SMP Orions, offset for Nth CPU
-
-Example:
-
-               gpio0: gpio@10100 {
-                       compatible = "marvell,orion-gpio";
-                       #gpio-cells = <2>;
-                       gpio-controller;
-                       reg = <0x10100 0x40>;
-                       ngpio = <32>;
-                       interrupts = <35>, <36>, <37>, <38>;
-               };
index 8da26b3..7c1ab3b 100644 (file)
@@ -11,6 +11,7 @@ Required Properties:
     - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller.
     - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
     - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
+    - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
     - "renesas,gpio-rcar": for generic R-Car GPIO controller.
 
   - reg: Base address and length of each memory resource used by the GPIO
index 3fb68bf..f9065a5 100644 (file)
@@ -4,7 +4,7 @@ STMPE is an MFD device which may expose the following inbuilt devices: gpio,
 keypad, touchscreen, adc, pwm, rotator.
 
 Required properties:
- - compatible                   : "st,stmpe[610|801|811|1601|2401|2403]"
+ - compatible                   : "st,stmpe[610|801|811|1600|1601|2401|2403]"
  - reg                          : I2C/SPI address of the device
 
 Optional properties:
index 86d3fa9..40884c4 100644 (file)
@@ -8,9 +8,9 @@ gpio-legacy.txt (actually, there is no real mapping possible with the old
 interface; you just fetch an integer from somewhere and request the
 corresponding GPIO.
 
-Platforms that make use of GPIOs must select ARCH_REQUIRE_GPIOLIB (if GPIO usage
-is mandatory) or ARCH_WANT_OPTIONAL_GPIOLIB (if GPIO support can be omitted) in
-their Kconfig. Then, how GPIOs are mapped depends on what the platform uses to
+All platforms can enable the GPIO library, but if the platform strictly
+requires GPIO functionality to be present, it needs to select GPIOLIB from its
+Kconfig. Then, how GPIOs are mapped depends on what the platform uses to
 describe its hardware layout. Currently, mappings can be defined through device
 tree, ACPI, and platform data.
 
index 79ab564..b34fd94 100644 (file)
@@ -72,8 +72,8 @@ in this document, but drivers acting as clients to the GPIO interface must
 not care how it's implemented.)
 
 That said, if the convention is supported on their platform, drivers should
-use it when possible.  Platforms must select ARCH_REQUIRE_GPIOLIB or
-ARCH_WANT_OPTIONAL_GPIOLIB in their Kconfig.  Drivers that can't work without
+use it when possible.  Platforms must select GPIOLIB if GPIO functionality
+is strictly required.  Drivers that can't work without
 standard GPIO calls should have Kconfig entries which depend on GPIOLIB.  The
 GPIO calls are available, either as "real code" or as optimized-away stubs,
 when drivers use the include file:
@@ -553,22 +553,14 @@ either NULL or the label associated with that GPIO when it was requested.
 
 Platform Support
 ----------------
-To support this framework, a platform's Kconfig will "select" either
-ARCH_REQUIRE_GPIOLIB or ARCH_WANT_OPTIONAL_GPIOLIB
-and arrange that its <asm/gpio.h> includes <asm-generic/gpio.h> and defines
-three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep().
+To force-enable this framework, a platform's Kconfig will "select" GPIOLIB,
+else it is up to the user to configure support for GPIO.
 
 It may also provide a custom value for ARCH_NR_GPIOS, so that it better
 reflects the number of GPIOs in actual use on that platform, without
 wasting static table space.  (It should count both built-in/SoC GPIOs and
 also ones on GPIO expanders.
 
-ARCH_REQUIRE_GPIOLIB means that the gpiolib code will always get compiled
-into the kernel on that architecture.
-
-ARCH_WANT_OPTIONAL_GPIOLIB means the gpiolib code defaults to off and the user
-can enable it and build it into the kernel optionally.
-
 If neither of these options are selected, the platform does not support
 GPIOs through GPIO-lib and the code cannot be enabled by the user.
 
index fcf05a0..6fa1d8a 100644 (file)
@@ -1374,6 +1374,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Format: <unsigned int> such that (rxsize & ~0x1fffc0) == 0.
                        Default: 1024
 
+       gpio-mockup.gpio_mockup_ranges
+                       [HW] Sets the ranges of gpiochip of for this device.
+                       Format: <start1>,<end1>,<start2>,<end2>...
+
        hardlockup_all_cpu_backtrace=
                        [KNL] Should the hard-lockup detector generate
                        backtraces on all cpus.
index f4b944c..4f4d561 100644 (file)
@@ -3794,6 +3794,12 @@ F:       include/linux/regulator/da9211.h
 F:     include/sound/da[79]*.h
 F:     sound/soc/codecs/da[79]*.[ch]
 
+DIAMOND SYSTEMS GPIO-MM GPIO DRIVER
+M:     William Breathitt Gray <vilhelm.gray@gmail.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-gpio-mm.c
+
 DIGI NEO AND CLASSIC PCI PRODUCTS
 M:     Lidza Louina <lidza.louina@gmail.com>
 M:     Mark Hounschell <markh@compro.net>
@@ -5274,6 +5280,13 @@ L:       linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/input/touchscreen/goodix.c
 
+GPIO MOCKUP DRIVER
+M:     Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-mockup.c
+F:     tools/testing/selftests/gpio/
+
 GPIO SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 M:     Alexandre Courbot <gnurou@gmail.com>
index a5ab712..6d3af43 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/power/isp1704_charger.h>
 #include <linux/platform_data/spi-omap2-mcspi.h>
 #include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/module.h>
 
 #include <plat/dmtimer.h>
 
index 4a2f9ab..66184f5 100644 (file)
 #include <linux/input.h>
 #include <linux/input/navpoint.h>
 #include <linux/lcd.h>
-#include <linux/mfd/htc-egpio.h>
 #include <linux/mfd/asic3.h>
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
+#include <linux/platform_data/gpio-htc-egpio.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 #include <linux/regulator/driver.h>
index abc9181..265f48b 100644 (file)
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
-#include <linux/mfd/htc-egpio.h>
 #include <linux/mfd/htc-pasic3.h>
 #include <linux/mtd/physmap.h>
 #include <linux/pda_power.h>
+#include <linux/platform_data/gpio-htc-egpio.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 #include <linux/regulator/driver.h>
index b1d4faa..b69e766 100644 (file)
@@ -14,9 +14,9 @@
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
-#include <linux/mfd/htc-egpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/platform_data/gpio-htc-egpio.h>
 #include <linux/platform_data/sa11x0-serial.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
index 7d6bcf6..0160040 100644 (file)
@@ -17,7 +17,6 @@ config ARM64
        select ARCH_USE_CMPXCHG_LOCKREF
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_NUMA_BALANCING
-       select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_COMPAT_IPC_PARSE_VERSION
        select ARCH_WANT_FRAME_POINTERS
        select ARCH_HAS_UBSAN_SANITIZE_ALL
index 96ef543..b6b3657 100644 (file)
@@ -15,8 +15,8 @@ config ARCH_ALPINE
 
 config ARCH_BCM2835
        bool "Broadcom BCM2835 family"
-       select ARCH_REQUIRE_GPIOLIB
        select CLKSRC_OF
+       select GPIOLIB
        select PINCTRL
        select PINCTRL_BCM2835
        select ARM_AMBA
@@ -29,15 +29,15 @@ config ARCH_BCM2835
 config ARCH_BCM_IPROC
        bool "Broadcom iProc SoC Family"
        select COMMON_CLK_IPROC
+       select GPIOLIB
        select PINCTRL
-       select ARCH_REQUIRE_GPIOLIB
        help
          This enables support for Broadcom iProc based SoCs
 
 config ARCH_BERLIN
        bool "Marvell Berlin SoC Family"
-       select ARCH_REQUIRE_GPIOLIB
        select DW_APB_ICTL
+       select GPIOLIB
        select PINCTRL
        help
          This enables support for Marvell Berlin SoC Family
@@ -110,7 +110,7 @@ config ARCH_QCOM
 config ARCH_ROCKCHIP
        bool "Rockchip Platforms"
        select ARCH_HAS_RESET_CONTROLLER
-       select ARCH_REQUIRE_GPIOLIB
+       select GPIOLIB
        select PINCTRL
        select PINCTRL_ROCKCHIP
        select ROCKCHIP_TIMER
@@ -156,11 +156,11 @@ config ARCH_STRATIX10
 config ARCH_TEGRA
        bool "NVIDIA Tegra SoC Family"
        select ARCH_HAS_RESET_CONTROLLER
-       select ARCH_REQUIRE_GPIOLIB
        select CLKDEV_LOOKUP
        select CLKSRC_MMIO
        select CLKSRC_OF
        select GENERIC_CLOCKEVENTS
+       select GPIOLIB
        select PINCTRL
        select RESET_CONTROLLER
        help
@@ -184,8 +184,8 @@ config ARCH_UNIPHIER
 
 config ARCH_VEXPRESS
        bool "ARMv8 software model (Versatile Express)"
-       select ARCH_REQUIRE_GPIOLIB
        select COMMON_CLK_VERSATILE
+       select GPIOLIB
        select PM
        select PM_GENERIC_DOMAINS
        select POWER_RESET_VEXPRESS
index 28c63fe..3c1bd64 100644 (file)
@@ -26,7 +26,7 @@ config BLACKFIN
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS
        select ARCH_HAVE_CUSTOM_GPIO_H
-       select ARCH_REQUIRE_GPIOLIB
+       select GPIOLIB
        select HAVE_UID16
        select HAVE_UNDERSCORE_SYMBOL_PREFIX
        select VIRT_TO_BUS
index 24caedb..26ee00f 100644 (file)
@@ -10,27 +10,6 @@ config ARCH_HAVE_CUSTOM_GPIO_H
          overriding the default implementations.  New uses of this are
          strongly discouraged.
 
-config ARCH_WANT_OPTIONAL_GPIOLIB
-       bool
-       help
-         Select this config option from the architecture Kconfig, if
-         it is possible to use gpiolib on the architecture, but let the
-         user decide whether to actually build it or not.
-         Select this instead of ARCH_REQUIRE_GPIOLIB, if your architecture does
-         not depend on GPIOs being available, but rather let the user
-         decide whether he needs it or not.
-
-config ARCH_REQUIRE_GPIOLIB
-       bool
-       select GPIOLIB
-       help
-         Platforms select gpiolib if they use this infrastructure
-         for all their GPIOs, usually starting with ones integrated
-         into SOC processors.
-         Selecting this from the architecture code will cause the gpiolib
-         code to always get built in.
-
-
 menuconfig GPIOLIB
        bool "GPIO Support"
        select ANON_INODES
@@ -87,6 +66,7 @@ config GPIO_SYSFS
          exported to userspace; this can be useful when debugging.
 
 config GPIO_GENERIC
+       depends on HAS_IOMEM # Only for IOMEM drivers
        tristate
 
 # put drivers in the right section, in alphabetical order
@@ -96,6 +76,7 @@ config GPIO_MAX730X
        tristate
 
 menu "Memory mapped GPIO drivers"
+       depends on HAS_IOMEM
 
 config GPIO_74XX_MMIO
        tristate "GPIO driver for 74xx-ICs with MMIO access"
@@ -128,6 +109,13 @@ config GPIO_AMDPT
          driver for GPIO functionality on Promontory IOHub
          Require ACPI ASL code to enumerate as a platform device.
 
+config GPIO_ASPEED
+       tristate "Aspeed GPIO support"
+       depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO
+       select GPIOLIB_IRQCHIP
+       help
+         Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers.
+
 config GPIO_ATH79
        tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
        default y if ATH79
@@ -138,6 +126,12 @@ config GPIO_ATH79
          Select this option to enable GPIO driver for
          Atheros AR71XX/AR724X/AR913X SoC devices.
 
+config GPIO_AXP209
+       tristate "X-Powers AXP209 PMIC GPIO Support"
+       depends on MFD_AXP20X
+       help
+         Say yes to enable GPIO support for the AXP209 PMIC
+
 config GPIO_BCM_KONA
        bool "Broadcom Kona GPIO"
        depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
@@ -237,7 +231,8 @@ config GPIO_ICH
 
 config GPIO_IOP
        tristate "Intel IOP GPIO"
-       depends on ARM && (ARCH_IOP32X || ARCH_IOP33X)
+       depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
+       select GPIO_GENERIC
        help
          Say yes here to support the GPIO functionality of a number of Intel
          IOP32X or IOP33X.
@@ -287,6 +282,18 @@ config GPIO_MM_LANTIQ
          (EBU) found on Lantiq SoCs. The gpios are output only as they are
          created by attaching a 16bit latch to the bus.
 
+config GPIO_MOCKUP
+       tristate "GPIO Testing Driver"
+       depends on GPIOLIB
+       select GPIO_SYSFS
+       help
+         This enables GPIO Testing driver, which provides a way to test GPIO
+         subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
+         must be selected for this test.
+         User could use it through the script in
+         tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
+         it.
+
 config GPIO_MOXART
        bool "MOXART GPIO support"
        depends on ARCH_MOXART || COMPILE_TEST
@@ -574,6 +581,19 @@ config GPIO_F7188X
          To compile this driver as a module, choose M here: the module will
          be called f7188x-gpio.
 
+config GPIO_GPIO_MM
+       tristate "Diamond Systems GPIO-MM GPIO support"
+       depends on ISA_BUS_API
+       help
+         Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
+
+         The Diamond Systems GPIO-MM device features 48 lines of digital I/O
+         via the emulation of dual 82C55A PPI chips. This driver provides GPIO
+         support for these 48 channels of digital I/O.
+
+         The base port addresses for the devices may be configured via the base
+         array module parameter.
+
 config GPIO_IT87
        tristate "IT87xx GPIO support"
        help
@@ -780,6 +800,13 @@ config GPIO_TPIC2810
          To compile this driver as a module, choose M here: the module will
          be called gpio-tpic2810.
 
+config GPIO_TS4900
+       tristate "Technologic Systems FPGA I2C GPIO"
+       select REGMAP_I2C
+       help
+         Say yes here to enabled the GPIO driver for Technologic's FPGA core.
+         Series supported include TS-4100, TS-4900, TS-7970 and TS-7990.
+
 endmenu
 
 menu "MFD GPIO expanders"
@@ -849,6 +876,14 @@ config GPIO_DLN2
          This driver can also be built as a module. If so, the module
          will be called gpio-dln2.
 
+config HTC_EGPIO
+       bool "HTC EGPIO support"
+       depends on GPIOLIB && ARM
+       help
+           This driver supports the CPLD egpio chip present on
+           several HTC phones.  It provides basic support for input
+           pins, output pins, and irqs.
+
 config GPIO_JANZ_TTL
        tristate "Janz VMOD-TTL Digital IO Module"
        depends on MFD_JANZ_CMODIO
@@ -875,6 +910,16 @@ config GPIO_LP3943
          LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.
          Open drain outputs are required for this usage.
 
+config GPIO_LP873X
+       tristate "TI LP873X GPO"
+       depends on MFD_TI_LP873X
+       help
+         This driver supports the GPO on TI Lp873x PMICs. 2 GPOs are present
+         on LP873X PMICs.
+
+         This driver can also be built as a module. If so, the module will be
+          called gpio-lp873x.
+
 config GPIO_MAX77620
        tristate "GPIO support for PMIC MAX77620 and MAX20024"
        depends on MFD_MAX77620
@@ -985,6 +1030,19 @@ config GPIO_UCB1400
          This enables support for the Philips UCB1400 GPIO pins.
          The UCB1400 is an AC97 audio codec.
 
+config GPIO_WHISKEY_COVE
+       tristate "GPIO support for Whiskey Cove PMIC"
+       depends on INTEL_SOC_PMIC
+       select GPIOLIB_IRQCHIP
+       help
+         Support for GPIO pins on Whiskey Cove PMIC.
+
+         Say Yes if you have a Intel SoC based tablet with Whiskey Cove PMIC
+         inside.
+
+         This driver can also be built as a module. If so, the module will be
+         called gpio-wcove.
+
 config GPIO_WM831X
        tristate "WM831x GPIOs"
        depends on MFD_WM831X
index 2a035ed..ab28a2d 100644 (file)
@@ -28,6 +28,8 @@ obj-$(CONFIG_GPIO_AMD8111)    += gpio-amd8111.o
 obj-$(CONFIG_GPIO_AMDPT)       += gpio-amdpt.o
 obj-$(CONFIG_GPIO_ARIZONA)     += gpio-arizona.o
 obj-$(CONFIG_GPIO_ATH79)       += gpio-ath79.o
+obj-$(CONFIG_GPIO_ASPEED)      += gpio-aspeed.o
+obj-$(CONFIG_GPIO_AXP209)      += gpio-axp209.o
 obj-$(CONFIG_GPIO_BCM_KONA)    += gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BRCMSTB)     += gpio-brcmstb.o
 obj-$(CONFIG_GPIO_BT8XX)       += gpio-bt8xx.o
@@ -44,7 +46,9 @@ obj-$(CONFIG_GPIO_EP93XX)     += gpio-ep93xx.o
 obj-$(CONFIG_GPIO_ETRAXFS)     += gpio-etraxfs.o
 obj-$(CONFIG_GPIO_F7188X)      += gpio-f7188x.o
 obj-$(CONFIG_GPIO_GE_FPGA)     += gpio-ge.o
+obj-$(CONFIG_GPIO_GPIO_MM)     += gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)      += gpio-grgpio.o
+obj-$(CONFIG_HTC_EGPIO)                += gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)         += gpio-ich.o
 obj-$(CONFIG_GPIO_IOP)         += gpio-iop.o
 obj-$(CONFIG_GPIO_IT87)                += gpio-it87.o
@@ -56,6 +60,7 @@ obj-$(CONFIG_GPIO_LOONGSON)   += gpio-loongson.o
 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_LYNXPOINT)   += gpio-lynxpoint.o
 obj-$(CONFIG_GPIO_MAX730X)     += gpio-max730x.o
 obj-$(CONFIG_GPIO_MAX7300)     += gpio-max7300.o
@@ -70,6 +75,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
 obj-$(CONFIG_GPIO_MCP23S08)    += gpio-mcp23s08.o
 obj-$(CONFIG_GPIO_ML_IOH)      += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MM_LANTIQ)   += gpio-mm-lantiq.o
+obj-$(CONFIG_GPIO_MOCKUP)      += gpio-mockup.o
 obj-$(CONFIG_GPIO_MOXART)      += gpio-moxart.o
 obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
 obj-$(CONFIG_GPIO_MPC8XXX)     += gpio-mpc8xxx.o
@@ -110,6 +116,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
 obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
 obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
 obj-$(CONFIG_GPIO_TS4800)      += gpio-ts4800.o
+obj-$(CONFIG_GPIO_TS4900)      += gpio-ts4900.o
 obj-$(CONFIG_GPIO_TS5500)      += gpio-ts5500.o
 obj-$(CONFIG_GPIO_TWL4030)     += gpio-twl4030.o
 obj-$(CONFIG_GPIO_TWL6040)     += gpio-twl6040.o
@@ -120,6 +127,7 @@ obj-$(CONFIG_GPIO_VF610)    += gpio-vf610.o
 obj-$(CONFIG_GPIO_VIPERBOARD)  += gpio-viperboard.o
 obj-$(CONFIG_GPIO_VR41XX)      += gpio-vr41xx.o
 obj-$(CONFIG_GPIO_VX855)       += gpio-vx855.o
+obj-$(CONFIG_GPIO_WHISKEY_COVE)        += gpio-wcove.o
 obj-$(CONFIG_GPIO_WM831X)      += gpio-wm831x.o
 obj-$(CONFIG_GPIO_WM8350)      += gpio-wm8350.o
 obj-$(CONFIG_GPIO_WM8994)      += gpio-wm8994.o
index 3f87a03..5bddbd5 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 
index 9913704..4824628 100644 (file)
@@ -79,7 +79,7 @@ static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                           ARIZONA_GPN_LVL, value);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "arizona",
        .owner                  = THIS_MODULE,
        .direction_input        = arizona_gpio_direction_in,
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
new file mode 100644 (file)
index 0000000..03a5925
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * Joel Stanley <joel@jms.id.au>
+ *
+ * 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 Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/gpio/driver.h>
+#include <linux/pinctrl/consumer.h>
+
+struct aspeed_gpio {
+       struct gpio_chip chip;
+       spinlock_t lock;
+       void __iomem *base;
+       int irq;
+};
+
+struct aspeed_gpio_bank {
+       uint16_t        val_regs;
+       uint16_t        irq_regs;
+       const char      names[4];
+};
+
+static const struct aspeed_gpio_bank aspeed_gpio_banks[] = {
+       {
+               .val_regs = 0x0000,
+               .irq_regs = 0x0008,
+               .names = { 'A', 'B', 'C', 'D' },
+       },
+       {
+               .val_regs = 0x0020,
+               .irq_regs = 0x0028,
+               .names = { 'E', 'F', 'G', 'H' },
+       },
+       {
+               .val_regs = 0x0070,
+               .irq_regs = 0x0098,
+               .names = { 'I', 'J', 'K', 'L' },
+       },
+       {
+               .val_regs = 0x0078,
+               .irq_regs = 0x00e8,
+               .names = { 'M', 'N', 'O', 'P' },
+       },
+       {
+               .val_regs = 0x0080,
+               .irq_regs = 0x0118,
+               .names = { 'Q', 'R', 'S', 'T' },
+       },
+       {
+               .val_regs = 0x0088,
+               .irq_regs = 0x0148,
+               .names = { 'U', 'V', 'W', 'X' },
+       },
+       /*
+        * A bank exists for { 'Y', 'Z', "AA", "AB" }, but is not implemented.
+        * Only half of GPIOs Y support interrupt configuration, and none of Z,
+        * AA or AB do as they are output only.
+        */
+};
+
+#define GPIO_BANK(x)   ((x) >> 5)
+#define GPIO_OFFSET(x) ((x) & 0x1f)
+#define GPIO_BIT(x)    BIT(GPIO_OFFSET(x))
+
+#define GPIO_DATA      0x00
+#define GPIO_DIR       0x04
+
+#define GPIO_IRQ_ENABLE        0x00
+#define GPIO_IRQ_TYPE0 0x04
+#define GPIO_IRQ_TYPE1 0x08
+#define GPIO_IRQ_TYPE2 0x0c
+#define GPIO_IRQ_STATUS        0x10
+
+static const struct aspeed_gpio_bank *to_bank(unsigned int offset)
+{
+       unsigned int bank = GPIO_BANK(offset);
+
+       WARN_ON(bank > ARRAY_SIZE(aspeed_gpio_banks));
+       return &aspeed_gpio_banks[bank];
+}
+
+static void __iomem *bank_val_reg(struct aspeed_gpio *gpio,
+               const struct aspeed_gpio_bank *bank,
+               unsigned int reg)
+{
+       return gpio->base + bank->val_regs + reg;
+}
+
+static void __iomem *bank_irq_reg(struct aspeed_gpio *gpio,
+               const struct aspeed_gpio_bank *bank,
+               unsigned int reg)
+{
+       return gpio->base + bank->irq_regs + reg;
+}
+
+static int aspeed_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+
+       return !!(ioread32(bank_val_reg(gpio, bank, GPIO_DATA))
+                       & GPIO_BIT(offset));
+}
+
+static void __aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
+                             int val)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+       void __iomem *addr;
+       u32 reg;
+
+       addr = bank_val_reg(gpio, bank, GPIO_DATA);
+       reg = ioread32(addr);
+
+       if (val)
+               reg |= GPIO_BIT(offset);
+       else
+               reg &= ~GPIO_BIT(offset);
+
+       iowrite32(reg, addr);
+}
+
+static void aspeed_gpio_set(struct gpio_chip *gc, unsigned int offset,
+                           int val)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       __aspeed_gpio_set(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static int aspeed_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
+       iowrite32(reg & ~GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR));
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_gpio_dir_out(struct gpio_chip *gc,
+                              unsigned int offset, int val)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       reg = ioread32(bank_val_reg(gpio, bank, GPIO_DIR));
+       iowrite32(reg | GPIO_BIT(offset), bank_val_reg(gpio, bank, GPIO_DIR));
+
+       __aspeed_gpio_set(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_gpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_gpio_bank *bank = to_bank(offset);
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       val = ioread32(bank_val_reg(gpio, bank, GPIO_DIR)) & GPIO_BIT(offset);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return !val;
+
+}
+
+static inline int irqd_to_aspeed_gpio_data(struct irq_data *d,
+               struct aspeed_gpio **gpio,
+               const struct aspeed_gpio_bank **bank,
+               u32 *bit)
+{
+       int offset;
+
+       offset = irqd_to_hwirq(d);
+
+       *gpio = irq_data_get_irq_chip_data(d);
+       *bank = to_bank(offset);
+       *bit = GPIO_BIT(offset);
+
+       return 0;
+}
+
+static void aspeed_gpio_irq_ack(struct irq_data *d)
+{
+       const struct aspeed_gpio_bank *bank;
+       struct aspeed_gpio *gpio;
+       unsigned long flags;
+       void __iomem *status_addr;
+       u32 bit;
+       int rc;
+
+       rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit);
+       if (rc)
+               return;
+
+       status_addr = bank_irq_reg(gpio, bank, GPIO_IRQ_STATUS);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+       iowrite32(bit, status_addr);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_gpio_irq_set_mask(struct irq_data *d, bool set)
+{
+       const struct aspeed_gpio_bank *bank;
+       struct aspeed_gpio *gpio;
+       unsigned long flags;
+       u32 reg, bit;
+       void __iomem *addr;
+       int rc;
+
+       rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit);
+       if (rc)
+               return;
+
+       addr = bank_irq_reg(gpio, bank, GPIO_IRQ_ENABLE);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       reg = ioread32(addr);
+       if (set)
+               reg |= bit;
+       else
+               reg &= bit;
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_gpio_irq_mask(struct irq_data *d)
+{
+       aspeed_gpio_irq_set_mask(d, false);
+}
+
+static void aspeed_gpio_irq_unmask(struct irq_data *d)
+{
+       aspeed_gpio_irq_set_mask(d, true);
+}
+
+static int aspeed_gpio_set_type(struct irq_data *d, unsigned int type)
+{
+       u32 type0 = 0;
+       u32 type1 = 0;
+       u32 type2 = 0;
+       u32 bit, reg;
+       const struct aspeed_gpio_bank *bank;
+       irq_flow_handler_t handler;
+       struct aspeed_gpio *gpio;
+       unsigned long flags;
+       void __iomem *addr;
+       int rc;
+
+       rc = irqd_to_aspeed_gpio_data(d, &gpio, &bank, &bit);
+       if (rc)
+               return -EINVAL;
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_BOTH:
+               type2 |= bit;
+       case IRQ_TYPE_EDGE_RISING:
+               type0 |= bit;
+       case IRQ_TYPE_EDGE_FALLING:
+               handler = handle_edge_irq;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type0 |= bit;
+       case IRQ_TYPE_LEVEL_LOW:
+               type1 |= bit;
+               handler = handle_level_irq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE0);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type0;
+       iowrite32(reg, addr);
+
+       addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE1);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type1;
+       iowrite32(reg, addr);
+
+       addr = bank_irq_reg(gpio, bank, GPIO_IRQ_TYPE2);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type2;
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       irq_set_handler_locked(d, handler);
+
+       return 0;
+}
+
+static void aspeed_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct irq_chip *ic = irq_desc_get_chip(desc);
+       struct aspeed_gpio *data = gpiochip_get_data(gc);
+       unsigned int i, p, girq;
+       unsigned long reg;
+
+       chained_irq_enter(ic, desc);
+
+       for (i = 0; i < ARRAY_SIZE(aspeed_gpio_banks); i++) {
+               const struct aspeed_gpio_bank *bank = &aspeed_gpio_banks[i];
+
+               reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS));
+
+               for_each_set_bit(p, &reg, 32) {
+                       girq = irq_find_mapping(gc->irqdomain, i * 32 + p);
+                       generic_handle_irq(girq);
+               }
+
+       }
+
+       chained_irq_exit(ic, desc);
+}
+
+static struct irq_chip aspeed_gpio_irqchip = {
+       .name           = "aspeed-gpio",
+       .irq_ack        = aspeed_gpio_irq_ack,
+       .irq_mask       = aspeed_gpio_irq_mask,
+       .irq_unmask     = aspeed_gpio_irq_unmask,
+       .irq_set_type   = aspeed_gpio_set_type,
+};
+
+static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
+               struct platform_device *pdev)
+{
+       int rc;
+
+       rc = platform_get_irq(pdev, 0);
+       if (rc < 0)
+               return rc;
+
+       gpio->irq = rc;
+
+       rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
+                       0, handle_bad_irq, IRQ_TYPE_NONE);
+       if (rc) {
+               dev_info(&pdev->dev, "Could not add irqchip\n");
+               return rc;
+       }
+
+       gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip,
+                                    gpio->irq, aspeed_gpio_irq_handler);
+
+       return 0;
+}
+
+static int aspeed_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void aspeed_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static int __init aspeed_gpio_probe(struct platform_device *pdev)
+{
+       struct aspeed_gpio *gpio;
+       struct resource *res;
+       int rc;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       gpio->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(gpio->base))
+               return PTR_ERR(gpio->base);
+
+       spin_lock_init(&gpio->lock);
+
+       gpio->chip.ngpio = ARRAY_SIZE(aspeed_gpio_banks) * 32;
+
+       gpio->chip.parent = &pdev->dev;
+       gpio->chip.direction_input = aspeed_gpio_dir_in;
+       gpio->chip.direction_output = aspeed_gpio_dir_out;
+       gpio->chip.get_direction = aspeed_gpio_get_direction;
+       gpio->chip.request = aspeed_gpio_request;
+       gpio->chip.free = aspeed_gpio_free;
+       gpio->chip.get = aspeed_gpio_get;
+       gpio->chip.set = aspeed_gpio_set;
+       gpio->chip.label = dev_name(&pdev->dev);
+       gpio->chip.base = -1;
+
+       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (rc < 0)
+               return rc;
+
+       return aspeed_gpio_setup_irqs(gpio, pdev);
+}
+
+static const struct of_device_id aspeed_gpio_of_table[] = {
+       { .compatible = "aspeed,ast2400-gpio" },
+       { .compatible = "aspeed,ast2500-gpio" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
+
+static struct platform_driver aspeed_gpio_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = aspeed_gpio_of_table,
+       },
+};
+
+module_platform_driver_probe(aspeed_gpio_driver, aspeed_gpio_probe);
+
+MODULE_DESCRIPTION("Aspeed GPIO Driver");
+MODULE_LICENSE("GPL");
index c4f4cdd..9457e20 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_data/gpio-ath79.h>
 #include <linux/of_device.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/irq.h>
 
 #define AR71XX_GPIO_REG_OE             0x00
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c
new file mode 100644 (file)
index 0000000..d9c2a51
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * AXP20x GPIO driver
+ *
+ * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * 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
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AXP20X_GPIO_FUNCTIONS          0x7
+#define AXP20X_GPIO_FUNCTION_OUT_LOW   0
+#define AXP20X_GPIO_FUNCTION_OUT_HIGH  1
+#define AXP20X_GPIO_FUNCTION_INPUT     2
+
+struct axp20x_gpio {
+       struct gpio_chip        chip;
+       struct regmap           *regmap;
+};
+
+static int axp20x_gpio_get_reg(unsigned offset)
+{
+       switch (offset) {
+       case 0:
+               return AXP20X_GPIO0_CTRL;
+       case 1:
+               return AXP20X_GPIO1_CTRL;
+       case 2:
+               return AXP20X_GPIO2_CTRL;
+       }
+
+       return -EINVAL;
+}
+
+static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+       int reg;
+
+       reg = axp20x_gpio_get_reg(offset);
+       if (reg < 0)
+               return reg;
+
+       return regmap_update_bits(gpio->regmap, reg,
+                                 AXP20X_GPIO_FUNCTIONS,
+                                 AXP20X_GPIO_FUNCTION_INPUT);
+}
+
+static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+       unsigned int val;
+       int reg, ret;
+
+       reg = axp20x_gpio_get_reg(offset);
+       if (reg < 0)
+               return reg;
+
+       ret = regmap_read(gpio->regmap, reg, &val);
+       if (ret)
+               return ret;
+
+       return !!(val & BIT(offset + 4));
+}
+
+static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+       unsigned int val;
+       int reg, ret;
+
+       reg = axp20x_gpio_get_reg(offset);
+       if (reg < 0)
+               return reg;
+
+       ret = regmap_read(gpio->regmap, reg, &val);
+       if (ret)
+               return ret;
+
+       /*
+        * This shouldn't really happen if the pin is in use already,
+        * or if it's not in use yet, it doesn't matter since we're
+        * going to change the value soon anyway. Default to output.
+        */
+       if ((val & AXP20X_GPIO_FUNCTIONS) > 2)
+               return 0;
+
+       /*
+        * The GPIO directions are the three lowest values.
+        * 2 is input, 0 and 1 are output
+        */
+       return val & 2;
+}
+
+static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
+                             int value)
+{
+       struct axp20x_gpio *gpio = gpiochip_get_data(chip);
+       int reg;
+
+       reg = axp20x_gpio_get_reg(offset);
+       if (reg < 0)
+               return reg;
+
+       return regmap_update_bits(gpio->regmap, reg,
+                                 AXP20X_GPIO_FUNCTIONS,
+                                 value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
+                                 : AXP20X_GPIO_FUNCTION_OUT_LOW);
+}
+
+static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
+                           int value)
+{
+       axp20x_gpio_output(chip, offset, value);
+}
+
+static int axp20x_gpio_probe(struct platform_device *pdev)
+{
+       struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+       struct axp20x_gpio *gpio;
+       int ret;
+
+       if (!of_device_is_available(pdev->dev.of_node))
+               return -ENODEV;
+
+       if (!axp20x) {
+               dev_err(&pdev->dev, "Parent drvdata not set\n");
+               return -EINVAL;
+       }
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       gpio->chip.base                 = -1;
+       gpio->chip.can_sleep            = true;
+       gpio->chip.parent               = &pdev->dev;
+       gpio->chip.label                = dev_name(&pdev->dev);
+       gpio->chip.owner                = THIS_MODULE;
+       gpio->chip.get                  = axp20x_gpio_get;
+       gpio->chip.get_direction        = axp20x_gpio_get_direction;
+       gpio->chip.set                  = axp20x_gpio_set;
+       gpio->chip.direction_input      = axp20x_gpio_input;
+       gpio->chip.direction_output     = axp20x_gpio_output;
+       gpio->chip.ngpio                = 3;
+
+       gpio->regmap = axp20x->regmap;
+
+       ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register GPIO chip\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
+
+       return 0;
+}
+
+static const struct of_device_id axp20x_gpio_match[] = {
+       { .compatible = "x-powers,axp209-gpio" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
+
+static struct platform_driver axp20x_gpio_driver = {
+       .probe          = axp20x_gpio_probe,
+       .driver = {
+               .name           = "axp20x-gpio",
+               .of_match_table = axp20x_gpio_match,
+       },
+};
+
+module_platform_driver(axp20x_gpio_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
+MODULE_LICENSE("GPL");
index 953e4b8..3d1cf01 100644 (file)
@@ -308,7 +308,7 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
        return 0;
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label = "bcm-kona-gpio",
        .owner = THIS_MODULE,
        .request = bcm_kona_gpio_request,
index e29553b..dd8977c 100644 (file)
@@ -184,7 +184,7 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
        return irq;
 }
 
-static struct gpio_chip reference_gp = {
+static const struct gpio_chip reference_gp = {
        .label = "da9052-gpio",
        .owner = THIS_MODULE,
        .get = da9052_gpio_get,
index 2c2c18d..82053b5 100644 (file)
@@ -121,7 +121,7 @@ static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
                                  DA9055_IRQ_GPI0 + offset);
 }
 
-static struct gpio_chip reference_gp = {
+static const struct gpio_chip reference_gp = {
        .label = "da9055-gpio",
        .owner = THIS_MODULE,
        .get = da9055_gpio_get,
index 600be84..e8accde 100644 (file)
@@ -214,8 +214,7 @@ static struct f7188x_gpio_bank f81866_gpio_bank[] = {
 static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
        int err;
-       struct f7188x_gpio_bank *bank =
-               container_of(chip, struct f7188x_gpio_bank, chip);
+       struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
        struct f7188x_sio *sio = bank->data->sio;
        u8 dir;
 
diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c
new file mode 100644 (file)
index 0000000..1e7def9
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * GPIO driver for the Diamond Systems GPIO-MM
+ * Copyright (C) 2016 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * This driver supports the following Diamond Systems devices: GPIO-MM and
+ * GPIO-MM-12.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/isa.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+
+#define GPIOMM_EXTENT 8
+#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
+
+static unsigned int base[MAX_NUM_GPIOMM];
+static unsigned int num_gpiomm;
+module_param_array(base, uint, &num_gpiomm, 0);
+MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
+
+/**
+ * struct gpiomm_gpio - GPIO device private data structure
+ * @chip:      instance of the gpio_chip
+ * @io_state:  bit I/O state (whether bit is set to input or output)
+ * @out_state: output bits state
+ * @control:   Control registers state
+ * @lock:      synchronization lock to prevent I/O race conditions
+ * @base:      base port address of the GPIO device
+ */
+struct gpiomm_gpio {
+       struct gpio_chip chip;
+       unsigned char io_state[6];
+       unsigned char out_state[6];
+       unsigned char control[2];
+       spinlock_t lock;
+       unsigned int base;
+};
+
+static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
+       unsigned int offset)
+{
+       struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+       const unsigned int port = offset / 8;
+       const unsigned int mask = BIT(offset % 8);
+
+       return !!(gpiommgpio->io_state[port] & mask);
+}
+
+static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
+       unsigned int offset)
+{
+       struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+       const unsigned int io_port = offset / 8;
+       const unsigned int control_port = io_port / 3;
+       const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
+       unsigned long flags;
+       unsigned int control;
+
+       spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+       /* Check if configuring Port C */
+       if (io_port == 2 || io_port == 5) {
+               /* Port C can be configured by nibble */
+               if (offset % 8 > 3) {
+                       gpiommgpio->io_state[io_port] |= 0xF0;
+                       gpiommgpio->control[control_port] |= BIT(3);
+               } else {
+                       gpiommgpio->io_state[io_port] |= 0x0F;
+                       gpiommgpio->control[control_port] |= BIT(0);
+               }
+       } else {
+               gpiommgpio->io_state[io_port] |= 0xFF;
+               if (io_port == 0 || io_port == 3)
+                       gpiommgpio->control[control_port] |= BIT(4);
+               else
+                       gpiommgpio->control[control_port] |= BIT(1);
+       }
+
+       control = BIT(7) | gpiommgpio->control[control_port];
+       outb(control, control_addr);
+
+       spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+       return 0;
+}
+
+static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
+       unsigned int offset, int value)
+{
+       struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+       const unsigned int io_port = offset / 8;
+       const unsigned int control_port = io_port / 3;
+       const unsigned int mask = BIT(offset % 8);
+       const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
+       const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
+       unsigned long flags;
+       unsigned int control;
+
+       spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+       /* Check if configuring Port C */
+       if (io_port == 2 || io_port == 5) {
+               /* Port C can be configured by nibble */
+               if (offset % 8 > 3) {
+                       gpiommgpio->io_state[io_port] &= 0x0F;
+                       gpiommgpio->control[control_port] &= ~BIT(3);
+               } else {
+                       gpiommgpio->io_state[io_port] &= 0xF0;
+                       gpiommgpio->control[control_port] &= ~BIT(0);
+               }
+       } else {
+               gpiommgpio->io_state[io_port] &= 0x00;
+               if (io_port == 0 || io_port == 3)
+                       gpiommgpio->control[control_port] &= ~BIT(4);
+               else
+                       gpiommgpio->control[control_port] &= ~BIT(1);
+       }
+
+       if (value)
+               gpiommgpio->out_state[io_port] |= mask;
+       else
+               gpiommgpio->out_state[io_port] &= ~mask;
+
+       control = BIT(7) | gpiommgpio->control[control_port];
+       outb(control, control_addr);
+
+       outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
+
+       spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+       return 0;
+}
+
+static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+       const unsigned int port = offset / 8;
+       const unsigned int mask = BIT(offset % 8);
+       const unsigned int in_port = (port > 2) ? port + 1 : port;
+       unsigned long flags;
+       unsigned int port_state;
+
+       spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+       /* ensure that GPIO is set for input */
+       if (!(gpiommgpio->io_state[port] & mask)) {
+               spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+               return -EINVAL;
+       }
+
+       port_state = inb(gpiommgpio->base + in_port);
+
+       spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+       return !!(port_state & mask);
+}
+
+static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
+       int value)
+{
+       struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+       const unsigned int port = offset / 8;
+       const unsigned int mask = BIT(offset % 8);
+       const unsigned int out_port = (port > 2) ? port + 1 : port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+       if (value)
+               gpiommgpio->out_state[port] |= mask;
+       else
+               gpiommgpio->out_state[port] &= ~mask;
+
+       outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
+
+       spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+}
+
+static int gpiomm_probe(struct device *dev, unsigned int id)
+{
+       struct gpiomm_gpio *gpiommgpio;
+       const char *const name = dev_name(dev);
+       int err;
+
+       gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
+       if (!gpiommgpio)
+               return -ENOMEM;
+
+       if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
+               dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
+                       base[id], base[id] + GPIOMM_EXTENT);
+               return -EBUSY;
+       }
+
+       gpiommgpio->chip.label = name;
+       gpiommgpio->chip.parent = dev;
+       gpiommgpio->chip.owner = THIS_MODULE;
+       gpiommgpio->chip.base = -1;
+       gpiommgpio->chip.ngpio = 48;
+       gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
+       gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
+       gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
+       gpiommgpio->chip.get = gpiomm_gpio_get;
+       gpiommgpio->chip.set = gpiomm_gpio_set;
+       gpiommgpio->base = base[id];
+
+       spin_lock_init(&gpiommgpio->lock);
+
+       dev_set_drvdata(dev, gpiommgpio);
+
+       err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
+       if (err) {
+               dev_err(dev, "GPIO registering failed (%d)\n", err);
+               return err;
+       }
+
+       /* initialize all GPIO as output */
+       outb(0x80, base[id] + 3);
+       outb(0x00, base[id]);
+       outb(0x00, base[id] + 1);
+       outb(0x00, base[id] + 2);
+       outb(0x80, base[id] + 7);
+       outb(0x00, base[id] + 4);
+       outb(0x00, base[id] + 5);
+       outb(0x00, base[id] + 6);
+
+       return 0;
+}
+
+static int gpiomm_remove(struct device *dev, unsigned int id)
+{
+       struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
+
+       gpiochip_remove(&gpiommgpio->chip);
+
+       return 0;
+}
+
+static struct isa_driver gpiomm_driver = {
+       .probe = gpiomm_probe,
+       .driver = {
+               .name = "gpio-mm"
+       },
+       .remove = gpiomm_remove
+};
+
+module_isa_driver(gpiomm_driver, num_gpiomm);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c
new file mode 100644 (file)
index 0000000..0b4df60
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ * Support for the GPIO/IRQ expander chips present on several HTC phones.
+ * These are implemented in CPLD chips present on the board.
+ *
+ * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This file may be distributed under the terms of the GNU GPL license.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/platform_data/gpio-htc-egpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+struct egpio_chip {
+       int              reg_start;
+       int              cached_values;
+       unsigned long    is_out;
+       struct device    *dev;
+       struct gpio_chip chip;
+};
+
+struct egpio_info {
+       spinlock_t        lock;
+
+       /* iomem info */
+       void __iomem      *base_addr;
+       int               bus_shift;    /* byte shift */
+       int               reg_shift;    /* bit shift */
+       int               reg_mask;
+
+       /* irq info */
+       int               ack_register;
+       int               ack_write;
+       u16               irqs_enabled;
+       uint              irq_start;
+       int               nirqs;
+       uint              chained_irq;
+
+       /* egpio info */
+       struct egpio_chip *chip;
+       int               nchips;
+};
+
+static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
+{
+       writew(value, ei->base_addr + (reg << ei->bus_shift));
+}
+
+static inline u16 egpio_readw(struct egpio_info *ei, int reg)
+{
+       return readw(ei->base_addr + (reg << ei->bus_shift));
+}
+
+/*
+ * IRQs
+ */
+
+static inline void ack_irqs(struct egpio_info *ei)
+{
+       egpio_writew(ei->ack_write, ei, ei->ack_register);
+       pr_debug("EGPIO ack - write %x to base+%x\n",
+                       ei->ack_write, ei->ack_register << ei->bus_shift);
+}
+
+static void egpio_ack(struct irq_data *data)
+{
+}
+
+/* There does not appear to be a way to proactively mask interrupts
+ * on the egpio chip itself.  So, we simply ignore interrupts that
+ * aren't desired. */
+static void egpio_mask(struct irq_data *data)
+{
+       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+       ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
+       pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
+}
+
+static void egpio_unmask(struct irq_data *data)
+{
+       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
+       ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
+       pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
+}
+
+static struct irq_chip egpio_muxed_chip = {
+       .name           = "htc-egpio",
+       .irq_ack        = egpio_ack,
+       .irq_mask       = egpio_mask,
+       .irq_unmask     = egpio_unmask,
+};
+
+static void egpio_handler(struct irq_desc *desc)
+{
+       struct egpio_info *ei = irq_desc_get_handler_data(desc);
+       int irqpin;
+
+       /* Read current pins. */
+       unsigned long readval = egpio_readw(ei, ei->ack_register);
+       pr_debug("IRQ reg: %x\n", (unsigned int)readval);
+       /* Ack/unmask interrupts. */
+       ack_irqs(ei);
+       /* Process all set pins. */
+       readval &= ei->irqs_enabled;
+       for_each_set_bit(irqpin, &readval, ei->nirqs) {
+               /* Run irq handler */
+               pr_debug("got IRQ %d\n", irqpin);
+               generic_handle_irq(ei->irq_start + irqpin);
+       }
+}
+
+int htc_egpio_get_wakeup_irq(struct device *dev)
+{
+       struct egpio_info *ei = dev_get_drvdata(dev);
+
+       /* Read current pins. */
+       u16 readval = egpio_readw(ei, ei->ack_register);
+       /* Ack/unmask interrupts. */
+       ack_irqs(ei);
+       /* Return first set pin. */
+       readval &= ei->irqs_enabled;
+       return ei->irq_start + ffs(readval) - 1;
+}
+EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
+
+static inline int egpio_pos(struct egpio_info *ei, int bit)
+{
+       return bit >> ei->reg_shift;
+}
+
+static inline int egpio_bit(struct egpio_info *ei, int bit)
+{
+       return 1 << (bit & ((1 << ei->reg_shift)-1));
+}
+
+/*
+ * Input pins
+ */
+
+static int egpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct egpio_chip *egpio;
+       struct egpio_info *ei;
+       unsigned           bit;
+       int                reg;
+       int                value;
+
+       pr_debug("egpio_get_value(%d)\n", chip->base + offset);
+
+       egpio = gpiochip_get_data(chip);
+       ei    = dev_get_drvdata(egpio->dev);
+       bit   = egpio_bit(ei, offset);
+       reg   = egpio->reg_start + egpio_pos(ei, offset);
+
+       value = egpio_readw(ei, reg);
+       pr_debug("readw(%p + %x) = %x\n",
+                       ei->base_addr, reg << ei->bus_shift, value);
+       return !!(value & bit);
+}
+
+static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct egpio_chip *egpio;
+
+       egpio = gpiochip_get_data(chip);
+       return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
+}
+
+
+/*
+ * Output pins
+ */
+
+static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       unsigned long     flag;
+       struct egpio_chip *egpio;
+       struct egpio_info *ei;
+       unsigned          bit;
+       int               pos;
+       int               reg;
+       int               shift;
+
+       pr_debug("egpio_set(%s, %d(%d), %d)\n",
+                       chip->label, offset, offset+chip->base, value);
+
+       egpio = gpiochip_get_data(chip);
+       ei    = dev_get_drvdata(egpio->dev);
+       bit   = egpio_bit(ei, offset);
+       pos   = egpio_pos(ei, offset);
+       reg   = egpio->reg_start + pos;
+       shift = pos << ei->reg_shift;
+
+       pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
+                       reg, (egpio->cached_values >> shift) & ei->reg_mask);
+
+       spin_lock_irqsave(&ei->lock, flag);
+       if (value)
+               egpio->cached_values |= (1 << offset);
+       else
+               egpio->cached_values &= ~(1 << offset);
+       egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
+       spin_unlock_irqrestore(&ei->lock, flag);
+}
+
+static int egpio_direction_output(struct gpio_chip *chip,
+                                       unsigned offset, int value)
+{
+       struct egpio_chip *egpio;
+
+       egpio = gpiochip_get_data(chip);
+       if (test_bit(offset, &egpio->is_out)) {
+               egpio_set(chip, offset, value);
+               return 0;
+       } else {
+               return -EINVAL;
+       }
+}
+
+static void egpio_write_cache(struct egpio_info *ei)
+{
+       int               i;
+       struct egpio_chip *egpio;
+       int               shift;
+
+       for (i = 0; i < ei->nchips; i++) {
+               egpio = &(ei->chip[i]);
+               if (!egpio->is_out)
+                       continue;
+
+               for (shift = 0; shift < egpio->chip.ngpio;
+                               shift += (1<<ei->reg_shift)) {
+
+                       int reg = egpio->reg_start + egpio_pos(ei, shift);
+
+                       if (!((egpio->is_out >> shift) & ei->reg_mask))
+                               continue;
+
+                       pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
+                               (egpio->cached_values >> shift) & ei->reg_mask,
+                               egpio_readw(ei, reg));
+
+                       egpio_writew((egpio->cached_values >> shift)
+                                       & ei->reg_mask, ei, reg);
+               }
+       }
+}
+
+
+/*
+ * Setup
+ */
+
+static int __init egpio_probe(struct platform_device *pdev)
+{
+       struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct resource   *res;
+       struct egpio_info *ei;
+       struct gpio_chip  *chip;
+       unsigned int      irq, irq_end;
+       int               i;
+       int               ret;
+
+       /* Initialize ei data structure. */
+       ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
+       if (!ei)
+               return -ENOMEM;
+
+       spin_lock_init(&ei->lock);
+
+       /* Find chained irq */
+       ret = -EINVAL;
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res)
+               ei->chained_irq = res->start;
+
+       /* Map egpio chip into virtual address space. */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               goto fail;
+       ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
+                                            resource_size(res));
+       if (!ei->base_addr)
+               goto fail;
+       pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
+
+       if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
+               goto fail;
+       ei->bus_shift = fls(pdata->bus_width - 1) - 3;
+       pr_debug("bus_shift = %d\n", ei->bus_shift);
+
+       if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
+               goto fail;
+       ei->reg_shift = fls(pdata->reg_width - 1);
+       pr_debug("reg_shift = %d\n", ei->reg_shift);
+
+       ei->reg_mask = (1 << pdata->reg_width) - 1;
+
+       platform_set_drvdata(pdev, ei);
+
+       ei->nchips = pdata->num_chips;
+       ei->chip = devm_kzalloc(&pdev->dev,
+                               sizeof(struct egpio_chip) * ei->nchips,
+                               GFP_KERNEL);
+       if (!ei->chip) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       for (i = 0; i < ei->nchips; i++) {
+               ei->chip[i].reg_start = pdata->chip[i].reg_start;
+               ei->chip[i].cached_values = pdata->chip[i].initial_values;
+               ei->chip[i].is_out = pdata->chip[i].direction;
+               ei->chip[i].dev = &(pdev->dev);
+               chip = &(ei->chip[i].chip);
+               chip->label           = "htc-egpio";
+               chip->parent          = &pdev->dev;
+               chip->owner           = THIS_MODULE;
+               chip->get             = egpio_get;
+               chip->set             = egpio_set;
+               chip->direction_input = egpio_direction_input;
+               chip->direction_output = egpio_direction_output;
+               chip->base            = pdata->chip[i].gpio_base;
+               chip->ngpio           = pdata->chip[i].num_gpios;
+
+               gpiochip_add_data(chip, &ei->chip[i]);
+       }
+
+       /* Set initial pin values */
+       egpio_write_cache(ei);
+
+       ei->irq_start = pdata->irq_base;
+       ei->nirqs = pdata->num_irqs;
+       ei->ack_register = pdata->ack_register;
+
+       if (ei->chained_irq) {
+               /* Setup irq handlers */
+               ei->ack_write = 0xFFFF;
+               if (pdata->invert_acks)
+                       ei->ack_write = 0;
+               irq_end = ei->irq_start + ei->nirqs;
+               for (irq = ei->irq_start; irq < irq_end; irq++) {
+                       irq_set_chip_and_handler(irq, &egpio_muxed_chip,
+                                                handle_simple_irq);
+                       irq_set_chip_data(irq, ei);
+                       irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
+               }
+               irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
+               irq_set_chained_handler_and_data(ei->chained_irq,
+                                                egpio_handler, ei);
+               ack_irqs(ei);
+
+               device_init_wakeup(&pdev->dev, 1);
+       }
+
+       return 0;
+
+fail:
+       printk(KERN_ERR "EGPIO failed to setup\n");
+       return ret;
+}
+
+static int __exit egpio_remove(struct platform_device *pdev)
+{
+       struct egpio_info *ei = platform_get_drvdata(pdev);
+       unsigned int      irq, irq_end;
+
+       if (ei->chained_irq) {
+               irq_end = ei->irq_start + ei->nirqs;
+               for (irq = ei->irq_start; irq < irq_end; irq++) {
+                       irq_set_chip_and_handler(irq, NULL, NULL);
+                       irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
+               }
+               irq_set_chained_handler(ei->chained_irq, NULL);
+               device_init_wakeup(&pdev->dev, 0);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct egpio_info *ei = platform_get_drvdata(pdev);
+
+       if (ei->chained_irq && device_may_wakeup(&pdev->dev))
+               enable_irq_wake(ei->chained_irq);
+       return 0;
+}
+
+static int egpio_resume(struct platform_device *pdev)
+{
+       struct egpio_info *ei = platform_get_drvdata(pdev);
+
+       if (ei->chained_irq && device_may_wakeup(&pdev->dev))
+               disable_irq_wake(ei->chained_irq);
+
+       /* Update registers from the cache, in case
+          the CPLD was powered off during suspend */
+       egpio_write_cache(ei);
+       return 0;
+}
+#else
+#define egpio_suspend NULL
+#define egpio_resume NULL
+#endif
+
+
+static struct platform_driver egpio_driver = {
+       .driver = {
+               .name = "htc-egpio",
+       },
+       .remove       = __exit_p(egpio_remove),
+       .suspend      = egpio_suspend,
+       .resume       = egpio_resume,
+};
+
+static int __init egpio_init(void)
+{
+       return platform_driver_probe(&egpio_driver, egpio_probe);
+}
+
+static void __exit egpio_exit(void)
+{
+       platform_driver_unregister(&egpio_driver);
+}
+
+/* start early for dependencies */
+subsys_initcall(egpio_init);
+module_exit(egpio_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");
index 860c535..98c7ff2 100644 (file)
  * your option) any later version.
  */
 
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/gpio.h>
-#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/io.h>
 
-#define IOP3XX_N_GPIOS 8
-
-#define GPIO_IN                        0
-#define GPIO_OUT               1
-#define GPIO_LOW               0
-#define GPIO_HIGH              1
-
-/* Memory base offset */
-static void __iomem *base;
-
-#define IOP3XX_GPIO_REG(reg)   (base + (reg))
-#define IOP3XX_GPOE            IOP3XX_GPIO_REG(0x0000)
-#define IOP3XX_GPID            IOP3XX_GPIO_REG(0x0004)
-#define IOP3XX_GPOD            IOP3XX_GPIO_REG(0x0008)
-
-static void gpio_line_config(int line, int direction)
-{
-       unsigned long flags;
-       u32 val;
-
-       local_irq_save(flags);
-       val = readl(IOP3XX_GPOE);
-       if (direction == GPIO_IN) {
-               val |= BIT(line);
-       } else if (direction == GPIO_OUT) {
-               val &= ~BIT(line);
-       }
-       writel(val, IOP3XX_GPOE);
-       local_irq_restore(flags);
-}
-
-static int gpio_line_get(int line)
-{
-       return !!(readl(IOP3XX_GPID) & BIT(line));
-}
-
-static void gpio_line_set(int line, int value)
-{
-       unsigned long flags;
-       u32 val;
-
-       local_irq_save(flags);
-       val = readl(IOP3XX_GPOD);
-       if (value == GPIO_LOW) {
-               val &= ~BIT(line);
-       } else if (value == GPIO_HIGH) {
-               val |= BIT(line);
-       }
-       writel(val, IOP3XX_GPOD);
-       local_irq_restore(flags);
-}
-
-static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-       gpio_line_config(gpio, GPIO_IN);
-       return 0;
-}
-
-static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
-{
-       gpio_line_set(gpio, level);
-       gpio_line_config(gpio, GPIO_OUT);
-       return 0;
-}
-
-static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-       return gpio_line_get(gpio);
-}
-
-static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-       gpio_line_set(gpio, value);
-}
-
-static struct gpio_chip iop3xx_chip = {
-       .label                  = "iop3xx",
-       .direction_input        = iop3xx_gpio_direction_input,
-       .get                    = iop3xx_gpio_get_value,
-       .direction_output       = iop3xx_gpio_direction_output,
-       .set                    = iop3xx_gpio_set_value,
-       .base                   = 0,
-       .ngpio                  = IOP3XX_N_GPIOS,
-};
+#define IOP3XX_GPOE    0x0000
+#define IOP3XX_GPID    0x0004
+#define IOP3XX_GPOD    0x0008
 
 static int iop3xx_gpio_probe(struct platform_device *pdev)
 {
        struct resource *res;
+       struct gpio_chip *gc;
+       void __iomem *base;
+       int err;
+
+       gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+       if (!gc)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
-       return devm_gpiochip_add_data(&pdev->dev, &iop3xx_chip, NULL);
+       err = bgpio_init(gc, &pdev->dev, 1, base + IOP3XX_GPID,
+                        base + IOP3XX_GPOD, NULL, NULL, base + IOP3XX_GPOE, 0);
+       if (err)
+               return err;
+
+       gc->base = 0;
+       gc->owner = THIS_MODULE;
+
+       return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
 }
 
 static struct platform_driver iop3xx_gpio_driver = {
index 63a962d..45d29e4 100644 (file)
@@ -273,7 +273,7 @@ exit:
        return rc;
 }
 
-static struct gpio_chip it87_template_chip = {
+static const struct gpio_chip it87_template_chip = {
        .label                  = KBUILD_MODNAME,
        .owner                  = THIS_MODULE,
        .request                = it87_gpio_request,
index 10c09bd..72b6403 100644 (file)
@@ -8,6 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 
+#include <linux/module.h>
 #include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 
@@ -55,11 +56,6 @@ static int ls1x_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(dev, "failed to get I/O memory\n");
-               return -EINVAL;
-       }
-
        gpio_reg_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(gpio_reg_base))
                return PTR_ERR(gpio_reg_base);
diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c
new file mode 100644 (file)
index 0000000..218c706
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 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 TPS65218 driver
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/lp873x.h>
+
+#define BITS_PER_GPO           0x4
+#define LP873X_GPO_CTRL_OD     0x2
+
+struct lp873x_gpio {
+       struct gpio_chip chip;
+       struct lp873x *lp873;
+};
+
+static int lp873x_gpio_get_direction(struct gpio_chip *chip,
+                                    unsigned int offset)
+{
+       /* This device is output only */
+       return 0;
+}
+
+static int lp873x_gpio_direction_input(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       /* This device is output only */
+       return -EINVAL;
+}
+
+static int lp873x_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned int offset, int value)
+{
+       struct lp873x_gpio *gpio = gpiochip_get_data(chip);
+
+       /* Set the initial value */
+       return regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL,
+                                 BIT(offset * BITS_PER_GPO),
+                                 value ? BIT(offset * BITS_PER_GPO) : 0);
+}
+
+static int lp873x_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct lp873x_gpio *gpio = gpiochip_get_data(chip);
+       int ret, val;
+
+       ret = regmap_read(gpio->lp873->regmap, LP873X_REG_GPO_CTRL, &val);
+       if (ret < 0)
+               return ret;
+
+       return val & BIT(offset * BITS_PER_GPO);
+}
+
+static void lp873x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                           int value)
+{
+       struct lp873x_gpio *gpio = gpiochip_get_data(chip);
+
+       regmap_update_bits(gpio->lp873->regmap, LP873X_REG_GPO_CTRL,
+                          BIT(offset * BITS_PER_GPO),
+                          value ? BIT(offset * BITS_PER_GPO) : 0);
+}
+
+static int lp873x_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+       struct lp873x_gpio *gpio = gpiochip_get_data(gc);
+       int ret;
+
+       switch (offset) {
+       case 0:
+               /* No MUX Set up Needed for GPO */
+               break;
+       case 1:
+               /* Setup the CLKIN_PIN_SEL MUX to GPO2 */
+               ret = regmap_update_bits(gpio->lp873->regmap, LP873X_REG_CONFIG,
+                                        LP873X_CONFIG_CLKIN_PIN_SEL, 0);
+               if (ret)
+                       return ret;
+
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int lp873x_gpio_set_single_ended(struct gpio_chip *gc,
+                                       unsigned int offset,
+                                       enum single_ended_mode mode)
+{
+       struct lp873x_gpio *gpio = gpiochip_get_data(gc);
+
+       switch (mode) {
+       case LINE_MODE_OPEN_DRAIN:
+               return regmap_update_bits(gpio->lp873->regmap,
+                                         LP873X_REG_GPO_CTRL,
+                                         BIT(offset * BITS_PER_GPO +
+                                         LP873X_GPO_CTRL_OD),
+                                         BIT(offset * BITS_PER_GPO +
+                                         LP873X_GPO_CTRL_OD));
+       case LINE_MODE_PUSH_PULL:
+               return regmap_update_bits(gpio->lp873->regmap,
+                                         LP873X_REG_GPO_CTRL,
+                                         BIT(offset * BITS_PER_GPO +
+                                         LP873X_GPO_CTRL_OD), 0);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static const struct gpio_chip template_chip = {
+       .label                  = "lp873x-gpio",
+       .owner                  = THIS_MODULE,
+       .request                = lp873x_gpio_request,
+       .get_direction          = lp873x_gpio_get_direction,
+       .direction_input        = lp873x_gpio_direction_input,
+       .direction_output       = lp873x_gpio_direction_output,
+       .get                    = lp873x_gpio_get,
+       .set                    = lp873x_gpio_set,
+       .set_single_ended       = lp873x_gpio_set_single_ended,
+       .base                   = -1,
+       .ngpio                  = 2,
+       .can_sleep              = true,
+};
+
+static int lp873x_gpio_probe(struct platform_device *pdev)
+{
+       struct lp873x_gpio *gpio;
+       int ret;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, gpio);
+
+       gpio->lp873 = dev_get_drvdata(pdev->dev.parent);
+       gpio->chip = template_chip;
+       gpio->chip.parent = gpio->lp873->dev;
+
+       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 lp873x_gpio_id_table[] = {
+       { "lp873x-gpio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, lp873x_gpio_id_table);
+
+static struct platform_driver lp873x_gpio_driver = {
+       .driver = {
+               .name = "lp873x-gpio",
+       },
+       .probe = lp873x_gpio_probe,
+       .id_table = lp873x_gpio_id_table,
+};
+module_platform_driver(lp873x_gpio_driver);
+
+MODULE_AUTHOR("Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("LP873X GPIO driver");
+MODULE_LICENSE("GPL v2");
index 98832c9..f12e02e 100644 (file)
@@ -78,7 +78,7 @@ static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
        return lpc18xx_gpio_direction(chip, offset, true);
 }
 
-static struct gpio_chip lpc18xx_chip = {
+static const struct gpio_chip lpc18xx_chip = {
        .label                  = "lpc18xx/43xx-gpio",
        .request                = gpiochip_generic_request,
        .free                   = gpiochip_generic_free,
index fc5f197..92b3ae2 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/module.h>
-#include <linux/platform_data/gpio-lpc32xx.h>
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
 #define GPI3_PIN_IN_SEL(x, y)                  (((x) >> (y)) & 1)
 #define GPO3_PIN_IN_SEL(x, y)                  (((x) >> (y)) & 1)
 
+#define LPC32XX_GPIO_P0_MAX    8
+#define LPC32XX_GPIO_P1_MAX    24
+#define LPC32XX_GPIO_P2_MAX    13
+#define LPC32XX_GPIO_P3_MAX    6
+#define LPC32XX_GPI_P3_MAX     29
+#define LPC32XX_GPO_P3_MAX     24
+
+#define LPC32XX_GPIO_P0_GRP    0
+#define LPC32XX_GPIO_P1_GRP    (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX)
+#define LPC32XX_GPIO_P2_GRP    (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX)
+#define LPC32XX_GPIO_P3_GRP    (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX)
+#define LPC32XX_GPI_P3_GRP     (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX)
+#define LPC32XX_GPO_P3_GRP     (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
+
 struct gpio_regs {
        void __iomem *inp_state;
        void __iomem *outp_state;
index 6ec144b..d7d03ad 100644 (file)
@@ -573,6 +573,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
 
 #ifdef CONFIG_OF
 static const struct of_device_id bgpio_of_match[] = {
+       { .compatible = "brcm,bcm6345-gpio" },
        { .compatible = "wd,mbl-gpio" },
        { }
 };
@@ -593,6 +594,9 @@ static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
 
        pdata->base = -1;
 
+       if (of_device_is_big_endian(pdev->dev.of_node))
+               *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+
        if (of_property_read_bool(pdev->dev.of_node, "no-output"))
                *flags |= BGPIOF_NO_OUTPUT;
 
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
new file mode 100644 (file)
index 0000000..1ef85b0
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * GPIO Testing Device Driver
+ *
+ * Copyright (C) 2014  Kamlakant Patel <kamlakant.patel@broadcom.com>
+ * Copyright (C) 2015-2016  Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
+ *
+ * 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
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+
+#define GPIO_NAME      "gpio-mockup"
+#define        MAX_GC          10
+
+enum direction {
+       OUT,
+       IN
+};
+
+/*
+ * struct gpio_pin_status - structure describing a GPIO status
+ * @dir:       Configures direction of gpio as "in" or "out", 0=in, 1=out
+ * @value:     Configures status of the gpio as 0(low) or 1(high)
+ */
+struct gpio_pin_status {
+       enum direction dir;
+       bool value;
+};
+
+struct mockup_gpio_controller {
+       struct gpio_chip gc;
+       struct gpio_pin_status *stats;
+};
+
+static int gpio_mockup_ranges[MAX_GC << 1];
+static int gpio_mockup_params_nr;
+module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
+
+const char pins_name_start = 'A';
+
+static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+
+       return cntr->stats[offset].value;
+}
+
+static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset,
+                           int value)
+{
+       struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+
+       cntr->stats[offset].value = !!value;
+}
+
+static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset,
+                             int value)
+{
+       struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+
+       mockup_gpio_set(gc, offset, value);
+       cntr->stats[offset].dir = OUT;
+       return 0;
+}
+
+static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+
+       cntr->stats[offset].dir = IN;
+       return 0;
+}
+
+static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
+
+       return cntr->stats[offset].dir;
+}
+
+static int mockup_gpio_add(struct device *dev,
+                          struct mockup_gpio_controller *cntr,
+                          const char *name, int base, int ngpio)
+{
+       int ret;
+
+       cntr->gc.base = base;
+       cntr->gc.ngpio = ngpio;
+       cntr->gc.label = name;
+       cntr->gc.owner = THIS_MODULE;
+       cntr->gc.parent = dev;
+       cntr->gc.get = mockup_gpio_get;
+       cntr->gc.set = mockup_gpio_set;
+       cntr->gc.direction_output = mockup_gpio_dirout;
+       cntr->gc.direction_input = mockup_gpio_dirin;
+       cntr->gc.get_direction = mockup_gpio_get_direction;
+       cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio,
+                                  GFP_KERNEL);
+       if (!cntr->stats) {
+               ret = -ENOMEM;
+               goto err;
+       }
+       ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr);
+       if (ret)
+               goto err;
+
+       dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio);
+       return 0;
+err:
+       dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio);
+       return ret;
+}
+
+static int mockup_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mockup_gpio_controller *cntr;
+       int ret;
+       int i;
+       int base;
+       int ngpio;
+       char chip_name[sizeof(GPIO_NAME) + 3];
+
+       if (gpio_mockup_params_nr < 2)
+               return -EINVAL;
+
+       cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1),
+                           GFP_KERNEL);
+       if (!cntr)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, cntr);
+
+       for (i = 0; i < gpio_mockup_params_nr >> 1; i++) {
+               base = gpio_mockup_ranges[i * 2];
+               if (base == -1)
+                       ngpio = gpio_mockup_ranges[i * 2 + 1];
+               else
+                       ngpio = gpio_mockup_ranges[i * 2 + 1] - base;
+
+               if (ngpio >= 0) {
+                       sprintf(chip_name, "%s-%c", GPIO_NAME,
+                               pins_name_start + i);
+                       ret = mockup_gpio_add(dev, &cntr[i],
+                                             chip_name, base, ngpio);
+               } else {
+                       ret = -1;
+               }
+               if (ret) {
+                       if (base < 0)
+                               dev_err(dev, "gpio<%d..%d> add failed\n",
+                                       base, ngpio);
+                       else
+                               dev_err(dev, "gpio<%d..%d> add failed\n",
+                                       base, base + ngpio);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct platform_driver mockup_gpio_driver = {
+       .driver = {
+                  .name = GPIO_NAME,
+                  },
+       .probe = mockup_gpio_probe,
+};
+
+static struct platform_device *pdev;
+static int __init mock_device_init(void)
+{
+       int err;
+
+       pdev = platform_device_alloc(GPIO_NAME, -1);
+       if (!pdev)
+               return -ENOMEM;
+
+       err = platform_device_add(pdev);
+       if (err) {
+               platform_device_put(pdev);
+               return err;
+       }
+
+       err = platform_driver_register(&mockup_gpio_driver);
+       if (err) {
+               platform_device_unregister(pdev);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __exit mock_device_exit(void)
+{
+       platform_driver_unregister(&mockup_gpio_driver);
+       platform_device_unregister(pdev);
+}
+
+module_init(mock_device_init);
+module_exit(mock_device_exit);
+
+MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
+MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
+MODULE_DESCRIPTION("GPIO Testing driver");
+MODULE_LICENSE("GPL v2");
index d756497..1b7ce7f 100644 (file)
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
@@ -328,9 +327,4 @@ static int __init platform_msic_gpio_init(void)
 {
        return platform_driver_register(&platform_msic_gpio_driver);
 }
-
 subsys_initcall(platform_msic_gpio_init);
-
-MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>");
-MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver");
-MODULE_LICENSE("GPL v2");
index e38989a..c1a1e00 100644 (file)
@@ -2,7 +2,8 @@
  * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>
  * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  *
- * Based on code from Freescale,
+ * Based on code from Freescale Semiconductor,
+ * Authors: Daniel Mack, Juergen Beisert.
  * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +34,6 @@
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/module.h>
 #include <linux/bug.h>
 
 enum mxc_gpio_hwtype {
@@ -516,9 +516,3 @@ static int __init gpio_mxc_init(void)
        return platform_driver_register(&mxc_gpio_driver);
 }
 subsys_initcall(gpio_mxc_init);
-
-MODULE_AUTHOR("Freescale Semiconductor, "
-             "Daniel Mack <danielncaiaq.de>, "
-             "Juergen Beisert <kernel@pengutronix.de>");
-MODULE_DESCRIPTION("Freescale MXC GPIO");
-MODULE_LICENSE("GPL");
index 8394744..3d81819 100644 (file)
@@ -152,7 +152,6 @@ static const struct of_device_id of_palmas_gpio_match[] = {
        { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},
        { },
 };
-MODULE_DEVICE_TABLE(of, of_palmas_gpio_match);
 
 static int palmas_gpio_probe(struct platform_device *pdev)
 {
index 02f2a56..5d05986 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/unaligned.h>
 #include <linux/of_platform.h>
 #include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
 
 #define PCA953X_INPUT          0
 #define PCA953X_OUTPUT         1
@@ -94,6 +95,24 @@ MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
 
 #define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)
 
+struct pca953x_reg_config {
+       int direction;
+       int output;
+       int input;
+};
+
+static const struct pca953x_reg_config pca953x_regs = {
+       .direction = PCA953X_DIRECTION,
+       .output = PCA953X_OUTPUT,
+       .input = PCA953X_INPUT,
+};
+
+static const struct pca953x_reg_config pca957x_regs = {
+       .direction = PCA957X_CFG,
+       .output = PCA957X_OUT,
+       .input = PCA957X_IN,
+};
+
 struct pca953x_chip {
        unsigned gpio_start;
        u8 reg_output[MAX_BANK];
@@ -111,8 +130,13 @@ struct pca953x_chip {
        struct i2c_client *client;
        struct gpio_chip gpio_chip;
        const char *const *names;
-       int     chip_type;
        unsigned long driver_data;
+       struct regulator *regulator;
+
+       const struct pca953x_reg_config *regs;
+
+       int (*write_regs)(struct pca953x_chip *, int, u8 *);
+       int (*read_regs)(struct pca953x_chip *, int, u8 *);
 };
 
 static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
@@ -152,38 +176,44 @@ static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
        return 0;
 }
 
-static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
+static int pca953x_write_regs_8(struct pca953x_chip *chip, int reg, u8 *val)
 {
-       int ret = 0;
+       return i2c_smbus_write_byte_data(chip->client, reg, *val);
+}
 
-       if (chip->gpio_chip.ngpio <= 8)
-               ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
-       else if (chip->gpio_chip.ngpio >= 24) {
-               int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
-               ret = i2c_smbus_write_i2c_block_data(chip->client,
-                                       (reg << bank_shift) | REG_ADDR_AI,
-                                       NBANK(chip), val);
-       } else {
-               switch (chip->chip_type) {
-               case PCA953X_TYPE: {
-                       __le16 word = cpu_to_le16(get_unaligned((u16 *)val));
+static int pca953x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       __le16 word = cpu_to_le16(get_unaligned((u16 *)val));
 
-                       ret = i2c_smbus_write_word_data(chip->client, reg << 1,
-                                                       (__force u16)word);
-                       break;
-               }
-               case PCA957X_TYPE:
-                       ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
-                                                       val[0]);
-                       if (ret < 0)
-                               break;
-                       ret = i2c_smbus_write_byte_data(chip->client,
-                                                       (reg << 1) + 1,
-                                                       val[1]);
-                       break;
-               }
-       }
+       return i2c_smbus_write_word_data(chip->client,
+                                        reg << 1, (__force u16)word);
+}
+
+static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(chip->client, reg << 1, val[0]);
+       if (ret < 0)
+               return ret;
+
+       return i2c_smbus_write_byte_data(chip->client, (reg << 1) + 1, val[1]);
+}
+
+static int pca953x_write_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
+       return i2c_smbus_write_i2c_block_data(chip->client,
+                                             (reg << bank_shift) | REG_ADDR_AI,
+                                             NBANK(chip), val);
+}
 
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int ret = 0;
+
+       ret = chip->write_regs(chip, reg, val);
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed writing register\n");
                return ret;
@@ -192,24 +222,41 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
        return 0;
 }
 
-static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
+static int pca953x_read_regs_8(struct pca953x_chip *chip, int reg, u8 *val)
 {
        int ret;
 
-       if (chip->gpio_chip.ngpio <= 8) {
-               ret = i2c_smbus_read_byte_data(chip->client, reg);
-               *val = ret;
-       } else if (chip->gpio_chip.ngpio >= 24) {
-               int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+       ret = i2c_smbus_read_byte_data(chip->client, reg);
+       *val = ret;
 
-               ret = i2c_smbus_read_i2c_block_data(chip->client,
-                                       (reg << bank_shift) | REG_ADDR_AI,
-                                       NBANK(chip), val);
-       } else {
-               ret = i2c_smbus_read_word_data(chip->client, reg << 1);
-               val[0] = (u16)ret & 0xFF;
-               val[1] = (u16)ret >> 8;
-       }
+       return ret;
+}
+
+static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int ret;
+
+       ret = i2c_smbus_read_word_data(chip->client, reg << 1);
+       val[0] = (u16)ret & 0xFF;
+       val[1] = (u16)ret >> 8;
+
+       return ret;
+}
+
+static int pca953x_read_regs_24(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
+       return i2c_smbus_read_i2c_block_data(chip->client,
+                                            (reg << bank_shift) | REG_ADDR_AI,
+                                            NBANK(chip), val);
+}
+
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
+{
+       int ret;
+
+       ret = chip->read_regs(chip, reg, val);
        if (ret < 0) {
                dev_err(&chip->client->dev, "failed reading register\n");
                return ret;
@@ -222,20 +269,12 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        u8 reg_val;
-       int ret, offset = 0;
+       int ret;
 
        mutex_lock(&chip->i2c_lock);
        reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
 
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_DIRECTION;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_CFG;
-               break;
-       }
-       ret = pca953x_write_single(chip, offset, reg_val, off);
+       ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
        if (ret)
                goto exit;
 
@@ -250,7 +289,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        u8 reg_val;
-       int ret, offset = 0;
+       int ret;
 
        mutex_lock(&chip->i2c_lock);
        /* set output level */
@@ -261,15 +300,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
                reg_val = chip->reg_output[off / BANK_SZ]
                        & ~(1u << (off % BANK_SZ));
 
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_OUTPUT;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_OUT;
-               break;
-       }
-       ret = pca953x_write_single(chip, offset, reg_val, off);
+       ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
        if (ret)
                goto exit;
 
@@ -277,15 +308,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 
        /* then direction */
        reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_DIRECTION;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_CFG;
-               break;
-       }
-       ret = pca953x_write_single(chip, offset, reg_val, off);
+       ret = pca953x_write_single(chip, chip->regs->direction, reg_val, off);
        if (ret)
                goto exit;
 
@@ -299,18 +322,10 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        u32 reg_val;
-       int ret, offset = 0;
+       int ret;
 
        mutex_lock(&chip->i2c_lock);
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_INPUT;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_IN;
-               break;
-       }
-       ret = pca953x_read_single(chip, offset, &reg_val, off);
+       ret = pca953x_read_single(chip, chip->regs->input, &reg_val, off);
        mutex_unlock(&chip->i2c_lock);
        if (ret < 0) {
                /* NOTE:  diagnostic already emitted; that's all we should
@@ -327,7 +342,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        u8 reg_val;
-       int ret, offset = 0;
+       int ret;
 
        mutex_lock(&chip->i2c_lock);
        if (val)
@@ -337,15 +352,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
                reg_val = chip->reg_output[off / BANK_SZ]
                        & ~(1u << (off % BANK_SZ));
 
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_OUTPUT;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_OUT;
-               break;
-       }
-       ret = pca953x_write_single(chip, offset, reg_val, off);
+       ret = pca953x_write_single(chip, chip->regs->output, reg_val, off);
        if (ret)
                goto exit;
 
@@ -355,35 +362,31 @@ exit:
 }
 
 static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
-               unsigned long *mask, unsigned long *bits)
+                                     unsigned long *mask, unsigned long *bits)
 {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
+       unsigned int bank_mask, bank_val;
+       int bank_shift, bank;
        u8 reg_val[MAX_BANK];
-       int ret, offset = 0;
-       int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
-       int bank;
-
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_OUTPUT;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_OUT;
-               break;
-       }
+       int ret;
+
+       bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 
        memcpy(reg_val, chip->reg_output, NBANK(chip));
        mutex_lock(&chip->i2c_lock);
-       for(bank=0; bank<NBANK(chip); bank++) {
-               unsigned bankmask = mask[bank / sizeof(*mask)] >>
-                                   ((bank % sizeof(*mask)) * 8);
-               if(bankmask) {
-                       unsigned bankval  = bits[bank / sizeof(*bits)] >>
-                                           ((bank % sizeof(*bits)) * 8);
-                       reg_val[bank] = (reg_val[bank] & ~bankmask) | bankval;
+       for (bank = 0; bank < NBANK(chip); bank++) {
+               bank_mask = mask[bank / sizeof(*mask)] >>
+                          ((bank % sizeof(*mask)) * 8);
+               if (bank_mask) {
+                       bank_val = bits[bank / sizeof(*bits)] >>
+                                 ((bank % sizeof(*bits)) * 8);
+                       reg_val[bank] = (reg_val[bank] & ~bank_mask) | bank_val;
                }
        }
-       ret = i2c_smbus_write_i2c_block_data(chip->client, offset << bank_shift, NBANK(chip), reg_val);
+
+       ret = i2c_smbus_write_i2c_block_data(chip->client,
+                                            chip->regs->output << bank_shift,
+                                            NBANK(chip), reg_val);
        if (ret)
                goto exit;
 
@@ -515,7 +518,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
        bool pending_seen = false;
        bool trigger_seen = false;
        u8 trigger[MAX_BANK];
-       int ret, i, offset = 0;
+       int ret, i;
 
        if (chip->driver_data & PCA_PCAL) {
                /* Read the current interrupt status from the device */
@@ -540,15 +543,7 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
                return pending_seen;
        }
 
-       switch (chip->chip_type) {
-       case PCA953X_TYPE:
-               offset = PCA953X_INPUT;
-               break;
-       case PCA957X_TYPE:
-               offset = PCA957X_IN;
-               break;
-       }
-       ret = pca953x_read_regs(chip, offset, cur_stat);
+       ret = pca953x_read_regs(chip, chip->regs->input, cur_stat);
        if (ret)
                return false;
 
@@ -608,20 +603,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
                             int irq_base)
 {
        struct i2c_client *client = chip->client;
-       int ret, i, offset = 0;
+       int ret, i;
 
        if (client->irq && irq_base != -1
                        && (chip->driver_data & PCA_INT)) {
 
-               switch (chip->chip_type) {
-               case PCA953X_TYPE:
-                       offset = PCA953X_INPUT;
-                       break;
-               case PCA957X_TYPE:
-                       offset = PCA957X_IN;
-                       break;
-               }
-               ret = pca953x_read_regs(chip, offset, chip->irq_stat);
+               ret = pca953x_read_regs(chip,
+                                       chip->regs->input, chip->irq_stat);
                if (ret)
                        return ret;
 
@@ -684,12 +672,14 @@ static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
        int ret;
        u8 val[MAX_BANK];
 
-       ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
+       chip->regs = &pca953x_regs;
+
+       ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
        if (ret)
                goto out;
 
-       ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
-                              chip->reg_direction);
+       ret = pca953x_read_regs(chip, chip->regs->direction,
+                               chip->reg_direction);
        if (ret)
                goto out;
 
@@ -709,10 +699,13 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
        int ret;
        u8 val[MAX_BANK];
 
-       ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
+       chip->regs = &pca957x_regs;
+
+       ret = pca953x_read_regs(chip, chip->regs->output, chip->reg_output);
        if (ret)
                goto out;
-       ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
+       ret = pca953x_read_regs(chip, chip->regs->direction,
+                               chip->reg_direction);
        if (ret)
                goto out;
 
@@ -746,6 +739,7 @@ static int pca953x_probe(struct i2c_client *client,
        int irq_base = 0;
        int ret;
        u32 invert = 0;
+       struct regulator *reg;
 
        chip = devm_kzalloc(&client->dev,
                        sizeof(struct pca953x_chip), GFP_KERNEL);
@@ -765,6 +759,20 @@ static int pca953x_probe(struct i2c_client *client,
 
        chip->client = client;
 
+       reg = devm_regulator_get(&client->dev, "vcc");
+       if (IS_ERR(reg)) {
+               ret = PTR_ERR(reg);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&client->dev, "reg get err: %d\n", ret);
+               return ret;
+       }
+       ret = regulator_enable(reg);
+       if (ret) {
+               dev_err(&client->dev, "reg en err: %d\n", ret);
+               return ret;
+       }
+       chip->regulator = reg;
+
        if (id) {
                chip->driver_data = id->driver_data;
        } else {
@@ -776,15 +784,15 @@ static int pca953x_probe(struct i2c_client *client,
                        chip->driver_data = (int)(uintptr_t)match->data;
                } else {
                        id = acpi_match_device(pca953x_acpi_ids, &client->dev);
-                       if (!id)
-                               return -ENODEV;
+                       if (!id) {
+                               ret = -ENODEV;
+                               goto err_exit;
+                       }
 
                        chip->driver_data = id->driver_data;
                }
        }
 
-       chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
-
        mutex_init(&chip->i2c_lock);
 
        /* initialize cached registers from their original values.
@@ -792,20 +800,34 @@ static int pca953x_probe(struct i2c_client *client,
         */
        pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
 
-       if (chip->chip_type == PCA953X_TYPE)
+       if (chip->gpio_chip.ngpio <= 8) {
+               chip->write_regs = pca953x_write_regs_8;
+               chip->read_regs = pca953x_read_regs_8;
+       } else if (chip->gpio_chip.ngpio >= 24) {
+               chip->write_regs = pca953x_write_regs_24;
+               chip->read_regs = pca953x_read_regs_24;
+       } else {
+               if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
+                       chip->write_regs = pca953x_write_regs_16;
+               else
+                       chip->write_regs = pca957x_write_regs_16;
+               chip->read_regs = pca953x_read_regs_16;
+       }
+
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
                ret = device_pca953x_init(chip, invert);
        else
                ret = device_pca957x_init(chip, invert);
        if (ret)
-               return ret;
+               goto err_exit;
 
        ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
        if (ret)
-               return ret;
+               goto err_exit;
 
        ret = pca953x_irq_setup(chip, irq_base);
        if (ret)
-               return ret;
+               goto err_exit;
 
        if (pdata && pdata->setup) {
                ret = pdata->setup(client, chip->gpio_chip.base,
@@ -816,6 +838,10 @@ static int pca953x_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, chip);
        return 0;
+
+err_exit:
+       regulator_disable(chip->regulator);
+       return ret;
 }
 
 static int pca953x_remove(struct i2c_client *client)
@@ -827,14 +853,16 @@ static int pca953x_remove(struct i2c_client *client)
        if (pdata && pdata->teardown) {
                ret = pdata->teardown(client, chip->gpio_chip.base,
                                chip->gpio_chip.ngpio, pdata->context);
-               if (ret < 0) {
+               if (ret < 0)
                        dev_err(&client->dev, "%s failed, %d\n",
                                        "teardown", ret);
-                       return ret;
-               }
+       } else {
+               ret = 0;
        }
 
-       return 0;
+       regulator_disable(chip->regulator);
+
+       return ret;
 }
 
 /* convenience to stop overlong match-table lines */
index cb14b8d..f554504 100644 (file)
@@ -90,7 +90,7 @@ static int pisosr_gpio_get(struct gpio_chip *chip, unsigned offset)
        return (gpio->buffer[offset / 8] >> (offset % 8)) & 0x1;
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "pisosr-gpio",
        .owner                  = THIS_MODULE,
        .get_direction          = pisosr_gpio_get_direction,
index b96e0b4..2be48f5 100644 (file)
@@ -347,6 +347,10 @@ static const struct of_device_id gpio_rcar_of_table[] = {
                .compatible = "renesas,gpio-r8a7795",
                /* Gen3 GPIO is identical to Gen2. */
                .data = &gpio_rcar_info_gen2,
+       }, {
+               .compatible = "renesas,gpio-r8a7796",
+               /* Gen3 GPIO is identical to Gen2. */
+               .data = &gpio_rcar_info_gen2,
        }, {
                .compatible = "renesas,gpio-rcar",
                .data = &gpio_rcar_info_gen1,
index eb43ae4..5450044 100644 (file)
@@ -138,7 +138,7 @@ static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
        return 0;
 }
 
-static struct gpio_chip sch_gpio_chip = {
+static const struct gpio_chip sch_gpio_chip = {
        .label                  = "sch_gpio",
        .owner                  = THIS_MODULE,
        .direction_input        = sch_gpio_direction_in,
index 7ffd164..2226747 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
@@ -183,7 +183,6 @@ static const struct of_device_id spics_gpio_of_match[] = {
        { .compatible = "st,spear-spics-gpio" },
        {}
 };
-MODULE_DEVICE_TABLE(of, spics_gpio_of_match);
 
 static struct platform_driver spics_gpio_driver = {
        .probe = spics_gpio_probe,
@@ -198,7 +197,3 @@ static int __init spics_gpio_init(void)
        return platform_driver_register(&spics_gpio_driver);
 }
 subsys_initcall(spics_gpio_init);
-
-MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>");
-MODULE_DESCRIPTION("STMicroelectronics SPEAr SPI Chip Select Abstraction");
-MODULE_LICENSE("GPL");
index f675132..e7d422a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of.h>
 #include <linux/mfd/stmpe.h>
 #include <linux/seq_file.h>
+#include <linux/bitops.h>
 
 /*
  * These registers are modified under the irq bus lock and cached to avoid
@@ -20,6 +21,8 @@
  */
 enum { REG_RE, REG_FE, REG_IE };
 
+enum { LSB, CSB, MSB };
+
 #define CACHE_NR_REGS  3
 /* No variant has more than 24 GPIOs */
 #define CACHE_NR_BANKS (24 / 8)
@@ -39,8 +42,8 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
-       u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB + (offset / 8)];
+       u8 mask = BIT(offset % 8);
        int ret;
 
        ret = stmpe_reg_read(stmpe, reg);
@@ -55,8 +58,8 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
        int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
-       u8 reg = stmpe->regs[which] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 reg = stmpe->regs[which + (offset / 8)];
+       u8 mask = BIT(offset % 8);
 
        /*
         * Some variants have single register for gpio set/clear functionality.
@@ -74,7 +77,7 @@ static int stmpe_gpio_get_direction(struct gpio_chip *chip,
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
        u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 mask = BIT(offset % 8);
        int ret;
 
        ret = stmpe_reg_read(stmpe, reg);
@@ -89,8 +92,8 @@ static int stmpe_gpio_direction_output(struct gpio_chip *chip,
 {
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
-       u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)];
+       u8 mask = BIT(offset % 8);
 
        stmpe_gpio_set(chip, offset, val);
 
@@ -102,8 +105,8 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip,
 {
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
-       u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)];
+       u8 mask = BIT(offset % 8);
 
        return stmpe_set_bits(stmpe, reg, mask, 0);
 }
@@ -113,13 +116,13 @@ static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
 
-       if (stmpe_gpio->norequest_mask & (1 << offset))
+       if (stmpe_gpio->norequest_mask & BIT(offset))
                return -EINVAL;
 
-       return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
+       return stmpe_set_altfunc(stmpe, BIT(offset), STMPE_BLOCK_GPIO);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "stmpe",
        .owner                  = THIS_MODULE,
        .get_direction          = stmpe_gpio_get_direction,
@@ -137,13 +140,14 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
        int offset = d->hwirq;
        int regoffset = offset / 8;
-       int mask = 1 << (offset % 8);
+       int mask = BIT(offset % 8);
 
        if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
                return -EINVAL;
 
-       /* STMPE801 doesn't have RE and FE registers */
-       if (stmpe_gpio->stmpe->partnum == STMPE801)
+       /* STMPE801 and STMPE 1600 don't have RE and FE registers */
+       if (stmpe_gpio->stmpe->partnum == STMPE801 ||
+           stmpe_gpio->stmpe->partnum == STMPE1600)
                return 0;
 
        if (type & IRQ_TYPE_EDGE_RISING)
@@ -173,17 +177,24 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
        int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
-       static const u8 regmap[] = {
-               [REG_RE]        = STMPE_IDX_GPRER_LSB,
-               [REG_FE]        = STMPE_IDX_GPFER_LSB,
-               [REG_IE]        = STMPE_IDX_IEGPIOR_LSB,
+       static const u8 regmap[CACHE_NR_REGS][CACHE_NR_BANKS] = {
+               [REG_RE][LSB] = STMPE_IDX_GPRER_LSB,
+               [REG_RE][CSB] = STMPE_IDX_GPRER_CSB,
+               [REG_RE][MSB] = STMPE_IDX_GPRER_MSB,
+               [REG_FE][LSB] = STMPE_IDX_GPFER_LSB,
+               [REG_FE][CSB] = STMPE_IDX_GPFER_CSB,
+               [REG_FE][MSB] = STMPE_IDX_GPFER_MSB,
+               [REG_IE][LSB] = STMPE_IDX_IEGPIOR_LSB,
+               [REG_IE][CSB] = STMPE_IDX_IEGPIOR_CSB,
+               [REG_IE][MSB] = STMPE_IDX_IEGPIOR_MSB,
        };
        int i, j;
 
        for (i = 0; i < CACHE_NR_REGS; i++) {
-               /* STMPE801 doesn't have RE and FE registers */
-               if ((stmpe->partnum == STMPE801) &&
-                               (i != REG_IE))
+               /* STMPE801 and STMPE1600 don't have RE and FE registers */
+               if ((stmpe->partnum == STMPE801 ||
+                    stmpe->partnum == STMPE1600) &&
+                    (i != REG_IE))
                        continue;
 
                for (j = 0; j < num_banks; j++) {
@@ -194,7 +205,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
                                continue;
 
                        stmpe_gpio->oldregs[i][j] = new;
-                       stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
+                       stmpe_reg_write(stmpe, stmpe->regs[regmap[i][j]], new);
                }
        }
 
@@ -207,7 +218,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
        int offset = d->hwirq;
        int regoffset = offset / 8;
-       int mask = 1 << (offset % 8);
+       int mask = BIT(offset % 8);
 
        stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
 }
@@ -216,11 +227,21 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
+       struct stmpe *stmpe = stmpe_gpio->stmpe;
        int offset = d->hwirq;
        int regoffset = offset / 8;
-       int mask = 1 << (offset % 8);
+       int mask = BIT(offset % 8);
 
        stmpe_gpio->regs[REG_IE][regoffset] |= mask;
+
+       /*
+        * STMPE1600 workaround: to be able to get IRQ from pins,
+        * a read must be done on GPMR register, or a write in
+        * GPSR or GPCR registers
+        */
+       if (stmpe->partnum == STMPE1600)
+               stmpe_reg_read(stmpe,
+                              stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]);
 }
 
 static void stmpe_dbg_show_one(struct seq_file *s,
@@ -230,10 +251,10 @@ static void stmpe_dbg_show_one(struct seq_file *s,
        struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
        struct stmpe *stmpe = stmpe_gpio->stmpe;
        const char *label = gpiochip_is_requested(gc, offset);
-       int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
        bool val = !!stmpe_gpio_get(gc, offset);
-       u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
-       u8 mask = 1 << (offset % 8);
+       u8 bank = offset / 8;
+       u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank];
+       u8 mask = BIT(offset % 8);
        int ret;
        u8 dir;
 
@@ -247,39 +268,72 @@ static void stmpe_dbg_show_one(struct seq_file *s,
                           gpio, label ?: "(none)",
                           val ? "hi" : "lo");
        } else {
-               u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8);
-               u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8);
-               u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8);
-               u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8);
-               bool edge_det;
-               bool rise;
-               bool fall;
+               u8 edge_det_reg;
+               u8 rise_reg;
+               u8 fall_reg;
+               u8 irqen_reg;
+
+               char *edge_det_values[] = {"edge-inactive",
+                                          "edge-asserted",
+                                          "not-supported"};
+               char *rise_values[] = {"no-rising-edge-detection",
+                                      "rising-edge-detection",
+                                      "not-supported"};
+               char *fall_values[] = {"no-falling-edge-detection",
+                                      "falling-edge-detection",
+                                      "not-supported"};
+               #define NOT_SUPPORTED_IDX 2
+               u8 edge_det = NOT_SUPPORTED_IDX;
+               u8 rise = NOT_SUPPORTED_IDX;
+               u8 fall = NOT_SUPPORTED_IDX;
                bool irqen;
 
-               ret = stmpe_reg_read(stmpe, edge_det_reg);
-               if (ret < 0)
+               switch (stmpe->partnum) {
+               case STMPE610:
+               case STMPE811:
+               case STMPE1601:
+               case STMPE2401:
+               case STMPE2403:
+                       edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_LSB + bank];
+                       ret = stmpe_reg_read(stmpe, edge_det_reg);
+                       if (ret < 0)
+                               return;
+                       edge_det = !!(ret & mask);
+
+               case STMPE1801:
+                       rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank];
+                       fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank];
+
+                       ret = stmpe_reg_read(stmpe, rise_reg);
+                       if (ret < 0)
+                               return;
+                       rise = !!(ret & mask);
+                       ret = stmpe_reg_read(stmpe, fall_reg);
+                       if (ret < 0)
+                               return;
+                       fall = !!(ret & mask);
+
+               case STMPE801:
+               case STMPE1600:
+                       irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank];
+                       break;
+
+               default:
                        return;
-               edge_det = !!(ret & mask);
-               ret = stmpe_reg_read(stmpe, rise_reg);
-               if (ret < 0)
-                       return;
-               rise = !!(ret & mask);
-               ret = stmpe_reg_read(stmpe, fall_reg);
-               if (ret < 0)
-                       return;
-               fall = !!(ret & mask);
+               }
+
                ret = stmpe_reg_read(stmpe, irqen_reg);
                if (ret < 0)
                        return;
                irqen = !!(ret & mask);
 
-               seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %s %s%s%s",
+               seq_printf(s, " gpio-%-3d (%-20.20s) in  %s %13s %13s %25s %25s",
                           gpio, label ?: "(none)",
                           val ? "hi" : "lo",
-                          edge_det ? "edge-asserted" : "edge-inactive",
-                          irqen ? "IRQ-enabled" : "",
-                          rise ? " rising-edge-detection" : "",
-                          fall ? " falling-edge-detection" : "");
+                          edge_det_values[edge_det],
+                          irqen ? "IRQ-enabled" : "IRQ-disabled",
+                          rise_values[rise],
+                          fall_values[fall]);
        }
 }
 
@@ -307,18 +361,32 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
 {
        struct stmpe_gpio *stmpe_gpio = dev;
        struct stmpe *stmpe = stmpe_gpio->stmpe;
-       u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+       u8 statmsbreg;
        int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
        u8 status[num_banks];
        int ret;
        int i;
 
+       /*
+        * the stmpe_block_read() call below, imposes to set statmsbreg
+        * with the register located at the lowest address. As STMPE1600
+        * variant is the only one which respect registers address's order
+        * (LSB regs located at lowest address than MSB ones) whereas all
+        * the others have a registers layout with MSB located before the
+        * LSB regs.
+        */
+       if (stmpe->partnum == STMPE1600)
+               statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_LSB];
+       else
+               statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+
        ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
        if (ret < 0)
                return IRQ_NONE;
 
        for (i = 0; i < num_banks; i++) {
-               int bank = num_banks - i - 1;
+               int bank = (stmpe_gpio->stmpe->partnum == STMPE1600) ? i :
+                          num_banks - i - 1;
                unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
                unsigned int stat = status[i];
 
@@ -333,15 +401,21 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
                                                         line);
 
                        handle_nested_irq(child_irq);
-                       stat &= ~(1 << bit);
+                       stat &= ~BIT(bit);
                }
 
-               stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
-
-               /* Edge detect register is not present on 801 */
-               if (stmpe->partnum != STMPE801)
-                       stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
-                                       + i, status[i]);
+               /*
+                * interrupt status register write has no effect on
+                * 801/1801/1600, bits are cleared when read.
+                * Edge detect register is not present on 801/1600/1801
+                */
+               if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 ||
+                   stmpe->partnum != STMPE1801) {
+                       stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
+                       stmpe_reg_write(stmpe,
+                                       stmpe->regs[STMPE_IDX_GPEDR_LSB + i],
+                                       status[i]);
+               }
        }
 
        return IRQ_HANDLED;
@@ -376,6 +450,8 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 
        of_property_read_u32(np, "st,norequest-mask",
                        &stmpe_gpio->norequest_mask);
+       if (stmpe_gpio->norequest_mask)
+               stmpe_gpio->chip.irq_need_valid_mask = true;
 
        if (irq < 0)
                dev_info(&pdev->dev,
@@ -400,6 +476,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
                        goto out_disable;
                }
+               if (stmpe_gpio->norequest_mask) {
+                       int i;
+
+                       /* Forbid unused lines to be mapped as IRQs */
+                       for (i = 0; i < sizeof(u32); i++)
+                               if (stmpe_gpio->norequest_mask & BIT(i))
+                                       clear_bit(i, stmpe_gpio->chip.irq_valid_mask);
+               }
                ret =  gpiochip_irqchip_add(&stmpe_gpio->chip,
                                            &stmpe_gpio_irq_chip,
                                            0,
index a177ebd..af95de8 100644 (file)
@@ -236,7 +236,6 @@ static const struct i2c_device_id sx150x_id[] = {
        {"sx1502q", 3},
        {}
 };
-MODULE_DEVICE_TABLE(i2c, sx150x_id);
 
 static const struct of_device_id sx150x_of_match[] = {
        { .compatible = "semtech,sx1508q" },
@@ -245,7 +244,6 @@ static const struct of_device_id sx150x_of_match[] = {
        { .compatible = "semtech,sx1502q" },
        {},
 };
-MODULE_DEVICE_TABLE(of, sx150x_of_match);
 
 static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
 {
index 8b36593..5a5a6cb 100644 (file)
@@ -34,7 +34,7 @@ struct tc3589x_gpio {
        u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
 };
 
-static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
@@ -49,24 +49,24 @@ static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
        return !!(ret & mask);
 }
 
-static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
        u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
-       unsigned pos = offset % 8;
+       unsigned int pos = offset % 8;
        u8 data[] = {val ? BIT(pos) : 0, BIT(pos)};
 
        tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
 }
 
 static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
-                                        unsigned offset, int val)
+                                        unsigned int offset, int val)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
        u8 reg = TC3589x_GPIODIR0 + offset / 8;
-       unsigned pos = offset % 8;
+       unsigned int pos = offset % 8;
 
        tc3589x_gpio_set(chip, offset, val);
 
@@ -74,19 +74,35 @@ static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
 }
 
 static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
-                                       unsigned offset)
+                                       unsigned int offset)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
        u8 reg = TC3589x_GPIODIR0 + offset / 8;
-       unsigned pos = offset % 8;
+       unsigned int pos = offset % 8;
 
        return tc3589x_set_bits(tc3589x, reg, BIT(pos), 0);
 }
 
-static int tc3589x_gpio_single_ended(struct gpio_chip *chip,
-                                    unsigned offset,
-                                    enum single_ended_mode mode)
+static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
+                                     unsigned int offset)
+{
+       struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
+       struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+       u8 reg = TC3589x_GPIODIR0 + offset / 8;
+       unsigned int pos = offset % 8;
+       int ret;
+
+       ret = tc3589x_reg_read(tc3589x, reg);
+       if (ret < 0)
+               return ret;
+
+       return !!(ret & BIT(pos));
+}
+
+static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
+                                        unsigned int offset,
+                                        enum single_ended_mode mode)
 {
        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
@@ -97,7 +113,7 @@ static int tc3589x_gpio_single_ended(struct gpio_chip *chip,
         */
        u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2;
        u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2;
-       unsigned pos = offset % 8;
+       unsigned int pos = offset % 8;
        int ret;
 
        switch(mode) {
@@ -124,14 +140,15 @@ static int tc3589x_gpio_single_ended(struct gpio_chip *chip,
        return -ENOTSUPP;
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "tc3589x",
        .owner                  = THIS_MODULE,
-       .direction_input        = tc3589x_gpio_direction_input,
        .get                    = tc3589x_gpio_get,
-       .direction_output       = tc3589x_gpio_direction_output,
        .set                    = tc3589x_gpio_set,
-       .set_single_ended       = tc3589x_gpio_single_ended,
+       .direction_output       = tc3589x_gpio_direction_output,
+       .direction_input        = tc3589x_gpio_direction_input,
+       .get_direction          = tc3589x_gpio_get_direction,
+       .set_single_ended       = tc3589x_gpio_set_single_ended,
        .can_sleep              = true,
 };
 
index cace79c..c8b34d7 100644 (file)
@@ -87,7 +87,7 @@ static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask,
        tpic2810_set_mask_bits(chip, *mask, *bits);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "tpic2810",
        .owner                  = THIS_MODULE,
        .get_direction          = tpic2810_get_direction,
index 8e25f01..b23c4d2 100644 (file)
@@ -72,7 +72,7 @@ static void tps65086_gpio_set(struct gpio_chip *chip, unsigned offset,
                           BIT(4 + offset), value ? BIT(4 + offset) : 0);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "tps65086-gpio",
        .owner                  = THIS_MODULE,
        .get_direction          = tps65086_gpio_get_direction,
index 1c09a19..d779307 100644 (file)
@@ -172,7 +172,7 @@ static int tps65218_gpio_set_single_ended(struct gpio_chip *gc,
        return -ENOTSUPP;
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "gpio-tps65218",
        .owner                  = THIS_MODULE,
        .request                = tps65218_gpio_request,
@@ -204,7 +204,8 @@ static int tps65218_gpio_probe(struct platform_device *pdev)
        tps65218_gpio->gpio_chip.of_node = pdev->dev.of_node;
 #endif
 
-       ret = gpiochip_add_data(&tps65218_gpio->gpio_chip, tps65218_gpio);
+       ret = devm_gpiochip_add_data(&pdev->dev, &tps65218_gpio->gpio_chip,
+                                    tps65218_gpio);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to register gpiochip, %d\n", ret);
                return ret;
@@ -215,15 +216,6 @@ static int tps65218_gpio_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int tps65218_gpio_remove(struct platform_device *pdev)
-{
-       struct tps65218_gpio *tps65218_gpio = platform_get_drvdata(pdev);
-
-       gpiochip_remove(&tps65218_gpio->gpio_chip);
-
-       return 0;
-}
-
 static const struct of_device_id tps65218_dt_match[] = {
        { .compatible = "ti,tps65218-gpio" },
        {  }
@@ -242,7 +234,6 @@ static struct platform_driver tps65218_gpio_driver = {
                .of_match_table = of_match_ptr(tps65218_dt_match)
        },
        .probe = tps65218_gpio_probe,
-       .remove = tps65218_gpio_remove,
        .id_table = tps65218_gpio_id_table,
 };
 
index acfd30a..abc0798 100644 (file)
@@ -90,7 +90,7 @@ static void tps65912_gpio_set(struct gpio_chip *gc, unsigned offset,
                           GPIO_SET_MASK, value ? GPIO_SET_MASK : 0);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "tps65912-gpio",
        .owner                  = THIS_MODULE,
        .get_direction          = tps65912_gpio_get_direction,
index 0c144a7..9925611 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/gpio/driver.h>
+#include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
new file mode 100644 (file)
index 0000000..5bd2172
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Digital I/O driver for Technologic Systems I2C FPGA Core
+ *
+ * Copyright (C) 2015 Technologic Systems
+ * Copyright (C) 2016 Savoir-Faire Linux
+ *
+ * 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.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define DEFAULT_PIN_NUMBER     32
+/*
+ * Register bits used by the GPIO device
+ * Some boards, such as TS-7970 do not have a separate input bit
+ */
+#define TS4900_GPIO_OE         0x01
+#define TS4900_GPIO_OUT                0x02
+#define TS4900_GPIO_IN         0x04
+#define TS7970_GPIO_IN         0x02
+
+struct ts4900_gpio_priv {
+       struct regmap *regmap;
+       struct gpio_chip gpio_chip;
+       unsigned int input_bit;
+};
+
+static int ts4900_gpio_get_direction(struct gpio_chip *chip,
+                                    unsigned int offset)
+{
+       struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+       unsigned int reg;
+
+       regmap_read(priv->regmap, offset, &reg);
+
+       return !(reg & TS4900_GPIO_OE);
+}
+
+static int ts4900_gpio_direction_input(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+
+       /*
+        * This will clear the output enable bit, the other bits are
+        * dontcare when this is cleared
+        */
+       return regmap_write(priv->regmap, offset, 0);
+}
+
+static int ts4900_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned int offset, int value)
+{
+       struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+       int ret;
+
+       if (value)
+               ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
+                                                        TS4900_GPIO_OUT);
+       else
+               ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE);
+
+       return ret;
+}
+
+static int ts4900_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+       unsigned int reg;
+
+       regmap_read(priv->regmap, offset, &reg);
+
+       return !!(reg & priv->input_bit);
+}
+
+static void ts4900_gpio_set(struct gpio_chip *chip, unsigned int offset,
+                           int value)
+{
+       struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+
+       if (value)
+               regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT,
+                                  TS4900_GPIO_OUT);
+       else
+               regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OUT, 0);
+}
+
+static const struct regmap_config ts4900_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+};
+
+static const struct gpio_chip template_chip = {
+       .label                  = "ts4900-gpio",
+       .owner                  = THIS_MODULE,
+       .get_direction          = ts4900_gpio_get_direction,
+       .direction_input        = ts4900_gpio_direction_input,
+       .direction_output       = ts4900_gpio_direction_output,
+       .get                    = ts4900_gpio_get,
+       .set                    = ts4900_gpio_set,
+       .base                   = -1,
+       .can_sleep              = true,
+};
+
+static const struct of_device_id ts4900_gpio_of_match_table[] = {
+       {
+               .compatible = "technologic,ts4900-gpio",
+               .data = (void *)TS4900_GPIO_IN,
+       }, {
+               .compatible = "technologic,ts7970-gpio",
+               .data = (void *)TS7970_GPIO_IN,
+       },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
+
+static int ts4900_gpio_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       const struct of_device_id *match;
+       struct ts4900_gpio_priv *priv;
+       u32 ngpio;
+       int ret;
+
+       match = of_match_device(ts4900_gpio_of_match_table, &client->dev);
+       if (!match)
+               return -EINVAL;
+
+       if (of_property_read_u32(client->dev.of_node, "ngpios", &ngpio))
+               ngpio = DEFAULT_PIN_NUMBER;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->gpio_chip = template_chip;
+       priv->gpio_chip.label = "ts4900-gpio";
+       priv->gpio_chip.ngpio = ngpio;
+       priv->gpio_chip.parent = &client->dev;
+       priv->input_bit = (uintptr_t)match->data;
+
+       priv->regmap = devm_regmap_init_i2c(client, &ts4900_regmap_config);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = devm_gpiochip_add_data(&client->dev, &priv->gpio_chip, priv);
+       if (ret < 0) {
+               dev_err(&client->dev, "Unable to register gpiochip\n");
+               return ret;
+       }
+
+       i2c_set_clientdata(client, priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id ts4900_gpio_id_table[] = {
+       { "ts4900-gpio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ts4900_gpio_id_table);
+
+static struct i2c_driver ts4900_gpio_driver = {
+       .driver = {
+               .name = "ts4900-gpio",
+               .of_match_table = ts4900_gpio_of_match_table,
+       },
+       .probe = ts4900_gpio_probe,
+       .id_table = ts4900_gpio_id_table,
+};
+module_i2c_driver(ts4900_gpio_driver);
+
+MODULE_AUTHOR("Technologic Systems");
+MODULE_DESCRIPTION("GPIO interface for Technologic Systems I2C-FPGA core");
+MODULE_LICENSE("GPL");
index 4b807b0..dfcfbba 100644 (file)
@@ -381,7 +381,7 @@ static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
                : -EINVAL;
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "twl4030",
        .owner                  = THIS_MODULE,
        .request                = twl_request,
index 6284bdb..3edb09c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * vf610 GPIO support through PORT and GPIO module
+ * Freescale vf610 GPIO support through PORT and GPIO
  *
  * Copyright (c) 2014 Toradex AG.
  *
@@ -23,7 +23,6 @@
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -289,7 +288,3 @@ static int __init gpio_vf610_init(void)
        return platform_driver_register(&vf610_gpio_driver);
 }
 device_initcall(gpio_vf610_init);
-
-MODULE_AUTHOR("Stefan Agner <stefan@agner.ch>");
-MODULE_DESCRIPTION("Freescale VF610 GPIO");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
new file mode 100644 (file)
index 0000000..d0ddba7
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Intel Whiskey Cove PMIC GPIO Driver
+ *
+ * This driver is written based on gpio-crystalcove.c
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/gpio/driver.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/seq_file.h>
+
+/*
+ * Whiskey Cove PMIC has 13 physical GPIO pins divided into 3 banks:
+ * Bank 0: Pin 0 - 6
+ * Bank 1: Pin 7 - 10
+ * Bank 2: Pin 11 -12
+ * Each pin has one output control register and one input control register.
+ */
+#define BANK0_NR_PINS          7
+#define BANK1_NR_PINS          4
+#define BANK2_NR_PINS          2
+#define WCOVE_GPIO_NUM         (BANK0_NR_PINS + BANK1_NR_PINS + BANK2_NR_PINS)
+#define WCOVE_VGPIO_NUM                94
+/* GPIO output control registers (one per pin): 0x4e44 - 0x4e50 */
+#define GPIO_OUT_CTRL_BASE     0x4e44
+/* GPIO input control registers (one per pin): 0x4e51 - 0x4e5d */
+#define GPIO_IN_CTRL_BASE      0x4e51
+
+/*
+ * GPIO interrupts are organized in two groups:
+ * Group 0: Bank 0 pins (Pin 0 - 6)
+ * Group 1: Bank 1 and Bank 2 pins (Pin 7 - 12)
+ * Each group has two registers (one bit per pin): status and mask.
+ */
+#define GROUP0_NR_IRQS         7
+#define GROUP1_NR_IRQS         6
+#define IRQ_MASK_BASE          0x4e19
+#define IRQ_STATUS_BASE                0x4e0b
+#define UPDATE_IRQ_TYPE                BIT(0)
+#define UPDATE_IRQ_MASK                BIT(1)
+
+#define CTLI_INTCNT_DIS                (0 << 1)
+#define CTLI_INTCNT_NE         (1 << 1)
+#define CTLI_INTCNT_PE         (2 << 1)
+#define CTLI_INTCNT_BE         (3 << 1)
+
+#define CTLO_DIR_IN            (0 << 5)
+#define CTLO_DIR_OUT           (1 << 5)
+
+#define CTLO_DRV_MASK          (1 << 4)
+#define CTLO_DRV_OD            (0 << 4)
+#define CTLO_DRV_CMOS          (1 << 4)
+
+#define CTLO_DRV_REN           (1 << 3)
+
+#define CTLO_RVAL_2KDOWN       (0 << 1)
+#define CTLO_RVAL_2KUP         (1 << 1)
+#define CTLO_RVAL_50KDOWN      (2 << 1)
+#define CTLO_RVAL_50KUP                (3 << 1)
+
+#define CTLO_INPUT_SET (CTLO_DRV_CMOS | CTLO_DRV_REN | CTLO_RVAL_2KUP)
+#define CTLO_OUTPUT_SET        (CTLO_DIR_OUT | CTLO_INPUT_SET)
+
+enum ctrl_register {
+       CTRL_IN,
+       CTRL_OUT,
+};
+
+/*
+ * struct wcove_gpio - Whiskey Cove GPIO controller
+ * @buslock: for bus lock/sync and unlock.
+ * @chip: the abstract gpio_chip structure.
+ * @dev: the gpio device
+ * @regmap: the regmap from the parent device.
+ * @regmap_irq_chip: the regmap of the gpio irq chip.
+ * @update: pending IRQ setting update, to be written to the chip upon unlock.
+ * @intcnt: the Interrupt Detect value to be written.
+ * @set_irq_mask: true if the IRQ mask needs to be set, false to clear.
+ */
+struct wcove_gpio {
+       struct mutex buslock;
+       struct gpio_chip chip;
+       struct device *dev;
+       struct regmap *regmap;
+       struct regmap_irq_chip_data *regmap_irq_chip;
+       int update;
+       int intcnt;
+       bool set_irq_mask;
+};
+
+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 (reg_type == CTRL_IN)
+               reg = GPIO_IN_CTRL_BASE + bank;
+       else
+               reg = GPIO_OUT_CTRL_BASE + bank;
+
+       return reg;
+}
+
+static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio)
+{
+       unsigned int reg, mask;
+
+       if (gpio < GROUP0_NR_IRQS) {
+               reg = IRQ_MASK_BASE;
+               mask = BIT(gpio % GROUP0_NR_IRQS);
+       } else {
+               reg = IRQ_MASK_BASE + 1;
+               mask = BIT((gpio - GROUP0_NR_IRQS) % GROUP1_NR_IRQS);
+       }
+
+       if (wg->set_irq_mask)
+               regmap_update_bits(wg->regmap, reg, mask, mask);
+       else
+               regmap_update_bits(wg->regmap, reg, mask, 0);
+}
+
+static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio)
+{
+       unsigned int reg = to_reg(gpio, CTRL_IN);
+
+       regmap_update_bits(wg->regmap, reg, CTLI_INTCNT_BE, wg->intcnt);
+}
+
+static int wcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio)
+{
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+
+       return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT),
+                           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);
+
+       return regmap_write(wg->regmap, to_reg(gpio, CTRL_OUT),
+                           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;
+
+       ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &val);
+       if (ret)
+               return ret;
+
+       return !(val & CTLO_DIR_OUT);
+}
+
+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;
+
+       ret = regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &val);
+       if (ret)
+               return ret;
+
+       return val & 0x1;
+}
+
+static void wcove_gpio_set(struct gpio_chip *chip,
+                                unsigned int gpio, int value)
+{
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+
+       if (value)
+               regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
+       else
+               regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
+}
+
+static int wcove_gpio_set_single_ended(struct gpio_chip *chip,
+                                       unsigned int gpio,
+                                       enum single_ended_mode mode)
+{
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+
+       switch (mode) {
+       case LINE_MODE_OPEN_DRAIN:
+               return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
+                                               CTLO_DRV_MASK, CTLO_DRV_OD);
+       case LINE_MODE_PUSH_PULL:
+               return regmap_update_bits(wg->regmap, to_reg(gpio, CTRL_OUT),
+                                               CTLO_DRV_MASK, CTLO_DRV_CMOS);
+       default:
+               break;
+       }
+
+       return -ENOTSUPP;
+}
+
+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);
+
+       switch (type) {
+       case IRQ_TYPE_NONE:
+               wg->intcnt = CTLI_INTCNT_DIS;
+               break;
+       case IRQ_TYPE_EDGE_BOTH:
+               wg->intcnt = CTLI_INTCNT_BE;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               wg->intcnt = CTLI_INTCNT_PE;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               wg->intcnt = CTLI_INTCNT_NE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wg->update |= UPDATE_IRQ_TYPE;
+
+       return 0;
+}
+
+static void wcove_bus_lock(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+
+       mutex_lock(&wg->buslock);
+}
+
+static void wcove_bus_sync_unlock(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int gpio = data->hwirq;
+
+       if (wg->update & UPDATE_IRQ_TYPE)
+               wcove_update_irq_ctrl(wg, gpio);
+       if (wg->update & UPDATE_IRQ_MASK)
+               wcove_update_irq_mask(wg, gpio);
+       wg->update = 0;
+
+       mutex_unlock(&wg->buslock);
+}
+
+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);
+
+       wg->set_irq_mask = false;
+       wg->update |= UPDATE_IRQ_MASK;
+}
+
+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);
+
+       wg->set_irq_mask = true;
+       wg->update |= UPDATE_IRQ_MASK;
+}
+
+static struct irq_chip wcove_irqchip = {
+       .name                   = "Whiskey Cove",
+       .irq_mask               = wcove_irq_mask,
+       .irq_unmask             = wcove_irq_unmask,
+       .irq_set_type           = wcove_irq_type,
+       .irq_bus_lock           = wcove_bus_lock,
+       .irq_bus_sync_unlock    = wcove_bus_sync_unlock,
+};
+
+static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
+{
+       struct wcove_gpio *wg = (struct wcove_gpio *)data;
+       unsigned int pending, virq, gpio, mask, offset;
+       u8 p[2];
+
+       if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) {
+               dev_err(wg->dev, "Failed to read irq status register\n");
+               return IRQ_NONE;
+       }
+
+       pending = p[0] | (p[1] << 8);
+       if (!pending)
+               return IRQ_NONE;
+
+       /* Iterate until no interrupt is pending */
+       while (pending) {
+               /* One iteration is for all pending bits */
+               for_each_set_bit(gpio, (const unsigned long *)&pending,
+                                                GROUP0_NR_IRQS) {
+                       offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
+                       mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
+                                                               BIT(gpio);
+                       virq = irq_find_mapping(wg->chip.irqdomain, gpio);
+                       handle_nested_irq(virq);
+                       regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset,
+                                                               mask, mask);
+               }
+
+               /* Next iteration */
+               if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) {
+                       dev_err(wg->dev, "Failed to read irq status\n");
+                       break;
+               }
+
+               pending = p[0] | (p[1] << 8);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void wcove_gpio_dbg_show(struct seq_file *s,
+                                     struct gpio_chip *chip)
+{
+       unsigned int ctlo, ctli, irq_mask, irq_status;
+       struct wcove_gpio *wg = gpiochip_get_data(chip);
+       int gpio, offset, group, ret = 0;
+
+       for (gpio = 0; gpio < WCOVE_GPIO_NUM; gpio++) {
+               group = gpio < GROUP0_NR_IRQS ? 0 : 1;
+               ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &ctlo);
+               ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &ctli);
+               ret += regmap_read(wg->regmap, IRQ_MASK_BASE + group,
+                                                       &irq_mask);
+               ret += regmap_read(wg->regmap, IRQ_STATUS_BASE + group,
+                                                       &irq_status);
+               if (ret) {
+                       pr_err("Failed to read registers: ctrl out/in or irq status/mask\n");
+                       break;
+               }
+
+               offset = gpio % 8;
+               seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s\n",
+                          gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ",
+                          ctli & 0x1 ? "hi" : "lo",
+                          ctli & CTLI_INTCNT_NE ? "fall" : "    ",
+                          ctli & CTLI_INTCNT_PE ? "rise" : "    ",
+                          ctlo,
+                          irq_mask & BIT(offset) ? "mask  " : "unmask",
+                          irq_status & BIT(offset) ? "pending" : "       ");
+       }
+}
+
+static int wcove_gpio_probe(struct platform_device *pdev)
+{
+       struct intel_soc_pmic *pmic;
+       struct wcove_gpio *wg;
+       int virq, ret, irq;
+       struct device *dev;
+
+       /*
+        * This gpio platform device is created by a mfd device (see
+        * drivers/mfd/intel_soc_pmic_bxtwc.c for details). Information
+        * shared by all sub-devices created by the mfd device, the regmap
+        * pointer for instance, is stored as driver data of the mfd device
+        * driver.
+        */
+       pmic = dev_get_drvdata(pdev->dev.parent);
+       if (!pmic)
+               return -ENODEV;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       dev = &pdev->dev;
+
+       wg = devm_kzalloc(dev, sizeof(*wg), GFP_KERNEL);
+       if (!wg)
+               return -ENOMEM;
+
+       wg->regmap_irq_chip = pmic->irq_chip_data_level2;
+
+       platform_set_drvdata(pdev, wg);
+
+       mutex_init(&wg->buslock);
+       wg->chip.label = KBUILD_MODNAME;
+       wg->chip.direction_input = wcove_gpio_dir_in;
+       wg->chip.direction_output = wcove_gpio_dir_out;
+       wg->chip.get_direction = wcove_gpio_get_direction;
+       wg->chip.get = wcove_gpio_get;
+       wg->chip.set = wcove_gpio_set;
+       wg->chip.set_single_ended = wcove_gpio_set_single_ended,
+       wg->chip.base = -1;
+       wg->chip.ngpio = WCOVE_VGPIO_NUM;
+       wg->chip.can_sleep = true;
+       wg->chip.parent = pdev->dev.parent;
+       wg->chip.dbg_show = wcove_gpio_dbg_show;
+       wg->dev = dev;
+       wg->regmap = pmic->regmap;
+
+       ret = devm_gpiochip_add_data(dev, &wg->chip, wg);
+       if (ret) {
+               dev_err(dev, "Failed to add gpiochip: %d\n", ret);
+               return ret;
+       }
+
+       ret = gpiochip_irqchip_add(&wg->chip, &wcove_irqchip, 0,
+                            handle_simple_irq, IRQ_TYPE_NONE);
+       if (ret) {
+               dev_err(dev, "Failed to add irqchip: %d\n", ret);
+               return ret;
+       }
+
+       virq = regmap_irq_get_virq(wg->regmap_irq_chip, irq);
+       if (virq < 0) {
+               dev_err(dev, "Failed to get virq by irq %d\n", irq);
+               return virq;
+       }
+
+       ret = devm_request_threaded_irq(dev, virq, NULL,
+               wcove_gpio_irq_handler, IRQF_ONESHOT, pdev->name, wg);
+       if (ret) {
+               dev_err(dev, "Failed to request irq %d\n", virq);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Whiskey Cove PMIC itself is a analog device(but with digital control
+ * interface) providing power management support for other devices in
+ * the accompanied SoC, so we have no .pm for Whiskey Cove GPIO driver.
+ */
+static struct platform_driver wcove_gpio_driver = {
+       .driver = {
+               .name = "bxt_wcove_gpio",
+       },
+       .probe = wcove_gpio_probe,
+};
+
+module_platform_driver(wcove_gpio_driver);
+
+MODULE_AUTHOR("Ajay Thomas <ajay.thomas.david.rajamanickam@intel.com>");
+MODULE_AUTHOR("Bin Gao <bin.gao@intel.com>");
+MODULE_DESCRIPTION("Intel Whiskey Cove GPIO Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bxt_wcove_gpio");
index 21f97bc..533707f 100644 (file)
@@ -247,7 +247,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #define wm831x_gpio_dbg_show NULL
 #endif
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "wm831x",
        .owner                  = THIS_MODULE,
        .direction_input        = wm831x_gpio_direction_in,
index e976570..e46752e 100644 (file)
@@ -93,7 +93,7 @@ static int wm8350_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
        return wm8350->irq_base + WM8350_IRQ_GPIO(offset);
 }
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "wm8350",
        .owner                  = THIS_MODULE,
        .direction_input        = wm8350_gpio_direction_in,
index 2457aac..68410fd 100644 (file)
@@ -249,7 +249,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #define wm8994_gpio_dbg_show NULL
 #endif
 
-static struct gpio_chip template_chip = {
+static const struct gpio_chip template_chip = {
        .label                  = "wm8994",
        .owner                  = THIS_MODULE,
        .request                = wm8994_gpio_request,
index e72794e..6b4d10d 100644 (file)
@@ -96,6 +96,9 @@
 /* GPIO upper 16 bit mask */
 #define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
 
+/* For GPIO quirks */
+#define ZYNQ_GPIO_QUIRK_FOO    BIT(0)
+
 /**
  * struct zynq_gpio - gpio device private data structure
  * @chip:      instance of the gpio_chip
@@ -122,6 +125,7 @@ struct zynq_gpio {
 */
 struct zynq_platform_data {
        const char *label;
+       u32 quirks;
        u16 ngpio;
        int max_bank;
        int bank_min[ZYNQMP_GPIO_MAX_BANK];
@@ -238,13 +242,19 @@ 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);
 
-       /* bank 0 pins 7 and 8 are special and cannot be used as inputs */
-       if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8))
+       /*
+        * On zynq bank 0 pins 7 and 8 are special and cannot be used
+        * as inputs.
+        */
+       if (is_zynq_gpio && bank_num == 0 &&
+               (bank_pin_num == 7 || bank_pin_num == 8))
                return -EINVAL;
 
        /* clear the bit in direction mode reg to set the pin as input */
@@ -627,6 +637,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,
        .ngpio = ZYNQ_GPIO_NR_GPIOS,
        .max_bank = ZYNQ_GPIO_MAX_BANK,
        .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
index af51461..58ece20 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
 #include <linux/export.h>
 #include <linux/acpi.h>
 #include <linux/interrupt.h>
@@ -395,7 +396,7 @@ struct acpi_gpio_lookup {
        int n;
 };
 
-static int acpi_find_gpio(struct acpi_resource *ares, void *data)
+static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
 {
        struct acpi_gpio_lookup *lookup = data;
 
@@ -440,7 +441,8 @@ static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
 
        INIT_LIST_HEAD(&res_list);
 
-       ret = acpi_dev_get_resources(lookup->adev, &res_list, acpi_find_gpio,
+       ret = acpi_dev_get_resources(lookup->adev, &res_list,
+                                    acpi_populate_gpio_lookup,
                                     lookup);
        if (ret < 0)
                return ret;
@@ -513,7 +515,7 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
  * Note: if the GPIO resource has multiple entries in the pin list, this
  * function only returns the first.
  */
-struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
                                          const char *propname, int index,
                                          struct acpi_gpio_info *info)
 {
@@ -546,6 +548,55 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
        return ret ? ERR_PTR(ret) : lookup.desc;
 }
 
+struct gpio_desc *acpi_find_gpio(struct device *dev,
+                                const char *con_id,
+                                unsigned int idx,
+                                enum gpiod_flags flags,
+                                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 i;
+
+       /* Try first from _DSD */
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id && strcmp(con_id, "gpios")) {
+                       snprintf(propname, sizeof(propname), "%s-%s",
+                                con_id, gpio_suffixes[i]);
+               } else {
+                       snprintf(propname, sizeof(propname), "%s",
+                                gpio_suffixes[i]);
+               }
+
+               desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
+               if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+                       break;
+       }
+
+       /* Then from plain _CRS GPIOs */
+       if (IS_ERR(desc)) {
+               if (!acpi_can_fallback_to_crs(adev, con_id))
+                       return ERR_PTR(-ENOENT);
+
+               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.polarity == GPIO_ACTIVE_LOW)
+               *lookupflags |= GPIO_ACTIVE_LOW;
+
+       return desc;
+}
+
 /**
  * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
  * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
index a28feb3..ecad3f0 100644 (file)
@@ -113,6 +113,45 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
 }
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
+struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
+                              unsigned int idx,
+                              enum gpio_lookup_flags *flags)
+{
+       char prop_name[32]; /* 32 is max size of property name */
+       enum of_gpio_flags of_flags;
+       struct gpio_desc *desc;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id)
+                       snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
+                                gpio_suffixes[i]);
+               else
+                       snprintf(prop_name, sizeof(prop_name), "%s",
+                                gpio_suffixes[i]);
+
+               desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
+                                               &of_flags);
+               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+                       break;
+       }
+
+       if (IS_ERR(desc))
+               return desc;
+
+       if (of_flags & OF_GPIO_ACTIVE_LOW)
+               *flags |= GPIO_ACTIVE_LOW;
+
+       if (of_flags & OF_GPIO_SINGLE_ENDED) {
+               if (of_flags & OF_GPIO_ACTIVE_LOW)
+                       *flags |= GPIO_OPEN_DRAIN;
+               else
+                       *flags |= GPIO_OPEN_SOURCE;
+       }
+
+       return desc;
+}
+
 /**
  * of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
  * @np:                device node to get GPIO from
index 932e510..4b44dd9 100644 (file)
@@ -670,10 +670,10 @@ int gpiod_export_link(struct device *dev, const char *name,
 EXPORT_SYMBOL_GPL(gpiod_export_link);
 
 /**
- * gpiod_unexport - reverse effect of gpio_export()
+ * gpiod_unexport - reverse effect of gpiod_export()
  * @gpio: gpio to make unavailable
  *
- * This is implicit on gpio_free().
+ * This is implicit on gpiod_free().
  */
 void gpiod_unexport(struct gpio_desc *desc)
 {
index 23be4da..f0fc3a0 100644 (file)
@@ -1370,19 +1370,15 @@ struct gpio_chip *gpiochip_find(void *data,
                                             void *data))
 {
        struct gpio_device *gdev;
-       struct gpio_chip *chip;
+       struct gpio_chip *chip = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&gpio_lock, flags);
        list_for_each_entry(gdev, &gpio_devices, list)
-               if (gdev->chip && match(gdev->chip, data))
+               if (gdev->chip && match(gdev->chip, data)) {
+                       chip = gdev->chip;
                        break;
-
-       /* No match? */
-       if (&gdev->list == &gpio_devices)
-               chip = NULL;
-       else
-               chip = gdev->chip;
+               }
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
@@ -1667,6 +1663,20 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
        if (gpiochip->of_node)
                of_node = gpiochip->of_node;
 #endif
+       /*
+        * Specifying a default trigger is a terrible idea if DT or ACPI is
+        * used to configure the interrupts, as you may end-up with
+        * conflicting triggers. Tell the user, and reset to NONE.
+        */
+       if (WARN(of_node && type != IRQ_TYPE_NONE,
+                "%s: Ignoring %d default trigger\n", of_node->full_name, type))
+               type = IRQ_TYPE_NONE;
+       if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
+               acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
+                                "Ignoring %d default trigger\n", type);
+               type = IRQ_TYPE_NONE;
+       }
+
        gpiochip->irqchip = irqchip;
        gpiochip->irq_handler = handler;
        gpiochip->irq_default_type = type;
@@ -2873,94 +2883,6 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
        mutex_unlock(&gpio_lookup_lock);
 }
 
-static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
-                                     unsigned int idx,
-                                     enum gpio_lookup_flags *flags)
-{
-       char prop_name[32]; /* 32 is max size of property name */
-       enum of_gpio_flags of_flags;
-       struct gpio_desc *desc;
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
-                                gpio_suffixes[i]);
-               else
-                       snprintf(prop_name, sizeof(prop_name), "%s",
-                                gpio_suffixes[i]);
-
-               desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
-                                               &of_flags);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
-                       break;
-       }
-
-       if (IS_ERR(desc))
-               return desc;
-
-       if (of_flags & OF_GPIO_ACTIVE_LOW)
-               *flags |= GPIO_ACTIVE_LOW;
-
-       if (of_flags & OF_GPIO_SINGLE_ENDED) {
-               if (of_flags & OF_GPIO_ACTIVE_LOW)
-                       *flags |= GPIO_OPEN_DRAIN;
-               else
-                       *flags |= GPIO_OPEN_SOURCE;
-       }
-
-       return desc;
-}
-
-static struct gpio_desc *acpi_find_gpio(struct device *dev,
-                                       const char *con_id,
-                                       unsigned int idx,
-                                       enum gpiod_flags flags,
-                                       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 i;
-
-       /* Try first from _DSD */
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id && strcmp(con_id, "gpios")) {
-                       snprintf(propname, sizeof(propname), "%s-%s",
-                                con_id, gpio_suffixes[i]);
-               } else {
-                       snprintf(propname, sizeof(propname), "%s",
-                                gpio_suffixes[i]);
-               }
-
-               desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
-                       break;
-       }
-
-       /* Then from plain _CRS GPIOs */
-       if (IS_ERR(desc)) {
-               if (!acpi_can_fallback_to_crs(adev, con_id))
-                       return ERR_PTR(-ENOENT);
-
-               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.polarity == GPIO_ACTIVE_LOW)
-               *lookupflags |= GPIO_ACTIVE_LOW;
-
-       return desc;
-}
-
 static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
        const char *dev_id = dev ? dev_name(dev) : NULL;
index 2d9ea5e..346fbda 100644 (file)
@@ -20,6 +20,7 @@
 
 enum of_gpio_flags;
 enum gpiod_flags;
+enum gpio_lookup_flags;
 struct acpi_device;
 
 /**
@@ -86,6 +87,32 @@ struct acpi_gpio_info {
 /* gpio suffixes used for ACPI and device tree lookup */
 static const char * const gpio_suffixes[] = { "gpios", "gpio" };
 
+#ifdef CONFIG_OF_GPIO
+struct gpio_desc *of_find_gpio(struct device *dev,
+                              const char *con_id,
+                              unsigned int idx,
+                              enum gpio_lookup_flags *flags);
+struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+                  const char *list_name, int index, enum of_gpio_flags *flags);
+int of_gpiochip_add(struct gpio_chip *gc);
+void of_gpiochip_remove(struct gpio_chip *gc);
+#else
+static inline struct gpio_desc *of_find_gpio(struct device *dev,
+                                            const char *con_id,
+                                            unsigned int idx,
+                                            enum gpio_lookup_flags *flags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+                  const char *list_name, int index, enum of_gpio_flags *flags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
+static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
+#endif /* CONFIG_OF_GPIO */
+
 #ifdef CONFIG_ACPI
 void acpi_gpiochip_add(struct gpio_chip *chip);
 void acpi_gpiochip_remove(struct gpio_chip *chip);
@@ -93,9 +120,11 @@ 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);
 
-struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
-                                         const char *propname, int index,
-                                         struct acpi_gpio_info *info);
+struct gpio_desc *acpi_find_gpio(struct device *dev,
+                                const char *con_id,
+                                unsigned int idx,
+                                enum gpiod_flags flags,
+                                enum gpio_lookup_flags *lookupflags);
 struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
                                      const char *propname, int index,
                                      struct acpi_gpio_info *info);
@@ -114,10 +143,11 @@ static inline void
 acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
 
 static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
-                       int index, struct acpi_gpio_info *info)
+acpi_find_gpio(struct device *dev, const char *con_id,
+              unsigned int idx, enum gpiod_flags flags,
+              enum gpio_lookup_flags *lookupflags)
 {
-       return ERR_PTR(-ENOSYS);
+       return ERR_PTR(-ENOENT);
 }
 static inline struct gpio_desc *
 acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
@@ -137,9 +167,6 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
 }
 #endif
 
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
-                  const char *list_name, int index, enum of_gpio_flags *flags);
-
 struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
 void gpiod_set_array_value_complex(bool raw, bool can_sleep,
                                   unsigned int array_size,
index 2d1fb64..2caf7e9 100644 (file)
@@ -340,14 +340,6 @@ config MFD_HI655X_PMIC
        help
          Select this option to enable Hisilicon hi655x series pmic driver.
 
-config HTC_EGPIO
-       bool "HTC EGPIO support"
-       depends on GPIOLIB && ARM
-       help
-           This driver supports the CPLD egpio chip present on
-           several HTC phones.  It provides basic support for input
-           pins, output pins, and irqs.
-
 config HTC_PASIC3
        tristate "HTC PASIC3 LED/DS1WM chip support"
        select MFD_CORE
@@ -1224,6 +1216,20 @@ config MFD_TPS65217
          This driver can also be built as a module.  If so, the module
          will be called tps65217.
 
+config MFD_TI_LP873X
+       tristate "TI LP873X Power Management IC"
+       depends on I2C
+       select MFD_CORE
+       select REGMAP_I2C
+       help
+         If you say yes here then you get support for the LP873X series of
+         Power Management Integrated Circuits (PMIC).
+         These include voltage regulators, thermal protection, configurable
+         General Purpose Outputs (GPO) that are used in portable devices.
+
+         This driver can also be built as a module. If so, the module
+         will be called lp873x.
+
 config MFD_TPS65218
        tristate "TI TPS65218 Power Management chips"
        depends on I2C
index 2ba3ba3..2bf6a1a 100644 (file)
@@ -18,10 +18,11 @@ rtsx_pci-objs                       := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
 obj-$(CONFIG_MFD_RTSX_PCI)     += rtsx_pci.o
 obj-$(CONFIG_MFD_RTSX_USB)     += rtsx_usb.o
 
-obj-$(CONFIG_HTC_EGPIO)                += htc-egpio.o
 obj-$(CONFIG_HTC_PASIC3)       += htc-pasic3.o
 obj-$(CONFIG_HTC_I2CPLD)       += htc-i2cpld.o
 
+obj-$(CONFIG_MFD_TI_LP873X)    += lp873x.o
+
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)   += davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
 obj-$(CONFIG_MFD_TI_AM335X_TSCADC)     += ti_am335x_tscadc.o
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
deleted file mode 100644 (file)
index 513cfc5..0000000
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Support for the GPIO/IRQ expander chips present on several HTC phones.
- * These are implemented in CPLD chips present on the board.
- *
- * Copyright (c) 2007 Kevin O'Connor <kevin@koconnor.net>
- * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
- *
- * This file may be distributed under the terms of the GNU GPL license.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mfd/htc-egpio.h>
-
-struct egpio_chip {
-       int              reg_start;
-       int              cached_values;
-       unsigned long    is_out;
-       struct device    *dev;
-       struct gpio_chip chip;
-};
-
-struct egpio_info {
-       spinlock_t        lock;
-
-       /* iomem info */
-       void __iomem      *base_addr;
-       int               bus_shift;    /* byte shift */
-       int               reg_shift;    /* bit shift */
-       int               reg_mask;
-
-       /* irq info */
-       int               ack_register;
-       int               ack_write;
-       u16               irqs_enabled;
-       uint              irq_start;
-       int               nirqs;
-       uint              chained_irq;
-
-       /* egpio info */
-       struct egpio_chip *chip;
-       int               nchips;
-};
-
-static inline void egpio_writew(u16 value, struct egpio_info *ei, int reg)
-{
-       writew(value, ei->base_addr + (reg << ei->bus_shift));
-}
-
-static inline u16 egpio_readw(struct egpio_info *ei, int reg)
-{
-       return readw(ei->base_addr + (reg << ei->bus_shift));
-}
-
-/*
- * IRQs
- */
-
-static inline void ack_irqs(struct egpio_info *ei)
-{
-       egpio_writew(ei->ack_write, ei, ei->ack_register);
-       pr_debug("EGPIO ack - write %x to base+%x\n",
-                       ei->ack_write, ei->ack_register << ei->bus_shift);
-}
-
-static void egpio_ack(struct irq_data *data)
-{
-}
-
-/* There does not appear to be a way to proactively mask interrupts
- * on the egpio chip itself.  So, we simply ignore interrupts that
- * aren't desired. */
-static void egpio_mask(struct irq_data *data)
-{
-       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
-       ei->irqs_enabled &= ~(1 << (data->irq - ei->irq_start));
-       pr_debug("EGPIO mask %d %04x\n", data->irq, ei->irqs_enabled);
-}
-
-static void egpio_unmask(struct irq_data *data)
-{
-       struct egpio_info *ei = irq_data_get_irq_chip_data(data);
-       ei->irqs_enabled |= 1 << (data->irq - ei->irq_start);
-       pr_debug("EGPIO unmask %d %04x\n", data->irq, ei->irqs_enabled);
-}
-
-static struct irq_chip egpio_muxed_chip = {
-       .name           = "htc-egpio",
-       .irq_ack        = egpio_ack,
-       .irq_mask       = egpio_mask,
-       .irq_unmask     = egpio_unmask,
-};
-
-static void egpio_handler(struct irq_desc *desc)
-{
-       struct egpio_info *ei = irq_desc_get_handler_data(desc);
-       int irqpin;
-
-       /* Read current pins. */
-       unsigned long readval = egpio_readw(ei, ei->ack_register);
-       pr_debug("IRQ reg: %x\n", (unsigned int)readval);
-       /* Ack/unmask interrupts. */
-       ack_irqs(ei);
-       /* Process all set pins. */
-       readval &= ei->irqs_enabled;
-       for_each_set_bit(irqpin, &readval, ei->nirqs) {
-               /* Run irq handler */
-               pr_debug("got IRQ %d\n", irqpin);
-               generic_handle_irq(ei->irq_start + irqpin);
-       }
-}
-
-int htc_egpio_get_wakeup_irq(struct device *dev)
-{
-       struct egpio_info *ei = dev_get_drvdata(dev);
-
-       /* Read current pins. */
-       u16 readval = egpio_readw(ei, ei->ack_register);
-       /* Ack/unmask interrupts. */
-       ack_irqs(ei);
-       /* Return first set pin. */
-       readval &= ei->irqs_enabled;
-       return ei->irq_start + ffs(readval) - 1;
-}
-EXPORT_SYMBOL(htc_egpio_get_wakeup_irq);
-
-static inline int egpio_pos(struct egpio_info *ei, int bit)
-{
-       return bit >> ei->reg_shift;
-}
-
-static inline int egpio_bit(struct egpio_info *ei, int bit)
-{
-       return 1 << (bit & ((1 << ei->reg_shift)-1));
-}
-
-/*
- * Input pins
- */
-
-static int egpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct egpio_chip *egpio;
-       struct egpio_info *ei;
-       unsigned           bit;
-       int                reg;
-       int                value;
-
-       pr_debug("egpio_get_value(%d)\n", chip->base + offset);
-
-       egpio = gpiochip_get_data(chip);
-       ei    = dev_get_drvdata(egpio->dev);
-       bit   = egpio_bit(ei, offset);
-       reg   = egpio->reg_start + egpio_pos(ei, offset);
-
-       value = egpio_readw(ei, reg);
-       pr_debug("readw(%p + %x) = %x\n",
-                       ei->base_addr, reg << ei->bus_shift, value);
-       return !!(value & bit);
-}
-
-static int egpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-       struct egpio_chip *egpio;
-
-       egpio = gpiochip_get_data(chip);
-       return test_bit(offset, &egpio->is_out) ? -EINVAL : 0;
-}
-
-
-/*
- * Output pins
- */
-
-static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       unsigned long     flag;
-       struct egpio_chip *egpio;
-       struct egpio_info *ei;
-       unsigned          bit;
-       int               pos;
-       int               reg;
-       int               shift;
-
-       pr_debug("egpio_set(%s, %d(%d), %d)\n",
-                       chip->label, offset, offset+chip->base, value);
-
-       egpio = gpiochip_get_data(chip);
-       ei    = dev_get_drvdata(egpio->dev);
-       bit   = egpio_bit(ei, offset);
-       pos   = egpio_pos(ei, offset);
-       reg   = egpio->reg_start + pos;
-       shift = pos << ei->reg_shift;
-
-       pr_debug("egpio %s: reg %d = 0x%04x\n", value ? "set" : "clear",
-                       reg, (egpio->cached_values >> shift) & ei->reg_mask);
-
-       spin_lock_irqsave(&ei->lock, flag);
-       if (value)
-               egpio->cached_values |= (1 << offset);
-       else
-               egpio->cached_values &= ~(1 << offset);
-       egpio_writew((egpio->cached_values >> shift) & ei->reg_mask, ei, reg);
-       spin_unlock_irqrestore(&ei->lock, flag);
-}
-
-static int egpio_direction_output(struct gpio_chip *chip,
-                                       unsigned offset, int value)
-{
-       struct egpio_chip *egpio;
-
-       egpio = gpiochip_get_data(chip);
-       if (test_bit(offset, &egpio->is_out)) {
-               egpio_set(chip, offset, value);
-               return 0;
-       } else {
-               return -EINVAL;
-       }
-}
-
-static void egpio_write_cache(struct egpio_info *ei)
-{
-       int               i;
-       struct egpio_chip *egpio;
-       int               shift;
-
-       for (i = 0; i < ei->nchips; i++) {
-               egpio = &(ei->chip[i]);
-               if (!egpio->is_out)
-                       continue;
-
-               for (shift = 0; shift < egpio->chip.ngpio;
-                               shift += (1<<ei->reg_shift)) {
-
-                       int reg = egpio->reg_start + egpio_pos(ei, shift);
-
-                       if (!((egpio->is_out >> shift) & ei->reg_mask))
-                               continue;
-
-                       pr_debug("EGPIO: setting %x to %x, was %x\n", reg,
-                               (egpio->cached_values >> shift) & ei->reg_mask,
-                               egpio_readw(ei, reg));
-
-                       egpio_writew((egpio->cached_values >> shift)
-                                       & ei->reg_mask, ei, reg);
-               }
-       }
-}
-
-
-/*
- * Setup
- */
-
-static int __init egpio_probe(struct platform_device *pdev)
-{
-       struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct resource   *res;
-       struct egpio_info *ei;
-       struct gpio_chip  *chip;
-       unsigned int      irq, irq_end;
-       int               i;
-       int               ret;
-
-       /* Initialize ei data structure. */
-       ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
-       if (!ei)
-               return -ENOMEM;
-
-       spin_lock_init(&ei->lock);
-
-       /* Find chained irq */
-       ret = -EINVAL;
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res)
-               ei->chained_irq = res->start;
-
-       /* Map egpio chip into virtual address space. */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               goto fail;
-       ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
-                                            resource_size(res));
-       if (!ei->base_addr)
-               goto fail;
-       pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
-
-       if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
-               goto fail;
-       ei->bus_shift = fls(pdata->bus_width - 1) - 3;
-       pr_debug("bus_shift = %d\n", ei->bus_shift);
-
-       if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
-               goto fail;
-       ei->reg_shift = fls(pdata->reg_width - 1);
-       pr_debug("reg_shift = %d\n", ei->reg_shift);
-
-       ei->reg_mask = (1 << pdata->reg_width) - 1;
-
-       platform_set_drvdata(pdev, ei);
-
-       ei->nchips = pdata->num_chips;
-       ei->chip = devm_kzalloc(&pdev->dev,
-                               sizeof(struct egpio_chip) * ei->nchips,
-                               GFP_KERNEL);
-       if (!ei->chip) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-       for (i = 0; i < ei->nchips; i++) {
-               ei->chip[i].reg_start = pdata->chip[i].reg_start;
-               ei->chip[i].cached_values = pdata->chip[i].initial_values;
-               ei->chip[i].is_out = pdata->chip[i].direction;
-               ei->chip[i].dev = &(pdev->dev);
-               chip = &(ei->chip[i].chip);
-               chip->label           = "htc-egpio";
-               chip->parent          = &pdev->dev;
-               chip->owner           = THIS_MODULE;
-               chip->get             = egpio_get;
-               chip->set             = egpio_set;
-               chip->direction_input = egpio_direction_input;
-               chip->direction_output = egpio_direction_output;
-               chip->base            = pdata->chip[i].gpio_base;
-               chip->ngpio           = pdata->chip[i].num_gpios;
-
-               gpiochip_add_data(chip, &ei->chip[i]);
-       }
-
-       /* Set initial pin values */
-       egpio_write_cache(ei);
-
-       ei->irq_start = pdata->irq_base;
-       ei->nirqs = pdata->num_irqs;
-       ei->ack_register = pdata->ack_register;
-
-       if (ei->chained_irq) {
-               /* Setup irq handlers */
-               ei->ack_write = 0xFFFF;
-               if (pdata->invert_acks)
-                       ei->ack_write = 0;
-               irq_end = ei->irq_start + ei->nirqs;
-               for (irq = ei->irq_start; irq < irq_end; irq++) {
-                       irq_set_chip_and_handler(irq, &egpio_muxed_chip,
-                                                handle_simple_irq);
-                       irq_set_chip_data(irq, ei);
-                       irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
-               }
-               irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING);
-               irq_set_chained_handler_and_data(ei->chained_irq,
-                                                egpio_handler, ei);
-               ack_irqs(ei);
-
-               device_init_wakeup(&pdev->dev, 1);
-       }
-
-       return 0;
-
-fail:
-       printk(KERN_ERR "EGPIO failed to setup\n");
-       return ret;
-}
-
-static int __exit egpio_remove(struct platform_device *pdev)
-{
-       struct egpio_info *ei = platform_get_drvdata(pdev);
-       unsigned int      irq, irq_end;
-
-       if (ei->chained_irq) {
-               irq_end = ei->irq_start + ei->nirqs;
-               for (irq = ei->irq_start; irq < irq_end; irq++) {
-                       irq_set_chip_and_handler(irq, NULL, NULL);
-                       irq_set_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE);
-               }
-               irq_set_chained_handler(ei->chained_irq, NULL);
-               device_init_wakeup(&pdev->dev, 0);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int egpio_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct egpio_info *ei = platform_get_drvdata(pdev);
-
-       if (ei->chained_irq && device_may_wakeup(&pdev->dev))
-               enable_irq_wake(ei->chained_irq);
-       return 0;
-}
-
-static int egpio_resume(struct platform_device *pdev)
-{
-       struct egpio_info *ei = platform_get_drvdata(pdev);
-
-       if (ei->chained_irq && device_may_wakeup(&pdev->dev))
-               disable_irq_wake(ei->chained_irq);
-
-       /* Update registers from the cache, in case
-          the CPLD was powered off during suspend */
-       egpio_write_cache(ei);
-       return 0;
-}
-#else
-#define egpio_suspend NULL
-#define egpio_resume NULL
-#endif
-
-
-static struct platform_driver egpio_driver = {
-       .driver = {
-               .name = "htc-egpio",
-       },
-       .remove       = __exit_p(egpio_remove),
-       .suspend      = egpio_suspend,
-       .resume       = egpio_resume,
-};
-
-static int __init egpio_init(void)
-{
-       return platform_driver_probe(&egpio_driver, egpio_probe);
-}
-
-static void __exit egpio_exit(void)
-{
-       platform_driver_unregister(&egpio_driver);
-}
-
-/* start early for dependencies */
-subsys_initcall(egpio_init);
-module_exit(egpio_exit)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kevin O'Connor <kevin@koconnor.net>");
diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c
new file mode 100644 (file)
index 0000000..9af064c
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Author: 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 as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/lp873x.h>
+
+static const struct regmap_config lp873x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = LP873X_REG_MAX,
+};
+
+static const struct mfd_cell lp873x_cells[] = {
+       { .name = "lp873x-regulator", },
+       { .name = "lp873x-gpio", },
+};
+
+static int lp873x_probe(struct i2c_client *client,
+                       const struct i2c_device_id *ids)
+{
+       struct lp873x *lp873;
+       int ret;
+       unsigned int otpid;
+
+       lp873 = devm_kzalloc(&client->dev, sizeof(*lp873), GFP_KERNEL);
+       if (!lp873)
+               return -ENOMEM;
+
+       lp873->dev = &client->dev;
+
+       lp873->regmap = devm_regmap_init_i2c(client, &lp873x_regmap_config);
+       if (IS_ERR(lp873->regmap)) {
+               ret = PTR_ERR(lp873->regmap);
+               dev_err(lp873->dev,
+                       "Failed to initialize register map: %d\n", ret);
+               return ret;
+       }
+
+       mutex_init(&lp873->lock);
+
+       ret = regmap_read(lp873->regmap, LP873X_REG_OTP_REV, &otpid);
+       if (ret) {
+               dev_err(lp873->dev, "Failed to read OTP ID\n");
+               return ret;
+       }
+
+       lp873->rev = otpid & LP873X_OTP_REV_OTP_ID;
+
+       i2c_set_clientdata(client, lp873);
+
+       ret = mfd_add_devices(lp873->dev, PLATFORM_DEVID_AUTO, lp873x_cells,
+                             ARRAY_SIZE(lp873x_cells), NULL, 0, NULL);
+
+       return ret;
+}
+
+static const struct of_device_id of_lp873x_match_table[] = {
+       { .compatible = "ti,lp8733", },
+       { .compatible = "ti,lp8732", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, of_lp873x_match_table);
+
+static const struct i2c_device_id lp873x_id_table[] = {
+       { "lp873x", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, lp873x_id_table);
+
+static struct i2c_driver lp873x_driver = {
+       .driver = {
+               .name   = "lp873x",
+               .of_match_table = of_lp873x_match_table,
+       },
+       .probe          = lp873x_probe,
+       .id_table       = lp873x_id_table,
+};
+module_i2c_driver(lp873x_driver);
+
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("LP873X chip family Multi-Function Device driver");
+MODULE_LICENSE("GPL v2");
index c3f4aab..863c39a 100644 (file)
@@ -57,6 +57,7 @@ static const struct of_device_id stmpe_of_match[] = {
        { .compatible = "st,stmpe610", .data = (void *)STMPE610, },
        { .compatible = "st,stmpe801", .data = (void *)STMPE801, },
        { .compatible = "st,stmpe811", .data = (void *)STMPE811, },
+       { .compatible = "st,stmpe1600", .data = (void *)STMPE1600, },
        { .compatible = "st,stmpe1601", .data = (void *)STMPE1601, },
        { .compatible = "st,stmpe1801", .data = (void *)STMPE1801, },
        { .compatible = "st,stmpe2401", .data = (void *)STMPE2401, },
@@ -101,6 +102,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = {
        { "stmpe610", STMPE610 },
        { "stmpe801", STMPE801 },
        { "stmpe811", STMPE811 },
+       { "stmpe1600", STMPE1600 },
        { "stmpe1601", STMPE1601 },
        { "stmpe1801", STMPE1801 },
        { "stmpe2401", STMPE2401 },
index 94c7cc0..cfdae8a 100644 (file)
@@ -469,6 +469,8 @@ static const struct mfd_cell stmpe_ts_cell = {
 
 static const u8 stmpe811_regs[] = {
        [STMPE_IDX_CHIP_ID]     = STMPE811_REG_CHIP_ID,
+       [STMPE_IDX_SYS_CTRL]    = STMPE811_REG_SYS_CTRL,
+       [STMPE_IDX_SYS_CTRL2]   = STMPE811_REG_SYS_CTRL2,
        [STMPE_IDX_ICR_LSB]     = STMPE811_REG_INT_CTRL,
        [STMPE_IDX_IER_LSB]     = STMPE811_REG_INT_EN,
        [STMPE_IDX_ISR_MSB]     = STMPE811_REG_INT_STA,
@@ -481,7 +483,7 @@ static const u8 stmpe811_regs[] = {
        [STMPE_IDX_GPAFR_U_MSB] = STMPE811_REG_GPIO_AF,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE811_REG_GPIO_INT_EN,
        [STMPE_IDX_ISGPIOR_MSB] = STMPE811_REG_GPIO_INT_STA,
-       [STMPE_IDX_GPEDR_MSB]   = STMPE811_REG_GPIO_ED,
+       [STMPE_IDX_GPEDR_LSB]   = STMPE811_REG_GPIO_ED,
 };
 
 static struct stmpe_variant_block stmpe811_blocks[] = {
@@ -511,7 +513,7 @@ static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
        if (blocks & STMPE_BLOCK_TOUCHSCREEN)
                mask |= STMPE811_SYS_CTRL2_TSC_OFF;
 
-       return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask,
+       return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2], mask,
                                enable ? 0 : mask);
 }
 
@@ -550,26 +552,90 @@ static struct stmpe_variant_info stmpe610 = {
        .get_altfunc    = stmpe811_get_altfunc,
 };
 
+/*
+ * STMPE1600
+ * Compared to all others STMPE variant, LSB and MSB regs are located in this
+ * order :     LSB   addr
+ *             MSB   addr + 1
+ * As there is only 2 * 8bits registers for GPMR/GPSR/IEGPIOPR, CSB index is MSB registers
+ */
+
+static const u8 stmpe1600_regs[] = {
+       [STMPE_IDX_CHIP_ID]     = STMPE1600_REG_CHIP_ID,
+       [STMPE_IDX_SYS_CTRL]    = STMPE1600_REG_SYS_CTRL,
+       [STMPE_IDX_ICR_LSB]     = STMPE1600_REG_SYS_CTRL,
+       [STMPE_IDX_GPMR_LSB]    = STMPE1600_REG_GPMR_LSB,
+       [STMPE_IDX_GPMR_CSB]    = STMPE1600_REG_GPMR_MSB,
+       [STMPE_IDX_GPSR_LSB]    = STMPE1600_REG_GPSR_LSB,
+       [STMPE_IDX_GPSR_CSB]    = STMPE1600_REG_GPSR_MSB,
+       [STMPE_IDX_GPDR_LSB]    = STMPE1600_REG_GPDR_LSB,
+       [STMPE_IDX_GPDR_CSB]    = STMPE1600_REG_GPDR_MSB,
+       [STMPE_IDX_IEGPIOR_LSB] = STMPE1600_REG_IEGPIOR_LSB,
+       [STMPE_IDX_IEGPIOR_CSB] = STMPE1600_REG_IEGPIOR_MSB,
+       [STMPE_IDX_ISGPIOR_LSB] = STMPE1600_REG_ISGPIOR_LSB,
+};
+
+static struct stmpe_variant_block stmpe1600_blocks[] = {
+       {
+               .cell   = &stmpe_gpio_cell,
+               .irq    = 0,
+               .block  = STMPE_BLOCK_GPIO,
+       },
+};
+
+static int stmpe1600_enable(struct stmpe *stmpe, unsigned int blocks,
+                          bool enable)
+{
+       if (blocks & STMPE_BLOCK_GPIO)
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static struct stmpe_variant_info stmpe1600 = {
+       .name           = "stmpe1600",
+       .id_val         = STMPE1600_ID,
+       .id_mask        = 0xffff,
+       .num_gpios      = 16,
+       .af_bits        = 0,
+       .regs           = stmpe1600_regs,
+       .blocks         = stmpe1600_blocks,
+       .num_blocks     = ARRAY_SIZE(stmpe1600_blocks),
+       .num_irqs       = STMPE1600_NR_INTERNAL_IRQS,
+       .enable         = stmpe1600_enable,
+};
+
 /*
  * STMPE1601
  */
 
 static const u8 stmpe1601_regs[] = {
        [STMPE_IDX_CHIP_ID]     = STMPE1601_REG_CHIP_ID,
+       [STMPE_IDX_SYS_CTRL]    = STMPE1601_REG_SYS_CTRL,
+       [STMPE_IDX_SYS_CTRL2]   = STMPE1601_REG_SYS_CTRL2,
        [STMPE_IDX_ICR_LSB]     = STMPE1601_REG_ICR_LSB,
+       [STMPE_IDX_IER_MSB]     = STMPE1601_REG_IER_MSB,
        [STMPE_IDX_IER_LSB]     = STMPE1601_REG_IER_LSB,
        [STMPE_IDX_ISR_MSB]     = STMPE1601_REG_ISR_MSB,
        [STMPE_IDX_GPMR_LSB]    = STMPE1601_REG_GPIO_MP_LSB,
+       [STMPE_IDX_GPMR_CSB]    = STMPE1601_REG_GPIO_MP_MSB,
        [STMPE_IDX_GPSR_LSB]    = STMPE1601_REG_GPIO_SET_LSB,
+       [STMPE_IDX_GPSR_CSB]    = STMPE1601_REG_GPIO_SET_MSB,
        [STMPE_IDX_GPCR_LSB]    = STMPE1601_REG_GPIO_CLR_LSB,
+       [STMPE_IDX_GPCR_CSB]    = STMPE1601_REG_GPIO_CLR_MSB,
        [STMPE_IDX_GPDR_LSB]    = STMPE1601_REG_GPIO_SET_DIR_LSB,
+       [STMPE_IDX_GPDR_CSB]    = STMPE1601_REG_GPIO_SET_DIR_MSB,
+       [STMPE_IDX_GPEDR_LSB]   = STMPE1601_REG_GPIO_ED_LSB,
+       [STMPE_IDX_GPEDR_CSB]   = STMPE1601_REG_GPIO_ED_MSB,
        [STMPE_IDX_GPRER_LSB]   = STMPE1601_REG_GPIO_RE_LSB,
+       [STMPE_IDX_GPRER_CSB]   = STMPE1601_REG_GPIO_RE_MSB,
        [STMPE_IDX_GPFER_LSB]   = STMPE1601_REG_GPIO_FE_LSB,
+       [STMPE_IDX_GPFER_CSB]   = STMPE1601_REG_GPIO_FE_MSB,
        [STMPE_IDX_GPPUR_LSB]   = STMPE1601_REG_GPIO_PU_LSB,
        [STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
+       [STMPE_IDX_IEGPIOR_CSB] = STMPE1601_REG_INT_EN_GPIO_MASK_MSB,
        [STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB,
-       [STMPE_IDX_GPEDR_MSB]   = STMPE1601_REG_GPIO_ED_MSB,
 };
 
 static struct stmpe_variant_block stmpe1601_blocks[] = {
@@ -640,13 +706,13 @@ static int stmpe1601_autosleep(struct stmpe *stmpe,
                return timeout;
        }
 
-       ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+       ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2],
                        STMPE1601_AUTOSLEEP_TIMEOUT_MASK,
                        timeout);
        if (ret < 0)
                return ret;
 
-       return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+       return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2],
                        STPME1601_AUTOSLEEP_ENABLE,
                        STPME1601_AUTOSLEEP_ENABLE);
 }
@@ -671,7 +737,7 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
        else
                mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM;
 
-       return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
+       return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask,
                                enable ? mask : 0);
 }
 
@@ -710,18 +776,33 @@ static struct stmpe_variant_info stmpe1601 = {
  */
 static const u8 stmpe1801_regs[] = {
        [STMPE_IDX_CHIP_ID]     = STMPE1801_REG_CHIP_ID,
+       [STMPE_IDX_SYS_CTRL]    = STMPE1801_REG_SYS_CTRL,
        [STMPE_IDX_ICR_LSB]     = STMPE1801_REG_INT_CTRL_LOW,
        [STMPE_IDX_IER_LSB]     = STMPE1801_REG_INT_EN_MASK_LOW,
        [STMPE_IDX_ISR_LSB]     = STMPE1801_REG_INT_STA_LOW,
        [STMPE_IDX_GPMR_LSB]    = STMPE1801_REG_GPIO_MP_LOW,
+       [STMPE_IDX_GPMR_CSB]    = STMPE1801_REG_GPIO_MP_MID,
+       [STMPE_IDX_GPMR_MSB]    = STMPE1801_REG_GPIO_MP_HIGH,
        [STMPE_IDX_GPSR_LSB]    = STMPE1801_REG_GPIO_SET_LOW,
+       [STMPE_IDX_GPSR_CSB]    = STMPE1801_REG_GPIO_SET_MID,
+       [STMPE_IDX_GPSR_MSB]    = STMPE1801_REG_GPIO_SET_HIGH,
        [STMPE_IDX_GPCR_LSB]    = STMPE1801_REG_GPIO_CLR_LOW,
+       [STMPE_IDX_GPCR_CSB]    = STMPE1801_REG_GPIO_CLR_MID,
+       [STMPE_IDX_GPCR_MSB]    = STMPE1801_REG_GPIO_CLR_HIGH,
        [STMPE_IDX_GPDR_LSB]    = STMPE1801_REG_GPIO_SET_DIR_LOW,
+       [STMPE_IDX_GPDR_CSB]    = STMPE1801_REG_GPIO_SET_DIR_MID,
+       [STMPE_IDX_GPDR_MSB]    = STMPE1801_REG_GPIO_SET_DIR_HIGH,
        [STMPE_IDX_GPRER_LSB]   = STMPE1801_REG_GPIO_RE_LOW,
+       [STMPE_IDX_GPRER_CSB]   = STMPE1801_REG_GPIO_RE_MID,
+       [STMPE_IDX_GPRER_MSB]   = STMPE1801_REG_GPIO_RE_HIGH,
        [STMPE_IDX_GPFER_LSB]   = STMPE1801_REG_GPIO_FE_LOW,
+       [STMPE_IDX_GPFER_CSB]   = STMPE1801_REG_GPIO_FE_MID,
+       [STMPE_IDX_GPFER_MSB]   = STMPE1801_REG_GPIO_FE_HIGH,
        [STMPE_IDX_GPPUR_LSB]   = STMPE1801_REG_GPIO_PULL_UP_LOW,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW,
-       [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW,
+       [STMPE_IDX_IEGPIOR_CSB] = STMPE1801_REG_INT_EN_GPIO_MASK_MID,
+       [STMPE_IDX_IEGPIOR_MSB] = STMPE1801_REG_INT_EN_GPIO_MASK_HIGH,
+       [STMPE_IDX_ISGPIOR_MSB] = STMPE1801_REG_INT_STA_GPIO_HIGH,
 };
 
 static struct stmpe_variant_block stmpe1801_blocks[] = {
@@ -751,22 +832,31 @@ static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks,
                                enable ? mask : 0);
 }
 
-static int stmpe1801_reset(struct stmpe *stmpe)
+static int stmpe_reset(struct stmpe *stmpe)
 {
+       u16 id_val = stmpe->variant->id_val;
        unsigned long timeout;
        int ret = 0;
+       u8 reset_bit;
+
+       if (id_val == STMPE811_ID)
+               /* STMPE801 and STMPE610 use bit 1 of SYS_CTRL register */
+               reset_bit = STMPE811_SYS_CTRL_RESET;
+       else
+               /* all other STMPE variant use bit 7 of SYS_CTRL register */
+               reset_bit = STMPE_SYS_CTRL_RESET;
 
-       ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL,
-               STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET);
+       ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL],
+                              reset_bit, reset_bit);
        if (ret < 0)
                return ret;
 
        timeout = jiffies + msecs_to_jiffies(100);
        while (time_before(jiffies, timeout)) {
-               ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL);
+               ret = __stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL]);
                if (ret < 0)
                        return ret;
-               if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET))
+               if (!(ret & reset_bit))
                        return 0;
                usleep_range(100, 200);
        }
@@ -794,20 +884,39 @@ static struct stmpe_variant_info stmpe1801 = {
 
 static const u8 stmpe24xx_regs[] = {
        [STMPE_IDX_CHIP_ID]     = STMPE24XX_REG_CHIP_ID,
+       [STMPE_IDX_SYS_CTRL]    = STMPE24XX_REG_SYS_CTRL,
+       [STMPE_IDX_SYS_CTRL2]   = STMPE24XX_REG_SYS_CTRL2,
        [STMPE_IDX_ICR_LSB]     = STMPE24XX_REG_ICR_LSB,
+       [STMPE_IDX_IER_MSB]     = STMPE24XX_REG_IER_MSB,
        [STMPE_IDX_IER_LSB]     = STMPE24XX_REG_IER_LSB,
        [STMPE_IDX_ISR_MSB]     = STMPE24XX_REG_ISR_MSB,
        [STMPE_IDX_GPMR_LSB]    = STMPE24XX_REG_GPMR_LSB,
+       [STMPE_IDX_GPMR_CSB]    = STMPE24XX_REG_GPMR_CSB,
+       [STMPE_IDX_GPMR_MSB]    = STMPE24XX_REG_GPMR_MSB,
        [STMPE_IDX_GPSR_LSB]    = STMPE24XX_REG_GPSR_LSB,
+       [STMPE_IDX_GPSR_CSB]    = STMPE24XX_REG_GPSR_CSB,
+       [STMPE_IDX_GPSR_MSB]    = STMPE24XX_REG_GPSR_MSB,
        [STMPE_IDX_GPCR_LSB]    = STMPE24XX_REG_GPCR_LSB,
+       [STMPE_IDX_GPCR_CSB]    = STMPE24XX_REG_GPCR_CSB,
+       [STMPE_IDX_GPCR_MSB]    = STMPE24XX_REG_GPCR_MSB,
        [STMPE_IDX_GPDR_LSB]    = STMPE24XX_REG_GPDR_LSB,
+       [STMPE_IDX_GPDR_CSB]    = STMPE24XX_REG_GPDR_CSB,
+       [STMPE_IDX_GPDR_MSB]    = STMPE24XX_REG_GPDR_MSB,
        [STMPE_IDX_GPRER_LSB]   = STMPE24XX_REG_GPRER_LSB,
+       [STMPE_IDX_GPRER_CSB]   = STMPE24XX_REG_GPRER_CSB,
+       [STMPE_IDX_GPRER_MSB]   = STMPE24XX_REG_GPRER_MSB,
        [STMPE_IDX_GPFER_LSB]   = STMPE24XX_REG_GPFER_LSB,
+       [STMPE_IDX_GPFER_CSB]   = STMPE24XX_REG_GPFER_CSB,
+       [STMPE_IDX_GPFER_MSB]   = STMPE24XX_REG_GPFER_MSB,
        [STMPE_IDX_GPPUR_LSB]   = STMPE24XX_REG_GPPUR_LSB,
        [STMPE_IDX_GPPDR_LSB]   = STMPE24XX_REG_GPPDR_LSB,
        [STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB,
+       [STMPE_IDX_IEGPIOR_CSB] = STMPE24XX_REG_IEGPIOR_CSB,
+       [STMPE_IDX_IEGPIOR_MSB] = STMPE24XX_REG_IEGPIOR_MSB,
        [STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB,
+       [STMPE_IDX_GPEDR_LSB]   = STMPE24XX_REG_GPEDR_LSB,
+       [STMPE_IDX_GPEDR_CSB]   = STMPE24XX_REG_GPEDR_CSB,
        [STMPE_IDX_GPEDR_MSB]   = STMPE24XX_REG_GPEDR_MSB,
 };
 
@@ -840,7 +949,7 @@ static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks,
        if (blocks & STMPE_BLOCK_KEYPAD)
                mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC;
 
-       return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask,
+       return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask,
                                enable ? mask : 0);
 }
 
@@ -893,6 +1002,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
        [STMPE610]      = &stmpe610,
        [STMPE801]      = &stmpe801,
        [STMPE811]      = &stmpe811,
+       [STMPE1600]     = &stmpe1600,
        [STMPE1601]     = &stmpe1601,
        [STMPE1801]     = &stmpe1801,
        [STMPE2401]     = &stmpe2401,
@@ -919,7 +1029,8 @@ static irqreturn_t stmpe_irq(int irq, void *data)
        int ret;
        int i;
 
-       if (variant->id_val == STMPE801_ID) {
+       if (variant->id_val == STMPE801_ID ||
+           variant->id_val == STMPE1600_ID) {
                int base = irq_create_mapping(stmpe->domain, 0);
 
                handle_nested_irq(base);
@@ -982,7 +1093,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data)
                        continue;
 
                stmpe->oldier[i] = new;
-               stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new);
+               stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB + i], new);
        }
 
        mutex_unlock(&stmpe->irq_lock);
@@ -1088,20 +1199,18 @@ static int stmpe_chip_init(struct stmpe *stmpe)
        if (ret)
                return ret;
 
-       if (id == STMPE1801_ID) {
-               ret =  stmpe1801_reset(stmpe);
-               if (ret < 0)
-                       return ret;
-       }
+       ret =  stmpe_reset(stmpe);
+       if (ret < 0)
+               return ret;
 
        if (stmpe->irq >= 0) {
-               if (id == STMPE801_ID)
-                       icr = STMPE801_REG_SYS_CTRL_INT_EN;
+               if (id == STMPE801_ID || id == STMPE1600_ID)
+                       icr = STMPE_SYS_CTRL_INT_EN;
                else
                        icr = STMPE_ICR_LSB_GIM;
 
-               /* STMPE801 doesn't support Edge interrupts */
-               if (id != STMPE801_ID) {
+               /* STMPE801 and STMPE1600 don't support Edge interrupts */
+               if (id != STMPE801_ID && id != STMPE1600_ID) {
                        if (irq_trigger == IRQF_TRIGGER_FALLING ||
                                        irq_trigger == IRQF_TRIGGER_RISING)
                                icr |= STMPE_ICR_LSB_EDGE;
@@ -1109,8 +1218,8 @@ static int stmpe_chip_init(struct stmpe *stmpe)
 
                if (irq_trigger == IRQF_TRIGGER_RISING ||
                                irq_trigger == IRQF_TRIGGER_HIGH) {
-                       if (id == STMPE801_ID)
-                               icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+                       if (id == STMPE801_ID || id == STMPE1600_ID)
+                               icr |= STMPE_SYS_CTRL_INT_HI;
                        else
                                icr |= STMPE_ICR_LSB_HIGH;
                }
index 84adb46..f7efdd8 100644 (file)
@@ -104,6 +104,10 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE_ICR_LSB_EDGE     (1 << 1)
 #define STMPE_ICR_LSB_GIM      (1 << 0)
 
+#define STMPE_SYS_CTRL_RESET   (1 << 7)
+#define STMPE_SYS_CTRL_INT_EN  (1 << 2)
+#define STMPE_SYS_CTRL_INT_HI  (1 << 0)
+
 /*
  * STMPE801
  */
@@ -119,13 +123,10 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE801_REG_GPIO_SET_PIN      0x11
 #define STMPE801_REG_GPIO_DIR          0x12
 
-#define STMPE801_REG_SYS_CTRL_RESET    (1 << 7)
-#define STMPE801_REG_SYS_CTRL_INT_EN   (1 << 2)
-#define STMPE801_REG_SYS_CTRL_INT_HI   (1 << 0)
-
 /*
  * STMPE811
  */
+#define STMPE811_ID                    0x0811
 
 #define STMPE811_IRQ_TOUCH_DET         0
 #define STMPE811_IRQ_FIFO_TH           1
@@ -138,6 +139,7 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE811_NR_INTERNAL_IRQS      8
 
 #define STMPE811_REG_CHIP_ID           0x00
+#define STMPE811_REG_SYS_CTRL          0x03
 #define STMPE811_REG_SYS_CTRL2         0x04
 #define STMPE811_REG_SPI_CFG           0x08
 #define STMPE811_REG_INT_CTRL          0x09
@@ -154,11 +156,34 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE811_REG_GPIO_FE           0x16
 #define STMPE811_REG_GPIO_AF           0x17
 
+#define STMPE811_SYS_CTRL_RESET                (1 << 1)
+
 #define STMPE811_SYS_CTRL2_ADC_OFF     (1 << 0)
 #define STMPE811_SYS_CTRL2_TSC_OFF     (1 << 1)
 #define STMPE811_SYS_CTRL2_GPIO_OFF    (1 << 2)
 #define STMPE811_SYS_CTRL2_TS_OFF      (1 << 3)
 
+/*
+ * STMPE1600
+ */
+#define STMPE1600_ID                   0x0016
+#define STMPE1600_NR_INTERNAL_IRQS     16
+
+#define STMPE1600_REG_CHIP_ID          0x00
+#define STMPE1600_REG_SYS_CTRL         0x03
+#define STMPE1600_REG_IEGPIOR_LSB      0x08
+#define STMPE1600_REG_IEGPIOR_MSB      0x09
+#define STMPE1600_REG_ISGPIOR_LSB      0x0A
+#define STMPE1600_REG_ISGPIOR_MSB      0x0B
+#define STMPE1600_REG_GPMR_LSB         0x10
+#define STMPE1600_REG_GPMR_MSB         0x11
+#define STMPE1600_REG_GPSR_LSB         0x12
+#define STMPE1600_REG_GPSR_MSB         0x13
+#define STMPE1600_REG_GPDR_LSB         0x14
+#define STMPE1600_REG_GPDR_MSB         0x15
+#define STMPE1600_REG_GPPIR_LSB                0x16
+#define STMPE1600_REG_GPPIR_MSB                0x17
+
 /*
  * STMPE1601
  */
@@ -175,19 +200,32 @@ int stmpe_remove(struct stmpe *stmpe);
 
 #define STMPE1601_REG_SYS_CTRL                 0x02
 #define STMPE1601_REG_SYS_CTRL2                        0x03
+#define STMPE1601_REG_ICR_MSB                  0x10
 #define STMPE1601_REG_ICR_LSB                  0x11
+#define STMPE1601_REG_IER_MSB                  0x12
 #define STMPE1601_REG_IER_LSB                  0x13
 #define STMPE1601_REG_ISR_MSB                  0x14
-#define STMPE1601_REG_CHIP_ID                  0x80
+#define STMPE1601_REG_ISR_LSB                  0x15
+#define STMPE1601_REG_INT_EN_GPIO_MASK_MSB     0x16
 #define STMPE1601_REG_INT_EN_GPIO_MASK_LSB     0x17
 #define STMPE1601_REG_INT_STA_GPIO_MSB         0x18
-#define STMPE1601_REG_GPIO_MP_LSB              0x87
+#define STMPE1601_REG_INT_STA_GPIO_LSB         0x19
+#define STMPE1601_REG_CHIP_ID                  0x80
+#define STMPE1601_REG_GPIO_SET_MSB             0x82
 #define STMPE1601_REG_GPIO_SET_LSB             0x83
+#define STMPE1601_REG_GPIO_CLR_MSB             0x84
 #define STMPE1601_REG_GPIO_CLR_LSB             0x85
+#define STMPE1601_REG_GPIO_MP_MSB              0x86
+#define STMPE1601_REG_GPIO_MP_LSB              0x87
+#define STMPE1601_REG_GPIO_SET_DIR_MSB         0x88
 #define STMPE1601_REG_GPIO_SET_DIR_LSB         0x89
 #define STMPE1601_REG_GPIO_ED_MSB              0x8A
+#define STMPE1601_REG_GPIO_ED_LSB              0x8B
+#define STMPE1601_REG_GPIO_RE_MSB              0x8C
 #define STMPE1601_REG_GPIO_RE_LSB              0x8D
+#define STMPE1601_REG_GPIO_FE_MSB              0x8E
 #define STMPE1601_REG_GPIO_FE_LSB              0x8F
+#define STMPE1601_REG_GPIO_PU_MSB              0x90
 #define STMPE1601_REG_GPIO_PU_LSB              0x91
 #define STMPE1601_REG_GPIO_AF_U_MSB            0x92
 
@@ -243,8 +281,6 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE1801_REG_GPIO_PULL_UP_MID         0x23
 #define STMPE1801_REG_GPIO_PULL_UP_HIGH                0x24
 
-#define STMPE1801_MSK_SYS_CTRL_RESET           (1 << 7)
-
 #define STMPE1801_MSK_INT_EN_KPC               (1 << 1)
 #define STMPE1801_MSK_INT_EN_GPIO              (1 << 3)
 
@@ -264,23 +300,48 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE24XX_NR_INTERNAL_IRQS     9
 
 #define STMPE24XX_REG_SYS_CTRL         0x02
+#define STMPE24XX_REG_SYS_CTRL2                0x03
+#define STMPE24XX_REG_ICR_MSB          0x10
 #define STMPE24XX_REG_ICR_LSB          0x11
+#define STMPE24XX_REG_IER_MSB          0x12
 #define STMPE24XX_REG_IER_LSB          0x13
 #define STMPE24XX_REG_ISR_MSB          0x14
-#define STMPE24XX_REG_CHIP_ID          0x80
+#define STMPE24XX_REG_ISR_LSB          0x15
+#define STMPE24XX_REG_IEGPIOR_MSB      0x16
+#define STMPE24XX_REG_IEGPIOR_CSB      0x17
 #define STMPE24XX_REG_IEGPIOR_LSB      0x18
 #define STMPE24XX_REG_ISGPIOR_MSB      0x19
-#define STMPE24XX_REG_GPMR_LSB         0xA4
+#define STMPE24XX_REG_ISGPIOR_CSB      0x1A
+#define STMPE24XX_REG_ISGPIOR_LSB      0x1B
+#define STMPE24XX_REG_CHIP_ID          0x80
+#define STMPE24XX_REG_GPSR_MSB         0x83
+#define STMPE24XX_REG_GPSR_CSB         0x84
 #define STMPE24XX_REG_GPSR_LSB         0x85
+#define STMPE24XX_REG_GPCR_MSB         0x86
+#define STMPE24XX_REG_GPCR_CSB         0x87
 #define STMPE24XX_REG_GPCR_LSB         0x88
+#define STMPE24XX_REG_GPDR_MSB         0x89
+#define STMPE24XX_REG_GPDR_CSB         0x8A
 #define STMPE24XX_REG_GPDR_LSB         0x8B
 #define STMPE24XX_REG_GPEDR_MSB                0x8C
+#define STMPE24XX_REG_GPEDR_CSB                0x8D
+#define STMPE24XX_REG_GPEDR_LSB                0x8E
+#define STMPE24XX_REG_GPRER_MSB                0x8F
+#define STMPE24XX_REG_GPRER_CSB                0x90
 #define STMPE24XX_REG_GPRER_LSB                0x91
+#define STMPE24XX_REG_GPFER_MSB                0x92
+#define STMPE24XX_REG_GPFER_CSB                0x93
 #define STMPE24XX_REG_GPFER_LSB                0x94
+#define STMPE24XX_REG_GPPUR_MSB                0x95
+#define STMPE24XX_REG_GPPUR_CSB                0x96
 #define STMPE24XX_REG_GPPUR_LSB                0x97
-#define STMPE24XX_REG_GPPDR_LSB                0x9a
+#define STMPE24XX_REG_GPPDR_MSB                0x98
+#define STMPE24XX_REG_GPPDR_CSB                0x99
+#define STMPE24XX_REG_GPPDR_LSB                0x9A
 #define STMPE24XX_REG_GPAFR_U_MSB      0x9B
-
+#define STMPE24XX_REG_GPMR_MSB         0xA2
+#define STMPE24XX_REG_GPMR_CSB         0xA3
+#define STMPE24XX_REG_GPMR_LSB         0xA4
 #define STMPE24XX_SYS_CTRL_ENABLE_GPIO         (1 << 3)
 #define STMPE24XX_SYSCON_ENABLE_PWM            (1 << 2)
 #define STMPE24XX_SYS_CTRL_ENABLE_KPC          (1 << 1)
index 54455af..0facbea 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 
 #include "../core.h"
-#include "../../gpio/gpiolib.h"
 #include "pinctrl-sunxi.h"
 
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
index 4c2631a..06c7518 100644 (file)
@@ -323,7 +323,7 @@ config REGULATOR_LP872X
 
 config REGULATOR_LP873X
        tristate "TI LP873X Power regulators"
-       depends on MFD_LP873X && OF
+       depends on MFD_TI_LP873X && OF
        help
          This driver supports LP873X voltage regulator chips. LP873X
          provides two step-down converters and two general-purpose LDO
index 420b837..1f0be72 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <linux/device.h>
 #include <linux/types.h>
-#include <linux/module.h>
 #include <linux/irq.h>
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqdomain.h>
@@ -16,6 +15,7 @@ struct of_phandle_args;
 struct device_node;
 struct seq_file;
 struct gpio_device;
+struct module;
 
 #ifdef CONFIG_GPIOLIB
 
diff --git a/include/linux/mfd/htc-egpio.h b/include/linux/mfd/htc-egpio.h
deleted file mode 100644 (file)
index b4201c9..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * HTC simple EGPIO irq and gpio extender
- */
-
-#ifndef __HTC_EGPIO_H__
-#define __HTC_EGPIO_H__
-
-#include <linux/gpio.h>
-
-/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */
-#define HTC_EGPIO_OUTPUT (~0)
-#define HTC_EGPIO_INPUT  0
-
-/**
- * struct htc_egpio_chip - descriptor to create gpio_chip for register range
- * @reg_start: index of first register
- * @gpio_base: gpio number of first pin in this register range
- * @num_gpios: number of gpios in this register range, max BITS_PER_LONG
- *    (number of registers = DIV_ROUND_UP(num_gpios, reg_width))
- * @direction: bitfield, '0' = input, '1' = output,
- */
-struct htc_egpio_chip {
-       int           reg_start;
-       int           gpio_base;
-       int           num_gpios;
-       unsigned long direction;
-       unsigned long initial_values;
-};
-
-/**
- * struct htc_egpio_platform_data - description provided by the arch
- * @irq_base: beginning of available IRQs (eg, IRQ_BOARD_START)
- * @num_irqs: number of irqs
- * @reg_width: number of bits per register, either 8 or 16 bit
- * @bus_width: alignment of the registers, either 16 or 32 bit
- * @invert_acks: set if chip requires writing '0' to ack an irq, instead of '1'
- * @ack_register: location of the irq/ack register
- * @chip: pointer to array of htc_egpio_chip descriptors
- * @num_chips: number of egpio chip descriptors
- */
-struct htc_egpio_platform_data {
-       int                   bus_width;
-       int                   reg_width;
-
-       int                   irq_base;
-       int                   num_irqs;
-       int                   invert_acks;
-       int                   ack_register;
-
-       struct htc_egpio_chip *chip;
-       int                   num_chips;
-};
-
-/* Determine the wakeup irq, to be called during early resume */
-extern int htc_egpio_get_wakeup_irq(struct device *dev);
-
-#endif
diff --git a/include/linux/mfd/lp873x.h b/include/linux/mfd/lp873x.h
new file mode 100644 (file)
index 0000000..83b1bd7
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Functions to access LP873X power management chip.
+ *
+ * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_MFD_LP873X_H
+#define __LINUX_MFD_LP873X_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* LP873x chip id list */
+#define LP873X                 0x00
+
+/* All register addresses */
+#define LP873X_REG_DEV_REV             0X00
+#define LP873X_REG_OTP_REV             0X01
+#define LP873X_REG_BUCK0_CTRL_1                0X02
+#define LP873X_REG_BUCK0_CTRL_2                0X03
+#define LP873X_REG_BUCK1_CTRL_1                0X04
+#define LP873X_REG_BUCK1_CTRL_2                0X05
+#define LP873X_REG_BUCK0_VOUT          0X06
+#define LP873X_REG_BUCK1_VOUT          0X07
+#define LP873X_REG_LDO0_CTRL           0X08
+#define LP873X_REG_LDO1_CTRL            0X09
+#define LP873X_REG_LDO0_VOUT           0X0A
+#define LP873X_REG_LDO1_VOUT           0X0B
+#define LP873X_REG_BUCK0_DELAY         0X0C
+#define LP873X_REG_BUCK1_DELAY         0X0D
+#define LP873X_REG_LDO0_DELAY          0X0E
+#define LP873X_REG_LDO1_DELAY          0X0F
+#define LP873X_REG_GPO_DELAY           0X10
+#define LP873X_REG_GPO2_DELAY          0X11
+#define LP873X_REG_GPO_CTRL            0X12
+#define LP873X_REG_CONFIG              0X13
+#define LP873X_REG_PLL_CTRL            0X14
+#define LP873X_REG_PGOOD_CTRL1         0X15
+#define LP873X_REG_PGOOD_CTRL2         0X16
+#define LP873X_REG_PG_FAULT            0X17
+#define LP873X_REG_RESET               0X18
+#define LP873X_REG_INT_TOP_1           0X19
+#define LP873X_REG_INT_TOP_2           0X1A
+#define LP873X_REG_INT_BUCK            0X1B
+#define LP873X_REG_INT_LDO             0X1C
+#define LP873X_REG_TOP_STAT            0X1D
+#define LP873X_REG_BUCK_STAT           0X1E
+#define LP873X_REG_LDO_STAT            0x1F
+#define LP873X_REG_TOP_MASK_1          0x20
+#define LP873X_REG_TOP_MASK_2          0x21
+#define LP873X_REG_BUCK_MASK           0x22
+#define LP873X_REG_LDO_MASK            0x23
+#define LP873X_REG_SEL_I_LOAD          0x24
+#define LP873X_REG_I_LOAD_2            0x25
+#define LP873X_REG_I_LOAD_1            0x26
+
+#define LP873X_REG_MAX                 LP873X_REG_I_LOAD_1
+
+/* Register field definitions */
+#define LP873X_DEV_REV_DEV_ID                  0xC0
+#define LP873X_DEV_REV_ALL_LAYER               0x30
+#define LP873X_DEV_REV_METAL_LAYER             0x0F
+
+#define LP873X_OTP_REV_OTP_ID                  0xFF
+
+#define LP873X_BUCK0_CTRL_1_BUCK0_FPWM         BIT(3)
+#define LP873X_BUCK0_CTRL_1_BUCK0_RDIS_EN      BIT(2)
+#define LP873X_BUCK0_CTRL_1_BUCK0_EN_PIN_CTRL  BIT(1)
+#define LP873X_BUCK0_CTRL_1_BUCK0_EN           BIT(0)
+
+#define LP873X_BUCK0_CTRL_2_BUCK0_ILIM         0x38
+#define LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE    0x07
+
+#define LP873X_BUCK1_CTRL_1_BUCK1_FPWM         BIT(3)
+#define LP873X_BUCK1_CTRL_1_BUCK1_RDIS_EN      BIT(2)
+#define LP873X_BUCK1_CTRL_1_BUCK1_EN_PIN_CTRL  BIT(1)
+#define LP873X_BUCK1_CTRL_1_BUCK1_EN           BIT(0)
+
+#define LP873X_BUCK1_CTRL_2_BUCK1_ILIM         0x38
+#define LP873X_BUCK1_CTRL_2_BUCK1_SLEW_RATE    0x07
+
+#define LP873X_BUCK0_VOUT_BUCK0_VSET           0xFF
+
+#define LP873X_BUCK1_VOUT_BUCK1_VSET           0xFF
+
+#define LP873X_LDO0_CTRL_LDO0_RDIS_EN          BIT(2)
+#define LP873X_LDO0_CTRL_LDO0_EN_PIN_CTRL      BIT(1)
+#define LP873X_LDO0_CTRL_LDO0_EN               BIT(0)
+
+#define LP873X_LDO1_CTRL_LDO1_RDIS_EN          BIT(2)
+#define LP873X_LDO1_CTRL_LDO1_EN_PIN_CTRL      BIT(1)
+#define LP873X_LDO1_CTRL_LDO1_EN               BIT(0)
+
+#define LP873X_LDO0_VOUT_LDO0_VSET             0x1F
+
+#define LP873X_LDO1_VOUT_LDO1_VSET             0x1F
+
+#define LP873X_BUCK0_DELAY_BUCK0_SD_DELAY      0xF0
+#define LP873X_BUCK0_DELAY_BUCK0_SU_DELAY      0x0F
+
+#define LP873X_BUCK1_DELAY_BUCK1_SD_DELAY      0xF0
+#define LP873X_BUCK1_DELAY_BUCK1_SU_DELAY      0x0F
+
+#define LP873X_LDO0_DELAY_LDO0_SD_DELAY        0xF0
+#define LP873X_LDO0_DELAY_LDO0_SU_DELAY        0x0F
+
+#define LP873X_LDO1_DELAY_LDO1_SD_DELAY        0xF0
+#define LP873X_LDO1_DELAY_LDO1_SU_DELAY        0x0F
+
+#define LP873X_GPO_DELAY_GPO_SD_DELAY          0xF0
+#define LP873X_GPO_DELAY_GPO_SU_DELAY          0x0F
+
+#define LP873X_GPO2_DELAY_GPO2_SD_DELAY        0xF0
+#define LP873X_GPO2_DELAY_GPO2_SU_DELAY        0x0F
+
+#define LP873X_GPO_CTRL_GPO2_OD                BIT(6)
+#define LP873X_GPO_CTRL_GPO2_EN_PIN_CTRL       BIT(5)
+#define LP873X_GPO_CTRL_GPO2_EN                BIT(4)
+#define LP873X_GPO_CTRL_GPO_OD                 BIT(2)
+#define LP873X_GPO_CTRL_GPO_EN_PIN_CTRL        BIT(1)
+#define LP873X_GPO_CTRL_GPO_EN                 BIT(0)
+
+#define LP873X_CONFIG_SU_DELAY_SEL             BIT(6)
+#define LP873X_CONFIG_SD_DELAY_SEL             BIT(5)
+#define LP873X_CONFIG_CLKIN_PIN_SEL            BIT(4)
+#define LP873X_CONFIG_CLKIN_PD                 BIT(3)
+#define LP873X_CONFIG_EN_PD                    BIT(2)
+#define LP873X_CONFIG_TDIE_WARN_LEVEL          BIT(1)
+#define LP873X_EN_SPREAD_SPEC                  BIT(0)
+
+#define LP873X_PLL_CTRL_EN_PLL                 BIT(6)
+#define LP873X_EXT_CLK_FREQ                    0x1F
+
+#define LP873X_PGOOD_CTRL1_PGOOD_POL           BIT(7)
+#define LP873X_PGOOD_CTRL1_PGOOD_OD            BIT(6)
+#define LP873X_PGOOD_CTRL1_PGOOD_WINDOW_LDO    BIT(5)
+#define LP873X_PGOOD_CTRL1_PGOOD_WINDOWN_BUCK  BIT(4)
+#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_LDO1 BIT(3)
+#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_LDO0 BIT(2)
+#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_BUCK1        BIT(1)
+#define LP873X_PGOOD_CTRL1_PGOOD_EN_PGOOD_BUCK0        BIT(0)
+
+#define LP873X_PGOOD_CTRL2_EN_PGOOD_TWARN      BIT(2)
+#define LP873X_PGOOD_CTRL2_EN_PG_FAULT_GATE    BIT(1)
+#define LP873X_PGOOD_CTRL2_PGOOD_MODE          BIT(0)
+
+#define LP873X_PG_FAULT_PG_FAULT_LDO1          BIT(3)
+#define LP873X_PG_FAULT_PG_FAULT_LDO0          BIT(2)
+#define LP873X_PG_FAULT_PG_FAULT_BUCK1         BIT(1)
+#define LP873X_PG_FAULT_PG_FAULT_BUCK0         BIT(0)
+
+#define LP873X_RESET_SW_RESET                  BIT(0)
+
+#define LP873X_INT_TOP_1_PGOOD_INT             BIT(7)
+#define LP873X_INT_TOP_1_LDO_INT               BIT(6)
+#define LP873X_INT_TOP_1_BUCK_INT              BIT(5)
+#define LP873X_INT_TOP_1_SYNC_CLK_INT          BIT(4)
+#define LP873X_INT_TOP_1_TDIE_SD_INT           BIT(3)
+#define LP873X_INT_TOP_1_TDIE_WARN_INT         BIT(2)
+#define LP873X_INT_TOP_1_OVP_INT               BIT(1)
+#define LP873X_INT_TOP_1_I_MEAS_INT            BIT(0)
+
+#define LP873X_INT_TOP_2_RESET_REG_INT         BIT(0)
+
+#define LP873X_INT_BUCK_BUCK1_PG_INT           BIT(6)
+#define LP873X_INT_BUCK_BUCK1_SC_INT           BIT(5)
+#define LP873X_INT_BUCK_BUCK1_ILIM_INT         BIT(4)
+#define LP873X_INT_BUCK_BUCK0_PG_INT           BIT(2)
+#define LP873X_INT_BUCK_BUCK0_SC_INT           BIT(1)
+#define LP873X_INT_BUCK_BUCK0_ILIM_INT         BIT(0)
+
+#define LP873X_INT_LDO_LDO1_PG_INT             BIT(6)
+#define LP873X_INT_LDO_LDO1_SC_INT             BIT(5)
+#define LP873X_INT_LDO_LDO1_ILIM_INT           BIT(4)
+#define LP873X_INT_LDO_LDO0_PG_INT             BIT(2)
+#define LP873X_INT_LDO_LDO0_SC_INT             BIT(1)
+#define LP873X_INT_LDO_LDO0_ILIM_INT           BIT(0)
+
+#define LP873X_TOP_STAT_PGOOD_STAT             BIT(7)
+#define LP873X_TOP_STAT_SYNC_CLK_STAT          BIT(4)
+#define LP873X_TOP_STAT_TDIE_SD_STAT           BIT(3)
+#define LP873X_TOP_STAT_TDIE_WARN_STAT         BIT(2)
+#define LP873X_TOP_STAT_OVP_STAT               BIT(1)
+
+#define LP873X_BUCK_STAT_BUCK1_STAT            BIT(7)
+#define LP873X_BUCK_STAT_BUCK1_PG_STAT         BIT(6)
+#define LP873X_BUCK_STAT_BUCK1_ILIM_STAT       BIT(4)
+#define LP873X_BUCK_STAT_BUCK0_STAT            BIT(3)
+#define LP873X_BUCK_STAT_BUCK0_PG_STAT         BIT(2)
+#define LP873X_BUCK_STAT_BUCK0_ILIM_STAT       BIT(0)
+
+#define LP873X_LDO_STAT_LDO1_STAT              BIT(7)
+#define LP873X_LDO_STAT_LDO1_PG_STAT           BIT(6)
+#define LP873X_LDO_STAT_LDO1_ILIM_STAT         BIT(4)
+#define LP873X_LDO_STAT_LDO0_STAT              BIT(3)
+#define LP873X_LDO_STAT_LDO0_PG_STAT           BIT(2)
+#define LP873X_LDO_STAT_LDO0_ILIM_STAT         BIT(0)
+
+#define LP873X_TOP_MASK_1_PGOOD_INT_MASK       BIT(7)
+#define LP873X_TOP_MASK_1_SYNC_CLK_MASK        BIT(4)
+#define LP873X_TOP_MASK_1_TDIE_WARN_MASK       BIT(2)
+#define LP873X_TOP_MASK_1_I_MEAS_MASK          BIT(0)
+
+#define LP873X_TOP_MASK_2_RESET_REG_MASK       BIT(0)
+
+#define LP873X_BUCK_MASK_BUCK1_PGF_MASK        BIT(7)
+#define LP873X_BUCK_MASK_BUCK1_PGR_MASK        BIT(6)
+#define LP873X_BUCK_MASK_BUCK1_ILIM_MASK       BIT(4)
+#define LP873X_BUCK_MASK_BUCK0_PGF_MASK        BIT(3)
+#define LP873X_BUCK_MASK_BUCK0_PGR_MASK        BIT(2)
+#define LP873X_BUCK_MASK_BUCK0_ILIM_MASK       BIT(0)
+
+#define LP873X_LDO_MASK_LDO1_PGF_MASK          BIT(7)
+#define LP873X_LDO_MASK_LDO1_PGR_MASK          BIT(6)
+#define LP873X_LDO_MASK_LDO1_ILIM_MASK         BIT(4)
+#define LP873X_LDO_MASK_LDO0_PGF_MASK          BIT(3)
+#define LP873X_LDO_MASK_LDO0_PGR_MASK          BIT(2)
+#define LP873X_LDO_MASK_LDO0_ILIM_MASK         BIT(0)
+
+#define LP873X_SEL_I_LOAD_CURRENT_BUCK_SELECT  BIT(0)
+
+#define LP873X_I_LOAD_2_BUCK_LOAD_CURRENT      BIT(0)
+
+#define LP873X_I_LOAD_1_BUCK_LOAD_CURRENT      0xFF
+
+#define LP873X_MAX_REG_ID              LP873X_LDO_1
+
+/* Number of step-down converters available */
+#define LP873X_NUM_BUCK                2
+/* Number of LDO voltage regulators available */
+#define LP873X_NUM_LDO         2
+/* Number of total regulators available */
+#define LP873X_NUM_REGULATOR           (LP873X_NUM_BUCK + LP873X_NUM_LDO)
+
+enum lp873x_regulator_id {
+       /* BUCK's */
+       LP873X_BUCK_0,
+       LP873X_BUCK_1,
+       /* LDOs */
+       LP873X_LDO_0,
+       LP873X_LDO_1,
+};
+
+/**
+ * struct lp873x - state holder for the lp873x driver
+ * @dev: struct device pointer for MFD device
+ * @rev: revision of the lp873x
+ * @lock: lock guarding the data structure
+ * @regmap: register map of the lp873x PMIC
+ *
+ * Device data may be used to access the LP873X chip
+ */
+struct lp873x {
+       struct device *dev;
+       u8 rev;
+       struct mutex lock;      /* lock guarding the data structure */
+       struct regmap *regmap;
+};
+#endif /* __LINUX_MFD_LP873X_H */
index de748bc..4a827af 100644 (file)
@@ -26,6 +26,7 @@ enum stmpe_partnum {
        STMPE610,
        STMPE801,
        STMPE811,
+       STMPE1600,
        STMPE1601,
        STMPE1801,
        STMPE2401,
@@ -39,22 +40,42 @@ enum stmpe_partnum {
  */
 enum {
        STMPE_IDX_CHIP_ID,
+       STMPE_IDX_SYS_CTRL,
+       STMPE_IDX_SYS_CTRL2,
        STMPE_IDX_ICR_LSB,
        STMPE_IDX_IER_LSB,
+       STMPE_IDX_IER_MSB,
        STMPE_IDX_ISR_LSB,
        STMPE_IDX_ISR_MSB,
        STMPE_IDX_GPMR_LSB,
+       STMPE_IDX_GPMR_CSB,
+       STMPE_IDX_GPMR_MSB,
        STMPE_IDX_GPSR_LSB,
+       STMPE_IDX_GPSR_CSB,
+       STMPE_IDX_GPSR_MSB,
        STMPE_IDX_GPCR_LSB,
+       STMPE_IDX_GPCR_CSB,
+       STMPE_IDX_GPCR_MSB,
        STMPE_IDX_GPDR_LSB,
+       STMPE_IDX_GPDR_CSB,
+       STMPE_IDX_GPDR_MSB,
+       STMPE_IDX_GPEDR_LSB,
+       STMPE_IDX_GPEDR_CSB,
        STMPE_IDX_GPEDR_MSB,
        STMPE_IDX_GPRER_LSB,
+       STMPE_IDX_GPRER_CSB,
+       STMPE_IDX_GPRER_MSB,
        STMPE_IDX_GPFER_LSB,
+       STMPE_IDX_GPFER_CSB,
+       STMPE_IDX_GPFER_MSB,
        STMPE_IDX_GPPUR_LSB,
        STMPE_IDX_GPPDR_LSB,
        STMPE_IDX_GPAFR_U_MSB,
        STMPE_IDX_IEGPIOR_LSB,
+       STMPE_IDX_IEGPIOR_CSB,
+       STMPE_IDX_IEGPIOR_MSB,
        STMPE_IDX_ISGPIOR_LSB,
+       STMPE_IDX_ISGPIOR_CSB,
        STMPE_IDX_ISGPIOR_MSB,
        STMPE_IDX_MAX,
 };
index 092186c..3f87ea5 100644 (file)
@@ -61,8 +61,6 @@ static inline int of_mm_gpiochip_add(struct device_node *np,
 }
 extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 
-extern int of_gpiochip_add(struct gpio_chip *gc);
-extern void of_gpiochip_remove(struct gpio_chip *gc);
 extern int of_gpio_simple_xlate(struct gpio_chip *gc,
                                const struct of_phandle_args *gpiospec,
                                u32 *flags);
@@ -86,9 +84,6 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
        return -ENOSYS;
 }
 
-static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
-static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
-
 #endif /* CONFIG_OF_GPIO */
 
 /**
diff --git a/include/linux/platform_data/gpio-htc-egpio.h b/include/linux/platform_data/gpio-htc-egpio.h
new file mode 100644 (file)
index 0000000..b4201c9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * HTC simple EGPIO irq and gpio extender
+ */
+
+#ifndef __HTC_EGPIO_H__
+#define __HTC_EGPIO_H__
+
+#include <linux/gpio.h>
+
+/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */
+#define HTC_EGPIO_OUTPUT (~0)
+#define HTC_EGPIO_INPUT  0
+
+/**
+ * struct htc_egpio_chip - descriptor to create gpio_chip for register range
+ * @reg_start: index of first register
+ * @gpio_base: gpio number of first pin in this register range
+ * @num_gpios: number of gpios in this register range, max BITS_PER_LONG
+ *    (number of registers = DIV_ROUND_UP(num_gpios, reg_width))
+ * @direction: bitfield, '0' = input, '1' = output,
+ */
+struct htc_egpio_chip {
+       int           reg_start;
+       int           gpio_base;
+       int           num_gpios;
+       unsigned long direction;
+       unsigned long initial_values;
+};
+
+/**
+ * struct htc_egpio_platform_data - description provided by the arch
+ * @irq_base: beginning of available IRQs (eg, IRQ_BOARD_START)
+ * @num_irqs: number of irqs
+ * @reg_width: number of bits per register, either 8 or 16 bit
+ * @bus_width: alignment of the registers, either 16 or 32 bit
+ * @invert_acks: set if chip requires writing '0' to ack an irq, instead of '1'
+ * @ack_register: location of the irq/ack register
+ * @chip: pointer to array of htc_egpio_chip descriptors
+ * @num_chips: number of egpio chip descriptors
+ */
+struct htc_egpio_platform_data {
+       int                   bus_width;
+       int                   reg_width;
+
+       int                   irq_base;
+       int                   num_irqs;
+       int                   invert_acks;
+       int                   ack_register;
+
+       struct htc_egpio_chip *chip;
+       int                   num_chips;
+};
+
+/* Determine the wakeup irq, to be called during early resume */
+extern int htc_egpio_get_wakeup_irq(struct device *dev);
+
+#endif
diff --git a/include/linux/platform_data/gpio-lpc32xx.h b/include/linux/platform_data/gpio-lpc32xx.h
deleted file mode 100644 (file)
index a544e96..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Author: Kevin Wells <kevin.wells@nxp.com>
- *
- * Copyright (C) 2010 NXP Semiconductors
- *
- * 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 Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __MACH_GPIO_LPC32XX_H
-#define __MACH_GPIO_LPC32XX_H
-
-/*
- * Note!
- * Muxed GP pins need to be setup to the GP state in the board level
- * code prior to using this driver.
- * GPI pins : 28xP3 group
- * GPO pins : 24xP3 group
- * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group
- */
-
-#define LPC32XX_GPIO_P0_MAX 8
-#define LPC32XX_GPIO_P1_MAX 24
-#define LPC32XX_GPIO_P2_MAX 13
-#define LPC32XX_GPIO_P3_MAX 6
-#define LPC32XX_GPI_P3_MAX 29
-#define LPC32XX_GPO_P3_MAX 24
-
-#define LPC32XX_GPIO_P0_GRP 0
-#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX)
-#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX)
-#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX)
-#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX)
-#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
-
-/*
- * A specific GPIO can be selected with this macro
- * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
- * See the LPC32x0 User's guide for GPIO group numbers
- */
-#define LPC32XX_GPIO(x, y) ((x) + (y))
-
-#endif /* __MACH_GPIO_LPC32XX_H */