Merge remote-tracking branch 'gpio/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 03:13:14 +0000 (13:13 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 03:13:14 +0000 (13:13 +1000)
33 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/gpio/board.txt
Documentation/gpio/gpio-legacy.txt
MAINTAINERS
arch/arm64/Kconfig
arch/arm64/Kconfig.platforms
arch/blackfin/Kconfig
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-aspeed.c [new file with mode: 0644]
drivers/gpio/gpio-axp209.c [new file with mode: 0644]
drivers/gpio/gpio-gpio-mm.c [new file with mode: 0644]
drivers/gpio/gpio-iop.c
drivers/gpio/gpio-lpc32xx.c
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-msic.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-spear-spics.c
drivers/gpio/gpio-ts4900.c [new file with mode: 0644]
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-wcove.c [new file with mode: 0644]
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
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 98d1983969566a0278b4544a5a24cef3c14fe85c..c3d016532d8e69b81fbb834057c5cd4976f430ba 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 8da26b35b5c3c8857a6ebb4dec71bf32e83d8b57..7c1ab3b3254f44f51b10e0d9ffeaba6fbd1af006 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 86d3fa95fd12828f5110d4ae19e6721740af8d85..40884c4fe40c5f85c4f64e096b7469141652a8cd 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 79ab5648d69b3e39a198c108c739eb1a08c20b06..b34fd94f70898a7f65c2a0313349588411eb8e81 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 87daa811ab94f0cb85a6529b941cc1c48bae2519..fce8c8e2be3b97afe831f1cdb21a8a19e9a34ba9 100644 (file)
@@ -3799,6 +3799,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>
index 0e11c8a2aec1bb9190597f507f19552cb8a9ba6f..04394d4653616dcbe8dfb9b5a2c957074f9f62c4 100644 (file)
@@ -15,7 +15,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 4e0e1071f2e8cd9190d009f6345df616208f1621..f14e0613b9de963098c8b5c212a3f4174bef9b06 100644 (file)
@@ -17,8 +17,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
@@ -31,15 +31,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
@@ -112,7 +112,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
@@ -158,11 +158,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 PM
        select PM_GENERIC_DOMAINS
@@ -188,8 +188,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 28c63fea786d38b1e6f671296e908f784eb18a59..3c1bd640042a0dc9f0c0866c8c93c7346cf1171a 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 b469c0e1adc70e43dfe225b2e0f3f658796bca52..fcbd8e318474d98b8fa3d7f5b2e5835b5b8414eb 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
@@ -128,6 +107,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 +124,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 +229,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.
@@ -574,6 +567,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 +786,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"
@@ -995,6 +1008,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 d60432f2a126c731249482fa828737948c129226..b3e039c3ae8d6146d64d9bf30b45827f5f7c915e 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,6 +46,7 @@ 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_GPIO_ICH)         += gpio-ich.o
 obj-$(CONFIG_GPIO_IOP)         += gpio-iop.o
@@ -111,6 +114,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
@@ -121,6 +125,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
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
new file mode 100644 (file)
index 0000000..64348a6
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ * 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);
+       if (!res)
+               return -ENXIO;
+
+       gpio->base = devm_ioremap_resource(&pdev->dev, res);
+       if (!gpio->base)
+               return -ENOMEM;
+
+       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");
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c
new file mode 100644 (file)
index 0000000..3174799
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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_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.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");
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");
index 860c535922fd184d929e1fda6a9fff2c9452622c..98c7ff2a76e76a24194f2c3278af42f5d5c4ff9c 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 fc5f197906ac97b09b14617ca56d52896b59453a..92b3ae2a67357f7714faa224a10f86a440bd4257 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 6ec144baeb11f1d124586b53ba353db7da7adab9..d7d03ad052d007bd1d7531a015e4688e2f603754 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;
 
index d75649787e6c4eac55c582cbc7e992804f4eee21..1b7ce7f8588669f3dda9a1a8a05462d0afd7d868 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 e38989a4fa0c6b7ce0384722a07f65154aea178b..c1a1e00b8cb024f12d6243226fc01de4aa37064a 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 02f2a5621bb0fd132a3a7dd131c865b8d24b107a..f170c5678289b5c892f0ffdceae5792ca5f0380e 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,25 +838,31 @@ 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)
 {
        struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct pca953x_chip *chip = i2c_get_clientdata(client);
-       int ret;
+       int ret = 0;
 
        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 b96e0b466f742ea2930ee0d2d79774f0ce903c32..2be48f5eba361af18817c8124dcc6637d1cff419 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 7ffd164952867a870ff06c5120462b38cf6df928..22267479ba6846dd2088fe62dbc946281f72d6ae 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");
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
new file mode 100644 (file)
index 0000000..9dd9aca
--- /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 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 6284bdbe1e0cbbc95fca1118686dfe8c3c9b1b22..3edb09cb9ee08080ca6da66e369c8729e57e8392 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..e11d6a3
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * 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/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 932e510aec50db6c2dba5f2ce539f5cb46925d31..4b44dd97c07f52c34ff9ad35d64e2766c4aeb071 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 53ff25ac66d8c49df53c41cdd1efff693ea90751..e183ee2f5f659ff553cba0ab01a71f046c2be537 100644 (file)
@@ -1363,19 +1363,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);
 
@@ -1617,6 +1613,15 @@ 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 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;
+
        gpiochip->irqchip = irqchip;
        gpiochip->irq_handler = handler;
        gpiochip->irq_default_type = type;
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 */
This page took 0.066931 seconds and 5 git commands to generate.