summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-06-19 16:07:07 +0200
committerHerbert Xu <herbert@gondor.apana.org.au>2015-06-19 16:07:07 +0200
commitc0b59fafe31bf91f589736be304d739b13952fdd (patch)
tree0088a41c6b68132739294643be06734e3af67677 /drivers/gpio
parentMAINTAINERS: clarify drivers/crypto/nx/ file ownership (diff)
parentbus: mvebu-mbus: add mv_mbus_dram_info_nooverlap() (diff)
downloadlinux-c0b59fafe31bf91f589736be304d739b13952fdd.tar.xz
linux-c0b59fafe31bf91f589736be304d739b13952fdd.zip
Merge branch 'mvebu/drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Merge the mvebu/drivers branch of the arm-soc tree which contains just a single patch bfa1ce5f38938cc9e6c7f2d1011f88eba2b9e2b2 ("bus: mvebu-mbus: add mv_mbus_dram_info_nooverlap()") that happens to be a prerequisite of the new marvell/cesa crypto driver.
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig732
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/devres.c107
-rw-r--r--drivers/gpio/gpio-adp5588.c8
-rw-r--r--drivers/gpio/gpio-altera.c374
-rw-r--r--drivers/gpio/gpio-arizona.c3
-rw-r--r--drivers/gpio/gpio-crystalcove.c7
-rw-r--r--drivers/gpio/gpio-da9052.c2
-rw-r--r--drivers/gpio/gpio-da9055.c2
-rw-r--r--drivers/gpio/gpio-f7188x.c47
-rw-r--r--drivers/gpio/gpio-ich.c6
-rw-r--r--drivers/gpio/gpio-kempld.c2
-rw-r--r--drivers/gpio/gpio-loongson.c115
-rw-r--r--drivers/gpio/gpio-max7300.c4
-rw-r--r--drivers/gpio/gpio-max732x.c134
-rw-r--r--drivers/gpio/gpio-mb86s7x.c5
-rw-r--r--drivers/gpio/gpio-mc33880.c2
-rw-r--r--drivers/gpio/gpio-mcp23s08.c9
-rw-r--r--drivers/gpio/gpio-msm-v1.c714
-rw-r--r--drivers/gpio/gpio-mvebu.c24
-rw-r--r--drivers/gpio/gpio-omap.c131
-rw-r--r--drivers/gpio/gpio-pcf857x.c134
-rw-r--r--drivers/gpio/gpio-pxa.c3
-rw-r--r--drivers/gpio/gpio-rcar.c63
-rw-r--r--drivers/gpio/gpio-tb10x.c2
-rw-r--r--drivers/gpio/gpio-vf610.c16
-rw-r--r--drivers/gpio/gpio-xgene-sb.c2
-rw-r--r--drivers/gpio/gpiolib-acpi.c86
-rw-r--r--drivers/gpio/gpiolib-of.c111
-rw-r--r--drivers/gpio/gpiolib.c299
-rw-r--r--drivers/gpio/gpiolib.h13
31 files changed, 1740 insertions, 1420 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index dc1aaa83a347..caefe806db5e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -90,27 +90,11 @@ config GPIO_GENERIC
# put drivers in the right section, in alphabetical order
-config GPIO_DA9052
- tristate "Dialog DA9052 GPIO"
- depends on PMIC_DA9052
- help
- Say yes here to enable the GPIO driver for the DA9052 chip.
-
-config GPIO_DA9055
- tristate "Dialog Semiconductor DA9055 GPIO"
- depends on MFD_DA9055
- help
- Say yes here to enable the GPIO driver for the DA9055 chip.
-
- The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
- be controller by this driver.
-
- If driver is built as a module it will be called gpio-da9055.
-
+# This symbol is selected by both I2C and SPI expanders
config GPIO_MAX730X
tristate
-comment "Memory mapped GPIO drivers:"
+menu "Memory mapped GPIO drivers"
config GPIO_74XX_MMIO
tristate "GPIO driver for 74xx-ICs with MMIO access"
@@ -126,6 +110,22 @@ config GPIO_74XX_MMIO
8 bits: 74244 (Input), 74273 (Output)
16 bits: 741624 (Input), 7416374 (Output)
+config GPIO_ALTERA
+ tristate "Altera GPIO"
+ depends on OF_GPIO
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y or M here to build support for the Altera PIO device.
+
+ If driver is built as a module it will be called gpio-altera.
+
+config GPIO_BCM_KONA
+ bool "Broadcom Kona GPIO"
+ depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
+ help
+ Turn on GPIO support for Broadcom "Kona" chips.
+
config GPIO_CLPS711X
tristate "CLPS711X GPIO support"
depends on ARCH_CLPS711X || COMPILE_TEST
@@ -140,28 +140,14 @@ config GPIO_DAVINCI
help
Say yes here to enable GPIO support for TI Davinci/Keystone SoCs.
-config GPIO_GENERIC_PLATFORM
- tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
- select GPIO_GENERIC
- help
- Say yes here to support basic platform_device memory-mapped GPIO controllers.
-
config GPIO_DWAPB
tristate "Synopsys DesignWare APB GPIO driver"
- depends on ARM
- depends on OF_GPIO
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
help
Say Y or M here to build support for the Synopsys DesignWare APB
GPIO block.
-config GPIO_IT8761E
- tristate "IT8761E GPIO support"
- depends on X86 # unconditional access to IO space.
- help
- Say yes here to support GPIO functionality of IT8761E super I/O chip.
-
config GPIO_EM
tristate "Emma Mobile GPIO"
depends on ARM && OF_GPIO
@@ -173,36 +159,99 @@ config GPIO_EP93XX
depends on ARCH_EP93XX
select GPIO_GENERIC
-config GPIO_ZEVIO
- bool "LSI ZEVIO SoC memory mapped GPIOs"
- depends on ARM && OF_GPIO
- help
- Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
-
-config GPIO_MM_LANTIQ
- bool "Lantiq Memory mapped GPIOs"
- depends on LANTIQ && SOC_XWAY
- help
- This enables support for memory mapped GPIOs on the External Bus Unit
- (EBU) found on Lantiq SoCs. The gpios are output only as they are
- created by attaching a 16bit latch to the bus.
-
config GPIO_F7188X
- tristate "F71882FG and F71889F GPIO support"
+ tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
depends on X86
help
This option enables support for GPIOs found on Fintek Super-I/O
- chips F71882FG and F71889F.
+ chips F71869, F71869A, F71882FG and F71889F.
To compile this driver as a module, choose M here: the module will
be called f7188x-gpio.
+config GPIO_GE_FPGA
+ bool "GE FPGA based GPIO"
+ depends on GE_FPGA
+ select GPIO_GENERIC
+ help
+ Support for common GPIO functionality provided on some GE Single Board
+ Computers.
+
+ This driver provides basic support (configure as input or output, read
+ and write pin state) for GPIO implemented in a number of GE single
+ board computers.
+
+config GPIO_GENERIC_PLATFORM
+ tristate "Generic memory-mapped GPIO controller support (MMIO platform device)"
+ select GPIO_GENERIC
+ help
+ Say yes here to support basic platform_device memory-mapped GPIO controllers.
+
+config GPIO_GRGPIO
+ tristate "Aeroflex Gaisler GRGPIO support"
+ depends on OF
+ select GPIO_GENERIC
+ select IRQ_DOMAIN
+ help
+ Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
+ VHDL IP core library.
+
+config GPIO_ICH
+ tristate "Intel ICH GPIO"
+ depends on PCI && X86
+ select MFD_CORE
+ select LPC_ICH
+ help
+ Say yes here to support the GPIO functionality of a number of Intel
+ ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8
+ ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg
+ Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake).
+
+ If unsure, say N.
+
+config GPIO_IOP
+ tristate "Intel IOP GPIO"
+ depends on ARM && (ARCH_IOP32X || ARCH_IOP33X)
+ help
+ Say yes here to support the GPIO functionality of a number of Intel
+ IOP32X or IOP33X.
+
+ If unsure, say N.
+
+config GPIO_IT8761E
+ tristate "IT8761E GPIO support"
+ depends on X86 # unconditional access to IO space.
+ help
+ Say yes here to support GPIO functionality of IT8761E super I/O chip.
+
+config GPIO_LOONGSON
+ bool "Loongson-2/3 GPIO support"
+ depends on CPU_LOONGSON2 || CPU_LOONGSON3
+ help
+ driver for GPIO functionality on Loongson-2F/3A/3B processors.
+
+config GPIO_LYNXPOINT
+ tristate "Intel Lynxpoint GPIO support"
+ depends on ACPI && X86
+ select GPIOLIB_IRQCHIP
+ help
+ driver for GPIO functionality on Intel Lynxpoint PCH chipset
+ Requires ACPI device enumeration code to set up a platform device.
+
config GPIO_MB86S7X
bool "GPIO support for Fujitsu MB86S7x Platforms"
depends on ARCH_MB86S7X
help
Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs.
+config GPIO_MM_LANTIQ
+ bool "Lantiq Memory mapped GPIOs"
+ depends on LANTIQ && SOC_XWAY
+ help
+ This enables support for memory mapped GPIOs on the External Bus Unit
+ (EBU) found on Lantiq SoCs. The gpios are output only as they are
+ created by attaching a 16bit latch to the bus.
+
config GPIO_MOXART
bool "MOXART GPIO support"
depends on ARCH_MOXART
@@ -223,14 +272,6 @@ config GPIO_MPC8XXX
Say Y here if you're going to use hardware that connects to the
MPC512x/831x/834x/837x/8572/8610 GPIOs.
-config GPIO_MSM_V1
- tristate "Qualcomm MSM GPIO v1"
- depends on GPIOLIB && ARCH_MSM && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
- help
- Say yes here to support the GPIO interface on ARM v6 based
- Qualcomm MSM chips. Most of the pins on the MSM can be
- selected for GPIO, and are controlled by this driver.
-
config GPIO_MSM_V2
tristate "Qualcomm MSM GPIO v2"
depends on GPIOLIB && OF && ARCH_QCOM
@@ -303,6 +344,33 @@ config GPIO_SAMSUNG
Legacy GPIO support. Use only for platforms without support for
pinctrl.
+config GPIO_SCH
+ tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
+ depends on PCI && X86
+ select MFD_CORE
+ select LPC_SCH
+ help
+ Say yes here to support GPIO interface on Intel Poulsbo SCH,
+ Intel Tunnel Creek processor, Intel Centerton processor or
+ Intel Quark X1000 SoC.
+
+ The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
+ powered by the core power rail and are turned off during sleep
+ modes (S3 and higher). The remaining four GPIOs are powered by
+ the Intel SCH suspend power supply. These GPIOs remain
+ active during S3. The suspend powered GPIOs can be used to wake the
+ system from the Suspend-to-RAM state.
+
+ The Intel Tunnel Creek processor has 5 GPIOs powered by the
+ core power rail and 9 from suspend power supply.
+
+ The Intel Centerton processor has a total of 30 GPIO pins.
+ Twenty-one are powered by the core power rail and 9 from the
+ suspend power supply.
+
+ The Intel Quark X1000 SoC has 2 GPIOs powered by the core
+ power well and 6 from the suspend power well.
+
config GPIO_SCH311X
tristate "SMSC SCH311x SuperI/O GPIO"
help
@@ -327,12 +395,27 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_STP_XWAY
+ bool "XWAY STP GPIOs"
+ depends on SOC_XWAY
+ help
+ This enables support for the Serial To Parallel (STP) unit found on
+ XWAY SoC. The STP allows the SoC to drive a shift registers cascade,
+ that can be up to 24 bit. This peripheral is aimed at driving leds.
+ Some of the gpios/leds can be auto updated by the soc with dsl and
+ phy status.
+
config GPIO_SYSCON
tristate "GPIO based on SYSCON"
depends on MFD_SYSCON && OF
help
Say yes here to support GPIO functionality though SYSCON driver.
+config GPIO_TB10X
+ bool
+ select GENERIC_IRQ_CHIP
+ select OF_GPIO
+
config GPIO_TS5500
tristate "TS-5500 DIO blocks and compatibles"
depends on TS5500 || COMPILE_TEST
@@ -364,6 +447,24 @@ config GPIO_VF610
help
Say yes here to support Vybrid vf610 GPIOs.
+config GPIO_VR41XX
+ tristate "NEC VR4100 series General-purpose I/O Uint support"
+ depends on CPU_VR41XX
+ help
+ Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
+config GPIO_VX855
+ tristate "VIA VX855/VX875 GPIO"
+ depends on PCI
+ select MFD_CORE
+ select MFD_VX855
+ help
+ Support access to the VX855/VX875 GPIO lines through the gpio library.
+
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config GPIO_XGENE
bool "APM X-Gene GPIO controller support"
depends on ARM64 && OF_GPIO
@@ -387,13 +488,6 @@ config GPIO_XILINX
help
Say yes here to support the Xilinx FPGA GPIO device
-config GPIO_ZYNQ
- tristate "Xilinx Zynq GPIO support"
- depends on ARCH_ZYNQ
- select GPIOLIB_IRQCHIP
- help
- Say yes here to support Xilinx Zynq GPIO controller.
-
config GPIO_XTENSA
bool "Xtensa GPIO32 support"
depends on XTENSA
@@ -403,135 +497,49 @@ config GPIO_XTENSA
Say yes here to support the Xtensa internal GPIO32 IMPWIRE (input)
and EXPSTATE (output) ports
-config GPIO_VR41XX
- tristate "NEC VR4100 series General-purpose I/O Uint support"
- depends on CPU_VR41XX
- help
- Say yes here to support the NEC VR4100 series General-purpose I/O Uint
-
-config GPIO_SCH
- tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
- depends on PCI && X86
- select MFD_CORE
- select LPC_SCH
- help
- Say yes here to support GPIO interface on Intel Poulsbo SCH,
- Intel Tunnel Creek processor, Intel Centerton processor or
- Intel Quark X1000 SoC.
-
- The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
- powered by the core power rail and are turned off during sleep
- modes (S3 and higher). The remaining four GPIOs are powered by
- the Intel SCH suspend power supply. These GPIOs remain
- active during S3. The suspend powered GPIOs can be used to wake the
- system from the Suspend-to-RAM state.
-
- The Intel Tunnel Creek processor has 5 GPIOs powered by the
- core power rail and 9 from suspend power supply.
-
- The Intel Centerton processor has a total of 30 GPIO pins.
- Twenty-one are powered by the core power rail and 9 from the
- suspend power supply.
-
- The Intel Quark X1000 SoC has 2 GPIOs powered by the core
- power well and 6 from the suspend power well.
-
-config GPIO_ICH
- tristate "Intel ICH GPIO"
- depends on PCI && X86
- select MFD_CORE
- select LPC_ICH
- help
- Say yes here to support the GPIO functionality of a number of Intel
- ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8
- ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg
- Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake).
-
- If unsure, say N.
-
-config GPIO_IOP
- tristate "Intel IOP GPIO"
- depends on ARM && (ARCH_IOP32X || ARCH_IOP33X)
- help
- Say yes here to support the GPIO functionality of a number of Intel
- IOP32X or IOP33X.
-
- If unsure, say N.
-
-config GPIO_VX855
- tristate "VIA VX855/VX875 GPIO"
- depends on PCI
- select MFD_CORE
- select MFD_VX855
- help
- Support access to the VX855/VX875 GPIO lines through the gpio library.
-
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
-
-config GPIO_GE_FPGA
- bool "GE FPGA based GPIO"
- depends on GE_FPGA
- select GPIO_GENERIC
+config GPIO_ZEVIO
+ bool "LSI ZEVIO SoC memory mapped GPIOs"
+ depends on ARM && OF_GPIO
help
- Support for common GPIO functionality provided on some GE Single Board
- Computers.
-
- This driver provides basic support (configure as input or output, read
- and write pin state) for GPIO implemented in a number of GE single
- board computers.
+ Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
-config GPIO_LYNXPOINT
- tristate "Intel Lynxpoint GPIO support"
- depends on ACPI && X86
+config GPIO_ZYNQ
+ tristate "Xilinx Zynq GPIO support"
+ depends on ARCH_ZYNQ
select GPIOLIB_IRQCHIP
help
- driver for GPIO functionality on Intel Lynxpoint PCH chipset
- Requires ACPI device enumeration code to set up a platform device.
-
-config GPIO_GRGPIO
- tristate "Aeroflex Gaisler GRGPIO support"
- depends on OF
- select GPIO_GENERIC
- select IRQ_DOMAIN
- help
- Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
- VHDL IP core library.
+ Say yes here to support Xilinx Zynq GPIO controller.
-config GPIO_TB10X
- bool
- select GENERIC_IRQ_CHIP
- select OF_GPIO
+endmenu
-comment "I2C GPIO expanders:"
+menu "I2C GPIO expanders"
+ depends on I2C
-config GPIO_ARIZONA
- tristate "Wolfson Microelectronics Arizona class devices"
- depends on MFD_ARIZONA
+config GPIO_ADP5588
+ tristate "ADP5588 I2C GPIO expander"
+ depends on I2C
help
- Support for GPIOs on Wolfson Arizona class devices.
+ This option enables support for 18 GPIOs found
+ on Analog Devices ADP5588 GPIO Expanders.
-config GPIO_CRYSTAL_COVE
- tristate "GPIO support for Crystal Cove PMIC"
- depends on INTEL_SOC_PMIC
- select GPIOLIB_IRQCHIP
+config GPIO_ADP5588_IRQ
+ bool "Interrupt controller support for ADP5588"
+ depends on GPIO_ADP5588=y
help
- Support for GPIO pins on Crystal Cove PMIC.
-
- Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC
- inside.
-
- This driver can also be built as a module. If so, the module will be
- called gpio-crystalcove.
+ Say yes here to enable the adp5588 to be used as an interrupt
+ controller. It requires the driver to be built in the kernel.
-config GPIO_LP3943
- tristate "TI/National Semiconductor LP3943 GPIO expander"
- depends on MFD_LP3943
+config GPIO_ADNP
+ tristate "Avionic Design N-bit GPIO expander"
+ depends on I2C && OF_GPIO
+ select GPIOLIB_IRQCHIP
help
- GPIO driver for LP3943 MFD.
- LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.
- Open drain outputs are required for this usage.
+ This option enables support for N GPIOs found on Avionic Design
+ I2C GPIO expanders. The register space will be extended by powers
+ of two, so the controller will need to accommodate for that. For
+ example: if a controller provides 48 pins, 6 registers will be
+ enough to represent all pins, but the driver will assume a
+ register layout for 64 pins (8 registers).
config GPIO_MAX7300
tristate "Maxim MAX7300 GPIO expander"
@@ -543,7 +551,6 @@ config GPIO_MAX7300
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
depends on I2C
- select IRQ_DOMAIN
help
Say yes here to support the MAX7319, MAX7320-7327 series of I2C
Port Expanders. Each IO port on these chips has a fixed role of
@@ -563,6 +570,7 @@ config GPIO_MAX732X
config GPIO_MAX732X_IRQ
bool "Interrupt controller support for MAX732x"
depends on GPIO_MAX732X=y
+ select GPIOLIB_IRQCHIP
help
Say yes here to enable the max732x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
@@ -604,6 +612,7 @@ config GPIO_PCA953X_IRQ
config GPIO_PCF857X
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
depends on I2C
+ select GPIOLIB_IRQCHIP
select IRQ_DOMAIN
help
Say yes here to provide access to most "quasi-bidirectional" I2C
@@ -626,15 +635,6 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls.
-config GPIO_RC5T583
- bool "RICOH RC5T583 GPIO"
- depends on MFD_RC5T583
- help
- Select this option to enable GPIO driver for the Ricoh RC5T583
- chip family.
- This driver provides the support for driving/reading the gpio pins
- of RC5T583 device through standard gpio library.
-
config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander"
depends on I2C=y
@@ -647,6 +647,124 @@ config GPIO_SX150X
8 bits: sx1508q
16 bits: sx1509q
+endmenu
+
+menu "MFD GPIO expanders"
+
+config GPIO_ADP5520
+ tristate "GPIO Support for ADP5520 PMIC"
+ depends on PMIC_ADP5520
+ help
+ This option enables support for on-chip GPIO found
+ on Analog Devices ADP5520 PMICs.
+
+config GPIO_ARIZONA
+ tristate "Wolfson Microelectronics Arizona class devices"
+ depends on MFD_ARIZONA
+ help
+ Support for GPIOs on Wolfson Arizona class devices.
+
+config GPIO_CRYSTAL_COVE
+ tristate "GPIO support for Crystal Cove PMIC"
+ depends on INTEL_SOC_PMIC
+ select GPIOLIB_IRQCHIP
+ help
+ Support for GPIO pins on Crystal Cove PMIC.
+
+ Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC
+ inside.
+
+ This driver can also be built as a module. If so, the module will be
+ called gpio-crystalcove.
+
+config GPIO_CS5535
+ tristate "AMD CS5535/CS5536 GPIO support"
+ depends on MFD_CS5535
+ help
+ The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
+ can be used for quite a number of things. The CS5535/6 is found on
+ AMD Geode and Lemote Yeeloong devices.
+
+ If unsure, say N.
+
+config GPIO_DA9052
+ tristate "Dialog DA9052 GPIO"
+ depends on PMIC_DA9052
+ help
+ Say yes here to enable the GPIO driver for the DA9052 chip.
+
+config GPIO_DA9055
+ tristate "Dialog Semiconductor DA9055 GPIO"
+ depends on MFD_DA9055
+ help
+ Say yes here to enable the GPIO driver for the DA9055 chip.
+
+ The Dialog DA9055 PMIC chip has 3 GPIO pins that can be
+ be controller by this driver.
+
+ If driver is built as a module it will be called gpio-da9055.
+
+config GPIO_DLN2
+ tristate "Diolan DLN2 GPIO support"
+ depends on MFD_DLN2
+ select GPIOLIB_IRQCHIP
+
+ help
+ Select this option to enable GPIO driver for the Diolan DLN2
+ board.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-dln2.
+
+config GPIO_JANZ_TTL
+ tristate "Janz VMOD-TTL Digital IO Module"
+ depends on MFD_JANZ_CMODIO
+ help
+ This enables support for the Janz VMOD-TTL Digital IO module.
+ This driver provides support for driving the pins in output
+ mode only. Input mode is not supported.
+
+config GPIO_KEMPLD
+ tristate "Kontron ETX / COMexpress GPIO"
+ depends on MFD_KEMPLD
+ help
+ This enables support for the PLD GPIO interface on some Kontron ETX
+ and COMexpress (ETXexpress) modules.
+
+ This driver can also be built as a module. If so, the module will be
+ called gpio-kempld.
+
+config GPIO_LP3943
+ tristate "TI/National Semiconductor LP3943 GPIO expander"
+ depends on MFD_LP3943
+ help
+ GPIO driver for LP3943 MFD.
+ LP3943 can be used as a GPIO expander which provides up to 16 GPIOs.
+ Open drain outputs are required for this usage.
+
+config GPIO_MSIC
+ bool "Intel MSIC mixed signal gpio support"
+ depends on MFD_INTEL_MSIC
+ help
+ Enable support for GPIO on intel MSIC controllers found in
+ intel MID devices
+
+config GPIO_PALMAS
+ bool "TI PALMAS series PMICs GPIO"
+ depends on MFD_PALMAS
+ help
+ Select this option to enable GPIO driver for the TI PALMAS
+ series chip family.
+
+config GPIO_RC5T583
+ bool "RICOH RC5T583 GPIO"
+ depends on MFD_RC5T583
+ help
+ Select this option to enable GPIO driver for the Ricoh RC5T583
+ chip family.
+ This driver provides the support for driving/reading the gpio pins
+ of RC5T583 device through standard gpio library.
+
config GPIO_STMPE
bool "STMPE GPIOs"
depends on MFD_STMPE
@@ -656,16 +774,6 @@ config GPIO_STMPE
This enables support for the GPIOs found on the STMPE I/O
Expanders.
-config GPIO_STP_XWAY
- bool "XWAY STP GPIOs"
- depends on SOC_XWAY
- help
- This enables support for the Serial To Parallel (STP) unit found on
- XWAY SoC. The STP allows the SoC to drive a shift registers cascade,
- that can be up to 24 bit. This peripheral is aimed at driving leds.
- Some of the gpios/leds can be auto updated by the soc with dsl and
- phy status.
-
config GPIO_TC3589X
bool "TC3589X GPIOs"
depends on MFD_TC3589X
@@ -675,6 +783,26 @@ config GPIO_TC3589X
This enables support for the GPIOs found on the TC3589X
I/O Expander.
+config GPIO_TIMBERDALE
+ bool "Support for timberdale GPIO IP"
+ depends on MFD_TIMBERDALE
+ ---help---
+ Add support for the GPIO IP in the timberdale FPGA.
+
+config GPIO_TPS6586X
+ bool "TPS6586X GPIO"
+ depends on MFD_TPS6586X
+ help
+ Select this option to enable GPIO driver for the TPS6586X
+ chip family.
+
+config GPIO_TPS65910
+ bool "TPS65910 GPIO"
+ depends on MFD_TPS65910
+ help
+ Select this option to enable GPIO driver for the TPS65910
+ chip family.
+
config GPIO_TPS65912
tristate "TI TPS65912 GPIO"
depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
@@ -695,6 +823,13 @@ config GPIO_TWL6040
Say yes here to access the GPO signals of twl6040
audio chip from Texas Instruments.
+config GPIO_UCB1400
+ tristate "Philips UCB1400 GPIO"
+ depends on UCB1400_CORE
+ help
+ This enables support for the Philips UCB1400 GPIO pins.
+ The UCB1400 is an AC97 audio codec.
+
config GPIO_WM831X
tristate "WM831x GPIOs"
depends on MFD_WM831X
@@ -716,50 +851,22 @@ config GPIO_WM8994
Say yes here to access the GPIO signals of WM8994 audio hub
CODECs from Wolfson Microelectronics.
-config GPIO_ADP5520
- tristate "GPIO Support for ADP5520 PMIC"
- depends on PMIC_ADP5520
- help
- This option enables support for on-chip GPIO found
- on Analog Devices ADP5520 PMICs.
+endmenu
-config GPIO_ADP5588
- tristate "ADP5588 I2C GPIO expander"
- depends on I2C
- help
- This option enables support for 18 GPIOs found
- on Analog Devices ADP5588 GPIO Expanders.
-
-config GPIO_ADP5588_IRQ
- bool "Interrupt controller support for ADP5588"
- depends on GPIO_ADP5588=y
- help
- Say yes here to enable the adp5588 to be used as an interrupt
- controller. It requires the driver to be built in the kernel.
+menu "PCI GPIO expanders"
+ depends on PCI
-config GPIO_ADNP
- tristate "Avionic Design N-bit GPIO expander"
- depends on I2C && OF_GPIO
- select GPIOLIB_IRQCHIP
+config GPIO_AMD8111
+ tristate "AMD 8111 GPIO driver"
+ depends on PCI
help
- This option enables support for N GPIOs found on Avionic Design
- I2C GPIO expanders. The register space will be extended by powers
- of two, so the controller will need to accommodate for that. For
- example: if a controller provides 48 pins, 6 registers will be
- enough to represent all pins, but the driver will assume a
- register layout for 64 pins (8 registers).
-
-comment "PCI GPIO expanders:"
+ The AMD 8111 south bridge contains 32 GPIO pins which can be used.
-config GPIO_CS5535
- tristate "AMD CS5535/CS5536 GPIO support"
- depends on MFD_CS5535
- help
- The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
- can be used for quite a number of things. The CS5535/6 is found on
- AMD Geode and Lemote Yeeloong devices.
+ Note, that usually system firmware/ACPI handles GPIO pins on their
+ own and users might easily break their systems with uncarefull usage
+ of this driver!
- If unsure, say N.
+ If unsure, say N
config GPIO_BT8XX
tristate "BT8XX GPIO abuser"
@@ -777,18 +884,6 @@ config GPIO_BT8XX
If unsure, say N.
-config GPIO_AMD8111
- tristate "AMD 8111 GPIO driver"
- depends on PCI
- help
- The AMD 8111 south bridge contains 32 GPIO pins which can be used.
-
- Note, that usually system firmware/ACPI handles GPIO pins on their
- own and users might easily break their systems with uncarefull usage
- of this driver!
-
- If unsure, say N
-
config GPIO_INTEL_MID
bool "Intel Mid GPIO support"
depends on PCI && X86
@@ -796,6 +891,16 @@ config GPIO_INTEL_MID
help
Say Y here to support Intel Mid GPIO.
+config GPIO_ML_IOH
+ tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
+ depends on PCI
+ select GENERIC_IRQ_CHIP
+ help
+ ML7213 is companion chip for Intel Atom E6xx series.
+ This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
+ Hub) which is for IVI(In-Vehicle Infotainment) use.
+ This driver can access the IOH's GPIO device.
+
config GPIO_PCH
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
depends on PCI && (X86_32 || COMPILE_TEST)
@@ -812,15 +917,14 @@ config GPIO_PCH
ML7223/ML7831 is companion chip for Intel Atom E6xx series.
ML7223/ML7831 is completely compatible for Intel EG20T PCH.
-config GPIO_ML_IOH
- tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
+config GPIO_RDC321X
+ tristate "RDC R-321x GPIO support"
depends on PCI
- select GENERIC_IRQ_CHIP
+ select MFD_CORE
+ select MFD_RDC321X
help
- ML7213 is companion chip for Intel Atom E6xx series.
- This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
- Hub) which is for IVI(In-Vehicle Infotainment) use.
- This driver can access the IOH's GPIO device.
+ Support for the RDC R321x SoC GPIOs over southbridge
+ PCI configuration space.
config GPIO_SODAVILLE
bool "Intel Sodaville GPIO support"
@@ -830,22 +934,18 @@ config GPIO_SODAVILLE
help
Say Y here to support Intel Sodaville GPIO.
-config GPIO_TIMBERDALE
- bool "Support for timberdale GPIO IP"
- depends on MFD_TIMBERDALE
- ---help---
- Add support for the GPIO IP in the timberdale FPGA.
+endmenu
-config GPIO_RDC321X
- tristate "RDC R-321x GPIO support"
- depends on PCI
- select MFD_CORE
- select MFD_RDC321X
- help
- Support for the RDC R321x SoC GPIOs over southbridge
- PCI configuration space.
+menu "SPI GPIO expanders"
+ depends on SPI_MASTER
-comment "SPI GPIO expanders:"
+config GPIO_74X164
+ tristate "74x164 serial-in/parallel-out 8-bits shift register"
+ depends on SPI_MASTER && OF
+ help
+ Driver for 74x164 compatible serial-in/parallel-out 8-outputs
+ shift registers. This driver can be used to provide access
+ to more gpio outputs.
config GPIO_MAX7301
tristate "Maxim MAX7301 GPIO expander"
@@ -870,80 +970,10 @@ config GPIO_MC33880
SPI driver for Freescale MC33880 high-side/low-side switch.
This provides GPIO interface supporting inputs and outputs.
-config GPIO_74X164
- tristate "74x164 serial-in/parallel-out 8-bits shift register"
- depends on SPI_MASTER && OF
- help
- Driver for 74x164 compatible serial-in/parallel-out 8-outputs
- shift registers. This driver can be used to provide access
- to more gpio outputs.
-
-comment "AC97 GPIO expanders:"
-
-config GPIO_UCB1400
- tristate "Philips UCB1400 GPIO"
- depends on UCB1400_CORE
- help
- This enables support for the Philips UCB1400 GPIO pins.
- The UCB1400 is an AC97 audio codec.
-
-comment "LPC GPIO expanders:"
-
-config GPIO_KEMPLD
- tristate "Kontron ETX / COMexpress GPIO"
- depends on MFD_KEMPLD
- help
- This enables support for the PLD GPIO interface on some Kontron ETX
- and COMexpress (ETXexpress) modules.
-
- This driver can also be built as a module. If so, the module will be
- called gpio-kempld.
-
-comment "MODULbus GPIO expanders:"
-
-config GPIO_JANZ_TTL
- tristate "Janz VMOD-TTL Digital IO Module"
- depends on MFD_JANZ_CMODIO
- help
- This enables support for the Janz VMOD-TTL Digital IO module.
- This driver provides support for driving the pins in output
- mode only. Input mode is not supported.
-
-config GPIO_PALMAS
- bool "TI PALMAS series PMICs GPIO"
- depends on MFD_PALMAS
- help
- Select this option to enable GPIO driver for the TI PALMAS
- series chip family.
-
-config GPIO_TPS6586X
- bool "TPS6586X GPIO"
- depends on MFD_TPS6586X
- help
- Select this option to enable GPIO driver for the TPS6586X
- chip family.
+endmenu
-config GPIO_TPS65910
- bool "TPS65910 GPIO"
- depends on MFD_TPS65910
- help
- Select this option to enable GPIO driver for the TPS65910
- chip family.
-
-config GPIO_MSIC
- bool "Intel MSIC mixed signal gpio support"
- depends on MFD_INTEL_MSIC
- help
- Enable support for GPIO on intel MSIC controllers found in
- intel MID devices
-
-config GPIO_BCM_KONA
- bool "Broadcom Kona GPIO"
- depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
- help
- Turn on GPIO support for Broadcom "Kona" chips.
-
-comment "USB GPIO expanders:"
+menu "USB GPIO expanders"
+ depends on USB
config GPIO_VIPERBOARD
tristate "Viperboard GPIO a & b support"
@@ -956,16 +986,6 @@ config GPIO_VIPERBOARD
River Tech's viperboard.h for detailed meaning
of the module parameters.
-config GPIO_DLN2
- tristate "Diolan DLN2 GPIO support"
- depends on MFD_DLN2
- select GPIOLIB_IRQCHIP
-
- help
- Select this option to enable GPIO driver for the Diolan DLN2
- board.
-
- This driver can also be built as a module. If so, the module
- will be called gpio-dln2.
+endmenu
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index bdda6a94d2cd..f71bb971329c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
+obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
+obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
@@ -58,7 +60,6 @@ obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
-obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 13dbd3dfc33a..07ba82317ece 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -35,6 +35,20 @@ static int devm_gpiod_match(struct device *dev, void *res, void *data)
return *this == *gpio;
}
+static void devm_gpiod_release_array(struct device *dev, void *res)
+{
+ struct gpio_descs **descs = res;
+
+ gpiod_put_array(*descs);
+}
+
+static int devm_gpiod_match_array(struct device *dev, void *res, void *data)
+{
+ struct gpio_descs **this = res, **gpios = data;
+
+ return *this == *gpios;
+}
+
/**
* devm_gpiod_get - Resource-managed gpiod_get()
* @dev: GPIO consumer
@@ -111,23 +125,39 @@ EXPORT_SYMBOL(__devm_gpiod_get_index);
/**
* devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
* @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
* @child: firmware node (child of @dev)
*
* GPIO descriptors returned from this function are automatically disposed on
* driver detach.
*/
struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ const char *con_id,
struct fwnode_handle *child)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ char prop_name[32]; /* 32 is max size of property name */
struct gpio_desc **dr;
struct gpio_desc *desc;
+ unsigned int i;
dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
GFP_KERNEL);
if (!dr)
return ERR_PTR(-ENOMEM);
- desc = fwnode_get_named_gpiod(child, "gpios");
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id)
+ snprintf(prop_name, sizeof(prop_name), "%s-%s",
+ con_id, suffixes[i]);
+ else
+ snprintf(prop_name, sizeof(prop_name), "%s",
+ suffixes[i]);
+
+ desc = fwnode_get_named_gpiod(child, prop_name);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
if (IS_ERR(desc)) {
devres_free(dr);
return desc;
@@ -170,6 +200,66 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de
EXPORT_SYMBOL(__devm_gpiod_get_index_optional);
/**
+ * devm_gpiod_get_array - Resource-managed gpiod_get_array()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_array(). GPIO descriptors returned from this function are
+ * automatically disposed on driver detach. See gpiod_get_array() for detailed
+ * information about behavior and return values.
+ */
+struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs **dr;
+ struct gpio_descs *descs;
+
+ dr = devres_alloc(devm_gpiod_release_array,
+ sizeof(struct gpio_descs *), GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ descs = gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs)) {
+ devres_free(dr);
+ return descs;
+ }
+
+ *dr = descs;
+ devres_add(dev, dr);
+
+ return descs;
+}
+EXPORT_SYMBOL(devm_gpiod_get_array);
+
+/**
+ * devm_gpiod_get_array_optional - Resource-managed gpiod_get_array_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * Managed gpiod_get_array_optional(). GPIO descriptors returned from this
+ * function are automatically disposed on driver detach.
+ * See gpiod_get_array_optional() for detailed information about behavior and
+ * return values.
+ */
+struct gpio_descs *__must_check
+devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs *descs;
+
+ descs = devm_gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT))
+ return NULL;
+
+ return descs;
+}
+EXPORT_SYMBOL(devm_gpiod_get_array_optional);
+
+/**
* devm_gpiod_put - Resource-managed gpiod_put()
* @desc: GPIO descriptor to dispose of
*
@@ -184,6 +274,21 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
}
EXPORT_SYMBOL(devm_gpiod_put);
+/**
+ * devm_gpiod_put_array - Resource-managed gpiod_put_array()
+ * @descs: GPIO descriptor array to dispose of
+ *
+ * Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array().
+ * Normally this function will not be called as the GPIOs will be disposed of
+ * by the resource management code.
+ */
+void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs)
+{
+ WARN_ON(devres_release(dev, devm_gpiod_release_array,
+ devm_gpiod_match_array, &descs));
+}
+EXPORT_SYMBOL(devm_gpiod_put_array);
+
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index 3beed6ea8c65..d3fe6a6776da 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -367,7 +367,7 @@ static int adp5588_gpio_probe(struct i2c_client *client,
struct gpio_chip *gc;
int ret, i, revid;
- if (pdata == NULL) {
+ if (!pdata) {
dev_err(&client->dev, "missing platform data\n");
return -ENODEV;
}
@@ -378,8 +378,8 @@ static int adp5588_gpio_probe(struct i2c_client *client,
return -EIO;
}
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL)
+ dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
return -ENOMEM;
dev->client = client;
@@ -446,7 +446,6 @@ static int adp5588_gpio_probe(struct i2c_client *client,
err_irq:
adp5588_irq_teardown(dev);
err:
- kfree(dev);
return ret;
}
@@ -472,7 +471,6 @@ static int adp5588_gpio_remove(struct i2c_client *client)
gpiochip_remove(&dev->gpio_chip);
- kfree(dev);
return 0;
}
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
new file mode 100644
index 000000000000..449fb46cb8a0
--- /dev/null
+++ b/drivers/gpio/gpio-altera.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Based on gpio-mpc8xxx.c
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#define ALTERA_GPIO_MAX_NGPIO 32
+#define ALTERA_GPIO_DATA 0x0
+#define ALTERA_GPIO_DIR 0x4
+#define ALTERA_GPIO_IRQ_MASK 0x8
+#define ALTERA_GPIO_EDGE_CAP 0xc
+
+/**
+* struct altera_gpio_chip
+* @mmchip : memory mapped chip structure.
+* @gpio_lock : synchronization lock so that new irq/set/get requests
+ will be blocked until the current one completes.
+* @interrupt_trigger : specifies the hardware configured IRQ trigger type
+ (rising, falling, both, high)
+* @mapped_irq : kernel mapped irq number.
+*/
+struct altera_gpio_chip {
+ struct of_mm_gpio_chip mmchip;
+ spinlock_t gpio_lock;
+ int interrupt_trigger;
+ int mapped_irq;
+};
+
+static void altera_gpio_irq_unmask(struct irq_data *d)
+{
+ struct altera_gpio_chip *altera_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ unsigned long flags;
+ u32 intmask;
+
+ altera_gc = irq_data_get_irq_chip_data(d);
+ mm_gc = &altera_gc->mmchip;
+
+ spin_lock_irqsave(&altera_gc->gpio_lock, flags);
+ intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
+ /* Set ALTERA_GPIO_IRQ_MASK bit to unmask */
+ intmask |= BIT(irqd_to_hwirq(d));
+ writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
+ spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
+}
+
+static void altera_gpio_irq_mask(struct irq_data *d)
+{
+ struct altera_gpio_chip *altera_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ unsigned long flags;
+ u32 intmask;
+
+ altera_gc = irq_data_get_irq_chip_data(d);
+ mm_gc = &altera_gc->mmchip;
+
+ spin_lock_irqsave(&altera_gc->gpio_lock, flags);
+ intmask = readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
+ /* Clear ALTERA_GPIO_IRQ_MASK bit to mask */
+ intmask &= ~BIT(irqd_to_hwirq(d));
+ writel(intmask, mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
+ spin_unlock_irqrestore(&altera_gc->gpio_lock, flags);
+}
+
+/**
+ * This controller's IRQ type is synthesized in hardware, so this function
+ * just checks if the requested set_type matches the synthesized IRQ type
+ */
+static int altera_gpio_irq_set_type(struct irq_data *d,
+ unsigned int type)
+{
+ struct altera_gpio_chip *altera_gc;
+
+ altera_gc = irq_data_get_irq_chip_data(d);
+
+ if (type == IRQ_TYPE_NONE)
+ return 0;
+ if (type == IRQ_TYPE_LEVEL_HIGH &&
+ altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
+ return 0;
+ if (type == IRQ_TYPE_EDGE_RISING &&
+ altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING)
+ return 0;
+ if (type == IRQ_TYPE_EDGE_FALLING &&
+ altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING)
+ return 0;
+ if (type == IRQ_TYPE_EDGE_BOTH &&
+ altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH)
+ return 0;
+
+ return -EINVAL;
+}
+
+static unsigned int altera_gpio_irq_startup(struct irq_data *d) {
+ altera_gpio_irq_unmask(d);
+
+ return 0;
+}
+
+static struct irq_chip altera_irq_chip = {
+ .name = "altera-gpio",
+ .irq_mask = altera_gpio_irq_mask,
+ .irq_unmask = altera_gpio_irq_unmask,
+ .irq_set_type = altera_gpio_irq_set_type,
+ .irq_startup = altera_gpio_irq_startup,
+ .irq_shutdown = altera_gpio_irq_mask,
+};
+
+static int altera_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct of_mm_gpio_chip *mm_gc;
+
+ mm_gc = to_of_mm_gpio_chip(gc);
+
+ return !!(readl(mm_gc->regs + ALTERA_GPIO_DATA) & BIT(offset));
+}
+
+static void altera_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct of_mm_gpio_chip *mm_gc;
+ struct altera_gpio_chip *chip;
+ unsigned long flags;
+ unsigned int data_reg;
+
+ mm_gc = to_of_mm_gpio_chip(gc);
+ chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+ data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
+ if (value)
+ data_reg |= BIT(offset);
+ else
+ data_reg &= ~BIT(offset);
+ writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+static int altera_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct of_mm_gpio_chip *mm_gc;
+ struct altera_gpio_chip *chip;
+ unsigned long flags;
+ unsigned int gpio_ddr;
+
+ mm_gc = to_of_mm_gpio_chip(gc);
+ chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+ /* Set pin as input, assumes software controlled IP */
+ gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR);
+ gpio_ddr &= ~BIT(offset);
+ writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+ return 0;
+}
+
+static int altera_gpio_direction_output(struct gpio_chip *gc,
+ unsigned offset, int value)
+{
+ struct of_mm_gpio_chip *mm_gc;
+ struct altera_gpio_chip *chip;
+ unsigned long flags;
+ unsigned int data_reg, gpio_ddr;
+
+ mm_gc = to_of_mm_gpio_chip(gc);
+ chip = container_of(mm_gc, struct altera_gpio_chip, mmchip);
+
+ spin_lock_irqsave(&chip->gpio_lock, flags);
+ /* Sets the GPIO value */
+ data_reg = readl(mm_gc->regs + ALTERA_GPIO_DATA);
+ if (value)
+ data_reg |= BIT(offset);
+ else
+ data_reg &= ~BIT(offset);
+ writel(data_reg, mm_gc->regs + ALTERA_GPIO_DATA);
+
+ /* Set pin as output, assumes software controlled IP */
+ gpio_ddr = readl(mm_gc->regs + ALTERA_GPIO_DIR);
+ gpio_ddr |= BIT(offset);
+ writel(gpio_ddr, mm_gc->regs + ALTERA_GPIO_DIR);
+ spin_unlock_irqrestore(&chip->gpio_lock, flags);
+
+ return 0;
+}
+
+static void altera_gpio_irq_edge_handler(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct altera_gpio_chip *altera_gc;
+ struct irq_chip *chip;
+ struct of_mm_gpio_chip *mm_gc;
+ struct irq_domain *irqdomain;
+ unsigned long status;
+ int i;
+
+ altera_gc = irq_desc_get_handler_data(desc);
+ chip = irq_desc_get_chip(desc);
+ mm_gc = &altera_gc->mmchip;
+ irqdomain = altera_gc->mmchip.gc.irqdomain;
+
+ chained_irq_enter(chip, desc);
+
+ while ((status =
+ (readl(mm_gc->regs + ALTERA_GPIO_EDGE_CAP) &
+ readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK)))) {
+ writel(status, mm_gc->regs + ALTERA_GPIO_EDGE_CAP);
+ for_each_set_bit(i, &status, mm_gc->gc.ngpio) {
+ generic_handle_irq(irq_find_mapping(irqdomain, i));
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+
+static void altera_gpio_irq_leveL_high_handler(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct altera_gpio_chip *altera_gc;
+ struct irq_chip *chip;
+ struct of_mm_gpio_chip *mm_gc;
+ struct irq_domain *irqdomain;
+ unsigned long status;
+ int i;
+
+ altera_gc = irq_desc_get_handler_data(desc);
+ chip = irq_desc_get_chip(desc);
+ mm_gc = &altera_gc->mmchip;
+ irqdomain = altera_gc->mmchip.gc.irqdomain;
+
+ chained_irq_enter(chip, desc);
+
+ status = readl(mm_gc->regs + ALTERA_GPIO_DATA);
+ status &= readl(mm_gc->regs + ALTERA_GPIO_IRQ_MASK);
+
+ for_each_set_bit(i, &status, mm_gc->gc.ngpio) {
+ generic_handle_irq(irq_find_mapping(irqdomain, i));
+ }
+ chained_irq_exit(chip, desc);
+}
+
+static int altera_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int reg, ret;
+ struct altera_gpio_chip *altera_gc;
+
+ altera_gc = devm_kzalloc(&pdev->dev, sizeof(*altera_gc), GFP_KERNEL);
+ if (!altera_gc)
+ return -ENOMEM;
+
+ spin_lock_init(&altera_gc->gpio_lock);
+
+ if (of_property_read_u32(node, "altr,ngpio", &reg))
+ /* By default assume maximum ngpio */
+ altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ else
+ altera_gc->mmchip.gc.ngpio = reg;
+
+ if (altera_gc->mmchip.gc.ngpio > ALTERA_GPIO_MAX_NGPIO) {
+ dev_warn(&pdev->dev,
+ "ngpio is greater than %d, defaulting to %d\n",
+ ALTERA_GPIO_MAX_NGPIO, ALTERA_GPIO_MAX_NGPIO);
+ altera_gc->mmchip.gc.ngpio = ALTERA_GPIO_MAX_NGPIO;
+ }
+
+ altera_gc->mmchip.gc.direction_input = altera_gpio_direction_input;
+ altera_gc->mmchip.gc.direction_output = altera_gpio_direction_output;
+ altera_gc->mmchip.gc.get = altera_gpio_get;
+ altera_gc->mmchip.gc.set = altera_gpio_set;
+ altera_gc->mmchip.gc.owner = THIS_MODULE;
+ altera_gc->mmchip.gc.dev = &pdev->dev;
+
+ ret = of_mm_gpiochip_add(node, &altera_gc->mmchip);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, altera_gc);
+
+ altera_gc->mapped_irq = platform_get_irq(pdev, 0);
+
+ if (altera_gc->mapped_irq < 0)
+ goto skip_irq;
+
+ if (of_property_read_u32(node, "altr,interrupt-type", &reg)) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev,
+ "altr,interrupt-type value not set in device tree\n");
+ goto teardown;
+ }
+ altera_gc->interrupt_trigger = reg;
+
+ ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+
+ if (ret) {
+ dev_info(&pdev->dev, "could not add irqchip\n");
+ return ret;
+ }
+
+ gpiochip_set_chained_irqchip(&altera_gc->mmchip.gc,
+ &altera_irq_chip,
+ altera_gc->mapped_irq,
+ altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH ?
+ altera_gpio_irq_leveL_high_handler :
+ altera_gpio_irq_edge_handler);
+
+skip_irq:
+ return 0;
+teardown:
+ pr_err("%s: registration failed with status %d\n",
+ node->full_name, ret);
+
+ return ret;
+}
+
+static int altera_gpio_remove(struct platform_device *pdev)
+{
+ struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&altera_gc->mmchip.gc);
+
+ return -EIO;
+}
+
+static const struct of_device_id altera_gpio_of_match[] = {
+ { .compatible = "altr,pio-1.0", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, altera_gpio_of_match);
+
+static struct platform_driver altera_gpio_driver = {
+ .driver = {
+ .name = "altera_gpio",
+ .of_match_table = of_match_ptr(altera_gpio_of_match),
+ },
+ .probe = altera_gpio_probe,
+ .remove = altera_gpio_remove,
+};
+
+static int __init altera_gpio_init(void)
+{
+ return platform_driver_register(&altera_gpio_driver);
+}
+subsys_initcall(altera_gpio_init);
+
+static void __exit altera_gpio_exit(void)
+{
+ platform_driver_unregister(&altera_gpio_driver);
+}
+module_exit(altera_gpio_exit);
+
+MODULE_AUTHOR("Tien Hock Loh <thloh@altera.com>");
+MODULE_DESCRIPTION("Altera GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 9665d0aa4ebb..052fbc8fdaaa 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -103,7 +103,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio),
GFP_KERNEL);
- if (arizona_gpio == NULL)
+ if (!arizona_gpio)
return -ENOMEM;
arizona_gpio->arizona = arizona;
@@ -156,7 +156,6 @@ static int arizona_gpio_remove(struct platform_device *pdev)
static struct platform_driver arizona_gpio_driver = {
.driver.name = "arizona-gpio",
- .driver.owner = THIS_MODULE,
.probe = arizona_gpio_probe,
.remove = arizona_gpio_remove,
};
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 3d9e08f7e823..91a7ffe83135 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -24,7 +24,7 @@
#include <linux/mfd/intel_soc_pmic.h>
#define CRYSTALCOVE_GPIO_NUM 16
-#define CRYSTALCOVE_VGPIO_NUM 94
+#define CRYSTALCOVE_VGPIO_NUM 95
#define UPDATE_IRQ_TYPE BIT(0)
#define UPDATE_IRQ_MASK BIT(1)
@@ -39,6 +39,7 @@
#define GPIO0P0CTLI 0x33
#define GPIO1P0CTLO 0x3b
#define GPIO1P0CTLI 0x43
+#define GPIOPANELCTL 0x52
#define CTLI_INTCNT_DIS (0)
#define CTLI_INTCNT_NE (1 << 1)
@@ -93,6 +94,10 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type)
{
int reg;
+ if (gpio == 94) {
+ return GPIOPANELCTL;
+ }
+
if (reg_type == CTRL_IN) {
if (gpio < 8)
reg = GPIO0P0CTLI;
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 389a4d2a4926..2e9578ec0ca1 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -212,7 +212,7 @@ static int da9052_gpio_probe(struct platform_device *pdev)
int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
- if (gpio == NULL)
+ if (!gpio)
return -ENOMEM;
gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
index b8d757036887..7227e6ed3cb9 100644
--- a/drivers/gpio/gpio-da9055.c
+++ b/drivers/gpio/gpio-da9055.c
@@ -146,7 +146,7 @@ static int da9055_gpio_probe(struct platform_device *pdev)
int ret;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
- if (gpio == NULL)
+ if (!gpio)
return -ENOMEM;
gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 1be291ac6319..dbda8433c4f7 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -1,5 +1,5 @@
/*
- * GPIO driver for Fintek Super-I/O F71882 and F71889
+ * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882 and F71889
*
* Copyright (C) 2010-2013 LaCie
*
@@ -32,12 +32,16 @@
#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
#define SIO_FINTEK_ID 0x1934 /* Manufacturer ID */
+#define SIO_F71869_ID 0x0814 /* F71869 chipset ID */
+#define SIO_F71869A_ID 0x1007 /* F71869A chipset ID */
#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */
#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */
-enum chips { f71882fg, f71889f };
+enum chips { f71869, f71869a, f71882fg, f71889f };
static const char * const f7188x_names[] = {
+ "f71869",
+ "f71869a",
"f71882fg",
"f71889f",
};
@@ -146,6 +150,27 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
/* Output mode register (0:open drain 1:push-pull). */
#define gpio_out_mode(base) (base + 3)
+static struct f7188x_gpio_bank f71869_gpio_bank[] = {
+ F7188X_GPIO_BANK(0, 6, 0xF0),
+ F7188X_GPIO_BANK(10, 8, 0xE0),
+ F7188X_GPIO_BANK(20, 8, 0xD0),
+ F7188X_GPIO_BANK(30, 8, 0xC0),
+ F7188X_GPIO_BANK(40, 8, 0xB0),
+ F7188X_GPIO_BANK(50, 5, 0xA0),
+ F7188X_GPIO_BANK(60, 6, 0x90),
+};
+
+static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
+ F7188X_GPIO_BANK(0, 6, 0xF0),
+ F7188X_GPIO_BANK(10, 8, 0xE0),
+ F7188X_GPIO_BANK(20, 8, 0xD0),
+ F7188X_GPIO_BANK(30, 8, 0xC0),
+ F7188X_GPIO_BANK(40, 8, 0xB0),
+ F7188X_GPIO_BANK(50, 5, 0xA0),
+ F7188X_GPIO_BANK(60, 8, 0x90),
+ F7188X_GPIO_BANK(70, 8, 0x80),
+};
+
static struct f7188x_gpio_bank f71882_gpio_bank[] = {
F7188X_GPIO_BANK(0 , 8, 0xF0),
F7188X_GPIO_BANK(10, 8, 0xE0),
@@ -281,6 +306,14 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
switch (sio->type) {
+ case f71869:
+ data->nr_bank = ARRAY_SIZE(f71869_gpio_bank);
+ data->bank = f71869_gpio_bank;
+ break;
+ case f71869a:
+ data->nr_bank = ARRAY_SIZE(f71869a_gpio_bank);
+ data->bank = f71869a_gpio_bank;
+ break;
case f71882fg:
data->nr_bank = ARRAY_SIZE(f71882_gpio_bank);
data->bank = f71882_gpio_bank;
@@ -354,6 +387,12 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
devid = superio_inw(addr, SIO_DEVID);
switch (devid) {
+ case SIO_F71869_ID:
+ sio->type = f71869;
+ break;
+ case SIO_F71869A_ID:
+ sio->type = f71869a;
+ break;
case SIO_F71882_ID:
sio->type = f71882fg;
break;
@@ -410,7 +449,7 @@ err:
}
/*
- * Try to match a supported Fintech device by reading the (hard-wired)
+ * Try to match a supported Fintek device by reading the (hard-wired)
* configuration I/O ports. If available, then register both the platform
* device and driver to support the GPIOs.
*/
@@ -450,6 +489,6 @@ static void __exit f7188x_gpio_exit(void)
}
module_exit(f7188x_gpio_exit);
-MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F");
+MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG and F71889F");
MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index 7818cd1453ae..4ba7ed502131 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -173,6 +173,11 @@ static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
return !!(ichx_priv.use_gpio & (1 << (nr / 32)));
}
+static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr)
+{
+ return ichx_read_bit(GPIO_IO_SEL, nr) ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
+}
+
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
/*
@@ -286,6 +291,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip)
ichx_priv.desc->get : ichx_gpio_get;
chip->set = ichx_gpio_set;
+ chip->get_direction = ichx_gpio_get_direction;
chip->direction_input = ichx_gpio_direction_input;
chip->direction_output = ichx_gpio_direction_output;
chip->base = modparam_gpiobase;
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
index 443518f63f15..6b8115f34208 100644
--- a/drivers/gpio/gpio-kempld.c
+++ b/drivers/gpio/gpio-kempld.c
@@ -156,7 +156,7 @@ static int kempld_gpio_probe(struct platform_device *pdev)
}
gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
- if (gpio == NULL)
+ if (!gpio)
return -ENOMEM;
gpio->pld = pld;
diff --git a/drivers/gpio/gpio-loongson.c b/drivers/gpio/gpio-loongson.c
new file mode 100644
index 000000000000..ccc65a1aea88
--- /dev/null
+++ b/drivers/gpio/gpio-loongson.c
@@ -0,0 +1,115 @@
+/*
+ * Loongson-2F/3A/3B GPIO Support
+ *
+ * Copyright (c) 2008 Richard Liu, STMicroelectronics <richard.liu@st.com>
+ * Copyright (c) 2008-2010 Arnaud Patard <apatard@mandriva.com>
+ * Copyright (c) 2013 Hongbing Hu <huhb@lemote.com>
+ * Copyright (c) 2014 Huacai Chen <chenhc@lemote.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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <asm/types.h>
+#include <loongson.h>
+#include <linux/gpio.h>
+
+#define STLS2F_N_GPIO 4
+#define STLS3A_N_GPIO 16
+
+#ifdef CONFIG_CPU_LOONGSON3
+#define LOONGSON_N_GPIO STLS3A_N_GPIO
+#else
+#define LOONGSON_N_GPIO STLS2F_N_GPIO
+#endif
+
+#define LOONGSON_GPIO_IN_OFFSET 16
+
+static DEFINE_SPINLOCK(gpio_lock);
+
+static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ u32 temp;
+ u32 mask;
+
+ spin_lock(&gpio_lock);
+ mask = 1 << gpio;
+ temp = LOONGSON_GPIOIE;
+ temp |= mask;
+ LOONGSON_GPIOIE = temp;
+ spin_unlock(&gpio_lock);
+
+ return 0;
+}
+
+static int loongson_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int level)
+{
+ u32 temp;
+ u32 mask;
+
+ gpio_set_value(gpio, level);
+ spin_lock(&gpio_lock);
+ mask = 1 << gpio;
+ temp = LOONGSON_GPIOIE;
+ temp &= (~mask);
+ LOONGSON_GPIOIE = temp;
+ spin_unlock(&gpio_lock);
+
+ return 0;
+}
+
+static int loongson_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ u32 val;
+ u32 mask;
+
+ mask = 1 << (gpio + LOONGSON_GPIO_IN_OFFSET);
+ spin_lock(&gpio_lock);
+ val = LOONGSON_GPIODATA;
+ spin_unlock(&gpio_lock);
+
+ return (val & mask) != 0;
+}
+
+static void loongson_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ u32 val;
+ u32 mask;
+
+ mask = 1 << gpio;
+
+ spin_lock(&gpio_lock);
+ val = LOONGSON_GPIODATA;
+ if (value)
+ val |= mask;
+ else
+ val &= (~mask);
+ LOONGSON_GPIODATA = val;
+ spin_unlock(&gpio_lock);
+}
+
+static struct gpio_chip loongson_chip = {
+ .label = "Loongson-gpio-chip",
+ .direction_input = loongson_gpio_direction_input,
+ .get = loongson_gpio_get_value,
+ .direction_output = loongson_gpio_direction_output,
+ .set = loongson_gpio_set_value,
+ .base = 0,
+ .ngpio = LOONGSON_N_GPIO,
+ .can_sleep = false,
+};
+
+static int __init loongson_gpio_setup(void)
+{
+ return gpiochip_add(&loongson_chip);
+}
+postcore_initcall(loongson_gpio_setup);
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 40ab6dfb6021..0cc2c279ab5c 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -35,7 +35,6 @@ static int max7300_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max7301 *ts;
- int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
@@ -49,8 +48,7 @@ static int max7300_probe(struct i2c_client *client,
ts->write = max7300_i2c_write;
ts->dev = &client->dev;
- ret = __max730x_probe(ts);
- return ret;
+ return __max730x_probe(ts);
}
static int max7300_remove(struct i2c_client *client)
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index a095b2393fe9..0fa4543c5e02 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -4,6 +4,7 @@
* Copyright (C) 2007 Marvell International Ltd.
* Copyright (C) 2008 Jack Ren <jack.ren@marvell.com>
* Copyright (C) 2008 Eric Miao <eric.miao@marvell.com>
+ * Copyright (C) 2015 Linus Walleij <linus.walleij@linaro.org>
*
* Derived from drivers/gpio/pca953x.c
*
@@ -16,10 +17,8 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/i2c.h>
#include <linux/i2c/max732x.h>
#include <linux/of.h>
@@ -150,9 +149,7 @@ struct max732x_chip {
uint8_t reg_out[2];
#ifdef CONFIG_GPIO_MAX732X_IRQ
- struct irq_domain *irq_domain;
struct mutex irq_lock;
- int irq_base;
uint8_t irq_mask;
uint8_t irq_mask_cur;
uint8_t irq_trig_raise;
@@ -356,35 +353,26 @@ static void max732x_irq_update_mask(struct max732x_chip *chip)
mutex_unlock(&chip->lock);
}
-static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
-{
- struct max732x_chip *chip = to_max732x(gc);
-
- if (chip->irq_domain) {
- return irq_create_mapping(chip->irq_domain,
- chip->irq_base + off);
- } else {
- return -ENXIO;
- }
-}
-
static void max732x_irq_mask(struct irq_data *d)
{
- struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct max732x_chip *chip = to_max732x(gc);
chip->irq_mask_cur &= ~(1 << d->hwirq);
}
static void max732x_irq_unmask(struct irq_data *d)
{
- struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct max732x_chip *chip = to_max732x(gc);
chip->irq_mask_cur |= 1 << d->hwirq;
}
static void max732x_irq_bus_lock(struct irq_data *d)
{
- struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct max732x_chip *chip = to_max732x(gc);
mutex_lock(&chip->irq_lock);
chip->irq_mask_cur = chip->irq_mask;
@@ -392,7 +380,8 @@ static void max732x_irq_bus_lock(struct irq_data *d)
static void max732x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct max732x_chip *chip = to_max732x(gc);
uint16_t new_irqs;
uint16_t level;
@@ -410,7 +399,8 @@ static void max732x_irq_bus_sync_unlock(struct irq_data *d)
static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct max732x_chip *chip = to_max732x(gc);
uint16_t off = d->hwirq;
uint16_t mask = 1 << off;
@@ -492,7 +482,8 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
do {
level = __ffs(pending);
- handle_nested_irq(irq_find_mapping(chip->irq_domain, level));
+ handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+ level));
pending &= ~(1 << level);
} while (pending);
@@ -500,86 +491,50 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
return IRQ_HANDLED;
}
-static int max732x_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct max732x_chip *chip = h->host_data;
-
- if (!(chip->dir_input & (1 << hw))) {
- dev_err(&chip->client->dev,
- "Attempt to map output line as IRQ line: %lu\n",
- hw);
- return -EPERM;
- }
-
- irq_set_chip_data(virq, chip);
- irq_set_chip_and_handler(virq, &max732x_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(virq, 1);
-#ifdef CONFIG_ARM
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
- set_irq_flags(virq, IRQF_VALID);
-#else
- irq_set_noprobe(virq);
-#endif
-
- return 0;
-}
-
-static struct irq_domain_ops max732x_irq_domain_ops = {
- .map = max732x_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static void max732x_irq_teardown(struct max732x_chip *chip)
-{
- if (chip->client->irq && chip->irq_domain)
- irq_domain_remove(chip->irq_domain);
-}
-
static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id)
{
struct i2c_client *client = chip->client;
struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
+ int irq_base = 0;
int ret;
if (((pdata && pdata->irq_base) || client->irq)
&& has_irq != INT_NONE) {
if (pdata)
- chip->irq_base = pdata->irq_base;
+ irq_base = pdata->irq_base;
chip->irq_features = has_irq;
mutex_init(&chip->irq_lock);
- chip->irq_domain = irq_domain_add_simple(client->dev.of_node,
- chip->gpio_chip.ngpio, chip->irq_base,
- &max732x_irq_domain_ops, chip);
- if (!chip->irq_domain) {
- dev_err(&client->dev, "Failed to create IRQ domain\n");
- return -ENOMEM;
- }
-
- ret = request_threaded_irq(client->irq,
- NULL,
- max732x_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- dev_name(&client->dev), chip);
+ ret = devm_request_threaded_irq(&client->dev,
+ client->irq,
+ NULL,
+ max732x_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
- goto out_failed;
+ return ret;
}
-
- chip->gpio_chip.to_irq = max732x_gpio_to_irq;
+ ret = gpiochip_irqchip_add(&chip->gpio_chip,
+ &max732x_irq_chip,
+ irq_base,
+ handle_edge_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&client->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
+ }
+ gpiochip_set_chained_irqchip(&chip->gpio_chip,
+ &max732x_irq_chip,
+ client->irq,
+ NULL);
}
return 0;
-
-out_failed:
- max732x_irq_teardown(chip);
- return ret;
}
#else /* CONFIG_GPIO_MAX732X_IRQ */
@@ -595,10 +550,6 @@ static int max732x_irq_setup(struct max732x_chip *chip,
return 0;
}
-
-static void max732x_irq_teardown(struct max732x_chip *chip)
-{
-}
#endif
static int max732x_setup_gpio(struct max732x_chip *chip,
@@ -730,13 +681,15 @@ static int max732x_probe(struct i2c_client *client,
if (nr_port > 8)
max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]);
- ret = max732x_irq_setup(chip, id);
+ ret = gpiochip_add(&chip->gpio_chip);
if (ret)
goto out_failed;
- ret = gpiochip_add(&chip->gpio_chip);
- if (ret)
+ ret = max732x_irq_setup(chip, id);
+ if (ret) {
+ gpiochip_remove(&chip->gpio_chip);
goto out_failed;
+ }
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
@@ -751,7 +704,6 @@ static int max732x_probe(struct i2c_client *client,
out_failed:
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy);
- max732x_irq_teardown(chip);
return ret;
}
@@ -774,8 +726,6 @@ static int max732x_remove(struct i2c_client *client)
gpiochip_remove(&chip->gpio_chip);
- max732x_irq_teardown(chip);
-
/* unregister any dummy i2c_client */
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy);
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index 21b1ce5abdfe..ee93c0ab0a59 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -58,6 +58,11 @@ static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
spin_lock_irqsave(&gchip->lock, flags);
val = readl(gchip->base + PFR(gpio));
+ if (!(val & OFFSET(gpio))) {
+ spin_unlock_irqrestore(&gchip->lock, flags);
+ return -EINVAL;
+ }
+
val &= ~OFFSET(gpio);
writel(val, gchip->base + PFR(gpio));
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 4e3e160e5db2..a431604c9e67 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -151,7 +151,7 @@ static int mc33880_remove(struct spi_device *spi)
struct mc33880 *mc;
mc = spi_get_drvdata(spi);
- if (mc == NULL)
+ if (!mc)
return -ENODEV;
gpiochip_remove(&mc->chip);
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index eea5d7e578c9..2fc7ff852d16 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -949,10 +949,12 @@ static int mcp23s08_probe(struct spi_device *spi)
if (!chips)
return -ENODEV;
- data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08),
- GFP_KERNEL);
+ data = devm_kzalloc(&spi->dev,
+ sizeof(*data) + chips * sizeof(struct mcp23s08),
+ GFP_KERNEL);
if (!data)
return -ENOMEM;
+
spi_set_drvdata(spi, data);
spi->irq = irq_of_parse_and_map(spi->dev.of_node, 0);
@@ -989,7 +991,6 @@ fail:
continue;
gpiochip_remove(&data->mcp[addr]->chip);
}
- kfree(data);
return status;
}
@@ -1007,7 +1008,7 @@ static int mcp23s08_remove(struct spi_device *spi)
mcp23s08_irq_teardown(data->mcp[addr]);
gpiochip_remove(&data->mcp[addr]->chip);
}
- kfree(data);
+
return 0;
}
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
deleted file mode 100644
index edf285e26667..000000000000
--- a/drivers/gpio/gpio-msm-v1.c
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-
-#include <mach/msm_gpiomux.h>
-
-/* see 80-VA736-2 Rev C pp 695-751
-**
-** These are actually the *shadow* gpio registers, since the
-** real ones (which allow full access) are only available to the
-** ARM9 side of the world.
-**
-** Since the _BASE need to be page-aligned when we're mapping them
-** to virtual addresses, adjust for the additional offset in these
-** macros.
-*/
-
-#define MSM_GPIO1_REG(off) (off)
-#define MSM_GPIO2_REG(off) (off)
-#define MSM_GPIO1_SHADOW_REG(off) (off)
-#define MSM_GPIO2_SHADOW_REG(off) (off)
-
-/*
- * MSM7X00 registers
- */
-/* output value */
-#define MSM7X00_GPIO_OUT_0 MSM_GPIO1_SHADOW_REG(0x00) /* gpio 15-0 */
-#define MSM7X00_GPIO_OUT_1 MSM_GPIO2_SHADOW_REG(0x00) /* gpio 42-16 */
-#define MSM7X00_GPIO_OUT_2 MSM_GPIO1_SHADOW_REG(0x04) /* gpio 67-43 */
-#define MSM7X00_GPIO_OUT_3 MSM_GPIO1_SHADOW_REG(0x08) /* gpio 94-68 */
-#define MSM7X00_GPIO_OUT_4 MSM_GPIO1_SHADOW_REG(0x0C) /* gpio 106-95 */
-#define MSM7X00_GPIO_OUT_5 MSM_GPIO1_SHADOW_REG(0x50) /* gpio 107-121 */
-
-/* same pin map as above, output enable */
-#define MSM7X00_GPIO_OE_0 MSM_GPIO1_SHADOW_REG(0x10)
-#define MSM7X00_GPIO_OE_1 MSM_GPIO2_SHADOW_REG(0x08)
-#define MSM7X00_GPIO_OE_2 MSM_GPIO1_SHADOW_REG(0x14)
-#define MSM7X00_GPIO_OE_3 MSM_GPIO1_SHADOW_REG(0x18)
-#define MSM7X00_GPIO_OE_4 MSM_GPIO1_SHADOW_REG(0x1C)
-#define MSM7X00_GPIO_OE_5 MSM_GPIO1_SHADOW_REG(0x54)
-
-/* same pin map as above, input read */
-#define MSM7X00_GPIO_IN_0 MSM_GPIO1_SHADOW_REG(0x34)
-#define MSM7X00_GPIO_IN_1 MSM_GPIO2_SHADOW_REG(0x20)
-#define MSM7X00_GPIO_IN_2 MSM_GPIO1_SHADOW_REG(0x38)
-#define MSM7X00_GPIO_IN_3 MSM_GPIO1_SHADOW_REG(0x3C)
-#define MSM7X00_GPIO_IN_4 MSM_GPIO1_SHADOW_REG(0x40)
-#define MSM7X00_GPIO_IN_5 MSM_GPIO1_SHADOW_REG(0x44)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM7X00_GPIO_INT_EDGE_0 MSM_GPIO1_SHADOW_REG(0x60)
-#define MSM7X00_GPIO_INT_EDGE_1 MSM_GPIO2_SHADOW_REG(0x50)
-#define MSM7X00_GPIO_INT_EDGE_2 MSM_GPIO1_SHADOW_REG(0x64)
-#define MSM7X00_GPIO_INT_EDGE_3 MSM_GPIO1_SHADOW_REG(0x68)
-#define MSM7X00_GPIO_INT_EDGE_4 MSM_GPIO1_SHADOW_REG(0x6C)
-#define MSM7X00_GPIO_INT_EDGE_5 MSM_GPIO1_SHADOW_REG(0xC0)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM7X00_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x70)
-#define MSM7X00_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
-#define MSM7X00_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x74)
-#define MSM7X00_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x78)
-#define MSM7X00_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x7C)
-#define MSM7X00_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xBC)
-
-/* same pin map as above, interrupt enable */
-#define MSM7X00_GPIO_INT_EN_0 MSM_GPIO1_SHADOW_REG(0x80)
-#define MSM7X00_GPIO_INT_EN_1 MSM_GPIO2_SHADOW_REG(0x60)
-#define MSM7X00_GPIO_INT_EN_2 MSM_GPIO1_SHADOW_REG(0x84)
-#define MSM7X00_GPIO_INT_EN_3 MSM_GPIO1_SHADOW_REG(0x88)
-#define MSM7X00_GPIO_INT_EN_4 MSM_GPIO1_SHADOW_REG(0x8C)
-#define MSM7X00_GPIO_INT_EN_5 MSM_GPIO1_SHADOW_REG(0xB8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM7X00_GPIO_INT_CLEAR_0 MSM_GPIO1_SHADOW_REG(0x90)
-#define MSM7X00_GPIO_INT_CLEAR_1 MSM_GPIO2_SHADOW_REG(0x68)
-#define MSM7X00_GPIO_INT_CLEAR_2 MSM_GPIO1_SHADOW_REG(0x94)
-#define MSM7X00_GPIO_INT_CLEAR_3 MSM_GPIO1_SHADOW_REG(0x98)
-#define MSM7X00_GPIO_INT_CLEAR_4 MSM_GPIO1_SHADOW_REG(0x9C)
-#define MSM7X00_GPIO_INT_CLEAR_5 MSM_GPIO1_SHADOW_REG(0xB4)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM7X00_GPIO_INT_STATUS_0 MSM_GPIO1_SHADOW_REG(0xA0)
-#define MSM7X00_GPIO_INT_STATUS_1 MSM_GPIO2_SHADOW_REG(0x70)
-#define MSM7X00_GPIO_INT_STATUS_2 MSM_GPIO1_SHADOW_REG(0xA4)
-#define MSM7X00_GPIO_INT_STATUS_3 MSM_GPIO1_SHADOW_REG(0xA8)
-#define MSM7X00_GPIO_INT_STATUS_4 MSM_GPIO1_SHADOW_REG(0xAC)
-#define MSM7X00_GPIO_INT_STATUS_5 MSM_GPIO1_SHADOW_REG(0xB0)
-
-/*
- * QSD8X50 registers
- */
-/* output value */
-#define QSD8X50_GPIO_OUT_0 MSM_GPIO1_SHADOW_REG(0x00) /* gpio 15-0 */
-#define QSD8X50_GPIO_OUT_1 MSM_GPIO2_SHADOW_REG(0x00) /* gpio 42-16 */
-#define QSD8X50_GPIO_OUT_2 MSM_GPIO1_SHADOW_REG(0x04) /* gpio 67-43 */
-#define QSD8X50_GPIO_OUT_3 MSM_GPIO1_SHADOW_REG(0x08) /* gpio 94-68 */
-#define QSD8X50_GPIO_OUT_4 MSM_GPIO1_SHADOW_REG(0x0C) /* gpio 103-95 */
-#define QSD8X50_GPIO_OUT_5 MSM_GPIO1_SHADOW_REG(0x10) /* gpio 121-104 */
-#define QSD8X50_GPIO_OUT_6 MSM_GPIO1_SHADOW_REG(0x14) /* gpio 152-122 */
-#define QSD8X50_GPIO_OUT_7 MSM_GPIO1_SHADOW_REG(0x18) /* gpio 164-153 */
-
-/* same pin map as above, output enable */
-#define QSD8X50_GPIO_OE_0 MSM_GPIO1_SHADOW_REG(0x20)
-#define QSD8X50_GPIO_OE_1 MSM_GPIO2_SHADOW_REG(0x08)
-#define QSD8X50_GPIO_OE_2 MSM_GPIO1_SHADOW_REG(0x24)
-#define QSD8X50_GPIO_OE_3 MSM_GPIO1_SHADOW_REG(0x28)
-#define QSD8X50_GPIO_OE_4 MSM_GPIO1_SHADOW_REG(0x2C)
-#define QSD8X50_GPIO_OE_5 MSM_GPIO1_SHADOW_REG(0x30)
-#define QSD8X50_GPIO_OE_6 MSM_GPIO1_SHADOW_REG(0x34)
-#define QSD8X50_GPIO_OE_7 MSM_GPIO1_SHADOW_REG(0x38)
-
-/* same pin map as above, input read */
-#define QSD8X50_GPIO_IN_0 MSM_GPIO1_SHADOW_REG(0x50)
-#define QSD8X50_GPIO_IN_1 MSM_GPIO2_SHADOW_REG(0x20)
-#define QSD8X50_GPIO_IN_2 MSM_GPIO1_SHADOW_REG(0x54)
-#define QSD8X50_GPIO_IN_3 MSM_GPIO1_SHADOW_REG(0x58)
-#define QSD8X50_GPIO_IN_4 MSM_GPIO1_SHADOW_REG(0x5C)
-#define QSD8X50_GPIO_IN_5 MSM_GPIO1_SHADOW_REG(0x60)
-#define QSD8X50_GPIO_IN_6 MSM_GPIO1_SHADOW_REG(0x64)
-#define QSD8X50_GPIO_IN_7 MSM_GPIO1_SHADOW_REG(0x68)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define QSD8X50_GPIO_INT_EDGE_0 MSM_GPIO1_SHADOW_REG(0x70)
-#define QSD8X50_GPIO_INT_EDGE_1 MSM_GPIO2_SHADOW_REG(0x50)
-#define QSD8X50_GPIO_INT_EDGE_2 MSM_GPIO1_SHADOW_REG(0x74)
-#define QSD8X50_GPIO_INT_EDGE_3 MSM_GPIO1_SHADOW_REG(0x78)
-#define QSD8X50_GPIO_INT_EDGE_4 MSM_GPIO1_SHADOW_REG(0x7C)
-#define QSD8X50_GPIO_INT_EDGE_5 MSM_GPIO1_SHADOW_REG(0x80)
-#define QSD8X50_GPIO_INT_EDGE_6 MSM_GPIO1_SHADOW_REG(0x84)
-#define QSD8X50_GPIO_INT_EDGE_7 MSM_GPIO1_SHADOW_REG(0x88)
-
-/* same pin map as above, 1=positive 0=negative */
-#define QSD8X50_GPIO_INT_POS_0 MSM_GPIO1_SHADOW_REG(0x90)
-#define QSD8X50_GPIO_INT_POS_1 MSM_GPIO2_SHADOW_REG(0x58)
-#define QSD8X50_GPIO_INT_POS_2 MSM_GPIO1_SHADOW_REG(0x94)
-#define QSD8X50_GPIO_INT_POS_3 MSM_GPIO1_SHADOW_REG(0x98)
-#define QSD8X50_GPIO_INT_POS_4 MSM_GPIO1_SHADOW_REG(0x9C)
-#define QSD8X50_GPIO_INT_POS_5 MSM_GPIO1_SHADOW_REG(0xA0)
-#define QSD8X50_GPIO_INT_POS_6 MSM_GPIO1_SHADOW_REG(0xA4)
-#define QSD8X50_GPIO_INT_POS_7 MSM_GPIO1_SHADOW_REG(0xA8)
-
-/* same pin map as above, interrupt enable */
-#define QSD8X50_GPIO_INT_EN_0 MSM_GPIO1_SHADOW_REG(0xB0)
-#define QSD8X50_GPIO_INT_EN_1 MSM_GPIO2_SHADOW_REG(0x60)
-#define QSD8X50_GPIO_INT_EN_2 MSM_GPIO1_SHADOW_REG(0xB4)
-#define QSD8X50_GPIO_INT_EN_3 MSM_GPIO1_SHADOW_REG(0xB8)
-#define QSD8X50_GPIO_INT_EN_4 MSM_GPIO1_SHADOW_REG(0xBC)
-#define QSD8X50_GPIO_INT_EN_5 MSM_GPIO1_SHADOW_REG(0xC0)
-#define QSD8X50_GPIO_INT_EN_6 MSM_GPIO1_SHADOW_REG(0xC4)
-#define QSD8X50_GPIO_INT_EN_7 MSM_GPIO1_SHADOW_REG(0xC8)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define QSD8X50_GPIO_INT_CLEAR_0 MSM_GPIO1_SHADOW_REG(0xD0)
-#define QSD8X50_GPIO_INT_CLEAR_1 MSM_GPIO2_SHADOW_REG(0x68)
-#define QSD8X50_GPIO_INT_CLEAR_2 MSM_GPIO1_SHADOW_REG(0xD4)
-#define QSD8X50_GPIO_INT_CLEAR_3 MSM_GPIO1_SHADOW_REG(0xD8)
-#define QSD8X50_GPIO_INT_CLEAR_4 MSM_GPIO1_SHADOW_REG(0xDC)
-#define QSD8X50_GPIO_INT_CLEAR_5 MSM_GPIO1_SHADOW_REG(0xE0)
-#define QSD8X50_GPIO_INT_CLEAR_6 MSM_GPIO1_SHADOW_REG(0xE4)
-#define QSD8X50_GPIO_INT_CLEAR_7 MSM_GPIO1_SHADOW_REG(0xE8)
-
-/* same pin map as above, 1=interrupt pending */
-#define QSD8X50_GPIO_INT_STATUS_0 MSM_GPIO1_SHADOW_REG(0xF0)
-#define QSD8X50_GPIO_INT_STATUS_1 MSM_GPIO2_SHADOW_REG(0x70)
-#define QSD8X50_GPIO_INT_STATUS_2 MSM_GPIO1_SHADOW_REG(0xF4)
-#define QSD8X50_GPIO_INT_STATUS_3 MSM_GPIO1_SHADOW_REG(0xF8)
-#define QSD8X50_GPIO_INT_STATUS_4 MSM_GPIO1_SHADOW_REG(0xFC)
-#define QSD8X50_GPIO_INT_STATUS_5 MSM_GPIO1_SHADOW_REG(0x100)
-#define QSD8X50_GPIO_INT_STATUS_6 MSM_GPIO1_SHADOW_REG(0x104)
-#define QSD8X50_GPIO_INT_STATUS_7 MSM_GPIO1_SHADOW_REG(0x108)
-
-/*
- * MSM7X30 registers
- */
-/* output value */
-#define MSM7X30_GPIO_OUT_0 MSM_GPIO1_REG(0x00) /* gpio 15-0 */
-#define MSM7X30_GPIO_OUT_1 MSM_GPIO2_REG(0x00) /* gpio 43-16 */
-#define MSM7X30_GPIO_OUT_2 MSM_GPIO1_REG(0x04) /* gpio 67-44 */
-#define MSM7X30_GPIO_OUT_3 MSM_GPIO1_REG(0x08) /* gpio 94-68 */
-#define MSM7X30_GPIO_OUT_4 MSM_GPIO1_REG(0x0C) /* gpio 106-95 */
-#define MSM7X30_GPIO_OUT_5 MSM_GPIO1_REG(0x50) /* gpio 133-107 */
-#define MSM7X30_GPIO_OUT_6 MSM_GPIO1_REG(0xC4) /* gpio 150-134 */
-#define MSM7X30_GPIO_OUT_7 MSM_GPIO1_REG(0x214) /* gpio 181-151 */
-
-/* same pin map as above, output enable */
-#define MSM7X30_GPIO_OE_0 MSM_GPIO1_REG(0x10)
-#define MSM7X30_GPIO_OE_1 MSM_GPIO2_REG(0x08)
-#define MSM7X30_GPIO_OE_2 MSM_GPIO1_REG(0x14)
-#define MSM7X30_GPIO_OE_3 MSM_GPIO1_REG(0x18)
-#define MSM7X30_GPIO_OE_4 MSM_GPIO1_REG(0x1C)
-#define MSM7X30_GPIO_OE_5 MSM_GPIO1_REG(0x54)
-#define MSM7X30_GPIO_OE_6 MSM_GPIO1_REG(0xC8)
-#define MSM7X30_GPIO_OE_7 MSM_GPIO1_REG(0x218)
-
-/* same pin map as above, input read */
-#define MSM7X30_GPIO_IN_0 MSM_GPIO1_REG(0x34)
-#define MSM7X30_GPIO_IN_1 MSM_GPIO2_REG(0x20)
-#define MSM7X30_GPIO_IN_2 MSM_GPIO1_REG(0x38)
-#define MSM7X30_GPIO_IN_3 MSM_GPIO1_REG(0x3C)
-#define MSM7X30_GPIO_IN_4 MSM_GPIO1_REG(0x40)
-#define MSM7X30_GPIO_IN_5 MSM_GPIO1_REG(0x44)
-#define MSM7X30_GPIO_IN_6 MSM_GPIO1_REG(0xCC)
-#define MSM7X30_GPIO_IN_7 MSM_GPIO1_REG(0x21C)
-
-/* same pin map as above, 1=edge 0=level interrup */
-#define MSM7X30_GPIO_INT_EDGE_0 MSM_GPIO1_REG(0x60)
-#define MSM7X30_GPIO_INT_EDGE_1 MSM_GPIO2_REG(0x50)
-#define MSM7X30_GPIO_INT_EDGE_2 MSM_GPIO1_REG(0x64)
-#define MSM7X30_GPIO_INT_EDGE_3 MSM_GPIO1_REG(0x68)
-#define MSM7X30_GPIO_INT_EDGE_4 MSM_GPIO1_REG(0x6C)
-#define MSM7X30_GPIO_INT_EDGE_5 MSM_GPIO1_REG(0xC0)
-#define MSM7X30_GPIO_INT_EDGE_6 MSM_GPIO1_REG(0xD0)
-#define MSM7X30_GPIO_INT_EDGE_7 MSM_GPIO1_REG(0x240)
-
-/* same pin map as above, 1=positive 0=negative */
-#define MSM7X30_GPIO_INT_POS_0 MSM_GPIO1_REG(0x70)
-#define MSM7X30_GPIO_INT_POS_1 MSM_GPIO2_REG(0x58)
-#define MSM7X30_GPIO_INT_POS_2 MSM_GPIO1_REG(0x74)
-#define MSM7X30_GPIO_INT_POS_3 MSM_GPIO1_REG(0x78)
-#define MSM7X30_GPIO_INT_POS_4 MSM_GPIO1_REG(0x7C)
-#define MSM7X30_GPIO_INT_POS_5 MSM_GPIO1_REG(0xBC)
-#define MSM7X30_GPIO_INT_POS_6 MSM_GPIO1_REG(0xD4)
-#define MSM7X30_GPIO_INT_POS_7 MSM_GPIO1_REG(0x228)
-
-/* same pin map as above, interrupt enable */
-#define MSM7X30_GPIO_INT_EN_0 MSM_GPIO1_REG(0x80)
-#define MSM7X30_GPIO_INT_EN_1 MSM_GPIO2_REG(0x60)
-#define MSM7X30_GPIO_INT_EN_2 MSM_GPIO1_REG(0x84)
-#define MSM7X30_GPIO_INT_EN_3 MSM_GPIO1_REG(0x88)
-#define MSM7X30_GPIO_INT_EN_4 MSM_GPIO1_REG(0x8C)
-#define MSM7X30_GPIO_INT_EN_5 MSM_GPIO1_REG(0xB8)
-#define MSM7X30_GPIO_INT_EN_6 MSM_GPIO1_REG(0xD8)
-#define MSM7X30_GPIO_INT_EN_7 MSM_GPIO1_REG(0x22C)
-
-/* same pin map as above, write 1 to clear interrupt */
-#define MSM7X30_GPIO_INT_CLEAR_0 MSM_GPIO1_REG(0x90)
-#define MSM7X30_GPIO_INT_CLEAR_1 MSM_GPIO2_REG(0x68)
-#define MSM7X30_GPIO_INT_CLEAR_2 MSM_GPIO1_REG(0x94)
-#define MSM7X30_GPIO_INT_CLEAR_3 MSM_GPIO1_REG(0x98)
-#define MSM7X30_GPIO_INT_CLEAR_4 MSM_GPIO1_REG(0x9C)
-#define MSM7X30_GPIO_INT_CLEAR_5 MSM_GPIO1_REG(0xB4)
-#define MSM7X30_GPIO_INT_CLEAR_6 MSM_GPIO1_REG(0xDC)
-#define MSM7X30_GPIO_INT_CLEAR_7 MSM_GPIO1_REG(0x230)
-
-/* same pin map as above, 1=interrupt pending */
-#define MSM7X30_GPIO_INT_STATUS_0 MSM_GPIO1_REG(0xA0)
-#define MSM7X30_GPIO_INT_STATUS_1 MSM_GPIO2_REG(0x70)
-#define MSM7X30_GPIO_INT_STATUS_2 MSM_GPIO1_REG(0xA4)
-#define MSM7X30_GPIO_INT_STATUS_3 MSM_GPIO1_REG(0xA8)
-#define MSM7X30_GPIO_INT_STATUS_4 MSM_GPIO1_REG(0xAC)
-#define MSM7X30_GPIO_INT_STATUS_5 MSM_GPIO1_REG(0xB0)
-#define MSM7X30_GPIO_INT_STATUS_6 MSM_GPIO1_REG(0xE0)
-#define MSM7X30_GPIO_INT_STATUS_7 MSM_GPIO1_REG(0x234)
-
-#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
-
-#define MSM_GPIO_BANK(soc, bank, first, last) \
- { \
- .regs[MSM_GPIO_OUT] = soc##_GPIO_OUT_##bank, \
- .regs[MSM_GPIO_IN] = soc##_GPIO_IN_##bank, \
- .regs[MSM_GPIO_INT_STATUS] = soc##_GPIO_INT_STATUS_##bank, \
- .regs[MSM_GPIO_INT_CLEAR] = soc##_GPIO_INT_CLEAR_##bank, \
- .regs[MSM_GPIO_INT_EN] = soc##_GPIO_INT_EN_##bank, \
- .regs[MSM_GPIO_INT_EDGE] = soc##_GPIO_INT_EDGE_##bank, \
- .regs[MSM_GPIO_INT_POS] = soc##_GPIO_INT_POS_##bank, \
- .regs[MSM_GPIO_OE] = soc##_GPIO_OE_##bank, \
- .chip = { \
- .base = (first), \
- .ngpio = (last) - (first) + 1, \
- .get = msm_gpio_get, \
- .set = msm_gpio_set, \
- .direction_input = msm_gpio_direction_input, \
- .direction_output = msm_gpio_direction_output, \
- .to_irq = msm_gpio_to_irq, \
- .request = msm_gpio_request, \
- .free = msm_gpio_free, \
- } \
- }
-
-#define MSM_GPIO_BROKEN_INT_CLEAR 1
-
-enum msm_gpio_reg {
- MSM_GPIO_IN,
- MSM_GPIO_OUT,
- MSM_GPIO_INT_STATUS,
- MSM_GPIO_INT_CLEAR,
- MSM_GPIO_INT_EN,
- MSM_GPIO_INT_EDGE,
- MSM_GPIO_INT_POS,
- MSM_GPIO_OE,
- MSM_GPIO_REG_NR
-};
-
-struct msm_gpio_chip {
- spinlock_t lock;
- struct gpio_chip chip;
- unsigned long regs[MSM_GPIO_REG_NR];
-#if MSM_GPIO_BROKEN_INT_CLEAR
- unsigned int_status_copy;
-#endif
- unsigned int both_edge_detect;
- unsigned int int_enable[2]; /* 0: awake, 1: sleep */
- void __iomem *base;
-};
-
-struct msm_gpio_initdata {
- struct msm_gpio_chip *chips;
- int count;
-};
-
-static void msm_gpio_writel(struct msm_gpio_chip *chip, u32 val,
- enum msm_gpio_reg reg)
-{
- writel(val, chip->base + chip->regs[reg]);
-}
-
-static u32 msm_gpio_readl(struct msm_gpio_chip *chip, enum msm_gpio_reg reg)
-{
- return readl(chip->base + chip->regs[reg]);
-}
-
-static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
- unsigned offset, unsigned on)
-{
- unsigned mask = BIT(offset);
- unsigned val;
-
- val = msm_gpio_readl(msm_chip, MSM_GPIO_OUT);
- if (on)
- msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_OUT);
- else
- msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_OUT);
- return 0;
-}
-
-static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
-{
- int loop_limit = 100;
- unsigned pol, val, val2, intstat;
- do {
- val = msm_gpio_readl(msm_chip, MSM_GPIO_IN);
- pol = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);
- pol = (pol & ~msm_chip->both_edge_detect) |
- (~val & msm_chip->both_edge_detect);
- msm_gpio_writel(msm_chip, pol, MSM_GPIO_INT_POS);
- intstat = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
- val2 = msm_gpio_readl(msm_chip, MSM_GPIO_IN);
- if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
- return;
- } while (loop_limit-- > 0);
- printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
- "failed to reach stable state %x != %x\n", val, val2);
-}
-
-static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
- unsigned offset)
-{
- unsigned bit = BIT(offset);
-
-#if MSM_GPIO_BROKEN_INT_CLEAR
- /* Save interrupts that already triggered before we loose them. */
- /* Any interrupt that triggers between the read of int_status */
- /* and the write to int_clear will still be lost though. */
- msm_chip->int_status_copy |=
- msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
- msm_chip->int_status_copy &= ~bit;
-#endif
- msm_gpio_writel(msm_chip, bit, MSM_GPIO_INT_CLEAR);
- msm_gpio_update_both_edge_detect(msm_chip);
- return 0;
-}
-
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct msm_gpio_chip *msm_chip;
- unsigned long irq_flags;
- u32 val;
-
- msm_chip = container_of(chip, struct msm_gpio_chip, chip);
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) & ~BIT(offset);
- msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
- return 0;
-}
-
-static int
-msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct msm_gpio_chip *msm_chip;
- unsigned long irq_flags;
- u32 val;
-
- msm_chip = container_of(chip, struct msm_gpio_chip, chip);
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- msm_gpio_write(msm_chip, offset, value);
- val = msm_gpio_readl(msm_chip, MSM_GPIO_OE) | BIT(offset);
- msm_gpio_writel(msm_chip, val, MSM_GPIO_OE);
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
- return 0;
-}
-
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct msm_gpio_chip *msm_chip;
-
- msm_chip = container_of(chip, struct msm_gpio_chip, chip);
- return (msm_gpio_readl(msm_chip, MSM_GPIO_IN) & (1U << offset)) ? 1 : 0;
-}
-
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct msm_gpio_chip *msm_chip;
- unsigned long irq_flags;
-
- msm_chip = container_of(chip, struct msm_gpio_chip, chip);
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- msm_gpio_write(msm_chip, offset, value);
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- return MSM_GPIO_TO_INT(chip->base + offset);
-}
-
-#ifdef CONFIG_MSM_GPIOMUX
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- msm_gpiomux_put(chip->base + offset);
-}
-#else
-#define msm_gpio_request NULL
-#define msm_gpio_free NULL
-#endif
-
-static struct msm_gpio_chip *msm_gpio_chips;
-static int msm_gpio_count;
-
-static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {
- MSM_GPIO_BANK(MSM7X00, 0, 0, 15),
- MSM_GPIO_BANK(MSM7X00, 1, 16, 42),
- MSM_GPIO_BANK(MSM7X00, 2, 43, 67),
- MSM_GPIO_BANK(MSM7X00, 3, 68, 94),
- MSM_GPIO_BANK(MSM7X00, 4, 95, 106),
- MSM_GPIO_BANK(MSM7X00, 5, 107, 121),
-};
-
-static struct msm_gpio_initdata msm_gpio_7x01_init = {
- .chips = msm_gpio_chips_msm7x01,
- .count = ARRAY_SIZE(msm_gpio_chips_msm7x01),
-};
-
-static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
- MSM_GPIO_BANK(MSM7X30, 0, 0, 15),
- MSM_GPIO_BANK(MSM7X30, 1, 16, 43),
- MSM_GPIO_BANK(MSM7X30, 2, 44, 67),
- MSM_GPIO_BANK(MSM7X30, 3, 68, 94),
- MSM_GPIO_BANK(MSM7X30, 4, 95, 106),
- MSM_GPIO_BANK(MSM7X30, 5, 107, 133),
- MSM_GPIO_BANK(MSM7X30, 6, 134, 150),
- MSM_GPIO_BANK(MSM7X30, 7, 151, 181),
-};
-
-static struct msm_gpio_initdata msm_gpio_7x30_init = {
- .chips = msm_gpio_chips_msm7x30,
- .count = ARRAY_SIZE(msm_gpio_chips_msm7x30),
-};
-
-static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
- MSM_GPIO_BANK(QSD8X50, 0, 0, 15),
- MSM_GPIO_BANK(QSD8X50, 1, 16, 42),
- MSM_GPIO_BANK(QSD8X50, 2, 43, 67),
- MSM_GPIO_BANK(QSD8X50, 3, 68, 94),
- MSM_GPIO_BANK(QSD8X50, 4, 95, 103),
- MSM_GPIO_BANK(QSD8X50, 5, 104, 121),
- MSM_GPIO_BANK(QSD8X50, 6, 122, 152),
- MSM_GPIO_BANK(QSD8X50, 7, 153, 164),
-};
-
-static struct msm_gpio_initdata msm_gpio_8x50_init = {
- .chips = msm_gpio_chips_qsd8x50,
- .count = ARRAY_SIZE(msm_gpio_chips_qsd8x50),
-};
-
-static void msm_gpio_irq_ack(struct irq_data *d)
-{
- unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- msm_gpio_clear_detect_status(msm_chip,
- d->irq - gpio_to_irq(msm_chip->chip.base));
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_mask(struct irq_data *d)
-{
- unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
- unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- /* level triggered interrupts are also latched */
- if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))
- msm_gpio_clear_detect_status(msm_chip, offset);
- msm_chip->int_enable[0] &= ~BIT(offset);
- msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
- unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
- unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- /* level triggered interrupts are also latched */
- if (!(msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE) & BIT(offset)))
- msm_gpio_clear_detect_status(msm_chip, offset);
- msm_chip->int_enable[0] |= BIT(offset);
- msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
- unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
- unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
-
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
-
- if (on)
- msm_chip->int_enable[1] |= BIT(offset);
- else
- msm_chip->int_enable[1] &= ~BIT(offset);
-
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
- return 0;
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
- unsigned long irq_flags;
- struct msm_gpio_chip *msm_chip = irq_data_get_irq_chip_data(d);
- unsigned offset = d->irq - gpio_to_irq(msm_chip->chip.base);
- unsigned val, mask = BIT(offset);
-
- spin_lock_irqsave(&msm_chip->lock, irq_flags);
- val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE);
- if (flow_type & IRQ_TYPE_EDGE_BOTH) {
- msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_INT_EDGE);
- __irq_set_handler_locked(d->irq, handle_edge_irq);
- } else {
- msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_INT_EDGE);
- __irq_set_handler_locked(d->irq, handle_level_irq);
- }
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
- msm_chip->both_edge_detect |= mask;
- msm_gpio_update_both_edge_detect(msm_chip);
- } else {
- msm_chip->both_edge_detect &= ~mask;
- val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);
- if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
- val |= mask;
- else
- val &= ~mask;
- msm_gpio_writel(msm_chip, val, MSM_GPIO_INT_POS);
- }
- spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
- return 0;
-}
-
-static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- int i, j, mask;
- unsigned val;
-
- for (i = 0; i < msm_gpio_count; i++) {
- struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
- val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
- val &= msm_chip->int_enable[0];
- while (val) {
- mask = val & -val;
- j = fls(mask) - 1;
- /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
- __func__, v, m, j, msm_chip->chip.start + j,
- FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
- val &= ~mask;
- generic_handle_irq(FIRST_GPIO_IRQ +
- msm_chip->chip.base + j);
- }
- }
- desc->irq_data.chip->irq_ack(&desc->irq_data);
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
- .name = "msmgpio",
- .irq_ack = msm_gpio_irq_ack,
- .irq_mask = msm_gpio_irq_mask,
- .irq_unmask = msm_gpio_irq_unmask,
- .irq_set_wake = msm_gpio_irq_set_wake,
- .irq_set_type = msm_gpio_irq_set_type,
-};
-
-static int gpio_msm_v1_probe(struct platform_device *pdev)
-{
- int i, j = 0;
- const struct platform_device_id *dev_id = platform_get_device_id(pdev);
- struct msm_gpio_initdata *data;
- int irq1, irq2;
- struct resource *res;
- void __iomem *base1, __iomem *base2;
-
- data = (struct msm_gpio_initdata *)dev_id->driver_data;
- msm_gpio_chips = data->chips;
- msm_gpio_count = data->count;
-
- irq1 = platform_get_irq(pdev, 0);
- if (irq1 < 0)
- return irq1;
-
- irq2 = platform_get_irq(pdev, 1);
- if (irq2 < 0)
- return irq2;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base1 = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base1))
- return PTR_ERR(base1);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- base2 = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(base2))
- return PTR_ERR(base2);
-
- for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
- if (i - FIRST_GPIO_IRQ >=
- msm_gpio_chips[j].chip.base +
- msm_gpio_chips[j].chip.ngpio)
- j++;
- irq_set_chip_data(i, &msm_gpio_chips[j]);
- irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
- handle_edge_irq);
- set_irq_flags(i, IRQF_VALID);
- }
-
- for (i = 0; i < msm_gpio_count; i++) {
- if (i == 1)
- msm_gpio_chips[i].base = base2;
- else
- msm_gpio_chips[i].base = base1;
- spin_lock_init(&msm_gpio_chips[i].lock);
- msm_gpio_writel(&msm_gpio_chips[i], 0, MSM_GPIO_INT_EN);
- gpiochip_add(&msm_gpio_chips[i].chip);
- }
-
- irq_set_chained_handler(irq1, msm_gpio_irq_handler);
- irq_set_chained_handler(irq2, msm_gpio_irq_handler);
- irq_set_irq_wake(irq1, 1);
- irq_set_irq_wake(irq2, 1);
- return 0;
-}
-
-static struct platform_device_id gpio_msm_v1_device_ids[] = {
- { "gpio-msm-7201", (unsigned long)&msm_gpio_7x01_init },
- { "gpio-msm-7x30", (unsigned long)&msm_gpio_7x30_init },
- { "gpio-msm-8x50", (unsigned long)&msm_gpio_8x50_init },
- { }
-};
-MODULE_DEVICE_TABLE(platform, gpio_msm_v1_device_ids);
-
-static struct platform_driver gpio_msm_v1_driver = {
- .driver = {
- .name = "gpio-msm-v1",
- },
- .probe = gpio_msm_v1_probe,
- .id_table = gpio_msm_v1_device_ids,
-};
-
-static int __init gpio_msm_v1_init(void)
-{
- return platform_driver_register(&gpio_msm_v1_driver);
-}
-postcore_initcall(gpio_msm_v1_init);
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index d0bc123c7975..1a54205860f5 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -320,11 +320,13 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
u32 mask = 1 << (d->irq - gc->irq_base);
irq_gc_lock(gc);
- gc->mask_cache &= ~mask;
- writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
+ ct->mask_cache_priv &= ~mask;
+
+ writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
irq_gc_unlock(gc);
}
@@ -332,11 +334,13 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
u32 mask = 1 << (d->irq - gc->irq_base);
irq_gc_lock(gc);
- gc->mask_cache |= mask;
- writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
+ ct->mask_cache_priv |= mask;
+ writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
irq_gc_unlock(gc);
}
@@ -344,11 +348,13 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
u32 mask = 1 << (d->irq - gc->irq_base);
irq_gc_lock(gc);
- gc->mask_cache &= ~mask;
- writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
+ ct->mask_cache_priv &= ~mask;
+ writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
irq_gc_unlock(gc);
}
@@ -356,11 +362,13 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mvebu_gpio_chip *mvchip = gc->private;
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
u32 mask = 1 << (d->irq - gc->irq_base);
irq_gc_lock(gc);
- gc->mask_cache |= mask;
- writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
+ ct->mask_cache_priv |= mask;
+ writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
irq_gc_unlock(gc);
}
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index f476ae2eb0b3..cd1d5bf48f36 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -75,14 +75,12 @@ struct gpio_bank {
int power_mode;
bool workaround_enabled;
- void (*set_dataout)(struct gpio_bank *bank, int gpio, int enable);
+ void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
int (*get_context_loss_count)(struct device *dev);
struct omap_gpio_reg_offs *regs;
};
-#define GPIO_INDEX(bank, gpio) (gpio % bank->width)
-#define GPIO_BIT(bank, gpio) (BIT(GPIO_INDEX(bank, gpio)))
#define GPIO_MOD_CTRL_BIT BIT(0)
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
@@ -90,11 +88,6 @@ struct gpio_bank {
static void omap_gpio_unmask_irq(struct irq_data *d);
-static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
-{
- return bank->chip.base + gpio_irq;
-}
-
static inline struct gpio_bank *omap_irq_data_get_bank(struct irq_data *d)
{
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
@@ -119,11 +112,11 @@ static void omap_set_gpio_direction(struct gpio_bank *bank, int gpio,
/* set data out value using dedicate set/clear register */
-static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio,
+static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, unsigned offset,
int enable)
{
void __iomem *reg = bank->base;
- u32 l = GPIO_BIT(bank, gpio);
+ u32 l = BIT(offset);
if (enable) {
reg += bank->regs->set_dataout;
@@ -137,11 +130,11 @@ static void omap_set_gpio_dataout_reg(struct gpio_bank *bank, int gpio,
}
/* set data out value using mask register */
-static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, int gpio,
+static void omap_set_gpio_dataout_mask(struct gpio_bank *bank, unsigned offset,
int enable)
{
void __iomem *reg = bank->base + bank->regs->dataout;
- u32 gpio_bit = GPIO_BIT(bank, gpio);
+ u32 gpio_bit = BIT(offset);
u32 l;
l = readl_relaxed(reg);
@@ -208,13 +201,13 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank)
/**
* omap2_set_gpio_debounce - low level gpio debounce time
* @bank: the gpio bank we're acting upon
- * @gpio: the gpio number on this @gpio
+ * @offset: the gpio number on this @bank
* @debounce: debounce time to use
*
* OMAP's debounce time is in 31us steps so we need
* to convert and round up to the closest unit.
*/
-static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
+static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset,
unsigned debounce)
{
void __iomem *reg;
@@ -231,7 +224,7 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
else
debounce = (debounce / 0x1f) - 1;
- l = GPIO_BIT(bank, gpio);
+ l = BIT(offset);
clk_prepare_enable(bank->dbck);
reg = bank->base + bank->regs->debounce;
@@ -266,16 +259,16 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
/**
* omap_clear_gpio_debounce - clear debounce settings for a gpio
* @bank: the gpio bank we're acting upon
- * @gpio: the gpio number on this @gpio
+ * @offset: the gpio number on this @bank
*
* If a gpio is using debounce, then clear the debounce enable bit and if
* this is the only gpio in this bank using debounce, then clear the debounce
* time too. The debounce clock will also be disabled when calling this function
* if this is the only gpio in the bank using debounce.
*/
-static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
+static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset)
{
- u32 gpio_bit = GPIO_BIT(bank, gpio);
+ u32 gpio_bit = BIT(offset);
if (!bank->dbck_flag)
return;
@@ -472,42 +465,32 @@ static void omap_disable_gpio_module(struct gpio_bank *bank, unsigned offset)
}
}
-static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
+static int omap_gpio_is_input(struct gpio_bank *bank, unsigned offset)
{
void __iomem *reg = bank->base + bank->regs->direction;
- return readl_relaxed(reg) & mask;
+ return readl_relaxed(reg) & BIT(offset);
}
-static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio,
- unsigned offset)
+static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned offset)
{
if (!LINE_USED(bank->mod_usage, offset)) {
omap_enable_gpio_module(bank, offset);
omap_set_gpio_direction(bank, offset, 1);
}
- bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
+ bank->irq_usage |= BIT(offset);
}
static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned gpio = 0;
int retval;
unsigned long flags;
- unsigned offset;
+ unsigned offset = d->hwirq;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
-#ifdef CONFIG_ARCH_OMAP1
- if (d->irq > IH_MPUIO_BASE)
- gpio = OMAP_MPUIO(d->irq - IH_MPUIO_BASE);
-#endif
-
- if (!gpio)
- gpio = omap_irq_to_gpio(bank, d->hwirq);
-
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -516,10 +499,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
return -EINVAL;
spin_lock_irqsave(&bank->lock, flags);
- offset = GPIO_INDEX(bank, gpio);
retval = omap_set_gpio_triggering(bank, offset, type);
- omap_gpio_init_irq(bank, gpio, offset);
- if (!omap_gpio_is_input(bank, BIT(offset))) {
+ omap_gpio_init_irq(bank, offset);
+ if (!omap_gpio_is_input(bank, offset)) {
spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
}
@@ -550,9 +532,10 @@ static void omap_clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
readl_relaxed(reg);
}
-static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
+static inline void omap_clear_gpio_irqstatus(struct gpio_bank *bank,
+ unsigned offset)
{
- omap_clear_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_clear_gpio_irqbank(bank, BIT(offset));
}
static u32 omap_get_gpio_irqbank_mask(struct gpio_bank *bank)
@@ -613,13 +596,13 @@ static void omap_disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
writel_relaxed(l, reg);
}
-static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio,
- int enable)
+static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
+ unsigned offset, int enable)
{
if (enable)
- omap_enable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_enable_gpio_irqbank(bank, BIT(offset));
else
- omap_disable_gpio_irqbank(bank, GPIO_BIT(bank, gpio));
+ omap_disable_gpio_irqbank(bank, BIT(offset));
}
/*
@@ -630,14 +613,16 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank, int gpio,
* enabled. When system is suspended, only selected GPIO interrupts need
* to have wake-up enabled.
*/
-static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
+static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
+ int enable)
{
- u32 gpio_bit = GPIO_BIT(bank, gpio);
+ u32 gpio_bit = BIT(offset);
unsigned long flags;
if (bank->non_wakeup_gpios & gpio_bit) {
dev_err(bank->dev,
- "Unable to modify wakeup on non-wakeup GPIO%d\n", gpio);
+ "Unable to modify wakeup on non-wakeup GPIO%d\n",
+ offset);
return -EINVAL;
}
@@ -653,22 +638,22 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
return 0;
}
-static void omap_reset_gpio(struct gpio_bank *bank, int gpio)
+static void omap_reset_gpio(struct gpio_bank *bank, unsigned offset)
{
- omap_set_gpio_direction(bank, GPIO_INDEX(bank, gpio), 1);
- omap_set_gpio_irqenable(bank, gpio, 0);
- omap_clear_gpio_irqstatus(bank, gpio);
- omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
- omap_clear_gpio_debounce(bank, gpio);
+ omap_set_gpio_direction(bank, offset, 1);
+ omap_set_gpio_irqenable(bank, offset, 0);
+ omap_clear_gpio_irqstatus(bank, offset);
+ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_clear_gpio_debounce(bank, offset);
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
+ unsigned offset = d->hwirq;
- return omap_set_gpio_wakeup(bank, gpio, enable);
+ return omap_set_gpio_wakeup(bank, offset, enable);
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -706,7 +691,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
spin_lock_irqsave(&bank->lock, flags);
bank->mod_usage &= ~(BIT(offset));
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, bank->chip.base + offset);
+ omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -803,15 +788,14 @@ exit:
static unsigned int omap_gpio_irq_startup(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned long flags;
- unsigned offset = GPIO_INDEX(bank, gpio);
+ unsigned offset = d->hwirq;
if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
- omap_gpio_init_irq(bank, gpio, offset);
+ omap_gpio_init_irq(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
omap_gpio_unmask_irq(d);
@@ -821,15 +805,13 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
static void omap_gpio_irq_shutdown(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
unsigned long flags;
- unsigned offset = GPIO_INDEX(bank, gpio);
+ unsigned offset = d->hwirq;
spin_lock_irqsave(&bank->lock, flags);
- gpiochip_unlock_as_irq(&bank->chip, offset);
bank->irq_usage &= ~(BIT(offset));
omap_disable_gpio_module(bank, offset);
- omap_reset_gpio(bank, gpio);
+ omap_reset_gpio(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
/*
@@ -843,43 +825,42 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
static void omap_gpio_ack_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
+ unsigned offset = d->hwirq;
- omap_clear_gpio_irqstatus(bank, gpio);
+ omap_clear_gpio_irqstatus(bank, offset);
}
static void omap_gpio_mask_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
+ unsigned offset = d->hwirq;
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- omap_set_gpio_irqenable(bank, gpio, 0);
- omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+ omap_set_gpio_irqenable(bank, offset, 0);
+ omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
spin_unlock_irqrestore(&bank->lock, flags);
}
static void omap_gpio_unmask_irq(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
- unsigned int irq_mask = GPIO_BIT(bank, gpio);
+ unsigned offset = d->hwirq;
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
if (trigger)
- omap_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), trigger);
+ omap_set_gpio_triggering(bank, offset, trigger);
/* For level-triggered GPIOs, the clearing must be done after
* the HW source is cleared, thus after the handler has run */
- if (bank->level_mask & irq_mask) {
- omap_set_gpio_irqenable(bank, gpio, 0);
- omap_clear_gpio_irqstatus(bank, gpio);
+ if (bank->level_mask & BIT(offset)) {
+ omap_set_gpio_irqenable(bank, offset, 0);
+ omap_clear_gpio_irqstatus(bank, offset);
}
- omap_set_gpio_irqenable(bank, gpio, 1);
+ omap_set_gpio_irqenable(bank, offset, 1);
spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -977,12 +958,10 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset)
static int omap_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
- u32 mask;
bank = container_of(chip, struct gpio_bank, chip);
- mask = (BIT(offset));
- if (omap_gpio_is_input(bank, mask))
+ if (omap_gpio_is_input(bank, offset))
return omap_get_gpio_datain(bank, offset);
else
return omap_get_gpio_dataout(bank, offset);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 236708ad0a5b..945f0cda8529 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -88,11 +88,9 @@ struct pcf857x {
struct gpio_chip chip;
struct i2c_client *client;
struct mutex lock; /* protect 'out' */
- struct irq_domain *irq_domain; /* for irq demux */
spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */
unsigned status; /* current status */
- unsigned irq_mapped; /* mapped gpio irqs */
int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client);
@@ -182,18 +180,6 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
/*-------------------------------------------------------------------------*/
-static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
- int ret;
-
- ret = irq_create_mapping(gpio->irq_domain, offset);
- if (ret > 0)
- gpio->irq_mapped |= (1 << offset);
-
- return ret;
-}
-
static irqreturn_t pcf857x_irq(int irq, void *data)
{
struct pcf857x *gpio = data;
@@ -208,9 +194,9 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
* interrupt source, just to avoid bad irqs
*/
- change = ((gpio->status ^ status) & gpio->irq_mapped);
+ change = (gpio->status ^ status);
for_each_set_bit(i, &change, gpio->chip.ngpio)
- generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
+ handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
gpio->status = status;
spin_unlock_irqrestore(&gpio->slock, flags);
@@ -218,66 +204,36 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hw)
-{
- struct pcf857x *gpio = domain->host_data;
-
- irq_set_chip_and_handler(irq,
- &dummy_irq_chip,
- handle_level_irq);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
- gpio->irq_mapped |= (1 << hw);
-
- return 0;
-}
-
-static struct irq_domain_ops pcf857x_irq_domain_ops = {
- .map = pcf857x_irq_domain_map,
-};
+/*
+ * NOP functions
+ */
+static void noop(struct irq_data *data) { }
-static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
+static unsigned int noop_ret(struct irq_data *data)
{
- if (gpio->irq_domain)
- irq_domain_remove(gpio->irq_domain);
-
+ return 0;
}
-static int pcf857x_irq_domain_init(struct pcf857x *gpio,
- struct i2c_client *client)
+static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
{
- int status;
-
- gpio->irq_domain = irq_domain_add_linear(client->dev.of_node,
- gpio->chip.ngpio,
- &pcf857x_irq_domain_ops,
- gpio);
- if (!gpio->irq_domain)
- goto fail;
-
- /* enable real irq */
- status = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, pcf857x_irq, IRQF_ONESHOT |
- IRQF_TRIGGER_FALLING | IRQF_SHARED,
- dev_name(&client->dev), gpio);
-
- if (status)
- goto fail;
-
- /* enable gpio_to_irq() */
- gpio->chip.to_irq = pcf857x_to_irq;
+ struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+ irq_set_irq_wake(gpio->client->irq, on);
return 0;
-
-fail:
- pcf857x_irq_domain_cleanup(gpio);
- return -EINVAL;
}
+static struct irq_chip pcf857x_irq_chip = {
+ .name = "pcf857x",
+ .irq_startup = noop_ret,
+ .irq_shutdown = noop,
+ .irq_enable = noop,
+ .irq_disable = noop,
+ .irq_ack = noop,
+ .irq_mask = noop,
+ .irq_unmask = noop,
+ .irq_set_wake = pcf857x_irq_set_wake,
+};
+
/*-------------------------------------------------------------------------*/
static int pcf857x_probe(struct i2c_client *client,
@@ -314,15 +270,6 @@ static int pcf857x_probe(struct i2c_client *client,
gpio->chip.direction_output = pcf857x_output;
gpio->chip.ngpio = id->driver_data;
- /* enable gpio_to_irq() if platform has settings */
- if (client->irq) {
- status = pcf857x_irq_domain_init(gpio, client);
- if (status < 0) {
- dev_err(&client->dev, "irq_domain init failed\n");
- goto fail_irq_domain;
- }
- }
-
/* NOTE: the OnSemi jlc1562b is also largely compatible with
* these parts, notably for output. It has a low-resolution
* DAC instead of pin change IRQs; and its inputs can be the
@@ -398,6 +345,27 @@ static int pcf857x_probe(struct i2c_client *client,
if (status < 0)
goto fail;
+ /* Enable irqchip if we have an interrupt */
+ if (client->irq) {
+ status = gpiochip_irqchip_add(&gpio->chip, &pcf857x_irq_chip,
+ 0, handle_level_irq,
+ IRQ_TYPE_NONE);
+ if (status) {
+ dev_err(&client->dev, "cannot add irqchip\n");
+ goto fail_irq;
+ }
+
+ status = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, pcf857x_irq, IRQF_ONESHOT |
+ IRQF_TRIGGER_FALLING | IRQF_SHARED,
+ dev_name(&client->dev), gpio);
+ if (status)
+ goto fail_irq;
+
+ gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
+ client->irq, NULL);
+ }
+
/* Let platform code set up the GPIOs and their users.
* Now is the first time anyone could use them.
*/
@@ -413,13 +381,12 @@ static int pcf857x_probe(struct i2c_client *client,
return 0;
-fail:
- if (client->irq)
- pcf857x_irq_domain_cleanup(gpio);
+fail_irq:
+ gpiochip_remove(&gpio->chip);
-fail_irq_domain:
- dev_dbg(&client->dev, "probe error %d for '%s'\n",
- status, client->name);
+fail:
+ dev_dbg(&client->dev, "probe error %d for '%s'\n", status,
+ client->name);
return status;
}
@@ -441,9 +408,6 @@ static int pcf857x_remove(struct i2c_client *client)
}
}
- if (client->irq)
- pcf857x_irq_domain_cleanup(gpio);
-
gpiochip_remove(&gpio->chip);
return status;
}
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 2fdb04b6f101..cdbbcf0faf9d 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -59,8 +59,7 @@
#define GAFR_OFFSET 0x54
#define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */
-#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \
- + (((n) % 3) << 2))
+#define BANK_OFF(n) (((n) / 3) << 8) + (((n) % 3) << 2)
int pxa_last_gpio;
static int irq_base;
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index c49522efa7b3..fd3977465948 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -14,6 +14,7 @@
* GNU General Public License for more details.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
@@ -37,20 +38,22 @@ struct gpio_rcar_priv {
struct platform_device *pdev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
+ unsigned int irq_parent;
+ struct clk *clk;
};
-#define IOINTSEL 0x00
-#define INOUTSEL 0x04
-#define OUTDT 0x08
-#define INDT 0x0c
-#define INTDT 0x10
-#define INTCLR 0x14
-#define INTMSK 0x18
-#define MSKCLR 0x1c
-#define POSNEG 0x20
-#define EDGLEVEL 0x24
-#define FILONOFF 0x28
-#define BOTHEDGE 0x4c
+#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
+#define INOUTSEL 0x04 /* General Input/Output Switching Register */
+#define OUTDT 0x08 /* General Output Register */
+#define INDT 0x0c /* General Input Register */
+#define INTDT 0x10 /* Interrupt Display Register */
+#define INTCLR 0x14 /* Interrupt Clear Register */
+#define INTMSK 0x18 /* Interrupt Mask Register */
+#define MSKCLR 0x1c /* Interrupt Mask Clear Register */
+#define POSNEG 0x20 /* Positive/Negative Logic Select Register */
+#define EDGLEVEL 0x24 /* Edge/level Select Register */
+#define FILONOFF 0x28 /* Chattering Prevention On/Off Register */
+#define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */
#define RCAR_MAX_GPIO_PER_BANK 32
@@ -169,6 +172,25 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
+static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+ gpio_chip);
+
+ irq_set_irq_wake(p->irq_parent, on);
+
+ if (!p->clk)
+ return 0;
+
+ if (on)
+ clk_enable(p->clk);
+ else
+ clk_disable(p->clk);
+
+ return 0;
+}
+
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
{
struct gpio_rcar_priv *p = dev_id;
@@ -367,6 +389,12 @@ static int gpio_rcar_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, p);
+ p->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(p->clk)) {
+ dev_warn(dev, "unable to get clock\n");
+ p->clk = NULL;
+ }
+
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -404,8 +432,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->irq_mask = gpio_rcar_irq_disable;
irq_chip->irq_unmask = gpio_rcar_irq_enable;
irq_chip->irq_set_type = gpio_rcar_irq_set_type;
- irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED
- | IRQCHIP_MASK_ON_SUSPEND;
+ irq_chip->irq_set_wake = gpio_rcar_irq_set_wake;
+ irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ret = gpiochip_add(gpio_chip);
if (ret) {
@@ -413,13 +441,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err0;
}
- ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base,
+ ret = gpiochip_irqchip_add(gpio_chip, irq_chip, p->config.irq_base,
handle_level_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "cannot add irqchip\n");
goto err1;
}
+ p->irq_parent = irq->start;
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
IRQF_SHARED, name, p)) {
dev_err(dev, "failed to request IRQ\n");
@@ -431,7 +460,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
/* warn in case of mismatch if irq base is specified */
if (p->config.irq_base) {
- ret = irq_find_mapping(p->gpio_chip.irqdomain, 0);
+ ret = irq_find_mapping(gpio_chip->irqdomain, 0);
if (p->config.irq_base != ret)
dev_warn(dev, "irq base mismatch (%u/%u)\n",
p->config.irq_base, ret);
@@ -447,7 +476,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
return 0;
err1:
- gpiochip_remove(&p->gpio_chip);
+ gpiochip_remove(gpio_chip);
err0:
pm_runtime_put(dev);
pm_runtime_disable(dev);
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
index 62ab9f4b2cd3..46b89614aa91 100644
--- a/drivers/gpio/gpio-tb10x.c
+++ b/drivers/gpio/gpio-tb10x.c
@@ -283,7 +283,7 @@ fail_ioremap:
return ret;
}
-static int __exit tb10x_gpio_remove(struct platform_device *pdev)
+static int tb10x_gpio_remove(struct platform_device *pdev)
{
struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev);
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 971c73964ef1..7bd9f209ffa8 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -244,16 +244,16 @@ static int vf610_gpio_probe(struct platform_device *pdev)
gc = &port->gc;
gc->of_node = np;
gc->dev = dev;
- gc->label = "vf610-gpio",
- gc->ngpio = VF610_GPIO_PER_PORT,
+ gc->label = "vf610-gpio";
+ gc->ngpio = VF610_GPIO_PER_PORT;
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
- gc->request = vf610_gpio_request,
- gc->free = vf610_gpio_free,
- gc->direction_input = vf610_gpio_direction_input,
- gc->get = vf610_gpio_get,
- gc->direction_output = vf610_gpio_direction_output,
- gc->set = vf610_gpio_set,
+ gc->request = vf610_gpio_request;
+ gc->free = vf610_gpio_free;
+ gc->direction_input = vf610_gpio_direction_input;
+ gc->get = vf610_gpio_get;
+ gc->direction_output = vf610_gpio_direction_output;
+ gc->set = vf610_gpio_set;
ret = gpiochip_add(gc);
if (ret < 0)
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index b6a15c39293e..fb9d29a5d584 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -93,7 +93,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(&pdev->dev, res);
- if (!regs)
+ if (IS_ERR(regs))
return PTR_ERR(regs);
ret = bgpio_init(&priv->bgc, &pdev->dev, 4,
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index df990f29757a..d2303d50f561 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -304,7 +304,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
return;
INIT_LIST_HEAD(&acpi_gpio->events);
- acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI",
+ acpi_walk_resources(handle, "_AEI",
acpi_gpiochip_request_interrupt, acpi_gpio);
}
@@ -722,3 +722,87 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
acpi_detach_data(handle, acpi_gpio_chip_dh);
kfree(acpi_gpio);
}
+
+static unsigned int acpi_gpio_package_count(const union acpi_object *obj)
+{
+ const union acpi_object *element = obj->package.elements;
+ const union acpi_object *end = element + obj->package.count;
+ unsigned int count = 0;
+
+ while (element < end) {
+ if (element->type == ACPI_TYPE_LOCAL_REFERENCE)
+ count++;
+
+ element++;
+ }
+ return count;
+}
+
+static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
+{
+ unsigned int *count = data;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_GPIO)
+ *count += ares->data.gpio.pin_table_length;
+
+ return 1;
+}
+
+/**
+ * acpi_gpio_count - return the number of GPIOs associated with a
+ * device / function or -ENOENT if no GPIO has been
+ * assigned to the requested function.
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ */
+int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ const union acpi_object *obj;
+ const struct acpi_gpio_mapping *gm;
+ int count = -ENOENT;
+ int ret;
+ char propname[32];
+ unsigned int i;
+
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios"))
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, gpio_suffixes[i]);
+ else
+ snprintf(propname, sizeof(propname), "%s",
+ gpio_suffixes[i]);
+
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ &obj);
+ if (ret == 0) {
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
+ count = 1;
+ else if (obj->type == ACPI_TYPE_PACKAGE)
+ count = acpi_gpio_package_count(obj);
+ } else if (adev->driver_gpios) {
+ for (gm = adev->driver_gpios; gm->name; gm++)
+ if (strcmp(propname, gm->name) == 0) {
+ count = gm->size;
+ break;
+ }
+ }
+ if (count >= 0)
+ break;
+ }
+
+ /* Then from plain _CRS GPIOs */
+ if (count < 0) {
+ struct list_head resource_list;
+ unsigned int crs_count = 0;
+
+ INIT_LIST_HEAD(&resource_list);
+ acpi_dev_get_resources(adev, &resource_list,
+ acpi_find_gpio_count, &crs_count);
+ acpi_dev_free_resource_list(&resource_list);
+ if (crs_count > 0)
+ count = crs_count;
+ }
+ return count;
+}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 4650bf830d6b..a6c67c6b4680 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -22,6 +22,7 @@
#include <linux/of_gpio.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
+#include <linux/gpio/machine.h>
#include "gpiolib.h"
@@ -118,6 +119,114 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
+ * of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API
+ * @np: device node to get GPIO from
+ * @name: GPIO line name
+ * @lflags: gpio_lookup_flags - returned from of_find_gpio() or
+ * of_get_gpio_hog()
+ * @dflags: gpiod_flags - optional GPIO initialization flags
+ *
+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static struct gpio_desc *of_get_gpio_hog(struct device_node *np,
+ const char **name,
+ enum gpio_lookup_flags *lflags,
+ enum gpiod_flags *dflags)
+{
+ struct device_node *chip_np;
+ enum of_gpio_flags xlate_flags;
+ struct gpio_desc *desc;
+ struct gg_data gg_data = {
+ .flags = &xlate_flags,
+ };
+ u32 tmp;
+ int i, ret;
+
+ chip_np = np->parent;
+ if (!chip_np)
+ return ERR_PTR(-EINVAL);
+
+ xlate_flags = 0;
+ *lflags = 0;
+ *dflags = 0;
+
+ ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (tmp > MAX_PHANDLE_ARGS)
+ return ERR_PTR(-EINVAL);
+
+ gg_data.gpiospec.args_count = tmp;
+ gg_data.gpiospec.np = chip_np;
+ for (i = 0; i < tmp; i++) {
+ ret = of_property_read_u32_index(np, "gpios", i,
+ &gg_data.gpiospec.args[i]);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
+ if (!gg_data.out_gpio) {
+ if (np->parent == np)
+ return ERR_PTR(-ENXIO);
+ else
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (xlate_flags & OF_GPIO_ACTIVE_LOW)
+ *lflags |= GPIO_ACTIVE_LOW;
+
+ if (of_property_read_bool(np, "input"))
+ *dflags |= GPIOD_IN;
+ else if (of_property_read_bool(np, "output-low"))
+ *dflags |= GPIOD_OUT_LOW;
+ else if (of_property_read_bool(np, "output-high"))
+ *dflags |= GPIOD_OUT_HIGH;
+ else {
+ pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
+ desc_to_gpio(gg_data.out_gpio), np->name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (name && of_property_read_string(np, "line-name", name))
+ *name = np->name;
+
+ desc = gg_data.out_gpio;
+
+ return desc;
+}
+
+/**
+ * of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested
+ * @chip: gpio chip to act on
+ *
+ * This is only used by of_gpiochip_add to request/set GPIO initial
+ * configuration.
+ */
+static void of_gpiochip_scan_hogs(struct gpio_chip *chip)
+{
+ struct gpio_desc *desc = NULL;
+ struct device_node *np;
+ const char *name;
+ enum gpio_lookup_flags lflags;
+ enum gpiod_flags dflags;
+
+ for_each_child_of_node(chip->of_node, np) {
+ if (!of_property_read_bool(np, "gpio-hog"))
+ continue;
+
+ desc = of_get_gpio_hog(np, &name, &lflags, &dflags);
+ if (IS_ERR(desc))
+ continue;
+
+ if (gpiod_hog(desc, name, lflags, dflags))
+ continue;
+ }
+}
+
+/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
* @gc: pointer to the gpio_chip structure
* @np: device node of the GPIO chip
@@ -326,6 +435,8 @@ void of_gpiochip_add(struct gpio_chip *chip)
of_gpiochip_add_pin_range(chip);
of_node_get(chip->of_node);
+
+ of_gpiochip_scan_hogs(chip);
}
void of_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1ca9295b2c10..59eaa23767d8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -315,6 +315,7 @@ EXPORT_SYMBOL_GPL(gpiochip_add);
/* Forward-declaration */
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+static void gpiochip_free_hogs(struct gpio_chip *chip);
/**
* gpiochip_remove() - unregister a gpio_chip
@@ -333,6 +334,7 @@ void gpiochip_remove(struct gpio_chip *chip)
acpi_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip);
+ gpiochip_free_hogs(chip);
of_gpiochip_remove(chip);
spin_lock_irqsave(&gpio_lock, flags);
@@ -866,6 +868,7 @@ static bool __gpiod_free(struct gpio_desc *desc)
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+ clear_bit(FLAG_IS_HOGGED, &desc->flags);
ret = true;
}
@@ -1659,19 +1662,18 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
- static const char * const suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
struct gpio_desc *desc;
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id)
snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
- suffixes[i]);
+ gpio_suffixes[i]);
else
snprintf(prop_name, sizeof(prop_name), "%s",
- suffixes[i]);
+ gpio_suffixes[i]);
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
&of_flags);
@@ -1692,7 +1694,6 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
- static const char * const suffixes[] = { "gpios", "gpio" };
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
@@ -1700,13 +1701,13 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
int i;
/* Try first from _DSD */
- for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id && strcmp(con_id, "gpios")) {
snprintf(propname, sizeof(propname), "%s-%s",
- con_id, suffixes[i]);
+ con_id, gpio_suffixes[i]);
} else {
snprintf(propname, sizeof(propname), "%s",
- suffixes[i]);
+ gpio_suffixes[i]);
}
desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
@@ -1805,6 +1806,70 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return desc;
}
+static int dt_gpio_count(struct device *dev, const char *con_id)
+{
+ int ret;
+ char propname[32];
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+ if (con_id)
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, gpio_suffixes[i]);
+ else
+ snprintf(propname, sizeof(propname), "%s",
+ gpio_suffixes[i]);
+
+ ret = of_gpio_named_count(dev->of_node, propname);
+ if (ret >= 0)
+ break;
+ }
+ return ret;
+}
+
+static int platform_gpio_count(struct device *dev, const char *con_id)
+{
+ struct gpiod_lookup_table *table;
+ struct gpiod_lookup *p;
+ unsigned int count = 0;
+
+ table = gpiod_find_lookup_table(dev);
+ if (!table)
+ return -ENOENT;
+
+ for (p = &table->table[0]; p->chip_label; p++) {
+ if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) ||
+ (!con_id && !p->con_id))
+ count++;
+ }
+ if (!count)
+ return -ENOENT;
+
+ return count;
+}
+
+/**
+ * gpiod_count - return the number of GPIOs associated with a device / function
+ * or -ENOENT if no GPIO has been assigned to the requested function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ */
+int gpiod_count(struct device *dev, const char *con_id)
+{
+ int count = -ENOENT;
+
+ if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+ count = dt_gpio_count(dev, con_id);
+ else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
+ count = acpi_gpio_count(dev, con_id);
+
+ if (count < 0)
+ count = platform_gpio_count(dev, con_id);
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(gpiod_count);
+
/**
* gpiod_get - obtain a GPIO for a given GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
@@ -1840,6 +1905,47 @@ struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev,
}
EXPORT_SYMBOL_GPL(__gpiod_get_optional);
+
+/**
+ * gpiod_configure_flags - helper function to configure a given GPIO
+ * @desc: gpio whose value will be assigned
+ * @con_id: function within the GPIO consumer
+ * @lflags: gpio_lookup_flags - returned from of_find_gpio() or
+ * of_get_gpio_hog()
+ * @dflags: gpiod_flags - optional GPIO initialization flags
+ *
+ * Return 0 on success, -ENOENT if no GPIO has been assigned to the
+ * requested function and/or index, or another IS_ERR() code if an error
+ * occurred while trying to acquire the GPIO.
+ */
+static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
+ unsigned long lflags, enum gpiod_flags dflags)
+{
+ int status;
+
+ if (lflags & GPIO_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ if (lflags & GPIO_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ if (lflags & GPIO_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+ /* No particular flag request, return here... */
+ if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
+ pr_debug("no flags found for %s\n", con_id);
+ return 0;
+ }
+
+ /* Process flags */
+ if (dflags & GPIOD_FLAGS_BIT_DIR_OUT)
+ status = gpiod_direction_output(desc,
+ dflags & GPIOD_FLAGS_BIT_DIR_VAL);
+ else
+ status = gpiod_direction_input(desc);
+
+ return status;
+}
+
/**
* gpiod_get_index - obtain a GPIO from a multi-index GPIO function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
@@ -1865,13 +1971,15 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
- /* Using device tree? */
- if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node) {
- dev_dbg(dev, "using device tree for GPIO lookup\n");
- desc = of_find_gpio(dev, con_id, idx, &lookupflags);
- } else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev)) {
- dev_dbg(dev, "using ACPI for GPIO lookup\n");
- desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
+ if (dev) {
+ /* Using device tree? */
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ dev_dbg(dev, "using device tree for GPIO lookup\n");
+ desc = of_find_gpio(dev, con_id, idx, &lookupflags);
+ } else if (ACPI_COMPANION(dev)) {
+ dev_dbg(dev, "using ACPI for GPIO lookup\n");
+ desc = acpi_find_gpio(dev, con_id, idx, &lookupflags);
+ }
}
/*
@@ -1889,28 +1997,10 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
}
status = gpiod_request(desc, con_id);
-
if (status < 0)
return ERR_PTR(status);
- if (lookupflags & GPIO_ACTIVE_LOW)
- set_bit(FLAG_ACTIVE_LOW, &desc->flags);
- if (lookupflags & GPIO_OPEN_DRAIN)
- set_bit(FLAG_OPEN_DRAIN, &desc->flags);
- if (lookupflags & GPIO_OPEN_SOURCE)
- set_bit(FLAG_OPEN_SOURCE, &desc->flags);
-
- /* No particular flag request, return here... */
- if (!(flags & GPIOD_FLAGS_BIT_DIR_SET))
- return desc;
-
- /* Process flags */
- if (flags & GPIOD_FLAGS_BIT_DIR_OUT)
- status = gpiod_direction_output(desc,
- flags & GPIOD_FLAGS_BIT_DIR_VAL);
- else
- status = gpiod_direction_input(desc);
-
+ status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (status < 0) {
dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
gpiod_put(desc);
@@ -2006,6 +2096,132 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev,
EXPORT_SYMBOL_GPL(__gpiod_get_index_optional);
/**
+ * gpiod_hog - Hog the specified GPIO desc given the provided flags
+ * @desc: gpio whose value will be assigned
+ * @name: gpio line name
+ * @lflags: gpio_lookup_flags - returned from of_find_gpio() or
+ * of_get_gpio_hog()
+ * @dflags: gpiod_flags - optional GPIO initialization flags
+ */
+int gpiod_hog(struct gpio_desc *desc, const char *name,
+ unsigned long lflags, enum gpiod_flags dflags)
+{
+ struct gpio_chip *chip;
+ struct gpio_desc *local_desc;
+ int hwnum;
+ int status;
+
+ chip = gpiod_to_chip(desc);
+ hwnum = gpio_chip_hwgpio(desc);
+
+ local_desc = gpiochip_request_own_desc(chip, hwnum, name);
+ if (IS_ERR(local_desc)) {
+ pr_debug("requesting own GPIO %s failed\n", name);
+ return PTR_ERR(local_desc);
+ }
+
+ status = gpiod_configure_flags(desc, name, lflags, dflags);
+ if (status < 0) {
+ pr_debug("setup of GPIO %s failed\n", name);
+ gpiochip_free_own_desc(desc);
+ return status;
+ }
+
+ /* Mark GPIO as hogged so it can be identified and removed later */
+ set_bit(FLAG_IS_HOGGED, &desc->flags);
+
+ pr_info("GPIO line %d (%s) hogged as %s%s\n",
+ desc_to_gpio(desc), name,
+ (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input",
+ (dflags&GPIOD_FLAGS_BIT_DIR_OUT) ?
+ (dflags&GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low":"");
+
+ return 0;
+}
+
+/**
+ * gpiochip_free_hogs - Scan gpio-controller chip and release GPIO hog
+ * @chip: gpio chip to act on
+ *
+ * This is only used by of_gpiochip_remove to free hogged gpios
+ */
+static void gpiochip_free_hogs(struct gpio_chip *chip)
+{
+ int id;
+
+ for (id = 0; id < chip->ngpio; id++) {
+ if (test_bit(FLAG_IS_HOGGED, &chip->desc[id].flags))
+ gpiochip_free_own_desc(&chip->desc[id]);
+ }
+}
+
+/**
+ * gpiod_get_array - obtain multiple GPIOs from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This function acquires all the GPIOs defined under a given function.
+ *
+ * Return a struct gpio_descs containing an array of descriptors, -ENOENT if
+ * no GPIO has been assigned to the requested function, or another IS_ERR()
+ * code if an error occurred while trying to acquire the GPIOs.
+ */
+struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+ struct gpio_descs *descs;
+ int count;
+
+ count = gpiod_count(dev, con_id);
+ if (count < 0)
+ return ERR_PTR(count);
+
+ descs = kzalloc(sizeof(*descs) + sizeof(descs->desc[0]) * count,
+ GFP_KERNEL);
+ if (!descs)
+ return ERR_PTR(-ENOMEM);
+
+ for (descs->ndescs = 0; descs->ndescs < count; ) {
+ desc = gpiod_get_index(dev, con_id, descs->ndescs, flags);
+ if (IS_ERR(desc)) {
+ gpiod_put_array(descs);
+ return ERR_CAST(desc);
+ }
+ descs->desc[descs->ndescs] = desc;
+ descs->ndescs++;
+ }
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array);
+
+/**
+ * gpiod_get_array_optional - obtain multiple GPIOs from a multi-index GPIO
+ * function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get_array(), except that when no GPIO was
+ * assigned to the requested function it will return NULL.
+ */
+struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
+ const char *con_id,
+ enum gpiod_flags flags)
+{
+ struct gpio_descs *descs;
+
+ descs = gpiod_get_array(dev, con_id, flags);
+ if (IS_ERR(descs) && (PTR_ERR(descs) == -ENOENT))
+ return NULL;
+
+ return descs;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_array_optional);
+
+/**
* gpiod_put - dispose of a GPIO descriptor
* @desc: GPIO descriptor to dispose of
*
@@ -2017,6 +2233,21 @@ void gpiod_put(struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_put);
+/**
+ * gpiod_put_array - dispose of multiple GPIO descriptors
+ * @descs: struct gpio_descs containing an array of descriptors
+ */
+void gpiod_put_array(struct gpio_descs *descs)
+{
+ unsigned int i;
+
+ for (i = 0; i < descs->ndescs; i++)
+ gpiod_put(descs->desc[i]);
+
+ kfree(descs);
+}
+EXPORT_SYMBOL_GPL(gpiod_put_array);
+
#ifdef CONFIG_DEBUG_FS
static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index ab892be26dc2..594b1798c0e7 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -29,6 +29,9 @@ struct acpi_gpio_info {
bool active_low;
};
+/* gpio suffixes used for ACPI and device tree lookup */
+static const char * const gpio_suffixes[] = { "gpios", "gpio" };
+
#ifdef CONFIG_ACPI
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
@@ -39,6 +42,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
const char *propname, int index,
struct acpi_gpio_info *info);
+
+int acpi_gpio_count(struct device *dev, const char *con_id);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
@@ -55,6 +60,11 @@ acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
{
return ERR_PTR(-ENOSYS);
}
+
+static inline int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+ return -ENODEV;
+}
#endif
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
@@ -80,6 +90,7 @@ struct gpio_desc {
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define FLAG_SYSFS_DIR 10 /* show sysfs direction attribute */
+#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
#define ID_SHIFT 16 /* add new flags before this one */
@@ -91,6 +102,8 @@ struct gpio_desc {
int gpiod_request(struct gpio_desc *desc, const char *label);
void gpiod_free(struct gpio_desc *desc);
+int gpiod_hog(struct gpio_desc *desc, const char *name,
+ unsigned long lflags, enum gpiod_flags dflags);
/*
* Return the GPIO number of the passed descriptor relative to its chip