summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt46
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-aspeed.txt36
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-axp209.txt30
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt16
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-tps65086.txt16
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-ts4900.txt30
-rw-r--r--Documentation/devicetree/bindings/gpio/mrvl-gpio.txt23
-rw-r--r--Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt1
-rw-r--r--Documentation/devicetree/bindings/mfd/stmpe.txt2
-rw-r--r--Documentation/gpio/board.txt6
-rw-r--r--Documentation/gpio/gpio-legacy.txt16
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/Kconfig.platforms12
-rw-r--r--arch/blackfin/Kconfig2
-rw-r--r--drivers/gpio/Kconfig70
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/gpio-aspeed.c457
-rw-r--r--drivers/gpio/gpio-axp209.c162
-rw-r--r--drivers/gpio/gpio-gpio-mm.c267
-rw-r--r--drivers/gpio/gpio-iop.c115
-rw-r--r--drivers/gpio/gpio-lpc32xx.c15
-rw-r--r--drivers/gpio/gpio-mmio.c4
-rw-r--r--drivers/gpio/gpio-msic.c6
-rw-r--r--drivers/gpio/gpio-mxc.c10
-rw-r--r--drivers/gpio/gpio-pca953x.c330
-rw-r--r--drivers/gpio/gpio-rcar.c4
-rw-r--r--drivers/gpio/gpio-spear-spics.c7
-rw-r--r--drivers/gpio/gpio-stmpe.c167
-rw-r--r--drivers/gpio/gpio-ts4900.c190
-rw-r--r--drivers/gpio/gpio-vf610.c7
-rw-r--r--drivers/gpio/gpio-wcove.c469
-rw-r--r--drivers/gpio/gpiolib-sysfs.c4
-rw-r--r--drivers/gpio/gpiolib.c21
-rw-r--r--drivers/mfd/stmpe-i2c.c2
-rw-r--r--drivers/mfd/stmpe.c161
-rw-r--r--drivers/mfd/stmpe.h85
-rw-r--r--include/linux/mfd/stmpe.h21
-rw-r--r--include/linux/platform_data/gpio-lpc32xx.h50
39 files changed, 2371 insertions, 501 deletions
diff --git a/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt b/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt
new file mode 100644
index 000000000000..e7853143fa42
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/brcm,bcm6345-gpio.txt
@@ -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
index 000000000000..393bb2ed8a77
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-aspeed.txt
@@ -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
index 000000000000..a6611304dd3c
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt
@@ -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
index 000000000000..1afc2de7a537
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt
@@ -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
index ba051074bedc..000000000000
--- a/Documentation/devicetree/bindings/gpio/gpio-tps65086.txt
+++ /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
index 000000000000..3f8e71b1ab2a
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-ts4900.txt
@@ -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>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
index 98d198396956..c3d016532d8e 100644
--- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
@@ -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>;
- };
diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
index 8da26b35b5c3..7c1ab3b3254f 100644
--- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
+++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
@@ -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
diff --git a/Documentation/devicetree/bindings/mfd/stmpe.txt b/Documentation/devicetree/bindings/mfd/stmpe.txt
index 3fb68bfefc8b..f9065a5781a2 100644
--- a/Documentation/devicetree/bindings/mfd/stmpe.txt
+++ b/Documentation/devicetree/bindings/mfd/stmpe.txt
@@ -4,7 +4,7 @@ STMPE is an MFD device which may expose the following inbuilt devices: gpio,
keypad, touchscreen, adc, pwm, rotator.
Required properties:
- - compatible : "st,stmpe[610|801|811|1601|2401|2403]"
+ - compatible : "st,stmpe[610|801|811|1600|1601|2401|2403]"
- reg : I2C/SPI address of the device
Optional properties:
diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt
index 86d3fa95fd12..40884c4fe40c 100644
--- a/Documentation/gpio/board.txt
+++ b/Documentation/gpio/board.txt
@@ -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.
diff --git a/Documentation/gpio/gpio-legacy.txt b/Documentation/gpio/gpio-legacy.txt
index 79ab5648d69b..b34fd94f7089 100644
--- a/Documentation/gpio/gpio-legacy.txt
+++ b/Documentation/gpio/gpio-legacy.txt
@@ -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.
diff --git a/MAINTAINERS b/MAINTAINERS
index a306795a7450..5d0f88e0e8e3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3769,6 +3769,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>
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index bc3f00f586f1..41f300a87c51 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -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
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index be5d824ebdba..41d82b327e6a 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -15,8 +15,8 @@ config ARCH_ALPINE
config ARCH_BCM2835
bool "Broadcom BCM2835 family"
- select ARCH_REQUIRE_GPIOLIB
select CLKSRC_OF
+ select GPIOLIB
select PINCTRL
select PINCTRL_BCM2835
select ARM_AMBA
@@ -29,15 +29,15 @@ config ARCH_BCM2835
config ARCH_BCM_IPROC
bool "Broadcom iProc SoC Family"
select COMMON_CLK_IPROC
+ select GPIOLIB
select PINCTRL
- select ARCH_REQUIRE_GPIOLIB
help
This enables support for Broadcom iProc based SoCs
config ARCH_BERLIN
bool "Marvell Berlin SoC Family"
- select ARCH_REQUIRE_GPIOLIB
select DW_APB_ICTL
+ select GPIOLIB
select PINCTRL
help
This enables support for Marvell Berlin SoC Family
@@ -108,7 +108,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
@@ -154,11 +154,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 HAVE_CLK
select PINCTRL
select RESET_CONTROLLER
@@ -183,8 +183,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
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 28c63fea786d..3c1bd640042a 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -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
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 346e9a9b4397..0e41c45a2936 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -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
@@ -127,6 +106,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
@@ -137,6 +123,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)
@@ -236,7 +228,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.
@@ -573,6 +566,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
@@ -779,6 +785,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"
@@ -994,6 +1007,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
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d60432f2a126..b3e039c3ae8d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -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
index 000000000000..64348a6fb60f
--- /dev/null
+++ b/drivers/gpio/gpio-aspeed.c
@@ -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
index 000000000000..3174799c27c6
--- /dev/null
+++ b/drivers/gpio/gpio-axp209.c
@@ -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
index 000000000000..1e7def9449ce
--- /dev/null
+++ b/drivers/gpio/gpio-gpio-mm.c
@@ -0,0 +1,267 @@
+/*
+ * GPIO driver for the Diamond Systems GPIO-MM
+ * Copyright (C) 2016 William Breathitt Gray
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * This driver supports the following Diamond Systems devices: GPIO-MM and
+ * GPIO-MM-12.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/isa.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+
+#define GPIOMM_EXTENT 8
+#define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
+
+static unsigned int base[MAX_NUM_GPIOMM];
+static unsigned int num_gpiomm;
+module_param_array(base, uint, &num_gpiomm, 0);
+MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
+
+/**
+ * struct gpiomm_gpio - GPIO device private data structure
+ * @chip: instance of the gpio_chip
+ * @io_state: bit I/O state (whether bit is set to input or output)
+ * @out_state: output bits state
+ * @control: Control registers state
+ * @lock: synchronization lock to prevent I/O race conditions
+ * @base: base port address of the GPIO device
+ */
+struct gpiomm_gpio {
+ struct gpio_chip chip;
+ unsigned char io_state[6];
+ unsigned char out_state[6];
+ unsigned char control[2];
+ spinlock_t lock;
+ unsigned int base;
+};
+
+static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ const unsigned int port = offset / 8;
+ const unsigned int mask = BIT(offset % 8);
+
+ return !!(gpiommgpio->io_state[port] & mask);
+}
+
+static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ const unsigned int io_port = offset / 8;
+ const unsigned int control_port = io_port / 3;
+ const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
+ unsigned long flags;
+ unsigned int control;
+
+ spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+ /* Check if configuring Port C */
+ if (io_port == 2 || io_port == 5) {
+ /* Port C can be configured by nibble */
+ if (offset % 8 > 3) {
+ gpiommgpio->io_state[io_port] |= 0xF0;
+ gpiommgpio->control[control_port] |= BIT(3);
+ } else {
+ gpiommgpio->io_state[io_port] |= 0x0F;
+ gpiommgpio->control[control_port] |= BIT(0);
+ }
+ } else {
+ gpiommgpio->io_state[io_port] |= 0xFF;
+ if (io_port == 0 || io_port == 3)
+ gpiommgpio->control[control_port] |= BIT(4);
+ else
+ gpiommgpio->control[control_port] |= BIT(1);
+ }
+
+ control = BIT(7) | gpiommgpio->control[control_port];
+ outb(control, control_addr);
+
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+ return 0;
+}
+
+static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ const unsigned int io_port = offset / 8;
+ const unsigned int control_port = io_port / 3;
+ const unsigned int mask = BIT(offset % 8);
+ const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
+ const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
+ unsigned long flags;
+ unsigned int control;
+
+ spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+ /* Check if configuring Port C */
+ if (io_port == 2 || io_port == 5) {
+ /* Port C can be configured by nibble */
+ if (offset % 8 > 3) {
+ gpiommgpio->io_state[io_port] &= 0x0F;
+ gpiommgpio->control[control_port] &= ~BIT(3);
+ } else {
+ gpiommgpio->io_state[io_port] &= 0xF0;
+ gpiommgpio->control[control_port] &= ~BIT(0);
+ }
+ } else {
+ gpiommgpio->io_state[io_port] &= 0x00;
+ if (io_port == 0 || io_port == 3)
+ gpiommgpio->control[control_port] &= ~BIT(4);
+ else
+ gpiommgpio->control[control_port] &= ~BIT(1);
+ }
+
+ if (value)
+ gpiommgpio->out_state[io_port] |= mask;
+ else
+ gpiommgpio->out_state[io_port] &= ~mask;
+
+ control = BIT(7) | gpiommgpio->control[control_port];
+ outb(control, control_addr);
+
+ outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
+
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+ return 0;
+}
+
+static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ const unsigned int port = offset / 8;
+ const unsigned int mask = BIT(offset % 8);
+ const unsigned int in_port = (port > 2) ? port + 1 : port;
+ unsigned long flags;
+ unsigned int port_state;
+
+ spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+ /* ensure that GPIO is set for input */
+ if (!(gpiommgpio->io_state[port] & mask)) {
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+ return -EINVAL;
+ }
+
+ port_state = inb(gpiommgpio->base + in_port);
+
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+
+ return !!(port_state & mask);
+}
+
+static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
+{
+ struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+ const unsigned int port = offset / 8;
+ const unsigned int mask = BIT(offset % 8);
+ const unsigned int out_port = (port > 2) ? port + 1 : port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpiommgpio->lock, flags);
+
+ if (value)
+ gpiommgpio->out_state[port] |= mask;
+ else
+ gpiommgpio->out_state[port] &= ~mask;
+
+ outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
+
+ spin_unlock_irqrestore(&gpiommgpio->lock, flags);
+}
+
+static int gpiomm_probe(struct device *dev, unsigned int id)
+{
+ struct gpiomm_gpio *gpiommgpio;
+ const char *const name = dev_name(dev);
+ int err;
+
+ gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
+ if (!gpiommgpio)
+ return -ENOMEM;
+
+ if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
+ dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
+ base[id], base[id] + GPIOMM_EXTENT);
+ return -EBUSY;
+ }
+
+ gpiommgpio->chip.label = name;
+ gpiommgpio->chip.parent = dev;
+ gpiommgpio->chip.owner = THIS_MODULE;
+ gpiommgpio->chip.base = -1;
+ gpiommgpio->chip.ngpio = 48;
+ gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
+ gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
+ gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
+ gpiommgpio->chip.get = gpiomm_gpio_get;
+ gpiommgpio->chip.set = gpiomm_gpio_set;
+ gpiommgpio->base = base[id];
+
+ spin_lock_init(&gpiommgpio->lock);
+
+ dev_set_drvdata(dev, gpiommgpio);
+
+ err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
+ if (err) {
+ dev_err(dev, "GPIO registering failed (%d)\n", err);
+ return err;
+ }
+
+ /* initialize all GPIO as output */
+ outb(0x80, base[id] + 3);
+ outb(0x00, base[id]);
+ outb(0x00, base[id] + 1);
+ outb(0x00, base[id] + 2);
+ outb(0x80, base[id] + 7);
+ outb(0x00, base[id] + 4);
+ outb(0x00, base[id] + 5);
+ outb(0x00, base[id] + 6);
+
+ return 0;
+}
+
+static int gpiomm_remove(struct device *dev, unsigned int id)
+{
+ struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
+
+ gpiochip_remove(&gpiommgpio->chip);
+
+ return 0;
+}
+
+static struct isa_driver gpiomm_driver = {
+ .probe = gpiomm_probe,
+ .driver = {
+ .name = "gpio-mm"
+ },
+ .remove = gpiomm_remove
+};
+
+module_isa_driver(gpiomm_driver, num_gpiomm);
+
+MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
+MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
index 860c535922fd..98c7ff2a76e7 100644
--- a/drivers/gpio/gpio-iop.c
+++ b/drivers/gpio/gpio-iop.c
@@ -10,111 +10,40 @@
* 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 = {
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index fc5f197906ac..92b3ae2a6735 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -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>
@@ -68,6 +67,20 @@
#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;
diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c
index 6ec144baeb11..d7d03ad052d0 100644
--- a/drivers/gpio/gpio-mmio.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -573,6 +573,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
#ifdef CONFIG_OF
static const struct of_device_id bgpio_of_match[] = {
+ { .compatible = "brcm,bcm6345-gpio" },
{ .compatible = "wd,mbl-gpio" },
{ }
};
@@ -593,6 +594,9 @@ static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
pdata->base = -1;
+ if (of_device_is_big_endian(pdev->dev.of_node))
+ *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+
if (of_property_read_bool(pdev->dev.of_node, "no-output"))
*flags |= BGPIOF_NO_OUTPUT;
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
index d75649787e6c..1b7ce7f85886 100644
--- a/drivers/gpio/gpio-msic.c
+++ b/drivers/gpio/gpio-msic.c
@@ -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");
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 1b342a3842c8..e35af5249478 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -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 {
@@ -511,9 +511,3 @@ static int __init gpio_mxc_init(void)
return platform_driver_register(&mxc_gpio_driver);
}
postcore_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");
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 02f2a5621bb0..f170c5678289 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -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 */
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index b96e0b466f74..2be48f5eba36 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -348,6 +348,10 @@ static const struct of_device_id gpio_rcar_of_table[] = {
/* 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,
}, {
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
index 7ffd16495286..22267479ba68 100644
--- a/drivers/gpio/gpio-spear-spics.c
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -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-stmpe.c b/drivers/gpio/gpio-stmpe.c
index f675132de10e..5c0d8189a304 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -20,6 +20,8 @@
*/
enum { REG_RE, REG_FE, REG_IE };
+enum { LSB, CSB, MSB };
+
#define CACHE_NR_REGS 3
/* No variant has more than 24 GPIOs */
#define CACHE_NR_BANKS (24 / 8)
@@ -39,7 +41,7 @@ static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
- u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
+ u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB + (offset / 8)];
u8 mask = 1 << (offset % 8);
int ret;
@@ -55,7 +57,7 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
- u8 reg = stmpe->regs[which] - (offset / 8);
+ u8 reg = stmpe->regs[which + (offset / 8)];
u8 mask = 1 << (offset % 8);
/*
@@ -89,7 +91,7 @@ static int stmpe_gpio_direction_output(struct gpio_chip *chip,
{
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
- u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)];
u8 mask = 1 << (offset % 8);
stmpe_gpio_set(chip, offset, val);
@@ -102,7 +104,7 @@ static int stmpe_gpio_direction_input(struct gpio_chip *chip,
{
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
- u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB + (offset / 8)];
u8 mask = 1 << (offset % 8);
return stmpe_set_bits(stmpe, reg, mask, 0);
@@ -142,8 +144,9 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
return -EINVAL;
- /* STMPE801 doesn't have RE and FE registers */
- if (stmpe_gpio->stmpe->partnum == STMPE801)
+ /* STMPE801 and STMPE 1600 don't have RE and FE registers */
+ if (stmpe_gpio->stmpe->partnum == STMPE801 ||
+ stmpe_gpio->stmpe->partnum == STMPE1600)
return 0;
if (type & IRQ_TYPE_EDGE_RISING)
@@ -173,17 +176,24 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
- static const u8 regmap[] = {
- [REG_RE] = STMPE_IDX_GPRER_LSB,
- [REG_FE] = STMPE_IDX_GPFER_LSB,
- [REG_IE] = STMPE_IDX_IEGPIOR_LSB,
+ static const u8 regmap[CACHE_NR_REGS][CACHE_NR_BANKS] = {
+ [REG_RE][LSB] = STMPE_IDX_GPRER_LSB,
+ [REG_RE][CSB] = STMPE_IDX_GPRER_CSB,
+ [REG_RE][MSB] = STMPE_IDX_GPRER_MSB,
+ [REG_FE][LSB] = STMPE_IDX_GPFER_LSB,
+ [REG_FE][CSB] = STMPE_IDX_GPFER_CSB,
+ [REG_FE][MSB] = STMPE_IDX_GPFER_MSB,
+ [REG_IE][LSB] = STMPE_IDX_IEGPIOR_LSB,
+ [REG_IE][CSB] = STMPE_IDX_IEGPIOR_CSB,
+ [REG_IE][MSB] = STMPE_IDX_IEGPIOR_MSB,
};
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
- /* STMPE801 doesn't have RE and FE registers */
- if ((stmpe->partnum == STMPE801) &&
- (i != REG_IE))
+ /* STMPE801 and STMPE1600 don't have RE and FE registers */
+ if ((stmpe->partnum == STMPE801 ||
+ stmpe->partnum == STMPE1600) &&
+ (i != REG_IE))
continue;
for (j = 0; j < num_banks; j++) {
@@ -194,7 +204,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
continue;
stmpe_gpio->oldregs[i][j] = new;
- stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
+ stmpe_reg_write(stmpe, stmpe->regs[regmap[i][j]], new);
}
}
@@ -216,11 +226,21 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
+ struct stmpe *stmpe = stmpe_gpio->stmpe;
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] |= mask;
+
+ /*
+ * STMPE1600 workaround: to be able to get IRQ from pins,
+ * a read must be done on GPMR register, or a write in
+ * GPSR or GPCR registers
+ */
+ if (stmpe->partnum == STMPE1600)
+ stmpe_reg_read(stmpe,
+ stmpe->regs[STMPE_IDX_GPMR_LSB + regoffset]);
}
static void stmpe_dbg_show_one(struct seq_file *s,
@@ -230,9 +250,9 @@ static void stmpe_dbg_show_one(struct seq_file *s,
struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc);
struct stmpe *stmpe = stmpe_gpio->stmpe;
const char *label = gpiochip_is_requested(gc, offset);
- int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
bool val = !!stmpe_gpio_get(gc, offset);
- u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
+ u8 bank = offset / 8;
+ u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank];
u8 mask = 1 << (offset % 8);
int ret;
u8 dir;
@@ -247,39 +267,72 @@ static void stmpe_dbg_show_one(struct seq_file *s,
gpio, label ?: "(none)",
val ? "hi" : "lo");
} else {
- u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8);
- u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8);
- u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8);
- u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8);
- bool edge_det;
- bool rise;
- bool fall;
+ u8 edge_det_reg;
+ u8 rise_reg;
+ u8 fall_reg;
+ u8 irqen_reg;
+
+ char *edge_det_values[] = {"edge-inactive",
+ "edge-asserted",
+ "not-supported"};
+ char *rise_values[] = {"no-rising-edge-detection",
+ "rising-edge-detection",
+ "not-supported"};
+ char *fall_values[] = {"no-falling-edge-detection",
+ "falling-edge-detection",
+ "not-supported"};
+ #define NOT_SUPPORTED_IDX 2
+ u8 edge_det = NOT_SUPPORTED_IDX;
+ u8 rise = NOT_SUPPORTED_IDX;
+ u8 fall = NOT_SUPPORTED_IDX;
bool irqen;
- ret = stmpe_reg_read(stmpe, edge_det_reg);
- if (ret < 0)
- return;
- edge_det = !!(ret & mask);
- ret = stmpe_reg_read(stmpe, rise_reg);
- if (ret < 0)
+ switch (stmpe->partnum) {
+ case STMPE610:
+ case STMPE811:
+ case STMPE1601:
+ case STMPE2401:
+ case STMPE2403:
+ edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_LSB + bank];
+ ret = stmpe_reg_read(stmpe, edge_det_reg);
+ if (ret < 0)
+ return;
+ edge_det = !!(ret & mask);
+
+ case STMPE1801:
+ rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB + bank];
+ fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB + bank];
+
+ ret = stmpe_reg_read(stmpe, rise_reg);
+ if (ret < 0)
+ return;
+ rise = !!(ret & mask);
+ ret = stmpe_reg_read(stmpe, fall_reg);
+ if (ret < 0)
+ return;
+ fall = !!(ret & mask);
+
+ case STMPE801:
+ case STMPE1600:
+ irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB + bank];
+ break;
+
+ default:
return;
- rise = !!(ret & mask);
- ret = stmpe_reg_read(stmpe, fall_reg);
- if (ret < 0)
- return;
- fall = !!(ret & mask);
+ }
+
ret = stmpe_reg_read(stmpe, irqen_reg);
if (ret < 0)
return;
irqen = !!(ret & mask);
- seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s %s%s%s",
+ seq_printf(s, " gpio-%-3d (%-20.20s) in %s %13s %13s %25s %25s",
gpio, label ?: "(none)",
val ? "hi" : "lo",
- edge_det ? "edge-asserted" : "edge-inactive",
- irqen ? "IRQ-enabled" : "",
- rise ? " rising-edge-detection" : "",
- fall ? " falling-edge-detection" : "");
+ edge_det_values[edge_det],
+ irqen ? "IRQ-enabled" : "IRQ-disabled",
+ rise_values[rise],
+ fall_values[fall]);
}
}
@@ -307,18 +360,32 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
{
struct stmpe_gpio *stmpe_gpio = dev;
struct stmpe *stmpe = stmpe_gpio->stmpe;
- u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+ u8 statmsbreg;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
u8 status[num_banks];
int ret;
int i;
+ /*
+ * the stmpe_block_read() call below, imposes to set statmsbreg
+ * with the register located at the lowest address. As STMPE1600
+ * variant is the only one which respect registers address's order
+ * (LSB regs located at lowest address than MSB ones) whereas all
+ * the others have a registers layout with MSB located before the
+ * LSB regs.
+ */
+ if (stmpe->partnum == STMPE1600)
+ statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_LSB];
+ else
+ statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
+
ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < num_banks; i++) {
- int bank = num_banks - i - 1;
+ int bank = (stmpe_gpio->stmpe->partnum == STMPE1600) ? i :
+ num_banks - i - 1;
unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
unsigned int stat = status[i];
@@ -336,12 +403,18 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
stat &= ~(1 << bit);
}
- stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
-
- /* Edge detect register is not present on 801 */
- if (stmpe->partnum != STMPE801)
- stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
- + i, status[i]);
+ /*
+ * interrupt status register write has no effect on
+ * 801/1801/1600, bits are cleared when read.
+ * Edge detect register is not present on 801/1600/1801
+ */
+ if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 ||
+ stmpe->partnum != STMPE1801) {
+ stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
+ stmpe_reg_write(stmpe,
+ stmpe->regs[STMPE_IDX_GPEDR_LSB + i],
+ status[i]);
+ }
}
return IRQ_HANDLED;
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
new file mode 100644
index 000000000000..9dd9aca820e7
--- /dev/null
+++ b/drivers/gpio/gpio-ts4900.c
@@ -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");
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 6284bdbe1e0c..3edb09cb9ee0 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -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
index 000000000000..e11d6a3fb641
--- /dev/null
+++ b/drivers/gpio/gpio-wcove.c
@@ -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");
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 932e510aec50..4b44dd97c07f 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -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)
{
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 53ff25ac66d8..e183ee2f5f65 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -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/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index c3f4aab53b07..863c39a3353c 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -57,6 +57,7 @@ static const struct of_device_id stmpe_of_match[] = {
{ .compatible = "st,stmpe610", .data = (void *)STMPE610, },
{ .compatible = "st,stmpe801", .data = (void *)STMPE801, },
{ .compatible = "st,stmpe811", .data = (void *)STMPE811, },
+ { .compatible = "st,stmpe1600", .data = (void *)STMPE1600, },
{ .compatible = "st,stmpe1601", .data = (void *)STMPE1601, },
{ .compatible = "st,stmpe1801", .data = (void *)STMPE1801, },
{ .compatible = "st,stmpe2401", .data = (void *)STMPE2401, },
@@ -101,6 +102,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = {
{ "stmpe610", STMPE610 },
{ "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 },
+ { "stmpe1600", STMPE1600 },
{ "stmpe1601", STMPE1601 },
{ "stmpe1801", STMPE1801 },
{ "stmpe2401", STMPE2401 },
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 94c7cc02fdab..cfdae8a3d779 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -469,6 +469,8 @@ static const struct mfd_cell stmpe_ts_cell = {
static const u8 stmpe811_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE811_REG_CHIP_ID,
+ [STMPE_IDX_SYS_CTRL] = STMPE811_REG_SYS_CTRL,
+ [STMPE_IDX_SYS_CTRL2] = STMPE811_REG_SYS_CTRL2,
[STMPE_IDX_ICR_LSB] = STMPE811_REG_INT_CTRL,
[STMPE_IDX_IER_LSB] = STMPE811_REG_INT_EN,
[STMPE_IDX_ISR_MSB] = STMPE811_REG_INT_STA,
@@ -481,7 +483,7 @@ static const u8 stmpe811_regs[] = {
[STMPE_IDX_GPAFR_U_MSB] = STMPE811_REG_GPIO_AF,
[STMPE_IDX_IEGPIOR_LSB] = STMPE811_REG_GPIO_INT_EN,
[STMPE_IDX_ISGPIOR_MSB] = STMPE811_REG_GPIO_INT_STA,
- [STMPE_IDX_GPEDR_MSB] = STMPE811_REG_GPIO_ED,
+ [STMPE_IDX_GPEDR_LSB] = STMPE811_REG_GPIO_ED,
};
static struct stmpe_variant_block stmpe811_blocks[] = {
@@ -511,7 +513,7 @@ static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
if (blocks & STMPE_BLOCK_TOUCHSCREEN)
mask |= STMPE811_SYS_CTRL2_TSC_OFF;
- return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask,
+ return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2], mask,
enable ? 0 : mask);
}
@@ -551,25 +553,89 @@ static struct stmpe_variant_info stmpe610 = {
};
/*
+ * STMPE1600
+ * Compared to all others STMPE variant, LSB and MSB regs are located in this
+ * order : LSB addr
+ * MSB addr + 1
+ * As there is only 2 * 8bits registers for GPMR/GPSR/IEGPIOPR, CSB index is MSB registers
+ */
+
+static const u8 stmpe1600_regs[] = {
+ [STMPE_IDX_CHIP_ID] = STMPE1600_REG_CHIP_ID,
+ [STMPE_IDX_SYS_CTRL] = STMPE1600_REG_SYS_CTRL,
+ [STMPE_IDX_ICR_LSB] = STMPE1600_REG_SYS_CTRL,
+ [STMPE_IDX_GPMR_LSB] = STMPE1600_REG_GPMR_LSB,
+ [STMPE_IDX_GPMR_CSB] = STMPE1600_REG_GPMR_MSB,
+ [STMPE_IDX_GPSR_LSB] = STMPE1600_REG_GPSR_LSB,
+ [STMPE_IDX_GPSR_CSB] = STMPE1600_REG_GPSR_MSB,
+ [STMPE_IDX_GPDR_LSB] = STMPE1600_REG_GPDR_LSB,
+ [STMPE_IDX_GPDR_CSB] = STMPE1600_REG_GPDR_MSB,
+ [STMPE_IDX_IEGPIOR_LSB] = STMPE1600_REG_IEGPIOR_LSB,
+ [STMPE_IDX_IEGPIOR_CSB] = STMPE1600_REG_IEGPIOR_MSB,
+ [STMPE_IDX_ISGPIOR_LSB] = STMPE1600_REG_ISGPIOR_LSB,
+};
+
+static struct stmpe_variant_block stmpe1600_blocks[] = {
+ {
+ .cell = &stmpe_gpio_cell,
+ .irq = 0,
+ .block = STMPE_BLOCK_GPIO,
+ },
+};
+
+static int stmpe1600_enable(struct stmpe *stmpe, unsigned int blocks,
+ bool enable)
+{
+ if (blocks & STMPE_BLOCK_GPIO)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static struct stmpe_variant_info stmpe1600 = {
+ .name = "stmpe1600",
+ .id_val = STMPE1600_ID,
+ .id_mask = 0xffff,
+ .num_gpios = 16,
+ .af_bits = 0,
+ .regs = stmpe1600_regs,
+ .blocks = stmpe1600_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe1600_blocks),
+ .num_irqs = STMPE1600_NR_INTERNAL_IRQS,
+ .enable = stmpe1600_enable,
+};
+
+/*
* STMPE1601
*/
static const u8 stmpe1601_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE1601_REG_CHIP_ID,
+ [STMPE_IDX_SYS_CTRL] = STMPE1601_REG_SYS_CTRL,
+ [STMPE_IDX_SYS_CTRL2] = STMPE1601_REG_SYS_CTRL2,
[STMPE_IDX_ICR_LSB] = STMPE1601_REG_ICR_LSB,
+ [STMPE_IDX_IER_MSB] = STMPE1601_REG_IER_MSB,
[STMPE_IDX_IER_LSB] = STMPE1601_REG_IER_LSB,
[STMPE_IDX_ISR_MSB] = STMPE1601_REG_ISR_MSB,
[STMPE_IDX_GPMR_LSB] = STMPE1601_REG_GPIO_MP_LSB,
+ [STMPE_IDX_GPMR_CSB] = STMPE1601_REG_GPIO_MP_MSB,
[STMPE_IDX_GPSR_LSB] = STMPE1601_REG_GPIO_SET_LSB,
+ [STMPE_IDX_GPSR_CSB] = STMPE1601_REG_GPIO_SET_MSB,
[STMPE_IDX_GPCR_LSB] = STMPE1601_REG_GPIO_CLR_LSB,
+ [STMPE_IDX_GPCR_CSB] = STMPE1601_REG_GPIO_CLR_MSB,
[STMPE_IDX_GPDR_LSB] = STMPE1601_REG_GPIO_SET_DIR_LSB,
+ [STMPE_IDX_GPDR_CSB] = STMPE1601_REG_GPIO_SET_DIR_MSB,
+ [STMPE_IDX_GPEDR_LSB] = STMPE1601_REG_GPIO_ED_LSB,
+ [STMPE_IDX_GPEDR_CSB] = STMPE1601_REG_GPIO_ED_MSB,
[STMPE_IDX_GPRER_LSB] = STMPE1601_REG_GPIO_RE_LSB,
+ [STMPE_IDX_GPRER_CSB] = STMPE1601_REG_GPIO_RE_MSB,
[STMPE_IDX_GPFER_LSB] = STMPE1601_REG_GPIO_FE_LSB,
+ [STMPE_IDX_GPFER_CSB] = STMPE1601_REG_GPIO_FE_MSB,
[STMPE_IDX_GPPUR_LSB] = STMPE1601_REG_GPIO_PU_LSB,
[STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB,
[STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
+ [STMPE_IDX_IEGPIOR_CSB] = STMPE1601_REG_INT_EN_GPIO_MASK_MSB,
[STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB,
- [STMPE_IDX_GPEDR_MSB] = STMPE1601_REG_GPIO_ED_MSB,
};
static struct stmpe_variant_block stmpe1601_blocks[] = {
@@ -640,13 +706,13 @@ static int stmpe1601_autosleep(struct stmpe *stmpe,
return timeout;
}
- ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+ ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2],
STMPE1601_AUTOSLEEP_TIMEOUT_MASK,
timeout);
if (ret < 0)
return ret;
- return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
+ return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL2],
STPME1601_AUTOSLEEP_ENABLE,
STPME1601_AUTOSLEEP_ENABLE);
}
@@ -671,7 +737,7 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
else
mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM;
- return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
+ return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask,
enable ? mask : 0);
}
@@ -710,18 +776,33 @@ static struct stmpe_variant_info stmpe1601 = {
*/
static const u8 stmpe1801_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID,
+ [STMPE_IDX_SYS_CTRL] = STMPE1801_REG_SYS_CTRL,
[STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW,
[STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW,
[STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW,
[STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW,
+ [STMPE_IDX_GPMR_CSB] = STMPE1801_REG_GPIO_MP_MID,
+ [STMPE_IDX_GPMR_MSB] = STMPE1801_REG_GPIO_MP_HIGH,
[STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW,
+ [STMPE_IDX_GPSR_CSB] = STMPE1801_REG_GPIO_SET_MID,
+ [STMPE_IDX_GPSR_MSB] = STMPE1801_REG_GPIO_SET_HIGH,
[STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW,
+ [STMPE_IDX_GPCR_CSB] = STMPE1801_REG_GPIO_CLR_MID,
+ [STMPE_IDX_GPCR_MSB] = STMPE1801_REG_GPIO_CLR_HIGH,
[STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW,
+ [STMPE_IDX_GPDR_CSB] = STMPE1801_REG_GPIO_SET_DIR_MID,
+ [STMPE_IDX_GPDR_MSB] = STMPE1801_REG_GPIO_SET_DIR_HIGH,
[STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW,
+ [STMPE_IDX_GPRER_CSB] = STMPE1801_REG_GPIO_RE_MID,
+ [STMPE_IDX_GPRER_MSB] = STMPE1801_REG_GPIO_RE_HIGH,
[STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW,
+ [STMPE_IDX_GPFER_CSB] = STMPE1801_REG_GPIO_FE_MID,
+ [STMPE_IDX_GPFER_MSB] = STMPE1801_REG_GPIO_FE_HIGH,
[STMPE_IDX_GPPUR_LSB] = STMPE1801_REG_GPIO_PULL_UP_LOW,
[STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW,
- [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW,
+ [STMPE_IDX_IEGPIOR_CSB] = STMPE1801_REG_INT_EN_GPIO_MASK_MID,
+ [STMPE_IDX_IEGPIOR_MSB] = STMPE1801_REG_INT_EN_GPIO_MASK_HIGH,
+ [STMPE_IDX_ISGPIOR_MSB] = STMPE1801_REG_INT_STA_GPIO_HIGH,
};
static struct stmpe_variant_block stmpe1801_blocks[] = {
@@ -751,22 +832,31 @@ static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks,
enable ? mask : 0);
}
-static int stmpe1801_reset(struct stmpe *stmpe)
+static int stmpe_reset(struct stmpe *stmpe)
{
+ u16 id_val = stmpe->variant->id_val;
unsigned long timeout;
int ret = 0;
+ u8 reset_bit;
+
+ if (id_val == STMPE811_ID)
+ /* STMPE801 and STMPE610 use bit 1 of SYS_CTRL register */
+ reset_bit = STMPE811_SYS_CTRL_RESET;
+ else
+ /* all other STMPE variant use bit 7 of SYS_CTRL register */
+ reset_bit = STMPE_SYS_CTRL_RESET;
- ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL,
- STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET);
+ ret = __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL],
+ reset_bit, reset_bit);
if (ret < 0)
return ret;
timeout = jiffies + msecs_to_jiffies(100);
while (time_before(jiffies, timeout)) {
- ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL);
+ ret = __stmpe_reg_read(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL]);
if (ret < 0)
return ret;
- if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET))
+ if (!(ret & reset_bit))
return 0;
usleep_range(100, 200);
}
@@ -794,20 +884,39 @@ static struct stmpe_variant_info stmpe1801 = {
static const u8 stmpe24xx_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE24XX_REG_CHIP_ID,
+ [STMPE_IDX_SYS_CTRL] = STMPE24XX_REG_SYS_CTRL,
+ [STMPE_IDX_SYS_CTRL2] = STMPE24XX_REG_SYS_CTRL2,
[STMPE_IDX_ICR_LSB] = STMPE24XX_REG_ICR_LSB,
+ [STMPE_IDX_IER_MSB] = STMPE24XX_REG_IER_MSB,
[STMPE_IDX_IER_LSB] = STMPE24XX_REG_IER_LSB,
[STMPE_IDX_ISR_MSB] = STMPE24XX_REG_ISR_MSB,
[STMPE_IDX_GPMR_LSB] = STMPE24XX_REG_GPMR_LSB,
+ [STMPE_IDX_GPMR_CSB] = STMPE24XX_REG_GPMR_CSB,
+ [STMPE_IDX_GPMR_MSB] = STMPE24XX_REG_GPMR_MSB,
[STMPE_IDX_GPSR_LSB] = STMPE24XX_REG_GPSR_LSB,
+ [STMPE_IDX_GPSR_CSB] = STMPE24XX_REG_GPSR_CSB,
+ [STMPE_IDX_GPSR_MSB] = STMPE24XX_REG_GPSR_MSB,
[STMPE_IDX_GPCR_LSB] = STMPE24XX_REG_GPCR_LSB,
+ [STMPE_IDX_GPCR_CSB] = STMPE24XX_REG_GPCR_CSB,
+ [STMPE_IDX_GPCR_MSB] = STMPE24XX_REG_GPCR_MSB,
[STMPE_IDX_GPDR_LSB] = STMPE24XX_REG_GPDR_LSB,
+ [STMPE_IDX_GPDR_CSB] = STMPE24XX_REG_GPDR_CSB,
+ [STMPE_IDX_GPDR_MSB] = STMPE24XX_REG_GPDR_MSB,
[STMPE_IDX_GPRER_LSB] = STMPE24XX_REG_GPRER_LSB,
+ [STMPE_IDX_GPRER_CSB] = STMPE24XX_REG_GPRER_CSB,
+ [STMPE_IDX_GPRER_MSB] = STMPE24XX_REG_GPRER_MSB,
[STMPE_IDX_GPFER_LSB] = STMPE24XX_REG_GPFER_LSB,
+ [STMPE_IDX_GPFER_CSB] = STMPE24XX_REG_GPFER_CSB,
+ [STMPE_IDX_GPFER_MSB] = STMPE24XX_REG_GPFER_MSB,
[STMPE_IDX_GPPUR_LSB] = STMPE24XX_REG_GPPUR_LSB,
[STMPE_IDX_GPPDR_LSB] = STMPE24XX_REG_GPPDR_LSB,
[STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB,
[STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB,
+ [STMPE_IDX_IEGPIOR_CSB] = STMPE24XX_REG_IEGPIOR_CSB,
+ [STMPE_IDX_IEGPIOR_MSB] = STMPE24XX_REG_IEGPIOR_MSB,
[STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB,
+ [STMPE_IDX_GPEDR_LSB] = STMPE24XX_REG_GPEDR_LSB,
+ [STMPE_IDX_GPEDR_CSB] = STMPE24XX_REG_GPEDR_CSB,
[STMPE_IDX_GPEDR_MSB] = STMPE24XX_REG_GPEDR_MSB,
};
@@ -840,7 +949,7 @@ static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks,
if (blocks & STMPE_BLOCK_KEYPAD)
mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC;
- return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask,
+ return __stmpe_set_bits(stmpe, stmpe->regs[STMPE_IDX_SYS_CTRL], mask,
enable ? mask : 0);
}
@@ -893,6 +1002,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
[STMPE610] = &stmpe610,
[STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
+ [STMPE1600] = &stmpe1600,
[STMPE1601] = &stmpe1601,
[STMPE1801] = &stmpe1801,
[STMPE2401] = &stmpe2401,
@@ -919,7 +1029,8 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int ret;
int i;
- if (variant->id_val == STMPE801_ID) {
+ if (variant->id_val == STMPE801_ID ||
+ variant->id_val == STMPE1600_ID) {
int base = irq_create_mapping(stmpe->domain, 0);
handle_nested_irq(base);
@@ -982,7 +1093,7 @@ static void stmpe_irq_sync_unlock(struct irq_data *data)
continue;
stmpe->oldier[i] = new;
- stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new);
+ stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB + i], new);
}
mutex_unlock(&stmpe->irq_lock);
@@ -1088,20 +1199,18 @@ static int stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
- if (id == STMPE1801_ID) {
- ret = stmpe1801_reset(stmpe);
- if (ret < 0)
- return ret;
- }
+ ret = stmpe_reset(stmpe);
+ if (ret < 0)
+ return ret;
if (stmpe->irq >= 0) {
- if (id == STMPE801_ID)
- icr = STMPE801_REG_SYS_CTRL_INT_EN;
+ if (id == STMPE801_ID || id == STMPE1600_ID)
+ icr = STMPE_SYS_CTRL_INT_EN;
else
icr = STMPE_ICR_LSB_GIM;
- /* STMPE801 doesn't support Edge interrupts */
- if (id != STMPE801_ID) {
+ /* STMPE801 and STMPE1600 don't support Edge interrupts */
+ if (id != STMPE801_ID && id != STMPE1600_ID) {
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
@@ -1109,8 +1218,8 @@ static int stmpe_chip_init(struct stmpe *stmpe)
if (irq_trigger == IRQF_TRIGGER_RISING ||
irq_trigger == IRQF_TRIGGER_HIGH) {
- if (id == STMPE801_ID)
- icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+ if (id == STMPE801_ID || id == STMPE1600_ID)
+ icr |= STMPE_SYS_CTRL_INT_HI;
else
icr |= STMPE_ICR_LSB_HIGH;
}
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h
index 84adb46b3e2f..f7efdd8a5fc6 100644
--- a/drivers/mfd/stmpe.h
+++ b/drivers/mfd/stmpe.h
@@ -104,6 +104,10 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE_ICR_LSB_EDGE (1 << 1)
#define STMPE_ICR_LSB_GIM (1 << 0)
+#define STMPE_SYS_CTRL_RESET (1 << 7)
+#define STMPE_SYS_CTRL_INT_EN (1 << 2)
+#define STMPE_SYS_CTRL_INT_HI (1 << 0)
+
/*
* STMPE801
*/
@@ -119,13 +123,10 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE801_REG_GPIO_SET_PIN 0x11
#define STMPE801_REG_GPIO_DIR 0x12
-#define STMPE801_REG_SYS_CTRL_RESET (1 << 7)
-#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2)
-#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0)
-
/*
* STMPE811
*/
+#define STMPE811_ID 0x0811
#define STMPE811_IRQ_TOUCH_DET 0
#define STMPE811_IRQ_FIFO_TH 1
@@ -138,6 +139,7 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE811_NR_INTERNAL_IRQS 8
#define STMPE811_REG_CHIP_ID 0x00
+#define STMPE811_REG_SYS_CTRL 0x03
#define STMPE811_REG_SYS_CTRL2 0x04
#define STMPE811_REG_SPI_CFG 0x08
#define STMPE811_REG_INT_CTRL 0x09
@@ -154,12 +156,35 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE811_REG_GPIO_FE 0x16
#define STMPE811_REG_GPIO_AF 0x17
+#define STMPE811_SYS_CTRL_RESET (1 << 1)
+
#define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0)
#define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1)
#define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2)
#define STMPE811_SYS_CTRL2_TS_OFF (1 << 3)
/*
+ * STMPE1600
+ */
+#define STMPE1600_ID 0x0016
+#define STMPE1600_NR_INTERNAL_IRQS 16
+
+#define STMPE1600_REG_CHIP_ID 0x00
+#define STMPE1600_REG_SYS_CTRL 0x03
+#define STMPE1600_REG_IEGPIOR_LSB 0x08
+#define STMPE1600_REG_IEGPIOR_MSB 0x09
+#define STMPE1600_REG_ISGPIOR_LSB 0x0A
+#define STMPE1600_REG_ISGPIOR_MSB 0x0B
+#define STMPE1600_REG_GPMR_LSB 0x10
+#define STMPE1600_REG_GPMR_MSB 0x11
+#define STMPE1600_REG_GPSR_LSB 0x12
+#define STMPE1600_REG_GPSR_MSB 0x13
+#define STMPE1600_REG_GPDR_LSB 0x14
+#define STMPE1600_REG_GPDR_MSB 0x15
+#define STMPE1600_REG_GPPIR_LSB 0x16
+#define STMPE1600_REG_GPPIR_MSB 0x17
+
+/*
* STMPE1601
*/
@@ -175,19 +200,32 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE1601_REG_SYS_CTRL 0x02
#define STMPE1601_REG_SYS_CTRL2 0x03
+#define STMPE1601_REG_ICR_MSB 0x10
#define STMPE1601_REG_ICR_LSB 0x11
+#define STMPE1601_REG_IER_MSB 0x12
#define STMPE1601_REG_IER_LSB 0x13
#define STMPE1601_REG_ISR_MSB 0x14
-#define STMPE1601_REG_CHIP_ID 0x80
+#define STMPE1601_REG_ISR_LSB 0x15
+#define STMPE1601_REG_INT_EN_GPIO_MASK_MSB 0x16
#define STMPE1601_REG_INT_EN_GPIO_MASK_LSB 0x17
#define STMPE1601_REG_INT_STA_GPIO_MSB 0x18
-#define STMPE1601_REG_GPIO_MP_LSB 0x87
+#define STMPE1601_REG_INT_STA_GPIO_LSB 0x19
+#define STMPE1601_REG_CHIP_ID 0x80
+#define STMPE1601_REG_GPIO_SET_MSB 0x82
#define STMPE1601_REG_GPIO_SET_LSB 0x83
+#define STMPE1601_REG_GPIO_CLR_MSB 0x84
#define STMPE1601_REG_GPIO_CLR_LSB 0x85
+#define STMPE1601_REG_GPIO_MP_MSB 0x86
+#define STMPE1601_REG_GPIO_MP_LSB 0x87
+#define STMPE1601_REG_GPIO_SET_DIR_MSB 0x88
#define STMPE1601_REG_GPIO_SET_DIR_LSB 0x89
#define STMPE1601_REG_GPIO_ED_MSB 0x8A
+#define STMPE1601_REG_GPIO_ED_LSB 0x8B
+#define STMPE1601_REG_GPIO_RE_MSB 0x8C
#define STMPE1601_REG_GPIO_RE_LSB 0x8D
+#define STMPE1601_REG_GPIO_FE_MSB 0x8E
#define STMPE1601_REG_GPIO_FE_LSB 0x8F
+#define STMPE1601_REG_GPIO_PU_MSB 0x90
#define STMPE1601_REG_GPIO_PU_LSB 0x91
#define STMPE1601_REG_GPIO_AF_U_MSB 0x92
@@ -243,8 +281,6 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE1801_REG_GPIO_PULL_UP_MID 0x23
#define STMPE1801_REG_GPIO_PULL_UP_HIGH 0x24
-#define STMPE1801_MSK_SYS_CTRL_RESET (1 << 7)
-
#define STMPE1801_MSK_INT_EN_KPC (1 << 1)
#define STMPE1801_MSK_INT_EN_GPIO (1 << 3)
@@ -264,23 +300,48 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE24XX_NR_INTERNAL_IRQS 9
#define STMPE24XX_REG_SYS_CTRL 0x02
+#define STMPE24XX_REG_SYS_CTRL2 0x03
+#define STMPE24XX_REG_ICR_MSB 0x10
#define STMPE24XX_REG_ICR_LSB 0x11
+#define STMPE24XX_REG_IER_MSB 0x12
#define STMPE24XX_REG_IER_LSB 0x13
#define STMPE24XX_REG_ISR_MSB 0x14
-#define STMPE24XX_REG_CHIP_ID 0x80
+#define STMPE24XX_REG_ISR_LSB 0x15
+#define STMPE24XX_REG_IEGPIOR_MSB 0x16
+#define STMPE24XX_REG_IEGPIOR_CSB 0x17
#define STMPE24XX_REG_IEGPIOR_LSB 0x18
#define STMPE24XX_REG_ISGPIOR_MSB 0x19
-#define STMPE24XX_REG_GPMR_LSB 0xA4
+#define STMPE24XX_REG_ISGPIOR_CSB 0x1A
+#define STMPE24XX_REG_ISGPIOR_LSB 0x1B
+#define STMPE24XX_REG_CHIP_ID 0x80
+#define STMPE24XX_REG_GPSR_MSB 0x83
+#define STMPE24XX_REG_GPSR_CSB 0x84
#define STMPE24XX_REG_GPSR_LSB 0x85
+#define STMPE24XX_REG_GPCR_MSB 0x86
+#define STMPE24XX_REG_GPCR_CSB 0x87
#define STMPE24XX_REG_GPCR_LSB 0x88
+#define STMPE24XX_REG_GPDR_MSB 0x89
+#define STMPE24XX_REG_GPDR_CSB 0x8A
#define STMPE24XX_REG_GPDR_LSB 0x8B
#define STMPE24XX_REG_GPEDR_MSB 0x8C
+#define STMPE24XX_REG_GPEDR_CSB 0x8D
+#define STMPE24XX_REG_GPEDR_LSB 0x8E
+#define STMPE24XX_REG_GPRER_MSB 0x8F
+#define STMPE24XX_REG_GPRER_CSB 0x90
#define STMPE24XX_REG_GPRER_LSB 0x91
+#define STMPE24XX_REG_GPFER_MSB 0x92
+#define STMPE24XX_REG_GPFER_CSB 0x93
#define STMPE24XX_REG_GPFER_LSB 0x94
+#define STMPE24XX_REG_GPPUR_MSB 0x95
+#define STMPE24XX_REG_GPPUR_CSB 0x96
#define STMPE24XX_REG_GPPUR_LSB 0x97
-#define STMPE24XX_REG_GPPDR_LSB 0x9a
+#define STMPE24XX_REG_GPPDR_MSB 0x98
+#define STMPE24XX_REG_GPPDR_CSB 0x99
+#define STMPE24XX_REG_GPPDR_LSB 0x9A
#define STMPE24XX_REG_GPAFR_U_MSB 0x9B
-
+#define STMPE24XX_REG_GPMR_MSB 0xA2
+#define STMPE24XX_REG_GPMR_CSB 0xA3
+#define STMPE24XX_REG_GPMR_LSB 0xA4
#define STMPE24XX_SYS_CTRL_ENABLE_GPIO (1 << 3)
#define STMPE24XX_SYSCON_ENABLE_PWM (1 << 2)
#define STMPE24XX_SYS_CTRL_ENABLE_KPC (1 << 1)
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h
index de748bc7525e..4a827af17e59 100644
--- a/include/linux/mfd/stmpe.h
+++ b/include/linux/mfd/stmpe.h
@@ -26,6 +26,7 @@ enum stmpe_partnum {
STMPE610,
STMPE801,
STMPE811,
+ STMPE1600,
STMPE1601,
STMPE1801,
STMPE2401,
@@ -39,22 +40,42 @@ enum stmpe_partnum {
*/
enum {
STMPE_IDX_CHIP_ID,
+ STMPE_IDX_SYS_CTRL,
+ STMPE_IDX_SYS_CTRL2,
STMPE_IDX_ICR_LSB,
STMPE_IDX_IER_LSB,
+ STMPE_IDX_IER_MSB,
STMPE_IDX_ISR_LSB,
STMPE_IDX_ISR_MSB,
STMPE_IDX_GPMR_LSB,
+ STMPE_IDX_GPMR_CSB,
+ STMPE_IDX_GPMR_MSB,
STMPE_IDX_GPSR_LSB,
+ STMPE_IDX_GPSR_CSB,
+ STMPE_IDX_GPSR_MSB,
STMPE_IDX_GPCR_LSB,
+ STMPE_IDX_GPCR_CSB,
+ STMPE_IDX_GPCR_MSB,
STMPE_IDX_GPDR_LSB,
+ STMPE_IDX_GPDR_CSB,
+ STMPE_IDX_GPDR_MSB,
+ STMPE_IDX_GPEDR_LSB,
+ STMPE_IDX_GPEDR_CSB,
STMPE_IDX_GPEDR_MSB,
STMPE_IDX_GPRER_LSB,
+ STMPE_IDX_GPRER_CSB,
+ STMPE_IDX_GPRER_MSB,
STMPE_IDX_GPFER_LSB,
+ STMPE_IDX_GPFER_CSB,
+ STMPE_IDX_GPFER_MSB,
STMPE_IDX_GPPUR_LSB,
STMPE_IDX_GPPDR_LSB,
STMPE_IDX_GPAFR_U_MSB,
STMPE_IDX_IEGPIOR_LSB,
+ STMPE_IDX_IEGPIOR_CSB,
+ STMPE_IDX_IEGPIOR_MSB,
STMPE_IDX_ISGPIOR_LSB,
+ STMPE_IDX_ISGPIOR_CSB,
STMPE_IDX_ISGPIOR_MSB,
STMPE_IDX_MAX,
};
diff --git a/include/linux/platform_data/gpio-lpc32xx.h b/include/linux/platform_data/gpio-lpc32xx.h
deleted file mode 100644
index a544e962a818..000000000000
--- a/include/linux/platform_data/gpio-lpc32xx.h
+++ /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 */