aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig299
-rw-r--r--drivers/gpio/Makefile39
-rw-r--r--drivers/gpio/devres.c142
-rw-r--r--drivers/gpio/gpio-74x164.c74
-rw-r--r--drivers/gpio/gpio-ab8500.c520
-rw-r--r--drivers/gpio/gpio-adnp.c48
-rw-r--r--drivers/gpio/gpio-adp5520.c18
-rw-r--r--drivers/gpio/gpio-adp5588.c37
-rw-r--r--drivers/gpio/gpio-amd8111.c2
-rw-r--r--drivers/gpio/gpio-arizona.c14
-rw-r--r--drivers/gpio/gpio-bcm-kona.c681
-rw-r--r--drivers/gpio/gpio-bt8xx.c27
-rw-r--r--drivers/gpio/gpio-clps711x.c101
-rw-r--r--drivers/gpio/gpio-cs5535.c6
-rw-r--r--drivers/gpio/gpio-da9052.c18
-rw-r--r--drivers/gpio/gpio-da9055.c204
-rw-r--r--drivers/gpio/gpio-davinci.c376
-rw-r--r--drivers/gpio/gpio-dwapb.c444
-rw-r--r--drivers/gpio/gpio-em.c216
-rw-r--r--drivers/gpio/gpio-ep93xx.c54
-rw-r--r--drivers/gpio/gpio-f7188x.c470
-rw-r--r--drivers/gpio/gpio-ge.c174
-rw-r--r--drivers/gpio/gpio-generic.c95
-rw-r--r--drivers/gpio/gpio-grgpio.c505
-rw-r--r--drivers/gpio/gpio-ich.c140
-rw-r--r--drivers/gpio/gpio-intel-mid.c489
-rw-r--r--drivers/gpio/gpio-iop.c132
-rw-r--r--drivers/gpio/gpio-janz-ttl.c50
-rw-r--r--drivers/gpio/gpio-kempld.c219
-rw-r--r--drivers/gpio/gpio-ks8695.c2
-rw-r--r--drivers/gpio/gpio-langwell.c521
-rw-r--r--drivers/gpio/gpio-lp3943.c242
-rw-r--r--drivers/gpio/gpio-lpc32xx.c23
-rw-r--r--drivers/gpio/gpio-lynxpoint.c503
-rw-r--r--drivers/gpio/gpio-max7300.c10
-rw-r--r--drivers/gpio/gpio-max7301.c10
-rw-r--r--drivers/gpio/gpio-max730x.c28
-rw-r--r--drivers/gpio/gpio-max732x.c32
-rw-r--r--drivers/gpio/gpio-mc33880.c28
-rw-r--r--drivers/gpio/gpio-mc9s08dz60.c2
-rw-r--r--drivers/gpio/gpio-mcp23s08.c446
-rw-r--r--drivers/gpio/gpio-ml-ioh.c16
-rw-r--r--drivers/gpio/gpio-moxart.c154
-rw-r--r--drivers/gpio/gpio-mpc5200.c4
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c18
-rw-r--r--drivers/gpio/gpio-msic.c13
-rw-r--r--drivers/gpio/gpio-msm-v1.c221
-rw-r--r--drivers/gpio/gpio-msm-v2.c207
-rw-r--r--drivers/gpio/gpio-mvebu.c201
-rw-r--r--drivers/gpio/gpio-mxc.c47
-rw-r--r--drivers/gpio/gpio-mxs.c66
-rw-r--r--drivers/gpio/gpio-octeon.c157
-rw-r--r--drivers/gpio/gpio-omap.c643
-rw-r--r--drivers/gpio/gpio-palmas.c239
-rw-r--r--drivers/gpio/gpio-pca953x.c469
-rw-r--r--drivers/gpio/gpio-pcf857x.c154
-rw-r--r--drivers/gpio/gpio-pch.c25
-rw-r--r--drivers/gpio/gpio-pl061.c230
-rw-r--r--drivers/gpio/gpio-pxa.c178
-rw-r--r--drivers/gpio/gpio-rc5t583.c14
-rw-r--r--drivers/gpio/gpio-rcar.c500
-rw-r--r--drivers/gpio/gpio-rdc321x.c34
-rw-r--r--drivers/gpio/gpio-sa1100.c2
-rw-r--r--drivers/gpio/gpio-samsung.c1019
-rw-r--r--drivers/gpio/gpio-sch.c147
-rw-r--r--drivers/gpio/gpio-sch311x.c440
-rw-r--r--drivers/gpio/gpio-sodaville.c14
-rw-r--r--drivers/gpio/gpio-spear-spics.c208
-rw-r--r--drivers/gpio/gpio-sta2x11.c14
-rw-r--r--drivers/gpio/gpio-stmpe.c115
-rw-r--r--drivers/gpio/gpio-stp-xway.c11
-rw-r--r--drivers/gpio/gpio-sx150x.c29
-rw-r--r--drivers/gpio/gpio-syscon.c191
-rw-r--r--drivers/gpio/gpio-tb10x.c329
-rw-r--r--drivers/gpio/gpio-tc3589x.c163
-rw-r--r--drivers/gpio/gpio-tegra.c125
-rw-r--r--drivers/gpio/gpio-timberdale.c70
-rw-r--r--drivers/gpio/gpio-tnetv107x.c205
-rw-r--r--drivers/gpio/gpio-tps6586x.c21
-rw-r--r--drivers/gpio/gpio-tps65910.c14
-rw-r--r--drivers/gpio/gpio-tps65912.c10
-rw-r--r--drivers/gpio/gpio-ts5500.c466
-rw-r--r--drivers/gpio/gpio-twl4030.c265
-rw-r--r--drivers/gpio/gpio-twl6040.c12
-rw-r--r--drivers/gpio/gpio-tz1090-pdc.c243
-rw-r--r--drivers/gpio/gpio-tz1090.c606
-rw-r--r--drivers/gpio/gpio-ucb1400.c24
-rw-r--r--drivers/gpio/gpio-viperboard.c514
-rw-r--r--drivers/gpio/gpio-vr41xx.c26
-rw-r--r--drivers/gpio/gpio-vt8500.c316
-rw-r--r--drivers/gpio/gpio-vx855.c10
-rw-r--r--drivers/gpio/gpio-wm831x.c10
-rw-r--r--drivers/gpio/gpio-wm8350.c10
-rw-r--r--drivers/gpio/gpio-wm8994.c10
-rw-r--r--drivers/gpio/gpio-xilinx.c148
-rw-r--r--drivers/gpio/gpio-xtensa.c179
-rw-r--r--drivers/gpio/gpio-zevio.c224
-rw-r--r--drivers/gpio/gpiolib-acpi.c556
-rw-r--r--drivers/gpio/gpiolib-of.c158
-rw-r--r--drivers/gpio/gpiolib.c2054
-rw-r--r--drivers/gpio/gpiolib.h54
101 files changed, 14635 insertions, 5408 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d055cee3694..4a1b5113e52 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -31,11 +31,9 @@ config ARCH_REQUIRE_GPIOLIB
code to always get built in.
-
menuconfig GPIOLIB
bool "GPIO Support"
depends on ARCH_WANT_OPTIONAL_GPIOLIB || ARCH_REQUIRE_GPIOLIB
- select GENERIC_GPIO
help
This enables GPIO support through the generic GPIO library.
You only need to enable this, if you also want to enable
@@ -45,9 +43,21 @@ menuconfig GPIOLIB
if GPIOLIB
+config GPIO_DEVRES
+ def_bool y
+ depends on HAS_IOMEM
+
config OF_GPIO
def_bool y
- depends on OF && !SPARC
+ depends on OF
+
+config GPIO_ACPI
+ def_bool y
+ depends on ACPI
+
+config GPIOLIB_IRQCHIP
+ select IRQ_DOMAIN
+ bool
config DEBUG_GPIO
bool "Debug GPIO calls"
@@ -62,7 +72,7 @@ config DEBUG_GPIO
config GPIO_SYSFS
bool "/sys/class/gpio/... (sysfs interface)"
- depends on SYSFS && EXPERIMENTAL
+ depends on SYSFS
help
Say Y here to add a sysfs interface for GPIOs.
@@ -86,17 +96,51 @@ config GPIO_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_MAX730X
tristate
comment "Memory mapped GPIO drivers:"
+config GPIO_CLPS711X
+ tristate "CLPS711X GPIO support"
+ depends on ARCH_CLPS711X || COMPILE_TEST
+ select GPIO_GENERIC
+ help
+ Say yes here to support GPIO on CLPS711X SoCs.
+
+config GPIO_DAVINCI
+ bool "TI Davinci/Keystone GPIO support"
+ default y if ARCH_DAVINCI
+ depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE)
+ 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"
+ select GPIO_GENERIC
+ select GENERIC_IRQ_CHIP
+ depends on OF_GPIO
+ 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.
@@ -105,7 +149,7 @@ config GPIO_IT8761E
config GPIO_EM
tristate "Emma Mobile GPIO"
- depends on ARM
+ depends on ARM && OF_GPIO
help
Say yes here to support GPIO on Renesas Emma Mobile SoCs.
@@ -114,6 +158,12 @@ 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
@@ -122,6 +172,23 @@ config GPIO_MM_LANTIQ
(EBU) found on Lantiq SoCs. The gpios are output only as they are
created by attaching a 16bit latch to the bus.
+config GPIO_F7188X
+ tristate "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.
+
+ To compile this driver as a module, choose M here: the module will
+ be called f7188x-gpio.
+
+config GPIO_MOXART
+ bool "MOXART GPIO support"
+ depends on ARCH_MOXART
+ help
+ Select this option to enable GPIO driver for
+ MOXA ART SoC devices.
+
config GPIO_MPC5200
def_bool y
depends on PPC_MPC52xx
@@ -144,7 +211,7 @@ config GPIO_MSM_V1
config GPIO_MSM_V2
tristate "Qualcomm MSM GPIO v2"
- depends on GPIOLIB && ARCH_MSM
+ depends on GPIOLIB && OF && ARCH_QCOM
help
Say yes here to support the GPIO interface on ARM v7 based
Qualcomm MSM chips. Most of the pins on the MSM can be
@@ -152,7 +219,8 @@ config GPIO_MSM_V2
config GPIO_MVEBU
def_bool y
- depends on ARCH_MVEBU
+ depends on PLAT_ORION
+ depends on OF
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
@@ -168,10 +236,28 @@ config GPIO_MXS
select GPIO_GENERIC
select GENERIC_IRQ_CHIP
+config GPIO_OCTEON
+ tristate "Cavium OCTEON GPIO"
+ depends on GPIOLIB && CAVIUM_OCTEON_SOC
+ default y
+ help
+ Say yes here to support the on-chip GPIO lines on the OCTEON
+ family of SOCs.
+
+config GPIO_OMAP
+ bool "TI OMAP GPIO support" if COMPILE_TEST && !ARCH_OMAP2PLUS
+ default y if ARCH_OMAP
+ depends on ARM
+ select GENERIC_IRQ_CHIP
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to enable GPIO support for TI OMAP SoCs.
+
config GPIO_PL061
bool "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
- select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+ select GPIOLIB_IRQCHIP
help
Say yes here to support the PrimeCell PL061 GPIO device
@@ -181,6 +267,35 @@ config GPIO_PXA
help
Say yes here to support the PXA GPIO device
+config GPIO_RCAR
+ tristate "Renesas R-Car GPIO"
+ depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST)
+ help
+ Say yes here to support GPIO on Renesas R-Car SoCs.
+
+config GPIO_SAMSUNG
+ bool
+ depends on PLAT_SAMSUNG
+ help
+ Legacy GPIO support. Use only for platforms without support for
+ pinctrl.
+
+config GPIO_SCH311X
+ tristate "SMSC SCH311x SuperI/O GPIO"
+ help
+ Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and
+ SCH3116 "Super I/O" chipsets.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gpio-sch311x.
+
+config GPIO_SPEAR_SPICS
+ bool "ST SPEAr13xx SPI Chip Select as GPIO support"
+ depends on PLAT_SPEAR
+ select GENERIC_IRQ_CHIP
+ help
+ Say yes here to support ST SPEAr SPI Chip Select as GPIO device
+
config GPIO_STA2X11
bool "STA2x11/ConneXt GPIO support"
depends on MFD_STA2X11
@@ -189,18 +304,51 @@ 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_VT8500
- bool "VIA/Wondermedia SoC GPIO Support"
- depends on ARCH_VT8500
+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_TS5500
+ tristate "TS-5500 DIO blocks and compatibles"
+ depends on TS5500 || COMPILE_TEST
+ help
+ This driver supports Digital I/O exposed by pin blocks found on some
+ Technologic Systems platforms. It includes, but is not limited to, 3
+ blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600
+ LCD port.
+
+config GPIO_TZ1090
+ bool "Toumaz Xenif TZ1090 GPIO support"
+ depends on SOC_TZ1090
+ select GENERIC_IRQ_CHIP
+ default y
+ help
+ Say yes here to support Toumaz Xenif TZ1090 GPIOs.
+
+config GPIO_TZ1090_PDC
+ bool "Toumaz Xenif TZ1090 PDC GPIO support"
+ depends on SOC_TZ1090
+ default y
help
- Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
+ Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
config GPIO_XILINX
bool "Xilinx GPIO support"
- depends on PPC_OF || MICROBLAZE
+ depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
help
Say yes here to support the Xilinx FPGA GPIO device
+config GPIO_XTENSA
+ bool "Xtensa GPIO32 support"
+ depends on XTENSA
+ depends on HAVE_XTENSA_GPIO32
+ depends on !SMP
+ help
+ 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
@@ -240,6 +388,15 @@ config GPIO_ICH
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
@@ -263,6 +420,28 @@ config GPIO_GE_FPGA
and write pin state) for GPIO implemented in a number of GE single
board computers.
+config GPIO_LYNXPOINT
+ tristate "Intel Lynxpoint GPIO support"
+ depends on ACPI && X86
+ select IRQ_DOMAIN
+ 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.
+
+config GPIO_TB10X
+ bool
+ select GENERIC_IRQ_CHIP
+ select OF_GPIO
+
comment "I2C GPIO expanders:"
config GPIO_ARIZONA
@@ -271,12 +450,20 @@ config GPIO_ARIZONA
help
Support for GPIOs on Wolfson Arizona class devices.
+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_MAX7300
tristate "Maxim MAX7300 GPIO expander"
depends on I2C
select GPIO_MAX730X
help
- GPIO driver for Maxim MAX7301 I2C-based GPIO expander.
+ GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
@@ -299,7 +486,7 @@ config GPIO_MAX732X
config GPIO_MAX732X_IRQ
bool "Interrupt controller support for MAX732x"
- depends on GPIO_MAX732X=y && GENERIC_HARDIRQS
+ depends on GPIO_MAX732X=y
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.
@@ -311,7 +498,7 @@ config GPIO_MC9S08DZ60
Select this to enable the MC9S08DZ60 GPIO driver
config GPIO_PCA953X
- tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports"
+ tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
depends on I2C
help
Say yes here to provide access to several register-oriented
@@ -321,14 +508,19 @@ config GPIO_PCA953X
4 bits: pca9536, pca9537
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
- pca9556, pca9557, pca9574, tca6408
+ pca9556, pca9557, pca9574, tca6408, xra1202
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
tca6416
+ 24 bits: tca6424
+
+ 40 bits: pca9505, pca9698
+
config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x"
depends on GPIO_PCA953X=y
+ select GPIOLIB_IRQCHIP
help
Say yes here to enable the pca953x to be used as an interrupt
controller. It requires the driver to be built in the kernel.
@@ -398,6 +590,7 @@ config GPIO_STP_XWAY
config GPIO_TC3589X
bool "TC3589X GPIOs"
depends on MFD_TC3589X
+ select GPIOLIB_IRQCHIP
help
This enables support for the GPIOs found on the TC3589X
I/O Expander.
@@ -466,11 +659,11 @@ config GPIO_ADP5588_IRQ
config GPIO_ADNP
tristate "Avionic Design N-bit GPIO expander"
- depends on I2C && OF
+ depends on I2C && OF_GPIO
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 accomodate for that. For
+ 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).
@@ -479,7 +672,7 @@ comment "PCI GPIO expanders:"
config GPIO_CS5535
tristate "AMD CS5535/CS5536 GPIO support"
- depends on PCI && X86 && MFD_CS5535
+ 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
@@ -491,7 +684,7 @@ config GPIO_BT8XX
tristate "BT8XX GPIO abuser"
depends on PCI && VIDEO_BT848=n
help
- The BT8xx frame grabber chip has 24 GPIO pins than can be abused
+ The BT8xx frame grabber chip has 24 GPIO pins that can be abused
as a cheap PCI GPIO card.
This chip can be found on Miro, Hauppauge and STB TV-cards.
@@ -515,16 +708,16 @@ config GPIO_AMD8111
If unsure, say N
-config GPIO_LANGWELL
- bool "Intel Langwell/Penwell GPIO support"
+config GPIO_INTEL_MID
+ bool "Intel Mid GPIO support"
depends on PCI && X86
- select IRQ_DOMAIN
+ select GPIOLIB_IRQCHIP
help
- Say Y here to support Intel Langwell/Penwell GPIO.
+ Say Y here to support Intel Mid GPIO.
config GPIO_PCH
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO"
- depends on PCI && X86
+ depends on PCI && (X86_32 || COMPILE_TEST)
select GENERIC_IRQ_CHIP
help
This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
@@ -558,7 +751,7 @@ config GPIO_SODAVILLE
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
- depends on MFD_TIMBERDALE && HAS_IOMEM
+ depends on MFD_TIMBERDALE
---help---
Add support for the GPIO IP in the timberdale FPGA.
@@ -582,11 +775,13 @@ config GPIO_MAX7301
config GPIO_MCP23S08
tristate "Microchip MCP23xxx I/O expander"
- depends on SPI_MASTER || I2C
+ depends on OF_GPIO
+ depends on (SPI_MASTER && !I2C) || I2C
help
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
I/O expanders.
This provides a GPIO interface supporting inputs and outputs.
+ The I2C versions of the chips can be used as interrupt-controller.
config GPIO_MC33880
tristate "Freescale MC33880 high-side/low-side switch"
@@ -597,21 +792,33 @@ config GPIO_MC33880
config GPIO_74X164
tristate "74x164 serial-in/parallel-out 8-bits shift register"
- depends on SPI_MASTER
+ depends on SPI_MASTER && OF
help
- Platform driver for 74x164 compatible serial-in/parallel-out
- 8-outputs shift registers. This driver can be used to provide access
+ 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
- bool "Philips UCB1400 GPIO"
+ 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
@@ -622,11 +829,12 @@ config GPIO_JANZ_TTL
This driver provides support for driving the pins in output
mode only. Input mode is not supported.
-config GPIO_AB8500
- bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions"
- depends on AB8500_CORE && BROKEN
+config GPIO_PALMAS
+ bool "TI PALMAS series PMICs GPIO"
+ depends on MFD_PALMAS
help
- Select this to enable the AB8500 IC GPIO driver
+ Select this option to enable GPIO driver for the TI PALMAS
+ series chip family.
config GPIO_TPS6586X
bool "TPS6586X GPIO"
@@ -649,4 +857,23 @@ config GPIO_MSIC
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
+ help
+ Turn on GPIO support for Broadcom "Kona" chips.
+
+comment "USB GPIO expanders:"
+
+config GPIO_VIPERBOARD
+ tristate "Viperboard GPIO a & b support"
+ depends on MFD_VIPERBOARD && USB
+ help
+ Say yes here to access the GPIO signals of Nano River
+ Technologies Viperboard. There are two GPIO chips on the
+ board: gpioa and gpiob.
+ See viperboard API specification and Nano
+ River Tech's viperboard.h for detailed meaning
+ of the module parameters.
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9aeed670732..d10f6a9d875 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -2,32 +2,43 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
-obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
+obj-$(CONFIG_GPIO_DEVRES) += devres.o
+obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
+obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
-obj-$(CONFIG_GPIO_AB8500) += gpio-ab8500.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_AMD8111) += gpio-amd8111.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
+obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
-obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
+obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
+obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
+obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
+obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
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_LANGWELL) += gpio-langwell.o
+obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
+obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
+obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
@@ -37,6 +48,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
+obj-$(CONFIG_GPIO_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
@@ -45,7 +57,8 @@ obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
-obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
+obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o
+obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
@@ -53,28 +66,38 @@ obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
-obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
+obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
+obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
+obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
+obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
+obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
+obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
-obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
+obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
+obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
+obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o
+obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
+obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
-obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
+obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
+obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 1077754f828..65978cf85f7 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -15,10 +15,138 @@
*/
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/device.h>
#include <linux/gfp.h>
+static void devm_gpiod_release(struct device *dev, void *res)
+{
+ struct gpio_desc **desc = res;
+
+ gpiod_put(*desc);
+}
+
+static int devm_gpiod_match(struct device *dev, void *res, void *data)
+{
+ struct gpio_desc **this = res, **gpio = data;
+
+ return *this == *gpio;
+}
+
+/**
+ * devm_gpiod_get - Resource-managed gpiod_get()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ *
+ * Managed gpiod_get(). GPIO descriptors returned from this function are
+ * automatically disposed on driver detach. See gpiod_get() for detailed
+ * information about behavior and return values.
+ */
+struct gpio_desc *__must_check devm_gpiod_get(struct device *dev,
+ const char *con_id)
+{
+ return devm_gpiod_get_index(dev, con_id, 0);
+}
+EXPORT_SYMBOL(devm_gpiod_get);
+
+/**
+ * devm_gpiod_get_optional - Resource-managed gpiod_get_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ *
+ * Managed gpiod_get_optional(). GPIO descriptors returned from this function
+ * are automatically disposed on driver detach. See gpiod_get_optional() for
+ * detailed information about behavior and return values.
+ */
+struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev,
+ const char *con_id)
+{
+ return devm_gpiod_get_index_optional(dev, con_id, 0);
+}
+EXPORT_SYMBOL(devm_gpiod_get_optional);
+
+/**
+ * devm_gpiod_get_index - Resource-managed gpiod_get_index()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ *
+ * Managed gpiod_get_index(). GPIO descriptors returned from this function are
+ * automatically disposed on driver detach. See gpiod_get_index() for detailed
+ * information about behavior and return values.
+ */
+struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev,
+ const char *con_id,
+ unsigned int idx)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpiod_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = gpiod_get_index(dev, con_id, idx);
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_gpiod_get_index);
+
+/**
+ * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
+ * @dev: GPIO consumer
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ *
+ * Managed gpiod_get_index_optional(). GPIO descriptors returned from this
+ * function are automatically disposed on driver detach. See
+ * gpiod_get_index_optional() for detailed information about behavior and
+ * return values.
+ */
+struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index)
+{
+ struct gpio_desc *desc;
+
+ desc = devm_gpiod_get_index(dev, con_id, index);
+ if (IS_ERR(desc)) {
+ if (PTR_ERR(desc) == -ENOENT)
+ return NULL;
+ }
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_gpiod_get_index_optional);
+
+/**
+ * devm_gpiod_put - Resource-managed gpiod_put()
+ * @desc: GPIO descriptor to dispose of
+ *
+ * Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
+ * devm_gpiod_get_index(). Normally this function will not be called as the GPIO
+ * will be disposed of by the resource management code.
+ */
+void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
+{
+ WARN_ON(devres_release(dev, devm_gpiod_release, devm_gpiod_match,
+ &desc));
+}
+EXPORT_SYMBOL(devm_gpiod_put);
+
+
+
+
static void devm_gpio_release(struct device *dev, void *res)
{
unsigned *gpio = res;
@@ -34,10 +162,10 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
}
/**
- * devm_gpio_request - request a gpio for a managed device
- * @dev: device to request the gpio for
- * @gpio: gpio to allocate
- * @label: the name of the requested gpio
+ * devm_gpio_request - request a GPIO for a managed device
+ * @dev: device to request the GPIO for
+ * @gpio: GPIO to allocate
+ * @label: the name of the requested GPIO
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as
@@ -101,9 +229,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
EXPORT_SYMBOL(devm_gpio_request_one);
/**
- * devm_gpio_free - free an interrupt
- * @dev: device to free gpio for
- * @gpio: gpio to free
+ * devm_gpio_free - free a GPIO
+ * @dev: device to free GPIO for
+ * @gpio: GPIO to free
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as gpio_free().
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index ed3e55161bd..e4ae29824c3 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
-#include <linux/spi/74x164.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
@@ -21,7 +20,6 @@
#define GEN_74X164_NUMBER_GPIOS 8
struct gen_74x164_chip {
- struct spi_device *spi;
u8 *buffer;
struct gpio_chip gpio_chip;
struct mutex lock;
@@ -35,6 +33,7 @@ static struct gen_74x164_chip *gpio_to_74x164_chip(struct gpio_chip *gc)
static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
{
+ struct spi_device *spi = to_spi_device(chip->gpio_chip.dev);
struct spi_message message;
struct spi_transfer *msg_buf;
int i, ret = 0;
@@ -55,12 +54,12 @@ static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
* byte of the buffer will end up in the last register.
*/
for (i = chip->registers - 1; i >= 0; i--) {
- msg_buf[i].tx_buf = chip->buffer +i;
+ msg_buf[i].tx_buf = chip->buffer + i;
msg_buf[i].len = sizeof(u8);
spi_message_add_tail(msg_buf + i, &message);
}
- ret = spi_sync(chip->spi, &message);
+ ret = spi_sync(spi, &message);
kfree(msg_buf);
@@ -105,17 +104,11 @@ static int gen_74x164_direction_output(struct gpio_chip *gc,
return 0;
}
-static int __devinit gen_74x164_probe(struct spi_device *spi)
+static int gen_74x164_probe(struct spi_device *spi)
{
struct gen_74x164_chip *chip;
- struct gen_74x164_chip_platform_data *pdata;
int ret;
- if (!spi->dev.of_node) {
- dev_err(&spi->dev, "No device tree data available.\n");
- return -EINVAL;
- }
-
/*
* bits_per_word cannot be configured in platform data
*/
@@ -129,40 +122,32 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
if (!chip)
return -ENOMEM;
- pdata = spi->dev.platform_data;
- if (pdata && pdata->base)
- chip->gpio_chip.base = pdata->base;
- else
- chip->gpio_chip.base = -1;
-
- mutex_init(&chip->lock);
-
- dev_set_drvdata(&spi->dev, chip);
-
- chip->spi = spi;
+ spi_set_drvdata(spi, chip);
chip->gpio_chip.label = spi->modalias;
chip->gpio_chip.direction_output = gen_74x164_direction_output;
chip->gpio_chip.get = gen_74x164_get_value;
chip->gpio_chip.set = gen_74x164_set_value;
+ chip->gpio_chip.base = -1;
- if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) {
- dev_err(&spi->dev, "Missing registers-number property in the DT.\n");
- ret = -EINVAL;
- goto exit_destroy;
+ if (of_property_read_u32(spi->dev.of_node, "registers-number",
+ &chip->registers)) {
+ dev_err(&spi->dev,
+ "Missing registers-number property in the DT.\n");
+ return -EINVAL;
}
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
- chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL);
- if (!chip->buffer) {
- ret = -ENOMEM;
- goto exit_destroy;
- }
+ chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
+ if (!chip->buffer)
+ return -ENOMEM;
- chip->gpio_chip.can_sleep = 1;
+ chip->gpio_chip.can_sleep = true;
chip->gpio_chip.dev = &spi->dev;
chip->gpio_chip.owner = THIS_MODULE;
+ mutex_init(&chip->lock);
+
ret = __gen_74x164_write_config(chip);
if (ret) {
dev_err(&spi->dev, "Failed writing: %d\n", ret);
@@ -170,34 +155,23 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
}
ret = gpiochip_add(&chip->gpio_chip);
- if (ret)
- goto exit_destroy;
-
- return ret;
+ if (!ret)
+ return 0;
exit_destroy:
- dev_set_drvdata(&spi->dev, NULL);
mutex_destroy(&chip->lock);
+
return ret;
}
-static int __devexit gen_74x164_remove(struct spi_device *spi)
+static int gen_74x164_remove(struct spi_device *spi)
{
- struct gen_74x164_chip *chip;
+ struct gen_74x164_chip *chip = spi_get_drvdata(spi);
int ret;
- chip = dev_get_drvdata(&spi->dev);
- if (chip == NULL)
- return -ENODEV;
-
- dev_set_drvdata(&spi->dev, NULL);
-
ret = gpiochip_remove(&chip->gpio_chip);
if (!ret)
mutex_destroy(&chip->lock);
- else
- dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
- ret);
return ret;
}
@@ -212,10 +186,10 @@ static struct spi_driver gen_74x164_driver = {
.driver = {
.name = "74x164",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gen_74x164_dt_ids),
+ .of_match_table = gen_74x164_dt_ids,
},
.probe = gen_74x164_probe,
- .remove = __devexit_p(gen_74x164_remove),
+ .remove = gen_74x164_remove,
};
module_spi_driver(gen_74x164_driver);
diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c
deleted file mode 100644
index 050c05d9189..00000000000
--- a/drivers/gpio/gpio-ab8500.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * Author: BIBEK BASU <bibek.basu@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpio.h>
-
-/*
- * GPIO registers offset
- * Bank: 0x10
- */
-#define AB8500_GPIO_SEL1_REG 0x00
-#define AB8500_GPIO_SEL2_REG 0x01
-#define AB8500_GPIO_SEL3_REG 0x02
-#define AB8500_GPIO_SEL4_REG 0x03
-#define AB8500_GPIO_SEL5_REG 0x04
-#define AB8500_GPIO_SEL6_REG 0x05
-
-#define AB8500_GPIO_DIR1_REG 0x10
-#define AB8500_GPIO_DIR2_REG 0x11
-#define AB8500_GPIO_DIR3_REG 0x12
-#define AB8500_GPIO_DIR4_REG 0x13
-#define AB8500_GPIO_DIR5_REG 0x14
-#define AB8500_GPIO_DIR6_REG 0x15
-
-#define AB8500_GPIO_OUT1_REG 0x20
-#define AB8500_GPIO_OUT2_REG 0x21
-#define AB8500_GPIO_OUT3_REG 0x22
-#define AB8500_GPIO_OUT4_REG 0x23
-#define AB8500_GPIO_OUT5_REG 0x24
-#define AB8500_GPIO_OUT6_REG 0x25
-
-#define AB8500_GPIO_PUD1_REG 0x30
-#define AB8500_GPIO_PUD2_REG 0x31
-#define AB8500_GPIO_PUD3_REG 0x32
-#define AB8500_GPIO_PUD4_REG 0x33
-#define AB8500_GPIO_PUD5_REG 0x34
-#define AB8500_GPIO_PUD6_REG 0x35
-
-#define AB8500_GPIO_IN1_REG 0x40
-#define AB8500_GPIO_IN2_REG 0x41
-#define AB8500_GPIO_IN3_REG 0x42
-#define AB8500_GPIO_IN4_REG 0x43
-#define AB8500_GPIO_IN5_REG 0x44
-#define AB8500_GPIO_IN6_REG 0x45
-#define AB8500_GPIO_ALTFUN_REG 0x45
-#define ALTFUN_REG_INDEX 6
-#define AB8500_NUM_GPIO 42
-#define AB8500_NUM_VIR_GPIO_IRQ 16
-
-enum ab8500_gpio_action {
- NONE,
- STARTUP,
- SHUTDOWN,
- MASK,
- UNMASK
-};
-
-struct ab8500_gpio {
- struct gpio_chip chip;
- struct ab8500 *parent;
- struct device *dev;
- struct mutex lock;
- u32 irq_base;
- enum ab8500_gpio_action irq_action;
- u16 rising;
- u16 falling;
-};
-/**
- * to_ab8500_gpio() - get the pointer to ab8500_gpio
- * @chip: Member of the structure ab8500_gpio
- */
-static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct ab8500_gpio, chip);
-}
-
-static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
- unsigned offset, int val)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- u8 pos = offset % 8;
- int ret;
-
- reg = reg + (offset / 8);
- ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev,
- AB8500_MISC, reg, 1 << pos, val << pos);
- if (ret < 0)
- dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
- return ret;
-}
-/**
- * ab8500_gpio_get() - Get the particular GPIO value
- * @chip: Gpio device
- * @offset: GPIO number to read
- */
-static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- u8 mask = 1 << (offset % 8);
- u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8);
- int ret;
- u8 data;
- ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
- reg, &data);
- if (ret < 0) {
- dev_err(ab8500_gpio->dev, "%s read failed\n", __func__);
- return ret;
- }
- return (data & mask) >> (offset % 8);
-}
-
-static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- int ret;
- /* Write the data */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1);
- if (ret < 0)
- dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-}
-
-static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int val)
-{
- int ret;
- /* set direction as output */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
- if (ret < 0)
- return ret;
- /* disable pull down */
- ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
- if (ret < 0)
- return ret;
- /* set the output as 1 or 0 */
- return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
-
-}
-
-static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- /* set the register as input */
- return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
-}
-
-static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- /*
- * Only some GPIOs are interrupt capable, and they are
- * organized in discontiguous clusters:
- *
- * GPIO6 to GPIO13
- * GPIO24 and GPIO25
- * GPIO36 to GPIO41
- */
- static struct ab8500_gpio_irq_cluster {
- int start;
- int end;
- } clusters[] = {
- {.start = 6, .end = 13},
- {.start = 24, .end = 25},
- {.start = 36, .end = 41},
- };
- struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
- int base = ab8500_gpio->irq_base;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clusters); i++) {
- struct ab8500_gpio_irq_cluster *cluster = &clusters[i];
-
- if (offset >= cluster->start && offset <= cluster->end)
- return base + offset - cluster->start;
-
- /* Advance by the number of gpios in this cluster */
- base += cluster->end - cluster->start + 1;
- }
-
- return -EINVAL;
-}
-
-static struct gpio_chip ab8500gpio_chip = {
- .label = "ab8500_gpio",
- .owner = THIS_MODULE,
- .direction_input = ab8500_gpio_direction_input,
- .get = ab8500_gpio_get,
- .direction_output = ab8500_gpio_direction_output,
- .set = ab8500_gpio_set,
- .to_irq = ab8500_gpio_to_irq,
-};
-
-static unsigned int irq_to_rising(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- int new_irq = offset + AB8500_INT_GPIO6R
- + ab8500_gpio->parent->irq_base;
- return new_irq;
-}
-
-static unsigned int irq_to_falling(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- int new_irq = offset + AB8500_INT_GPIO6F
- + ab8500_gpio->parent->irq_base;
- return new_irq;
-
-}
-
-static unsigned int rising_to_irq(unsigned int irq, void *dev)
-{
- struct ab8500_gpio *ab8500_gpio = dev;
- int offset = irq - AB8500_INT_GPIO6R
- - ab8500_gpio->parent->irq_base ;
- int new_irq = offset + ab8500_gpio->irq_base;
- return new_irq;
-}
-
-static unsigned int falling_to_irq(unsigned int irq, void *dev)
-{
- struct ab8500_gpio *ab8500_gpio = dev;
- int offset = irq - AB8500_INT_GPIO6F
- - ab8500_gpio->parent->irq_base ;
- int new_irq = offset + ab8500_gpio->irq_base;
- return new_irq;
-
-}
-
-/*
- * IRQ handler
- */
-
-static irqreturn_t handle_rising(int irq, void *dev)
-{
-
- handle_nested_irq(rising_to_irq(irq , dev));
- return IRQ_HANDLED;
-}
-
-static irqreturn_t handle_falling(int irq, void *dev)
-{
-
- handle_nested_irq(falling_to_irq(irq, dev));
- return IRQ_HANDLED;
-}
-
-static void ab8500_gpio_irq_lock(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- mutex_lock(&ab8500_gpio->lock);
-}
-
-static void ab8500_gpio_irq_sync_unlock(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
- bool rising = ab8500_gpio->rising & BIT(offset);
- bool falling = ab8500_gpio->falling & BIT(offset);
- int ret;
-
- switch (ab8500_gpio->irq_action) {
- case STARTUP:
- if (rising)
- ret = request_threaded_irq(irq_to_rising(irq),
- NULL, handle_rising,
- IRQF_TRIGGER_RISING,
- "ab8500-gpio-r", ab8500_gpio);
- if (falling)
- ret = request_threaded_irq(irq_to_falling(irq),
- NULL, handle_falling,
- IRQF_TRIGGER_FALLING,
- "ab8500-gpio-f", ab8500_gpio);
- break;
- case SHUTDOWN:
- if (rising)
- free_irq(irq_to_rising(irq), ab8500_gpio);
- if (falling)
- free_irq(irq_to_falling(irq), ab8500_gpio);
- break;
- case MASK:
- if (rising)
- disable_irq(irq_to_rising(irq));
- if (falling)
- disable_irq(irq_to_falling(irq));
- break;
- case UNMASK:
- if (rising)
- enable_irq(irq_to_rising(irq));
- if (falling)
- enable_irq(irq_to_falling(irq));
- break;
- case NONE:
- break;
- }
- ab8500_gpio->irq_action = NONE;
- ab8500_gpio->rising &= ~(BIT(offset));
- ab8500_gpio->falling &= ~(BIT(offset));
- mutex_unlock(&ab8500_gpio->lock);
-}
-
-
-static void ab8500_gpio_irq_mask(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = MASK;
-}
-
-static void ab8500_gpio_irq_unmask(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = UNMASK;
-}
-
-static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- int offset = irq - ab8500_gpio->irq_base;
-
- if (type == IRQ_TYPE_EDGE_BOTH) {
- ab8500_gpio->rising = BIT(offset);
- ab8500_gpio->falling = BIT(offset);
- } else if (type == IRQ_TYPE_EDGE_RISING) {
- ab8500_gpio->rising = BIT(offset);
- } else {
- ab8500_gpio->falling = BIT(offset);
- }
- return 0;
-}
-
-unsigned int ab8500_gpio_irq_startup(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = STARTUP;
- return 0;
-}
-
-void ab8500_gpio_irq_shutdown(unsigned int irq)
-{
- struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
- ab8500_gpio->irq_action = SHUTDOWN;
-}
-
-static struct irq_chip ab8500_gpio_irq_chip = {
- .name = "ab8500-gpio",
- .startup = ab8500_gpio_irq_startup,
- .shutdown = ab8500_gpio_irq_shutdown,
- .bus_lock = ab8500_gpio_irq_lock,
- .bus_sync_unlock = ab8500_gpio_irq_sync_unlock,
- .mask = ab8500_gpio_irq_mask,
- .unmask = ab8500_gpio_irq_unmask,
- .set_type = ab8500_gpio_irq_set_type,
-};
-
-static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio)
-{
- u32 base = ab8500_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
- set_irq_chip_data(irq, ab8500_gpio);
- set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip,
- handle_simple_irq);
- set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- set_irq_noprobe(irq);
-#endif
- }
-
- return 0;
-}
-
-static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio)
-{
- int base = ab8500_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
-#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
-#endif
- set_irq_chip_and_handler(irq, NULL, NULL);
- set_irq_chip_data(irq, NULL);
- }
-}
-
-static int __devinit ab8500_gpio_probe(struct platform_device *pdev)
-{
- struct ab8500_platform_data *ab8500_pdata =
- dev_get_platdata(pdev->dev.parent);
- struct ab8500_gpio_platform_data *pdata;
- struct ab8500_gpio *ab8500_gpio;
- int ret;
- int i;
-
- pdata = ab8500_pdata->gpio;
- if (!pdata) {
- dev_err(&pdev->dev, "gpio platform data missing\n");
- return -ENODEV;
- }
-
- ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL);
- if (ab8500_gpio == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
- return -ENOMEM;
- }
- ab8500_gpio->dev = &pdev->dev;
- ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent);
- ab8500_gpio->chip = ab8500gpio_chip;
- ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO;
- ab8500_gpio->chip.dev = &pdev->dev;
- ab8500_gpio->chip.base = pdata->gpio_base;
- ab8500_gpio->irq_base = pdata->irq_base;
- /* initialize the lock */
- mutex_init(&ab8500_gpio->lock);
- /*
- * AB8500 core will handle and clear the IRQ
- * configre GPIO based on config-reg value.
- * These values are for selecting the PINs as
- * GPIO or alternate function
- */
- for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) {
- ret = abx500_set_register_interruptible(ab8500_gpio->dev,
- AB8500_MISC, i,
- pdata->config_reg[i]);
- if (ret < 0)
- goto out_free;
- }
- ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
- AB8500_GPIO_ALTFUN_REG,
- pdata->config_reg[ALTFUN_REG_INDEX]);
- if (ret < 0)
- goto out_free;
-
- ret = ab8500_gpio_irq_init(ab8500_gpio);
- if (ret)
- goto out_free;
- ret = gpiochip_add(&ab8500_gpio->chip);
- if (ret) {
- dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
- ret);
- goto out_rem_irq;
- }
- platform_set_drvdata(pdev, ab8500_gpio);
- return 0;
-
-out_rem_irq:
- ab8500_gpio_irq_remove(ab8500_gpio);
-out_free:
- mutex_destroy(&ab8500_gpio->lock);
- kfree(ab8500_gpio);
- return ret;
-}
-
-/*
- * ab8500_gpio_remove() - remove Ab8500-gpio driver
- * @pdev : Platform device registered
- */
-static int __devexit ab8500_gpio_remove(struct platform_device *pdev)
-{
- struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev);
- int ret;
-
- ret = gpiochip_remove(&ab8500_gpio->chip);
- if (ret < 0) {
- dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n",
- ret);
- return ret;
- }
-
- platform_set_drvdata(pdev, NULL);
- mutex_destroy(&ab8500_gpio->lock);
- kfree(ab8500_gpio);
-
- return 0;
-}
-
-static struct platform_driver ab8500_gpio_driver = {
- .driver = {
- .name = "ab8500-gpio",
- .owner = THIS_MODULE,
- },
- .probe = ab8500_gpio_probe,
- .remove = __devexit_p(ab8500_gpio_remove),
-};
-
-static int __init ab8500_gpio_init(void)
-{
- return platform_driver_register(&ab8500_gpio_driver);
-}
-arch_initcall(ab8500_gpio_init);
-
-static void __exit ab8500_gpio_exit(void)
-{
- platform_driver_unregister(&ab8500_gpio_driver);
-}
-module_exit(ab8500_gpio_exit);
-
-MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
-MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
-MODULE_ALIAS("platform:ab8500-gpio");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 3df88336415..b2239d678d0 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -260,7 +260,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios)
chip->direction_output = adnp_gpio_direction_output;
chip->get = adnp_gpio_get;
chip->set = adnp_gpio_set;
- chip->can_sleep = 1;
+ chip->can_sleep = true;
if (IS_ENABLED(CONFIG_DEBUG_FS))
chip->dbg_show = adnp_gpio_dbg_show;
@@ -325,9 +325,9 @@ static irqreturn_t adnp_irq(int irq, void *data)
pending &= isr & ier;
for_each_set_bit(bit, &pending, 8) {
- unsigned int virq;
- virq = irq_find_mapping(adnp->domain, base + bit);
- handle_nested_irq(virq);
+ unsigned int child_irq;
+ child_irq = irq_find_mapping(adnp->domain, base + bit);
+ handle_nested_irq(child_irq);
}
}
@@ -408,6 +408,26 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
mutex_unlock(&adnp->irq_lock);
}
+static int adnp_irq_reqres(struct irq_data *data)
+{
+ struct adnp *adnp = irq_data_get_irq_chip_data(data);
+
+ if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
+ dev_err(adnp->gpio.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ data->hwirq);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void adnp_irq_relres(struct irq_data *data)
+{
+ struct adnp *adnp = irq_data_get_irq_chip_data(data);
+
+ gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
+}
+
static struct irq_chip adnp_irq_chip = {
.name = "gpio-adnp",
.irq_mask = adnp_irq_mask,
@@ -415,6 +435,8 @@ static struct irq_chip adnp_irq_chip = {
.irq_set_type = adnp_irq_set_type,
.irq_bus_lock = adnp_irq_bus_lock,
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
+ .irq_request_resources = adnp_irq_reqres,
+ .irq_release_resources = adnp_irq_relres,
};
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
@@ -490,15 +512,11 @@ static int adnp_irq_setup(struct adnp *adnp)
if (err != 0) {
dev_err(chip->dev, "can't request IRQ#%d: %d\n",
adnp->client->irq, err);
- goto error;
+ return err;
}
chip->to_irq = adnp_gpio_to_irq;
return 0;
-
-error:
- irq_domain_remove(adnp->domain);
- return err;
}
static void adnp_irq_teardown(struct adnp *adnp)
@@ -516,7 +534,7 @@ static void adnp_irq_teardown(struct adnp *adnp)
irq_domain_remove(adnp->domain);
}
-static __devinit int adnp_i2c_probe(struct i2c_client *client,
+static int adnp_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node;
@@ -563,7 +581,7 @@ teardown:
return err;
}
-static __devexit int adnp_i2c_remove(struct i2c_client *client)
+static int adnp_i2c_remove(struct i2c_client *client)
{
struct adnp *adnp = i2c_get_clientdata(client);
struct device_node *np = client->dev.of_node;
@@ -582,13 +600,13 @@ static __devexit int adnp_i2c_remove(struct i2c_client *client)
return 0;
}
-static const struct i2c_device_id adnp_i2c_id[] __devinitconst = {
+static const struct i2c_device_id adnp_i2c_id[] = {
{ "gpio-adnp" },
{ },
};
MODULE_DEVICE_TABLE(i2c, adnp_i2c_id);
-static const struct of_device_id adnp_of_match[] __devinitconst = {
+static const struct of_device_id adnp_of_match[] = {
{ .compatible = "ad,gpio-adnp", },
{ },
};
@@ -598,10 +616,10 @@ static struct i2c_driver adnp_i2c_driver = {
.driver = {
.name = "gpio-adnp",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(adnp_of_match),
+ .of_match_table = adnp_of_match,
},
.probe = adnp_i2c_probe,
- .remove = __devexit_p(adnp_i2c_remove),
+ .remove = adnp_i2c_remove,
.id_table = adnp_i2c_id,
};
module_i2c_driver(adnp_i2c_driver);
diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c
index 2f263cc3256..f1ade8fa321 100644
--- a/drivers/gpio/gpio-adp5520.c
+++ b/drivers/gpio/gpio-adp5520.c
@@ -87,9 +87,9 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip,
return ret;
}
-static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
+static int adp5520_gpio_probe(struct platform_device *pdev)
{
- struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct adp5520_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct adp5520_gpio *dev;
struct gpio_chip *gc;
int ret, i, gpios;
@@ -105,11 +105,9 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
return -ENODEV;
}
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&pdev->dev, "failed to alloc memory\n");
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
return -ENOMEM;
- }
dev->master = pdev->dev.parent;
@@ -127,7 +125,7 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
gc->direction_output = adp5520_gpio_direction_output;
gc->get = adp5520_gpio_get_value;
gc->set = adp5520_gpio_set_value;
- gc->can_sleep = 1;
+ gc->can_sleep = true;
gc->base = pdata->gpio_start;
gc->ngpio = gpios;
@@ -163,11 +161,10 @@ static int __devinit adp5520_gpio_probe(struct platform_device *pdev)
return 0;
err:
- kfree(dev);
return ret;
}
-static int __devexit adp5520_gpio_remove(struct platform_device *pdev)
+static int adp5520_gpio_remove(struct platform_device *pdev)
{
struct adp5520_gpio *dev;
int ret;
@@ -180,7 +177,6 @@ static int __devexit adp5520_gpio_remove(struct platform_device *pdev)
return ret;
}
- kfree(dev);
return 0;
}
@@ -190,7 +186,7 @@ static struct platform_driver adp5520_gpio_driver = {
.owner = THIS_MODULE,
},
.probe = adp5520_gpio_probe,
- .remove = __devexit_p(adp5520_gpio_remove),
+ .remove = adp5520_gpio_remove,
};
module_platform_driver(adp5520_gpio_driver);
diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c
index eeedad42913..ef19bc33f2b 100644
--- a/drivers/gpio/gpio-adp5588.c
+++ b/drivers/gpio/gpio-adp5588.c
@@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
struct adp5588_gpio *dev =
container_of(chip, struct adp5588_gpio, gpio_chip);
+ unsigned bank = ADP5588_BANK(off);
+ unsigned bit = ADP5588_BIT(off);
+ int val;
- return !!(adp5588_gpio_read(dev->client,
- GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
+ mutex_lock(&dev->lock);
+
+ if (dev->dir[bank] & bit)
+ val = dev->dat_out[bank];
+ else
+ val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank);
+
+ mutex_unlock(&dev->lock);
+
+ return !!(val & bit);
}
static void adp5588_gpio_set_value(struct gpio_chip *chip,
@@ -276,7 +287,8 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid)
static int adp5588_irq_setup(struct adp5588_gpio *dev)
{
struct i2c_client *client = dev->client;
- struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+ struct adp5588_gpio_platform_data *pdata =
+ dev_get_platdata(&client->dev);
unsigned gpio;
int ret;
@@ -346,10 +358,11 @@ static void adp5588_irq_teardown(struct adp5588_gpio *dev)
}
#endif /* CONFIG_GPIO_ADP5588_IRQ */
-static int __devinit adp5588_gpio_probe(struct i2c_client *client,
+static int adp5588_gpio_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+ struct adp5588_gpio_platform_data *pdata =
+ dev_get_platdata(&client->dev);
struct adp5588_gpio *dev;
struct gpio_chip *gc;
int ret, i, revid;
@@ -366,10 +379,8 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client,
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&client->dev, "failed to alloc memory\n");
+ if (dev == NULL)
return -ENOMEM;
- }
dev->client = client;
@@ -378,12 +389,13 @@ static int __devinit adp5588_gpio_probe(struct i2c_client *client,
gc->direction_output = adp5588_gpio_direction_output;
gc->get = adp5588_gpio_get_value;
gc->set = adp5588_gpio_set_value;
- gc->can_sleep = 1;
+ gc->can_sleep = true;
gc->base = pdata->gpio_start;
gc->ngpio = ADP5588_MAXGPIO;
gc->label = client->name;
gc->owner = THIS_MODULE;
+ gc->names = pdata->names;
mutex_init(&dev->lock);
@@ -438,9 +450,10 @@ err:
return ret;
}
-static int __devexit adp5588_gpio_remove(struct i2c_client *client)
+static int adp5588_gpio_remove(struct i2c_client *client)
{
- struct adp5588_gpio_platform_data *pdata = client->dev.platform_data;
+ struct adp5588_gpio_platform_data *pdata =
+ dev_get_platdata(&client->dev);
struct adp5588_gpio *dev = i2c_get_clientdata(client);
int ret;
@@ -479,7 +492,7 @@ static struct i2c_driver adp5588_gpio_driver = {
.name = DRV_NAME,
},
.probe = adp5588_gpio_probe,
- .remove = __devexit_p(adp5588_gpio_remove),
+ .remove = adp5588_gpio_remove,
.id_table = adp5588_gpio_id,
};
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index 710fafcdd1b..94e9992f890 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -60,7 +60,7 @@
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
-static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
+static const struct pci_device_id pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS), 0 },
{ 0, }, /* terminate list */
};
diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c
index 8740d2eb06f..29bdff55898 100644
--- a/drivers/gpio/gpio-arizona.c
+++ b/drivers/gpio/gpio-arizona.c
@@ -91,13 +91,13 @@ static struct gpio_chip template_chip = {
.get = arizona_gpio_get,
.direction_output = arizona_gpio_direction_out,
.set = arizona_gpio_set,
- .can_sleep = 1,
+ .can_sleep = true,
};
-static int __devinit arizona_gpio_probe(struct platform_device *pdev)
+static int arizona_gpio_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
- struct arizona_pdata *pdata = arizona->dev->platform_data;
+ struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
struct arizona_gpio *arizona_gpio;
int ret;
@@ -109,10 +109,14 @@ static int __devinit arizona_gpio_probe(struct platform_device *pdev)
arizona_gpio->arizona = arizona;
arizona_gpio->gpio_chip = template_chip;
arizona_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+ arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
+#endif
switch (arizona->type) {
case WM5102:
case WM5110:
+ case WM8997:
arizona_gpio->gpio_chip.ngpio = 5;
break;
default:
@@ -141,7 +145,7 @@ err:
return ret;
}
-static int __devexit arizona_gpio_remove(struct platform_device *pdev)
+static int arizona_gpio_remove(struct platform_device *pdev)
{
struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev);
@@ -152,7 +156,7 @@ static struct platform_driver arizona_gpio_driver = {
.driver.name = "arizona-gpio",
.driver.owner = THIS_MODULE,
.probe = arizona_gpio_probe,
- .remove = __devexit_p(arizona_gpio_remove),
+ .remove = arizona_gpio_remove,
};
module_platform_driver(arizona_gpio_driver);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
new file mode 100644
index 00000000000..3f6b33ce9bd
--- /dev/null
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2012-2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+
+#define BCM_GPIO_PASSWD 0x00a5a501
+#define GPIO_PER_BANK 32
+#define GPIO_MAX_BANK_NUM 8
+
+#define GPIO_BANK(gpio) ((gpio) >> 5)
+#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1))
+
+/* There is a GPIO control register for each GPIO */
+#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2))
+
+/* The remaining registers are per GPIO bank */
+#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
+#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
+#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
+#define GPIO_OUT_CLEAR(bank) (0x00000060 + ((bank) << 2))
+#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
+#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
+#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
+#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
+
+#define GPIO_GPPWR_OFFSET 0x00000520
+
+#define GPIO_GPCTR0_DBR_SHIFT 5
+#define GPIO_GPCTR0_DBR_MASK 0x000001e0
+
+#define GPIO_GPCTR0_ITR_SHIFT 3
+#define GPIO_GPCTR0_ITR_MASK 0x00000018
+#define GPIO_GPCTR0_ITR_CMD_RISING_EDGE 0x00000001
+#define GPIO_GPCTR0_ITR_CMD_FALLING_EDGE 0x00000002
+#define GPIO_GPCTR0_ITR_CMD_BOTH_EDGE 0x00000003
+
+#define GPIO_GPCTR0_IOTR_MASK 0x00000001
+#define GPIO_GPCTR0_IOTR_CMD_0UTPUT 0x00000000
+#define GPIO_GPCTR0_IOTR_CMD_INPUT 0x00000001
+
+#define GPIO_GPCTR0_DB_ENABLE_MASK 0x00000100
+
+#define LOCK_CODE 0xffffffff
+#define UNLOCK_CODE 0x00000000
+
+struct bcm_kona_gpio {
+ void __iomem *reg_base;
+ int num_bank;
+ spinlock_t lock;
+ struct gpio_chip gpio_chip;
+ struct irq_domain *irq_domain;
+ struct bcm_kona_gpio_bank *banks;
+ struct platform_device *pdev;
+};
+
+struct bcm_kona_gpio_bank {
+ int id;
+ int irq;
+ /* Used in the interrupt handler */
+ struct bcm_kona_gpio *kona_gpio;
+};
+
+static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct bcm_kona_gpio, gpio_chip);
+}
+
+static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
+ int bank_id, u32 lockcode)
+{
+ writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET);
+ writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id));
+}
+
+static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio,
+ unsigned gpio)
+{
+ u32 val;
+ unsigned long flags;
+ int bank_id = GPIO_BANK(gpio);
+
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
+ val |= BIT(gpio);
+ bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
+ unsigned gpio)
+{
+ u32 val;
+ unsigned long flags;
+ int bank_id = GPIO_BANK(gpio);
+
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
+ val &= ~BIT(gpio);
+ bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val, reg_offset;
+ unsigned long flags;
+
+ kona_gpio = to_kona_gpio(chip);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ /* determine the GPIO pin direction */
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= GPIO_GPCTR0_IOTR_MASK;
+
+ /* this function only applies to output pin */
+ if (GPIO_GPCTR0_IOTR_CMD_INPUT == val)
+ goto out;
+
+ reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+ val = readl(reg_base + reg_offset);
+ val |= BIT(bit);
+ writel(val, reg_base + reg_offset);
+
+out:
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val, reg_offset;
+ unsigned long flags;
+
+ kona_gpio = to_kona_gpio(chip);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ /* determine the GPIO pin direction */
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= GPIO_GPCTR0_IOTR_MASK;
+
+ /* read the GPIO bank status */
+ reg_offset = (GPIO_GPCTR0_IOTR_CMD_INPUT == val) ?
+ GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
+ val = readl(reg_base + reg_offset);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+
+ /* return the specified bit status */
+ return !!(val & BIT(bit));
+}
+
+static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+
+ bcm_kona_gpio_unlock_gpio(kona_gpio, gpio);
+ return 0;
+}
+
+static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
+
+ bcm_kona_gpio_lock_gpio(kona_gpio, gpio);
+}
+
+static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ u32 val;
+ unsigned long flags;
+
+ kona_gpio = to_kona_gpio(chip);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_IOTR_MASK;
+ val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
+ writel(val, reg_base + GPIO_CONTROL(gpio));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+
+ return 0;
+}
+
+static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int value)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val, reg_offset;
+ unsigned long flags;
+
+ kona_gpio = to_kona_gpio(chip);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_IOTR_MASK;
+ val |= GPIO_GPCTR0_IOTR_CMD_0UTPUT;
+ writel(val, reg_base + GPIO_CONTROL(gpio));
+ reg_offset = value ? GPIO_OUT_SET(bank_id) : GPIO_OUT_CLEAR(bank_id);
+
+ val = readl(reg_base + reg_offset);
+ val |= BIT(bit);
+ writel(val, reg_base + reg_offset);
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+
+ return 0;
+}
+
+static int bcm_kona_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+ struct bcm_kona_gpio *kona_gpio;
+
+ kona_gpio = to_kona_gpio(chip);
+ if (gpio >= kona_gpio->gpio_chip.ngpio)
+ return -ENXIO;
+ return irq_create_mapping(kona_gpio->irq_domain, gpio);
+}
+
+static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
+ unsigned debounce)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ u32 val, res;
+ unsigned long flags;
+
+ kona_gpio = to_kona_gpio(chip);
+ reg_base = kona_gpio->reg_base;
+ /* debounce must be 1-128ms (or 0) */
+ if ((debounce > 0 && debounce < 1000) || debounce > 128000) {
+ dev_err(chip->dev, "Debounce value %u not in range\n",
+ debounce);
+ return -EINVAL;
+ }
+
+ /* calculate debounce bit value */
+ if (debounce != 0) {
+ /* Convert to ms */
+ debounce /= 1000;
+ /* find the MSB */
+ res = fls(debounce) - 1;
+ /* Check if MSB-1 is set (round up or down) */
+ if (res > 0 && (debounce & BIT(res - 1)))
+ res++;
+ }
+
+ /* spin lock for read-modify-write of the GPIO register */
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_DBR_MASK;
+
+ if (debounce == 0) {
+ /* disable debounce */
+ val &= ~GPIO_GPCTR0_DB_ENABLE_MASK;
+ } else {
+ val |= GPIO_GPCTR0_DB_ENABLE_MASK |
+ (res << GPIO_GPCTR0_DBR_SHIFT);
+ }
+
+ writel(val, reg_base + GPIO_CONTROL(gpio));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+
+ return 0;
+}
+
+static struct gpio_chip template_chip = {
+ .label = "bcm-kona-gpio",
+ .owner = THIS_MODULE,
+ .request = bcm_kona_gpio_request,
+ .free = bcm_kona_gpio_free,
+ .direction_input = bcm_kona_gpio_direction_input,
+ .get = bcm_kona_gpio_get,
+ .direction_output = bcm_kona_gpio_direction_output,
+ .set = bcm_kona_gpio_set,
+ .set_debounce = bcm_kona_gpio_set_debounce,
+ .to_irq = bcm_kona_gpio_to_irq,
+ .base = 0,
+};
+
+static void bcm_kona_gpio_irq_ack(struct irq_data *d)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ unsigned gpio = d->hwirq;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val;
+ unsigned long flags;
+
+ kona_gpio = irq_data_get_irq_chip_data(d);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_INT_STATUS(bank_id));
+ val |= BIT(bit);
+ writel(val, reg_base + GPIO_INT_STATUS(bank_id));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static void bcm_kona_gpio_irq_mask(struct irq_data *d)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ unsigned gpio = d->hwirq;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val;
+ unsigned long flags;
+
+ kona_gpio = irq_data_get_irq_chip_data(d);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_INT_MASK(bank_id));
+ val |= BIT(bit);
+ writel(val, reg_base + GPIO_INT_MASK(bank_id));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ unsigned gpio = d->hwirq;
+ int bank_id = GPIO_BANK(gpio);
+ int bit = GPIO_BIT(gpio);
+ u32 val;
+ unsigned long flags;
+
+ kona_gpio = irq_data_get_irq_chip_data(d);
+ reg_base = kona_gpio->reg_base;
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
+ val |= BIT(bit);
+ writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+}
+
+static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct bcm_kona_gpio *kona_gpio;
+ void __iomem *reg_base;
+ unsigned gpio = d->hwirq;
+ u32 lvl_type;
+ u32 val;
+ unsigned long flags;
+
+ kona_gpio = irq_data_get_irq_chip_data(d);
+ reg_base = kona_gpio->reg_base;
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_RISING:
+ lvl_type = GPIO_GPCTR0_ITR_CMD_RISING_EDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ lvl_type = GPIO_GPCTR0_ITR_CMD_FALLING_EDGE;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ lvl_type = GPIO_GPCTR0_ITR_CMD_BOTH_EDGE;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ case IRQ_TYPE_LEVEL_LOW:
+ /* BCM GPIO doesn't support level triggering */
+ default:
+ dev_err(kona_gpio->gpio_chip.dev,
+ "Invalid BCM GPIO irq type 0x%x\n", type);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&kona_gpio->lock, flags);
+
+ val = readl(reg_base + GPIO_CONTROL(gpio));
+ val &= ~GPIO_GPCTR0_ITR_MASK;
+ val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT;
+ writel(val, reg_base + GPIO_CONTROL(gpio));
+
+ spin_unlock_irqrestore(&kona_gpio->lock, flags);
+
+ return 0;
+}
+
+static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *reg_base;
+ int bit, bank_id;
+ unsigned long sta;
+ struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ /*
+ * For bank interrupts, we can't use chip_data to store the kona_gpio
+ * pointer, since GIC needs it for its own purposes. Therefore, we get
+ * our pointer from the bank structure.
+ */
+ reg_base = bank->kona_gpio->reg_base;
+ bank_id = bank->id;
+
+ while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) &
+ (~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) {
+ for_each_set_bit(bit, &sta, 32) {
+ int hwirq = GPIO_PER_BANK * bank_id + bit;
+ int child_irq =
+ irq_find_mapping(bank->kona_gpio->irq_domain,
+ hwirq);
+ /*
+ * Clear interrupt before handler is called so we don't
+ * miss any interrupt occurred during executing them.
+ */
+ writel(readl(reg_base + GPIO_INT_STATUS(bank_id)) |
+ BIT(bit), reg_base + GPIO_INT_STATUS(bank_id));
+ /* Invoke interrupt handler */
+ generic_handle_irq(child_irq);
+ }
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
+{
+ struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) {
+ dev_err(kona_gpio->gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void bcm_kona_gpio_irq_relres(struct irq_data *d)
+{
+ struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
+}
+
+static struct irq_chip bcm_gpio_irq_chip = {
+ .name = "bcm-kona-gpio",
+ .irq_ack = bcm_kona_gpio_irq_ack,
+ .irq_mask = bcm_kona_gpio_irq_mask,
+ .irq_unmask = bcm_kona_gpio_irq_unmask,
+ .irq_set_type = bcm_kona_gpio_irq_set_type,
+ .irq_request_resources = bcm_kona_gpio_irq_reqres,
+ .irq_release_resources = bcm_kona_gpio_irq_relres,
+};
+
+static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
+ { .compatible = "brcm,kona-gpio" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, bcm_kona_gpio_of_match);
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ int ret;
+
+ ret = irq_set_chip_data(irq, d->host_data);
+ if (ret < 0)
+ return ret;
+ irq_set_lockdep_class(irq, &gpio_lock_class);
+ irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+
+ return 0;
+}
+
+static void bcm_kona_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static struct irq_domain_ops bcm_kona_irq_ops = {
+ .map = bcm_kona_gpio_irq_map,
+ .unmap = bcm_kona_gpio_irq_unmap,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio)
+{
+ void __iomem *reg_base;
+ int i;
+
+ reg_base = kona_gpio->reg_base;
+ /* disable interrupts and clear status */
+ for (i = 0; i < kona_gpio->num_bank; i++) {
+ /* Unlock the entire bank first */
+ bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE);
+ writel(0xffffffff, reg_base + GPIO_INT_MASK(i));
+ writel(0xffffffff, reg_base + GPIO_INT_STATUS(i));
+ /* Now re-lock the bank */
+ bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE);
+ }
+}
+
+static int bcm_kona_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *match;
+ struct resource *res;
+ struct bcm_kona_gpio_bank *bank;
+ struct bcm_kona_gpio *kona_gpio;
+ struct gpio_chip *chip;
+ int ret;
+ int i;
+
+ match = of_match_device(bcm_kona_gpio_of_match, dev);
+ if (!match) {
+ dev_err(dev, "Failed to find gpio controller\n");
+ return -ENODEV;
+ }
+
+ kona_gpio = devm_kzalloc(dev, sizeof(*kona_gpio), GFP_KERNEL);
+ if (!kona_gpio)
+ return -ENOMEM;
+
+ kona_gpio->gpio_chip = template_chip;
+ chip = &kona_gpio->gpio_chip;
+ kona_gpio->num_bank = of_irq_count(dev->of_node);
+ if (kona_gpio->num_bank == 0) {
+ dev_err(dev, "Couldn't determine # GPIO banks\n");
+ return -ENOENT;
+ }
+ if (kona_gpio->num_bank > GPIO_MAX_BANK_NUM) {
+ dev_err(dev, "Too many GPIO banks configured (max=%d)\n",
+ GPIO_MAX_BANK_NUM);
+ return -ENXIO;
+ }
+ kona_gpio->banks = devm_kzalloc(dev,
+ kona_gpio->num_bank *
+ sizeof(*kona_gpio->banks), GFP_KERNEL);
+ if (!kona_gpio->banks)
+ return -ENOMEM;
+
+ kona_gpio->pdev = pdev;
+ platform_set_drvdata(pdev, kona_gpio);
+ chip->of_node = dev->of_node;
+ chip->ngpio = kona_gpio->num_bank * GPIO_PER_BANK;
+
+ kona_gpio->irq_domain = irq_domain_add_linear(dev->of_node,
+ chip->ngpio,
+ &bcm_kona_irq_ops,
+ kona_gpio);
+ if (!kona_gpio->irq_domain) {
+ dev_err(dev, "Couldn't allocate IRQ domain\n");
+ return -ENXIO;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ kona_gpio->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(kona_gpio->reg_base)) {
+ ret = -ENXIO;
+ goto err_irq_domain;
+ }
+
+ for (i = 0; i < kona_gpio->num_bank; i++) {
+ bank = &kona_gpio->banks[i];
+ bank->id = i;
+ bank->irq = platform_get_irq(pdev, i);
+ bank->kona_gpio = kona_gpio;
+ if (bank->irq < 0) {
+ dev_err(dev, "Couldn't get IRQ for bank %d", i);
+ ret = -ENOENT;
+ goto err_irq_domain;
+ }
+ }
+
+ dev_info(&pdev->dev, "Setting up Kona GPIO\n");
+
+ bcm_kona_gpio_reset(kona_gpio);
+
+ ret = gpiochip_add(chip);
+ if (ret < 0) {
+ dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret);
+ goto err_irq_domain;
+ }
+ for (i = 0; i < chip->ngpio; i++) {
+ int irq = bcm_kona_gpio_to_irq(chip, i);
+ irq_set_lockdep_class(irq, &gpio_lock_class);
+ irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip,
+ handle_simple_irq);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+ }
+ for (i = 0; i < kona_gpio->num_bank; i++) {
+ bank = &kona_gpio->banks[i];
+ irq_set_chained_handler(bank->irq, bcm_kona_gpio_irq_handler);
+ irq_set_handler_data(bank->irq, bank);
+ }
+
+ spin_lock_init(&kona_gpio->lock);
+
+ return 0;
+
+err_irq_domain:
+ irq_domain_remove(kona_gpio->irq_domain);
+
+ return ret;
+}
+
+static struct platform_driver bcm_kona_gpio_driver = {
+ .driver = {
+ .name = "bcm-kona-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm_kona_gpio_of_match,
+ },
+ .probe = bcm_kona_gpio_probe,
+};
+
+module_platform_driver(bcm_kona_gpio_driver);
+
+MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Kona GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 7d9d7cb35f2..6557147d933 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -169,7 +169,7 @@ static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg)
c->dbg_show = NULL;
c->base = modparam_gpiobase;
c->ngpio = BT8XXGPIO_NR_GPIOS;
- c->can_sleep = 0;
+ c->can_sleep = false;
}
static int bt8xxgpio_probe(struct pci_dev *dev,
@@ -178,7 +178,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
struct bt8xxgpio *bg;
int err;
- bg = kzalloc(sizeof(*bg), GFP_KERNEL);
+ bg = devm_kzalloc(&dev->dev, sizeof(struct bt8xxgpio), GFP_KERNEL);
if (!bg)
return -ENOMEM;
@@ -188,9 +188,9 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err = pci_enable_device(dev);
if (err) {
printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
- goto err_freebg;
+ return err;
}
- if (!request_mem_region(pci_resource_start(dev, 0),
+ if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
pci_resource_len(dev, 0),
"bt8xxgpio")) {
printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
@@ -201,11 +201,11 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
pci_set_master(dev);
pci_set_drvdata(dev, bg);
- bg->mmio = ioremap(pci_resource_start(dev, 0), 0x1000);
+ bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
if (!bg->mmio) {
printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
err = -EIO;
- goto err_release_mem;
+ goto err_disable;
}
/* Disable interrupts */
@@ -220,19 +220,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
err = gpiochip_add(&bg->gpio);
if (err) {
printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
- goto err_release_mem;
+ goto err_disable;
}
return 0;
-err_release_mem:
- release_mem_region(pci_resource_start(dev, 0),
- pci_resource_len(dev, 0));
- pci_set_drvdata(dev, NULL);
err_disable:
pci_disable_device(dev);
-err_freebg:
- kfree(bg);
return err;
}
@@ -251,9 +245,6 @@ static void bt8xxgpio_remove(struct pci_dev *pdev)
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
pci_disable_device(pdev);
-
- pci_set_drvdata(pdev, NULL);
- kfree(bg);
}
#ifdef CONFIG_PM
@@ -286,7 +277,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
unsigned long flags;
int err;
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if (err)
return err;
@@ -310,7 +301,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
#define bt8xxgpio_resume NULL
#endif /* CONFIG_PM */
-static DEFINE_PCI_DEVICE_TABLE(bt8xxgpio_pci_tbl) = {
+static const struct pci_device_id bt8xxgpio_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878) },
diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c
new file mode 100644
index 00000000000..e1e861239e9
--- /dev/null
+++ b/drivers/gpio/gpio-clps711x.c
@@ -0,0 +1,101 @@
+/*
+ * CLPS711X GPIO driver
+ *
+ * Copyright (C) 2012,2013 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/basic_mmio_gpio.h>
+#include <linux/platform_device.h>
+
+static int clps711x_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ void __iomem *dat, *dir;
+ struct bgpio_chip *bgc;
+ struct resource *res;
+ int err, id = np ? of_alias_get_id(np, "gpio") : pdev->id;
+
+ if ((id < 0) || (id > 4))
+ return -ENODEV;
+
+ bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dat = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dat))
+ return PTR_ERR(dat);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dir = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ switch (id) {
+ case 3:
+ /* PORTD is inverted logic for direction register */
+ err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ NULL, dir, 0);
+ break;
+ default:
+ err = bgpio_init(bgc, &pdev->dev, 1, dat, NULL, NULL,
+ dir, NULL, 0);
+ break;
+ }
+
+ if (err)
+ return err;
+
+ switch (id) {
+ case 4:
+ /* PORTE is 3 lines only */
+ bgc->gc.ngpio = 3;
+ break;
+ default:
+ break;
+ }
+
+ bgc->gc.base = id * 8;
+ bgc->gc.owner = THIS_MODULE;
+ platform_set_drvdata(pdev, bgc);
+
+ return gpiochip_add(&bgc->gc);
+}
+
+static int clps711x_gpio_remove(struct platform_device *pdev)
+{
+ struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+
+ return bgpio_remove(bgc);
+}
+
+static const struct of_device_id __maybe_unused clps711x_gpio_ids[] = {
+ { .compatible = "cirrus,clps711x-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, clps711x_gpio_ids);
+
+static struct platform_driver clps711x_gpio_driver = {
+ .driver = {
+ .name = "clps711x-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(clps711x_gpio_ids),
+ },
+ .probe = clps711x_gpio_probe,
+ .remove = clps711x_gpio_remove,
+};
+module_platform_driver(clps711x_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("CLPS711X GPIO driver");
+MODULE_ALIAS("platform:clps711x-gpio");
diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c
index 19eda1bbe34..c0a3aeba6f2 100644
--- a/drivers/gpio/gpio-cs5535.c
+++ b/drivers/gpio/gpio-cs5535.c
@@ -300,7 +300,7 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = {
},
};
-static int __devinit cs5535_gpio_probe(struct platform_device *pdev)
+static int cs5535_gpio_probe(struct platform_device *pdev)
{
struct resource *res;
int err = -EIO;
@@ -355,7 +355,7 @@ done:
return err;
}
-static int __devexit cs5535_gpio_remove(struct platform_device *pdev)
+static int cs5535_gpio_remove(struct platform_device *pdev)
{
struct resource *r;
int err;
@@ -378,7 +378,7 @@ static struct platform_driver cs5535_gpio_driver = {
.owner = THIS_MODULE,
},
.probe = cs5535_gpio_probe,
- .remove = __devexit_p(cs5535_gpio_remove),
+ .remove = cs5535_gpio_remove,
};
module_platform_driver(cs5535_gpio_driver);
diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c
index 24b8c297404..416cdf786b0 100644
--- a/drivers/gpio/gpio-da9052.c
+++ b/drivers/gpio/gpio-da9052.c
@@ -185,10 +185,14 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset)
struct da9052_gpio *gpio = to_da9052_gpio(gc);
struct da9052 *da9052 = gpio->da9052;
- return da9052->irq_base + DA9052_IRQ_GPI0 + offset;
+ int irq;
+
+ irq = regmap_irq_get_virq(da9052->irq_data, DA9052_IRQ_GPI0 + offset);
+
+ return irq;
}
-static struct gpio_chip reference_gp __devinitdata = {
+static struct gpio_chip reference_gp = {
.label = "da9052-gpio",
.owner = THIS_MODULE,
.get = da9052_gpio_get,
@@ -196,12 +200,12 @@ static struct gpio_chip reference_gp __devinitdata = {
.direction_input = da9052_gpio_direction_input,
.direction_output = da9052_gpio_direction_output,
.to_irq = da9052_gpio_to_irq,
- .can_sleep = 1,
+ .can_sleep = true,
.ngpio = 16,
.base = -1,
};
-static int __devinit da9052_gpio_probe(struct platform_device *pdev)
+static int da9052_gpio_probe(struct platform_device *pdev)
{
struct da9052_gpio *gpio;
struct da9052_pdata *pdata;
@@ -212,7 +216,7 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
gpio->da9052 = dev_get_drvdata(pdev->dev.parent);
- pdata = gpio->da9052->dev->platform_data;
+ pdata = dev_get_platdata(gpio->da9052->dev);
gpio->gp = reference_gp;
if (pdata && pdata->gpio_base)
@@ -229,7 +233,7 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit da9052_gpio_remove(struct platform_device *pdev)
+static int da9052_gpio_remove(struct platform_device *pdev)
{
struct da9052_gpio *gpio = platform_get_drvdata(pdev);
@@ -238,7 +242,7 @@ static int __devexit da9052_gpio_remove(struct platform_device *pdev)
static struct platform_driver da9052_gpio_driver = {
.probe = da9052_gpio_probe,
- .remove = __devexit_p(da9052_gpio_remove),
+ .remove = da9052_gpio_remove,
.driver = {
.name = "da9052-gpio",
.owner = THIS_MODULE,
diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c
new file mode 100644
index 00000000000..f992997bc30
--- /dev/null
+++ b/drivers/gpio/gpio-da9055.c
@@ -0,0 +1,204 @@
+/*
+ * GPIO Driver for Dialog DA9055 PMICs.
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.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/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+#include <linux/mfd/da9055/pdata.h>
+
+#define DA9055_VDD_IO 0x0
+#define DA9055_PUSH_PULL 0x3
+#define DA9055_ACT_LOW 0x0
+#define DA9055_GPI 0x1
+#define DA9055_PORT_MASK 0x3
+#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2))
+
+#define DA9055_INPUT DA9055_GPI
+#define DA9055_OUTPUT DA9055_PUSH_PULL
+#define DA9055_IRQ_GPI0 3
+
+struct da9055_gpio {
+ struct da9055 *da9055;
+ struct gpio_chip gp;
+};
+
+static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct da9055_gpio, gp);
+}
+
+static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ int gpio_direction = 0;
+ int ret;
+
+ /* Get GPIO direction */
+ ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1);
+ if (ret < 0)
+ return ret;
+
+ gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset);
+ gpio_direction >>= DA9055_PORT_SHIFT(offset);
+ switch (gpio_direction) {
+ case DA9055_INPUT:
+ ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B);
+ if (ret < 0)
+ return ret;
+ break;
+ case DA9055_OUTPUT:
+ ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret & (1 << offset);
+
+}
+
+static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct da9055_gpio *gpio = to_da9055_gpio(gc);
+
+ da9055_reg_update(gpio->da9055,
+ DA9055_REG_GPIO_MODE0_2,
+ 1 << offset,
+ value << offset);
+}
+
+static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ unsigned char reg_byte;
+
+ reg_byte = (DA9055_ACT_LOW | DA9055_GPI)
+ << DA9055_PORT_SHIFT(offset);
+
+ return da9055_reg_update(gpio->da9055, (offset >> 1) +
+ DA9055_REG_GPIO0_1,
+ DA9055_PORT_MASK <<
+ DA9055_PORT_SHIFT(offset),
+ reg_byte);
+}
+
+static int da9055_gpio_direction_output(struct gpio_chip *gc,
+ unsigned offset, int value)
+{
+ struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ unsigned char reg_byte;
+ int ret;
+
+ reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL)
+ << DA9055_PORT_SHIFT(offset);
+
+ ret = da9055_reg_update(gpio->da9055, (offset >> 1) +
+ DA9055_REG_GPIO0_1,
+ DA9055_PORT_MASK <<
+ DA9055_PORT_SHIFT(offset),
+ reg_byte);
+ if (ret < 0)
+ return ret;
+
+ da9055_gpio_set(gc, offset, value);
+
+ return 0;
+}
+
+static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset)
+{
+ struct da9055_gpio *gpio = to_da9055_gpio(gc);
+ struct da9055 *da9055 = gpio->da9055;
+
+ return regmap_irq_get_virq(da9055->irq_data,
+ DA9055_IRQ_GPI0 + offset);
+}
+
+static struct gpio_chip reference_gp = {
+ .label = "da9055-gpio",
+ .owner = THIS_MODULE,
+ .get = da9055_gpio_get,
+ .set = da9055_gpio_set,
+ .direction_input = da9055_gpio_direction_input,
+ .direction_output = da9055_gpio_direction_output,
+ .to_irq = da9055_gpio_to_irq,
+ .can_sleep = true,
+ .ngpio = 3,
+ .base = -1,
+};
+
+static int da9055_gpio_probe(struct platform_device *pdev)
+{
+ struct da9055_gpio *gpio;
+ struct da9055_pdata *pdata;
+ int ret;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (gpio == NULL)
+ return -ENOMEM;
+
+ gpio->da9055 = dev_get_drvdata(pdev->dev.parent);
+ pdata = dev_get_platdata(gpio->da9055->dev);
+
+ gpio->gp = reference_gp;
+ if (pdata && pdata->gpio_base)
+ gpio->gp.base = pdata->gpio_base;
+
+ ret = gpiochip_add(&gpio->gp);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ goto err_mem;
+ }
+
+ platform_set_drvdata(pdev, gpio);
+
+ return 0;
+
+err_mem:
+ return ret;
+}
+
+static int da9055_gpio_remove(struct platform_device *pdev)
+{
+ struct da9055_gpio *gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&gpio->gp);
+}
+
+static struct platform_driver da9055_gpio_driver = {
+ .probe = da9055_gpio_probe,
+ .remove = da9055_gpio_remove,
+ .driver = {
+ .name = "da9055-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init da9055_gpio_init(void)
+{
+ return platform_driver_register(&da9055_gpio_driver);
+}
+subsys_initcall(da9055_gpio_init);
+
+static void __exit da9055_gpio_exit(void)
+{
+ platform_driver_unregister(&da9055_gpio_driver);
+}
+module_exit(da9055_gpio_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 GPIO Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-gpio");
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 17df6db5dca..9f0682534e2 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -15,8 +15,14 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
-
-#include <asm/mach/irq.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/gpio-davinci.h>
+#include <linux/irqchip/chained_irq.h>
struct davinci_gpio_regs {
u32 dir;
@@ -31,13 +37,16 @@ struct davinci_gpio_regs {
u32 intstat;
};
+typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
+
+#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
+
#define chip2controller(chip) \
container_of(chip, struct davinci_gpio_controller, chip)
-static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
static void __iomem *gpio_base;
-static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
+static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio)
{
void __iomem *ptr;
@@ -65,7 +74,7 @@ static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
return g;
}
-static int __init davinci_gpio_irq_setup(void);
+static int davinci_gpio_irq_setup(struct platform_device *pdev);
/*--------------------------------------------------------------------------*/
@@ -80,14 +89,14 @@ static inline int __davinci_direction(struct gpio_chip *chip,
u32 mask = 1 << offset;
spin_lock_irqsave(&d->lock, flags);
- temp = __raw_readl(&g->dir);
+ temp = readl_relaxed(&g->dir);
if (out) {
temp &= ~mask;
- __raw_writel(mask, value ? &g->set_data : &g->clr_data);
+ writel_relaxed(mask, value ? &g->set_data : &g->clr_data);
} else {
temp |= mask;
}
- __raw_writel(temp, &g->dir);
+ writel_relaxed(temp, &g->dir);
spin_unlock_irqrestore(&d->lock, flags);
return 0;
@@ -116,7 +125,7 @@ static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
struct davinci_gpio_controller *d = chip2controller(chip);
struct davinci_gpio_regs __iomem *g = d->regs;
- return (1 << offset) & __raw_readl(&g->in_data);
+ return (1 << offset) & readl_relaxed(&g->in_data);
}
/*
@@ -128,37 +137,112 @@ davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
struct davinci_gpio_controller *d = chip2controller(chip);
struct davinci_gpio_regs __iomem *g = d->regs;
- __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
+ writel_relaxed((1 << offset), value ? &g->set_data : &g->clr_data);
+}
+
+static struct davinci_gpio_platform_data *
+davinci_gpio_get_pdata(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ struct davinci_gpio_platform_data *pdata;
+ int ret;
+ u32 val;
+
+ if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
+ return pdev->dev.platform_data;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ ret = of_property_read_u32(dn, "ti,ngpio", &val);
+ if (ret)
+ goto of_err;
+
+ pdata->ngpio = val;
+
+ ret = of_property_read_u32(dn, "ti,davinci-gpio-unbanked", &val);
+ if (ret)
+ goto of_err;
+
+ pdata->gpio_unbanked = val;
+
+ return pdata;
+
+of_err:
+ dev_err(&pdev->dev, "Populating pdata from DT failed: err %d\n", ret);
+ return NULL;
}
-static int __init davinci_gpio_setup(void)
+#ifdef CONFIG_OF_GPIO
+static int davinci_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev);
+ struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev);
+
+ if (gpiospec->args[0] > pdata->ngpio)
+ return -EINVAL;
+
+ if (gc != &chips[gpiospec->args[0] / 32].chip)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpiospec->args[0] % 32;
+}
+#endif
+
+static int davinci_gpio_probe(struct platform_device *pdev)
{
int i, base;
unsigned ngpio;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct davinci_gpio_regs *regs;
+ struct davinci_gpio_controller *chips;
+ struct davinci_gpio_platform_data *pdata;
+ struct davinci_gpio_regs __iomem *regs;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ pdata = davinci_gpio_get_pdata(pdev);
+ if (!pdata) {
+ dev_err(dev, "No platform data found\n");
+ return -EINVAL;
+ }
- if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
- return 0;
+ dev->platform_data = pdata;
/*
* The gpio banks conceptually expose a segmented bitmap,
* and "ngpio" is one more than the largest zero-based
* bit index that's valid.
*/
- ngpio = soc_info->gpio_num;
+ ngpio = pdata->ngpio;
if (ngpio == 0) {
- pr_err("GPIO setup: how many GPIOs?\n");
+ dev_err(dev, "How many GPIOs?\n");
return -EINVAL;
}
- if (WARN_ON(DAVINCI_N_GPIO < ngpio))
- ngpio = DAVINCI_N_GPIO;
+ if (WARN_ON(ARCH_NR_GPIOS < ngpio))
+ ngpio = ARCH_NR_GPIOS;
- gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
- if (WARN_ON(!gpio_base))
+ chips = devm_kzalloc(dev,
+ ngpio * sizeof(struct davinci_gpio_controller),
+ GFP_KERNEL);
+ if (!chips)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "Invalid memory resource\n");
+ return -EBUSY;
+ }
+
+ gpio_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(gpio_base))
+ return PTR_ERR(gpio_base);
+
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
chips[i].chip.label = "DaVinci";
@@ -172,6 +256,12 @@ static int __init davinci_gpio_setup(void)
if (chips[i].chip.ngpio > 32)
chips[i].chip.ngpio = 32;
+#ifdef CONFIG_OF_GPIO
+ chips[i].chip.of_gpio_n_cells = 2;
+ chips[i].chip.of_xlate = davinci_gpio_of_xlate;
+ chips[i].chip.dev = dev;
+ chips[i].chip.of_node = dev->of_node;
+#endif
spin_lock_init(&chips[i].lock);
regs = gpio2regs(base);
@@ -183,13 +273,10 @@ static int __init davinci_gpio_setup(void)
gpiochip_add(&chips[i].chip);
}
- soc_info->gpio_ctlrs = chips;
- soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
-
- davinci_gpio_irq_setup();
+ platform_set_drvdata(pdev, chips);
+ davinci_gpio_irq_setup(pdev);
return 0;
}
-pure_initcall(davinci_gpio_setup);
/*--------------------------------------------------------------------------*/
/*
@@ -208,8 +295,8 @@ static void gpio_irq_disable(struct irq_data *d)
struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
u32 mask = (u32) irq_data_get_irq_handler_data(d);
- __raw_writel(mask, &g->clr_falling);
- __raw_writel(mask, &g->clr_rising);
+ writel_relaxed(mask, &g->clr_falling);
+ writel_relaxed(mask, &g->clr_rising);
}
static void gpio_irq_enable(struct irq_data *d)
@@ -223,9 +310,9 @@ static void gpio_irq_enable(struct irq_data *d)
status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
if (status & IRQ_TYPE_EDGE_FALLING)
- __raw_writel(mask, &g->set_falling);
+ writel_relaxed(mask, &g->set_falling);
if (status & IRQ_TYPE_EDGE_RISING)
- __raw_writel(mask, &g->set_rising);
+ writel_relaxed(mask, &g->set_rising);
}
static int gpio_irq_type(struct irq_data *d, unsigned trigger)
@@ -259,34 +346,28 @@ gpio_irq_handler(unsigned irq, struct irq_desc *desc)
mask <<= 16;
/* temporarily mask (level sensitive) parent IRQ */
- desc->irq_data.chip->irq_mask(&desc->irq_data);
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(irq_desc_get_chip(desc), desc);
while (1) {
u32 status;
- int n;
- int res;
+ int bit;
/* ack any irqs */
- status = __raw_readl(&g->intstat) & mask;
+ status = readl_relaxed(&g->intstat) & mask;
if (!status)
break;
- __raw_writel(status, &g->intstat);
+ writel_relaxed(status, &g->intstat);
/* now demux them to the right lowlevel handler */
- n = d->irq_base;
- if (irq & 1) {
- n += 16;
- status >>= 16;
- }
while (status) {
- res = ffs(status);
- n += res;
- generic_handle_irq(n - 1);
- status >>= res;
+ bit = __ffs(status);
+ status &= ~BIT(bit);
+ generic_handle_irq(
+ irq_find_mapping(d->irq_domain,
+ d->chip.base + bit));
}
}
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(irq_desc_get_chip(desc), desc);
/* now it may re-trigger */
}
@@ -294,21 +375,22 @@ static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
{
struct davinci_gpio_controller *d = chip2controller(chip);
- if (d->irq_base >= 0)
- return d->irq_base + offset;
+ if (d->irq_domain)
+ return irq_create_mapping(d->irq_domain, d->chip.base + offset);
else
- return -ENODEV;
+ return -ENXIO;
}
static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
{
- struct davinci_soc_info *soc_info = &davinci_soc_info;
+ struct davinci_gpio_controller *d = chip2controller(chip);
- /* NOTE: we assume for now that only irqs in the first gpio_chip
+ /*
+ * NOTE: we assume for now that only irqs in the first gpio_chip
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
*/
- if (offset < soc_info->gpio_unbanked)
- return soc_info->gpio_irq + offset;
+ if (offset < d->gpio_unbanked)
+ return d->gpio_irq + offset;
else
return -ENODEV;
}
@@ -317,24 +399,64 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
{
struct davinci_gpio_controller *d;
struct davinci_gpio_regs __iomem *g;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
u32 mask;
d = (struct davinci_gpio_controller *)data->handler_data;
g = (struct davinci_gpio_regs __iomem *)d->regs;
- mask = __gpio_mask(data->irq - soc_info->gpio_irq);
+ mask = __gpio_mask(data->irq - d->gpio_irq);
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
- __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+ writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
? &g->set_falling : &g->clr_falling);
- __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+ writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_RISING)
? &g->set_rising : &g->clr_rising);
return 0;
}
+static int
+davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct davinci_gpio_regs __iomem *g = gpio2regs(hw);
+
+ irq_set_chip_and_handler_name(irq, &gpio_irqchip, handle_simple_irq,
+ "davinci_gpio");
+ irq_set_irq_type(irq, IRQ_TYPE_NONE);
+ irq_set_chip_data(irq, (__force void *)g);
+ irq_set_handler_data(irq, (void *)__gpio_mask(hw));
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+static const struct irq_domain_ops davinci_gpio_irq_ops = {
+ .map = davinci_gpio_irq_map,
+ .xlate = irq_domain_xlate_onetwocell,
+};
+
+static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq)
+{
+ static struct irq_chip_type gpio_unbanked;
+
+ gpio_unbanked = *container_of(irq_get_chip(irq),
+ struct irq_chip_type, chip);
+
+ return &gpio_unbanked.chip;
+};
+
+static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq)
+{
+ static struct irq_chip gpio_unbanked;
+
+ gpio_unbanked = *irq_get_chip(irq);
+ return &gpio_unbanked;
+};
+
+static const struct of_device_id davinci_gpio_ids[];
+
/*
* NOTE: for suspend/resume, probably best to make a platform_device with
* suspend_late/resume_resume calls hooking into results of the set_wake()
@@ -343,24 +465,47 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
* (dm6446) can be set appropriately for GPIOV33 pins.
*/
-static int __init davinci_gpio_irq_setup(void)
+static int davinci_gpio_irq_setup(struct platform_device *pdev)
{
- unsigned gpio, irq, bank;
+ unsigned gpio, bank;
+ int irq;
struct clk *clk;
u32 binten = 0;
unsigned ngpio, bank_irq;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct davinci_gpio_regs __iomem *g;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct davinci_gpio_controller *chips = platform_get_drvdata(pdev);
+ struct davinci_gpio_platform_data *pdata = dev->platform_data;
+ struct davinci_gpio_regs __iomem *g;
+ struct irq_domain *irq_domain = NULL;
+ const struct of_device_id *match;
+ struct irq_chip *irq_chip;
+ gpio_get_irq_chip_cb_t gpio_get_irq_chip;
+
+ /*
+ * Use davinci_gpio_get_irq_chip by default to handle non DT cases
+ */
+ gpio_get_irq_chip = davinci_gpio_get_irq_chip;
+ match = of_match_device(of_match_ptr(davinci_gpio_ids),
+ dev);
+ if (match)
+ gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data;
+
+ ngpio = pdata->ngpio;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "Invalid IRQ resource\n");
+ return -EBUSY;
+ }
- ngpio = soc_info->gpio_num;
+ bank_irq = res->start;
- bank_irq = soc_info->gpio_irq;
- if (bank_irq == 0) {
- printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
- return -EINVAL;
+ if (!bank_irq) {
+ dev_err(dev, "Invalid IRQ resource\n");
+ return -ENODEV;
}
- clk = clk_get(NULL, "gpio");
+ clk = devm_clk_get(dev, "gpio");
if (IS_ERR(clk)) {
printk(KERN_ERR "Error %ld getting gpio clock?\n",
PTR_ERR(clk));
@@ -368,16 +513,31 @@ static int __init davinci_gpio_irq_setup(void)
}
clk_prepare_enable(clk);
- /* Arrange gpio_to_irq() support, handling either direct IRQs or
+ if (!pdata->gpio_unbanked) {
+ irq = irq_alloc_descs(-1, 0, ngpio, 0);
+ if (irq < 0) {
+ dev_err(dev, "Couldn't allocate IRQ numbers\n");
+ return irq;
+ }
+
+ irq_domain = irq_domain_add_legacy(NULL, ngpio, irq, 0,
+ &davinci_gpio_irq_ops,
+ chips);
+ if (!irq_domain) {
+ dev_err(dev, "Couldn't register an IRQ domain\n");
+ return -ENODEV;
+ }
+ }
+
+ /*
+ * Arrange gpio_to_irq() support, handling either direct IRQs or
* banked IRQs. Having GPIOs in the first GPIO bank use direct
* IRQs, while the others use banked IRQs, would need some setup
* tweaks to recognize hardware which can do that.
*/
for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
chips[bank].chip.to_irq = gpio_to_irq_banked;
- chips[bank].irq_base = soc_info->gpio_unbanked
- ? -EINVAL
- : (soc_info->intc_irq_num + gpio);
+ chips[bank].irq_domain = irq_domain;
}
/*
@@ -385,28 +545,27 @@ static int __init davinci_gpio_irq_setup(void)
* controller only handling trigger modes. We currently assume no
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
*/
- if (soc_info->gpio_unbanked) {
- static struct irq_chip_type gpio_unbanked;
-
+ if (pdata->gpio_unbanked) {
/* pass "bank 0" GPIO IRQs to AINTC */
chips[0].chip.to_irq = gpio_to_irq_unbanked;
+ chips[0].gpio_irq = bank_irq;
+ chips[0].gpio_unbanked = pdata->gpio_unbanked;
binten = BIT(0);
/* AINTC handles mask/unmask; GPIO handles triggering */
irq = bank_irq;
- gpio_unbanked = *container_of(irq_get_chip(irq),
- struct irq_chip_type, chip);
- gpio_unbanked.chip.name = "GPIO-AINTC";
- gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
+ irq_chip = gpio_get_irq_chip(irq);
+ irq_chip->name = "GPIO-AINTC";
+ irq_chip->irq_set_type = gpio_irq_type_unbanked;
/* default trigger: both edges */
g = gpio2regs(0);
- __raw_writel(~0, &g->set_falling);
- __raw_writel(~0, &g->set_rising);
+ writel_relaxed(~0, &g->set_falling);
+ writel_relaxed(~0, &g->set_rising);
/* set the direct IRQs up to use that irqchip */
- for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
- irq_set_chip(irq, &gpio_unbanked.chip);
+ for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
+ irq_set_chip(irq, irq_chip);
irq_set_handler_data(irq, &chips[gpio / 32]);
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
}
@@ -418,15 +577,11 @@ static int __init davinci_gpio_irq_setup(void)
* Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
* then chain through our own handler.
*/
- for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
- gpio < ngpio;
- bank++, bank_irq++) {
- unsigned i;
-
+ for (gpio = 0, bank = 0; gpio < ngpio; bank++, bank_irq++, gpio += 16) {
/* disabled by default, enabled only as needed */
g = gpio2regs(gpio);
- __raw_writel(~0, &g->clr_falling);
- __raw_writel(~0, &g->clr_rising);
+ writel_relaxed(~0, &g->clr_falling);
+ writel_relaxed(~0, &g->clr_rising);
/* set up all irqs in this bank */
irq_set_chained_handler(bank_irq, gpio_irq_handler);
@@ -438,24 +593,43 @@ static int __init davinci_gpio_irq_setup(void)
*/
irq_set_handler_data(bank_irq, &chips[gpio / 32]);
- for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
- irq_set_chip(irq, &gpio_irqchip);
- irq_set_chip_data(irq, (__force void *)g);
- irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
- irq_set_handler(irq, handle_simple_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
binten |= BIT(bank);
}
done:
- /* BINTEN -- per-bank interrupt enable. genirq would also let these
+ /*
+ * BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set/cleared dynamically.
*/
- __raw_writel(binten, gpio_base + 0x08);
-
- printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
+ writel_relaxed(binten, gpio_base + BINTEN);
return 0;
}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id davinci_gpio_ids[] = {
+ { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
+ { .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
+#endif
+
+static struct platform_driver davinci_gpio_driver = {
+ .probe = davinci_gpio_probe,
+ .driver = {
+ .name = "davinci_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(davinci_gpio_ids),
+ },
+};
+
+/**
+ * GPIO driver registration needs to be done before machine_init functions
+ * access GPIO. Hence davinci_gpio_drv_reg() is a postcore_initcall.
+ */
+static int __init davinci_gpio_drv_reg(void)
+{
+ return platform_driver_register(&davinci_gpio_driver);
+}
+postcore_initcall(davinci_gpio_drv_reg);
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
new file mode 100644
index 00000000000..cd3b8143527
--- /dev/null
+++ b/drivers/gpio/gpio-dwapb.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2011 Jamie Iles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * All enquiries to support@picochip.com
+ */
+#include <linux/basic_mmio_gpio.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define GPIO_SWPORTA_DR 0x00
+#define GPIO_SWPORTA_DDR 0x04
+#define GPIO_SWPORTB_DR 0x0c
+#define GPIO_SWPORTB_DDR 0x10
+#define GPIO_SWPORTC_DR 0x18
+#define GPIO_SWPORTC_DDR 0x1c
+#define GPIO_SWPORTD_DR 0x24
+#define GPIO_SWPORTD_DDR 0x28
+#define GPIO_INTEN 0x30
+#define GPIO_INTMASK 0x34
+#define GPIO_INTTYPE_LEVEL 0x38
+#define GPIO_INT_POLARITY 0x3c
+#define GPIO_INTSTATUS 0x40
+#define GPIO_PORTA_EOI 0x4c
+#define GPIO_EXT_PORTA 0x50
+#define GPIO_EXT_PORTB 0x54
+#define GPIO_EXT_PORTC 0x58
+#define GPIO_EXT_PORTD 0x5c
+
+#define DWAPB_MAX_PORTS 4
+#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA)
+#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
+#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
+
+struct dwapb_gpio;
+
+struct dwapb_gpio_port {
+ struct bgpio_chip bgc;
+ bool is_registered;
+ struct dwapb_gpio *gpio;
+};
+
+struct dwapb_gpio {
+ struct device *dev;
+ void __iomem *regs;
+ struct dwapb_gpio_port *ports;
+ unsigned int nr_ports;
+ struct irq_domain *domain;
+};
+
+static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ struct dwapb_gpio_port *port = container_of(bgc, struct
+ dwapb_gpio_port, bgc);
+ struct dwapb_gpio *gpio = port->gpio;
+
+ return irq_find_mapping(gpio->domain, offset);
+}
+
+static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
+{
+ u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
+
+ if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
+ v &= ~BIT(offs);
+ else
+ v |= BIT(offs);
+
+ writel(v, gpio->regs + GPIO_INT_POLARITY);
+}
+
+static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
+{
+ struct dwapb_gpio *gpio = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
+
+ while (irq_status) {
+ int hwirq = fls(irq_status) - 1;
+ int gpio_irq = irq_find_mapping(gpio->domain, hwirq);
+
+ generic_handle_irq(gpio_irq);
+ irq_status &= ~BIT(hwirq);
+
+ if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK)
+ == IRQ_TYPE_EDGE_BOTH)
+ dwapb_toggle_trigger(gpio, hwirq);
+ }
+
+ if (chip->irq_eoi)
+ chip->irq_eoi(irq_desc_get_irq_data(desc));
+}
+
+static void dwapb_irq_enable(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ val = readl(gpio->regs + GPIO_INTEN);
+ val |= BIT(d->hwirq);
+ writel(val, gpio->regs + GPIO_INTEN);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void dwapb_irq_disable(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ val = readl(gpio->regs + GPIO_INTEN);
+ val &= ~BIT(d->hwirq);
+ writel(val, gpio->regs + GPIO_INTEN);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int dwapb_irq_reqres(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+
+ if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) {
+ dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void dwapb_irq_relres(struct irq_data *d)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+
+ gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d));
+}
+
+static int dwapb_irq_set_type(struct irq_data *d, u32 type)
+{
+ struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
+ struct dwapb_gpio *gpio = igc->private;
+ struct bgpio_chip *bgc = &gpio->ports[0].bgc;
+ int bit = d->hwirq;
+ unsigned long level, polarity, flags;
+
+ if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+ return -EINVAL;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+ level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
+ polarity = readl(gpio->regs + GPIO_INT_POLARITY);
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ level |= BIT(bit);
+ dwapb_toggle_trigger(gpio, bit);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ level |= BIT(bit);
+ polarity |= BIT(bit);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ level |= BIT(bit);
+ polarity &= ~BIT(bit);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ level &= ~BIT(bit);
+ polarity |= BIT(bit);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ level &= ~BIT(bit);
+ polarity &= ~BIT(bit);
+ break;
+ }
+
+ irq_setup_alt_chip(d, type);
+
+ writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
+ writel(polarity, gpio->regs + GPIO_INT_POLARITY);
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
+ return 0;
+}
+
+static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
+ struct dwapb_gpio_port *port)
+{
+ struct gpio_chip *gc = &port->bgc.gc;
+ struct device_node *node = gc->of_node;
+ struct irq_chip_generic *irq_gc;
+ unsigned int hwirq, ngpio = gc->ngpio;
+ struct irq_chip_type *ct;
+ int err, irq, i;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ dev_warn(gpio->dev, "no irq for bank %s\n",
+ port->bgc.gc.of_node->full_name);
+ return;
+ }
+
+ gpio->domain = irq_domain_add_linear(node, ngpio,
+ &irq_generic_chip_ops, gpio);
+ if (!gpio->domain)
+ return;
+
+ err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
+ "gpio-dwapb", handle_level_irq,
+ IRQ_NOREQUEST, 0,
+ IRQ_GC_INIT_NESTED_LOCK);
+ if (err) {
+ dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n");
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+ return;
+ }
+
+ irq_gc = irq_get_domain_generic_chip(gpio->domain, 0);
+ if (!irq_gc) {
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+ return;
+ }
+
+ irq_gc->reg_base = gpio->regs;
+ irq_gc->private = gpio;
+
+ for (i = 0; i < 2; i++) {
+ ct = &irq_gc->chip_types[i];
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_type = dwapb_irq_set_type;
+ ct->chip.irq_enable = dwapb_irq_enable;
+ ct->chip.irq_disable = dwapb_irq_disable;
+ ct->chip.irq_request_resources = dwapb_irq_reqres;
+ ct->chip.irq_release_resources = dwapb_irq_relres;
+ ct->regs.ack = GPIO_PORTA_EOI;
+ ct->regs.mask = GPIO_INTMASK;
+ ct->type = IRQ_TYPE_LEVEL_MASK;
+ }
+
+ irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ irq_gc->chip_types[1].handler = handle_edge_irq;
+
+ irq_set_chained_handler(irq, dwapb_irq_handler);
+ irq_set_handler_data(irq, gpio);
+
+ for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
+ irq_create_mapping(gpio->domain, hwirq);
+
+ port->bgc.gc.to_irq = dwapb_gpio_to_irq;
+}
+
+static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
+{
+ struct dwapb_gpio_port *port = &gpio->ports[0];
+ struct gpio_chip *gc = &port->bgc.gc;
+ unsigned int ngpio = gc->ngpio;
+ irq_hw_number_t hwirq;
+
+ if (!gpio->domain)
+ return;
+
+ for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
+ irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq));
+
+ irq_domain_remove(gpio->domain);
+ gpio->domain = NULL;
+}
+
+static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
+ struct device_node *port_np,
+ unsigned int offs)
+{
+ struct dwapb_gpio_port *port;
+ u32 port_idx, ngpio;
+ void __iomem *dat, *set, *dirout;
+ int err;
+
+ if (of_property_read_u32(port_np, "reg", &port_idx) ||
+ port_idx >= DWAPB_MAX_PORTS) {
+ dev_err(gpio->dev, "missing/invalid port index for %s\n",
+ port_np->full_name);
+ return -EINVAL;
+ }
+
+ port = &gpio->ports[offs];
+ port->gpio = gpio;
+
+ if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
+ dev_info(gpio->dev, "failed to get number of gpios for %s\n",
+ port_np->full_name);
+ ngpio = 32;
+ }
+
+ dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
+ set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
+ dirout = gpio->regs + GPIO_SWPORTA_DDR +
+ (port_idx * GPIO_SWPORT_DDR_SIZE);
+
+ err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
+ NULL, false);
+ if (err) {
+ dev_err(gpio->dev, "failed to init gpio chip for %s\n",
+ port_np->full_name);
+ return err;
+ }
+
+ port->bgc.gc.ngpio = ngpio;
+ port->bgc.gc.of_node = port_np;
+
+ /*
+ * Only port A can provide interrupts in all configurations of the IP.
+ */
+ if (port_idx == 0 &&
+ of_property_read_bool(port_np, "interrupt-controller"))
+ dwapb_configure_irqs(gpio, port);
+
+ err = gpiochip_add(&port->bgc.gc);
+ if (err)
+ dev_err(gpio->dev, "failed to register gpiochip for %s\n",
+ port_np->full_name);
+ else
+ port->is_registered = true;
+
+ return err;
+}
+
+static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
+{
+ unsigned int m;
+
+ for (m = 0; m < gpio->nr_ports; ++m)
+ if (gpio->ports[m].is_registered)
+ WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc));
+}
+
+static int dwapb_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct dwapb_gpio *gpio;
+ struct device_node *np;
+ int err;
+ unsigned int offs = 0;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+ gpio->dev = &pdev->dev;
+
+ gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
+ if (!gpio->nr_ports) {
+ err = -EINVAL;
+ goto out_err;
+ }
+ gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
+ sizeof(*gpio->ports), GFP_KERNEL);
+ if (!gpio->ports) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gpio->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gpio->regs)) {
+ err = PTR_ERR(gpio->regs);
+ goto out_err;
+ }
+
+ for_each_child_of_node(pdev->dev.of_node, np) {
+ err = dwapb_gpio_add_port(gpio, np, offs++);
+ if (err)
+ goto out_unregister;
+ }
+ platform_set_drvdata(pdev, gpio);
+
+ return 0;
+
+out_unregister:
+ dwapb_gpio_unregister(gpio);
+ dwapb_irq_teardown(gpio);
+
+out_err:
+ return err;
+}
+
+static int dwapb_gpio_remove(struct platform_device *pdev)
+{
+ struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
+
+ dwapb_gpio_unregister(gpio);
+ dwapb_irq_teardown(gpio);
+
+ return 0;
+}
+
+static const struct of_device_id dwapb_of_match[] = {
+ { .compatible = "snps,dw-apb-gpio" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dwapb_of_match);
+
+static struct platform_driver dwapb_gpio_driver = {
+ .driver = {
+ .name = "gpio-dwapb",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(dwapb_of_match),
+ },
+ .probe = dwapb_gpio_probe,
+ .remove = dwapb_gpio_remove,
+};
+
+module_platform_driver(dwapb_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Iles");
+MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
index efb4c2d0d13..cde36054c38 100644
--- a/drivers/gpio/gpio-em.c
+++ b/drivers/gpio/gpio-em.c
@@ -30,12 +30,12 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/gpio-em.h>
struct em_gio_priv {
void __iomem *base0;
void __iomem *base1;
- unsigned int irq_base;
spinlock_t sense_lock;
struct platform_device *pdev;
struct gpio_chip gpio_chip;
@@ -99,6 +99,27 @@ static void em_gio_irq_enable(struct irq_data *d)
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
}
+static int em_gio_irq_reqres(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) {
+ dev_err(p->gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void em_gio_irq_relres(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
+}
+
+
#define GIO_ASYNC(x) (x + 8)
static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
@@ -191,7 +212,7 @@ static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
{
/* upper 16 bits contains mask and lower 16 actual value */
em_gio_write(gpio_to_priv(chip), reg,
- (1 << (shift + 16)) | (value << shift));
+ (BIT(shift + 16)) | (value << shift));
}
static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -214,63 +235,46 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
+ return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
}
-static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
+static int em_gio_request(struct gpio_chip *chip, unsigned offset)
{
- struct em_gio_priv *p = h->host_data;
+ return pinctrl_request_gpio(chip->base + offset);
+}
- pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
+static void em_gio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
- irq_set_chip_data(virq, h->host_data);
- irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
- set_irq_flags(virq, IRQF_VALID); /* kill me now */
- return 0;
+ /* Set the GPIO as an input to ensure that the next GPIO request won't
+ * drive the GPIO pin as an output.
+ */
+ em_gio_direction_input(chip, offset);
}
-static struct irq_domain_ops em_gio_irq_domain_ops = {
- .map = em_gio_irq_domain_map,
-};
-
-static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
+static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- struct platform_device *pdev = p->pdev;
- struct gpio_em_config *pdata = pdev->dev.platform_data;
-
- p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
- pdata->number_of_pins, numa_node_id());
- if (p->irq_base < 0) {
- dev_err(&pdev->dev, "cannot get irq_desc\n");
- return p->irq_base;
- }
- pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
- pdata->gpio_base, pdata->number_of_pins, p->irq_base);
+ struct em_gio_priv *p = h->host_data;
- p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
- pdata->number_of_pins,
- p->irq_base, 0,
- &em_gio_irq_domain_ops, p);
- if (!p->irq_domain) {
- irq_free_descs(p->irq_base, pdata->number_of_pins);
- return -ENXIO;
- }
+ pr_debug("gio: map hw irq = %d, irq = %d\n", (int)hwirq, irq);
+ irq_set_chip_data(irq, h->host_data);
+ irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID); /* kill me now */
return 0;
}
-static void em_gio_irq_domain_cleanup(struct em_gio_priv *p)
-{
- struct gpio_em_config *pdata = p->pdev->dev.platform_data;
-
- irq_free_descs(p->irq_base, pdata->number_of_pins);
- /* FIXME: irq domain wants to be freed! */
-}
+static struct irq_domain_ops em_gio_irq_domain_ops = {
+ .map = em_gio_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
+};
-static int __devinit em_gio_probe(struct platform_device *pdev)
+static int em_gio_probe(struct platform_device *pdev)
{
- struct gpio_em_config *pdata = pdev->dev.platform_data;
+ struct gpio_em_config pdata_dt;
+ struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev);
struct em_gio_priv *p;
struct resource *io[2], *irq[2];
struct gpio_chip *gpio_chip;
@@ -278,9 +282,8 @@ static int __devinit em_gio_probe(struct platform_device *pdev)
const char *name = dev_name(&pdev->dev);
int ret;
- p = kzalloc(sizeof(*p), GFP_KERNEL);
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
ret = -ENOMEM;
goto err0;
}
@@ -294,33 +297,58 @@ static int __devinit em_gio_probe(struct platform_device *pdev)
irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
- if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
- dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
+ if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
+ dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
ret = -EINVAL;
- goto err1;
+ goto err0;
}
- p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
+ p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
+ resource_size(io[0]));
if (!p->base0) {
dev_err(&pdev->dev, "failed to remap low I/O memory\n");
ret = -ENXIO;
- goto err1;
+ goto err0;
}
- p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
+ p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
+ resource_size(io[1]));
if (!p->base1) {
dev_err(&pdev->dev, "failed to remap high I/O memory\n");
ret = -ENXIO;
- goto err2;
+ goto err0;
+ }
+
+ if (!pdata) {
+ memset(&pdata_dt, 0, sizeof(pdata_dt));
+ pdata = &pdata_dt;
+
+ if (of_property_read_u32(pdev->dev.of_node, "ngpios",
+ &pdata->number_of_pins)) {
+ dev_err(&pdev->dev, "Missing ngpios OF property\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ ret = of_alias_get_id(pdev->dev.of_node, "gpio");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't get OF id\n");
+ goto err0;
+ }
+ pdata->gpio_base = ret * 32; /* 32 GPIOs per instance */
}
gpio_chip = &p->gpio_chip;
+ gpio_chip->of_node = pdev->dev.of_node;
gpio_chip->direction_input = em_gio_direction_input;
gpio_chip->get = em_gio_get;
gpio_chip->direction_output = em_gio_direction_output;
gpio_chip->set = em_gio_set;
gpio_chip->to_irq = em_gio_to_irq;
+ gpio_chip->request = em_gio_request;
+ gpio_chip->free = em_gio_free;
gpio_chip->label = name;
+ gpio_chip->dev = &pdev->dev;
gpio_chip->owner = THIS_MODULE;
gpio_chip->base = pdata->gpio_base;
gpio_chip->ngpio = pdata->number_of_pins;
@@ -329,83 +357,95 @@ static int __devinit em_gio_probe(struct platform_device *pdev)
irq_chip->name = name;
irq_chip->irq_mask = em_gio_irq_disable;
irq_chip->irq_unmask = em_gio_irq_enable;
- irq_chip->irq_enable = em_gio_irq_enable;
- irq_chip->irq_disable = em_gio_irq_disable;
irq_chip->irq_set_type = em_gio_irq_set_type;
- irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+ irq_chip->irq_request_resources = em_gio_irq_reqres;
+ irq_chip->irq_release_resources = em_gio_irq_relres;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
- ret = em_gio_irq_domain_init(p);
- if (ret) {
+ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
+ pdata->number_of_pins,
+ pdata->irq_base,
+ &em_gio_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ ret = -ENXIO;
dev_err(&pdev->dev, "cannot initialize irq domain\n");
- goto err3;
+ goto err0;
}
- if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
+ if (devm_request_irq(&pdev->dev, irq[0]->start,
+ em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request low IRQ\n");
ret = -ENOENT;
- goto err4;
+ goto err1;
}
- if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
+ if (devm_request_irq(&pdev->dev, irq[1]->start,
+ em_gio_irq_handler, 0, name, p)) {
dev_err(&pdev->dev, "failed to request high IRQ\n");
ret = -ENOENT;
- goto err5;
+ goto err1;
}
ret = gpiochip_add(gpio_chip);
if (ret) {
dev_err(&pdev->dev, "failed to add GPIO controller\n");
- goto err6;
+ goto err1;
+ }
+
+ if (pdata->pctl_name) {
+ ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0,
+ gpio_chip->base, gpio_chip->ngpio);
+ if (ret < 0)
+ dev_warn(&pdev->dev, "failed to add pin range\n");
}
return 0;
-err6:
- free_irq(irq[1]->start, pdev);
-err5:
- free_irq(irq[0]->start, pdev);
-err4:
- em_gio_irq_domain_cleanup(p);
-err3:
- iounmap(p->base1);
-err2:
- iounmap(p->base0);
err1:
- kfree(p);
+ irq_domain_remove(p->irq_domain);
err0:
return ret;
}
-static int __devexit em_gio_remove(struct platform_device *pdev)
+static int em_gio_remove(struct platform_device *pdev)
{
struct em_gio_priv *p = platform_get_drvdata(pdev);
- struct resource *irq[2];
int ret;
ret = gpiochip_remove(&p->gpio_chip);
if (ret)
return ret;
- irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-
- free_irq(irq[1]->start, pdev);
- free_irq(irq[0]->start, pdev);
- em_gio_irq_domain_cleanup(p);
- iounmap(p->base1);
- iounmap(p->base0);
- kfree(p);
+ irq_domain_remove(p->irq_domain);
return 0;
}
+static const struct of_device_id em_gio_dt_ids[] = {
+ { .compatible = "renesas,em-gio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, em_gio_dt_ids);
+
static struct platform_driver em_gio_device_driver = {
.probe = em_gio_probe,
- .remove = __devexit_p(em_gio_remove),
+ .remove = em_gio_remove,
.driver = {
.name = "em_gio",
+ .of_match_table = em_gio_dt_ids,
+ .owner = THIS_MODULE,
}
};
-module_platform_driver(em_gio_device_driver);
+static int __init em_gio_init(void)
+{
+ return platform_driver_register(&em_gio_device_driver);
+}
+postcore_initcall(em_gio_init);
+
+static void __exit em_gio_exit(void)
+{
+ platform_driver_unregister(&em_gio_device_driver);
+}
+module_exit(em_gio_exit);
MODULE_AUTHOR("Magnus Damm");
MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 9fe5b8fe9be..dcc2bb4074e 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -51,15 +51,15 @@ static void ep93xx_gpio_update_int_params(unsigned port)
{
BUG_ON(port > 2);
- __raw_writeb(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+ writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
- __raw_writeb(gpio_int_type2[port],
+ writeb_relaxed(gpio_int_type2[port],
EP93XX_GPIO_REG(int_type2_register_offset[port]));
- __raw_writeb(gpio_int_type1[port],
+ writeb_relaxed(gpio_int_type1[port],
EP93XX_GPIO_REG(int_type1_register_offset[port]));
- __raw_writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
+ writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
EP93XX_GPIO_REG(int_en_register_offset[port]));
}
@@ -74,7 +74,7 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
else
gpio_int_debounce[port] &= ~port_mask;
- __raw_writeb(gpio_int_debounce[port],
+ writeb(gpio_int_debounce[port],
EP93XX_GPIO_REG(int_debounce_register_offset[port]));
}
@@ -83,7 +83,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
unsigned char status;
int i;
- status = __raw_readb(EP93XX_GPIO_A_INT_STATUS);
+ status = readb(EP93XX_GPIO_A_INT_STATUS);
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
@@ -91,7 +91,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
}
}
- status = __raw_readb(EP93XX_GPIO_B_INT_STATUS);
+ status = readb(EP93XX_GPIO_B_INT_STATUS);
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
@@ -124,7 +124,7 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d)
ep93xx_gpio_update_int_params(port);
}
- __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+ writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
@@ -139,7 +139,7 @@ static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
gpio_int_unmasked[port] &= ~port_mask;
ep93xx_gpio_update_int_params(port);
- __raw_writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+ writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
}
static void ep93xx_gpio_irq_mask(struct irq_data *d)
@@ -340,41 +340,28 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
return gpiochip_add(&bgc->gc);
}
-static int __devinit ep93xx_gpio_probe(struct platform_device *pdev)
+static int ep93xx_gpio_probe(struct platform_device *pdev)
{
struct ep93xx_gpio *ep93xx_gpio;
struct resource *res;
- void __iomem *mmio;
int i;
- int ret;
+ struct device *dev = &pdev->dev;
- ep93xx_gpio = kzalloc(sizeof(*ep93xx_gpio), GFP_KERNEL);
+ ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL);
if (!ep93xx_gpio)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENXIO;
- goto exit_free;
- }
-
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- ret = -EBUSY;
- goto exit_free;
- }
-
- mmio = ioremap(res->start, resource_size(res));
- if (!mmio) {
- ret = -ENXIO;
- goto exit_release;
- }
- ep93xx_gpio->mmio_base = mmio;
+ ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ep93xx_gpio->mmio_base))
+ return PTR_ERR(ep93xx_gpio->mmio_base);
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
struct bgpio_chip *bgc = &ep93xx_gpio->bgc[i];
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
- if (ep93xx_gpio_add_bank(bgc, &pdev->dev, mmio, bank))
+ if (ep93xx_gpio_add_bank(bgc, &pdev->dev,
+ ep93xx_gpio->mmio_base, bank))
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
bank->label);
}
@@ -382,13 +369,6 @@ static int __devinit ep93xx_gpio_probe(struct platform_device *pdev)
ep93xx_gpio_init_irq();
return 0;
-
-exit_release:
- release_mem_region(res->start, resource_size(res));
-exit_free:
- kfree(ep93xx_gpio);
- dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, ret);
- return ret;
}
static struct platform_driver ep93xx_gpio_driver = {
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
new file mode 100644
index 00000000000..8f73ee09373
--- /dev/null
+++ b/drivers/gpio/gpio-f7188x.c
@@ -0,0 +1,470 @@
+/*
+ * GPIO driver for Fintek Super-I/O F71882 and F71889
+ *
+ * Copyright (C) 2010-2013 LaCie
+ *
+ * Author: Simon Guinot <simon.guinot@sequanux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#define DRVNAME "gpio-f7188x"
+
+/*
+ * Super-I/O registers
+ */
+#define SIO_LDSEL 0x07 /* Logical device select */
+#define SIO_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_DEVREV 0x22 /* Device revision */
+#define SIO_MANID 0x23 /* Fintek ID (2 bytes) */
+
+#define SIO_LD_GPIO 0x06 /* GPIO logical device */
+#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
+
+#define SIO_FINTEK_ID 0x1934 /* Manufacturer ID */
+#define SIO_F71882_ID 0x0541 /* F71882 chipset ID */
+#define SIO_F71889_ID 0x0909 /* F71889 chipset ID */
+
+enum chips { f71882fg, f71889f };
+
+static const char * const f7188x_names[] = {
+ "f71882fg",
+ "f71889f",
+};
+
+struct f7188x_sio {
+ int addr;
+ enum chips type;
+};
+
+struct f7188x_gpio_bank {
+ struct gpio_chip chip;
+ unsigned int regbase;
+ struct f7188x_gpio_data *data;
+};
+
+struct f7188x_gpio_data {
+ struct f7188x_sio *sio;
+ int nr_bank;
+ struct f7188x_gpio_bank *bank;
+};
+
+/*
+ * Super-I/O functions.
+ */
+
+static inline int superio_inb(int base, int reg)
+{
+ outb(reg, base);
+ return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+ int val;
+
+ outb(reg++, base);
+ val = inb(base + 1) << 8;
+ outb(reg, base);
+ val |= inb(base + 1);
+
+ return val;
+}
+
+static inline void superio_outb(int base, int reg, int val)
+{
+ outb(reg, base);
+ outb(val, base + 1);
+}
+
+static inline int superio_enter(int base)
+{
+ /* Don't step on other drivers' I/O space by accident. */
+ if (!request_muxed_region(base, 2, DRVNAME)) {
+ pr_err(DRVNAME "I/O address 0x%04x already in use\n", base);
+ return -EBUSY;
+ }
+
+ /* According to the datasheet the key must be send twice. */
+ outb(SIO_UNLOCK_KEY, base);
+ outb(SIO_UNLOCK_KEY, base);
+
+ return 0;
+}
+
+static inline void superio_select(int base, int ld)
+{
+ outb(SIO_LDSEL, base);
+ outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+ outb(SIO_LOCK_KEY, base);
+ release_region(base, 2);
+}
+
+/*
+ * GPIO chip.
+ */
+
+static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);
+static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
+static int f7188x_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value);
+static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
+
+#define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \
+ { \
+ .chip = { \
+ .label = DRVNAME, \
+ .owner = THIS_MODULE, \
+ .direction_input = f7188x_gpio_direction_in, \
+ .get = f7188x_gpio_get, \
+ .direction_output = f7188x_gpio_direction_out, \
+ .set = f7188x_gpio_set, \
+ .base = _base, \
+ .ngpio = _ngpio, \
+ .can_sleep = true, \
+ }, \
+ .regbase = _regbase, \
+ }
+
+#define gpio_dir(base) (base + 0)
+#define gpio_data_out(base) (base + 1)
+#define gpio_data_in(base) (base + 2)
+/* Output mode register (0:open drain 1:push-pull). */
+#define gpio_out_mode(base) (base + 3)
+
+static struct f7188x_gpio_bank f71882_gpio_bank[] = {
+ F7188X_GPIO_BANK(0 , 8, 0xF0),
+ F7188X_GPIO_BANK(10, 8, 0xE0),
+ F7188X_GPIO_BANK(20, 8, 0xD0),
+ F7188X_GPIO_BANK(30, 4, 0xC0),
+ F7188X_GPIO_BANK(40, 4, 0xB0),
+};
+
+static struct f7188x_gpio_bank f71889_gpio_bank[] = {
+ F7188X_GPIO_BANK(0 , 7, 0xF0),
+ F7188X_GPIO_BANK(10, 7, 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 int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ int err;
+ struct f7188x_gpio_bank *bank =
+ container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 dir;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return err;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+ dir &= ~(1 << offset);
+ superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+
+ superio_exit(sio->addr);
+
+ return 0;
+}
+
+static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ int err;
+ struct f7188x_gpio_bank *bank =
+ container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 dir, data;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return err;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+ dir = !!(dir & (1 << offset));
+ if (dir)
+ data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+ else
+ data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
+
+ superio_exit(sio->addr);
+
+ return !!(data & 1 << offset);
+}
+
+static int f7188x_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int err;
+ struct f7188x_gpio_bank *bank =
+ container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 dir, data_out;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return err;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+ if (value)
+ data_out |= (1 << offset);
+ else
+ data_out &= ~(1 << offset);
+ superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+
+ dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+ dir |= (1 << offset);
+ superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+
+ superio_exit(sio->addr);
+
+ return 0;
+}
+
+static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ int err;
+ struct f7188x_gpio_bank *bank =
+ container_of(chip, struct f7188x_gpio_bank, chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 data_out;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+ if (value)
+ data_out |= (1 << offset);
+ else
+ data_out &= ~(1 << offset);
+ superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+
+ superio_exit(sio->addr);
+}
+
+/*
+ * Platform device and driver.
+ */
+
+static int f7188x_gpio_probe(struct platform_device *pdev)
+{
+ int err;
+ int i;
+ struct f7188x_sio *sio = pdev->dev.platform_data;
+ struct f7188x_gpio_data *data;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ switch (sio->type) {
+ case f71882fg:
+ data->nr_bank = ARRAY_SIZE(f71882_gpio_bank);
+ data->bank = f71882_gpio_bank;
+ break;
+ case f71889f:
+ data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
+ data->bank = f71889_gpio_bank;
+ break;
+ default:
+ return -ENODEV;
+ }
+ data->sio = sio;
+
+ platform_set_drvdata(pdev, data);
+
+ /* For each GPIO bank, register a GPIO chip. */
+ for (i = 0; i < data->nr_bank; i++) {
+ struct f7188x_gpio_bank *bank = &data->bank[i];
+
+ bank->chip.dev = &pdev->dev;
+ bank->data = data;
+
+ err = gpiochip_add(&bank->chip);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to register gpiochip %d: %d\n",
+ i, err);
+ goto err_gpiochip;
+ }
+ }
+
+ return 0;
+
+err_gpiochip:
+ for (i = i - 1; i >= 0; i--) {
+ struct f7188x_gpio_bank *bank = &data->bank[i];
+ int tmp;
+
+ tmp = gpiochip_remove(&bank->chip);
+ if (tmp < 0)
+ dev_err(&pdev->dev,
+ "Failed to remove gpiochip %d: %d\n",
+ i, tmp);
+ }
+
+ return err;
+}
+
+static int f7188x_gpio_remove(struct platform_device *pdev)
+{
+ int err;
+ int i;
+ struct f7188x_gpio_data *data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < data->nr_bank; i++) {
+ struct f7188x_gpio_bank *bank = &data->bank[i];
+
+ err = gpiochip_remove(&bank->chip);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to remove GPIO gpiochip %d: %d\n",
+ i, err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int __init f7188x_find(int addr, struct f7188x_sio *sio)
+{
+ int err;
+ u16 devid;
+
+ err = superio_enter(addr);
+ if (err)
+ return err;
+
+ err = -ENODEV;
+ devid = superio_inw(addr, SIO_MANID);
+ if (devid != SIO_FINTEK_ID) {
+ pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
+ goto err;
+ }
+
+ devid = superio_inw(addr, SIO_DEVID);
+ switch (devid) {
+ case SIO_F71882_ID:
+ sio->type = f71882fg;
+ break;
+ case SIO_F71889_ID:
+ sio->type = f71889f;
+ break;
+ default:
+ pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
+ goto err;
+ }
+ sio->addr = addr;
+ err = 0;
+
+ pr_info(DRVNAME ": Found %s at %#x, revision %d\n",
+ f7188x_names[sio->type],
+ (unsigned int) addr,
+ (int) superio_inb(addr, SIO_DEVREV));
+
+err:
+ superio_exit(addr);
+ return err;
+}
+
+static struct platform_device *f7188x_gpio_pdev;
+
+static int __init
+f7188x_gpio_device_add(const struct f7188x_sio *sio)
+{
+ int err;
+
+ f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1);
+ if (!f7188x_gpio_pdev)
+ return -ENOMEM;
+
+ err = platform_device_add_data(f7188x_gpio_pdev,
+ sio, sizeof(*sio));
+ if (err) {
+ pr_err(DRVNAME "Platform data allocation failed\n");
+ goto err;
+ }
+
+ err = platform_device_add(f7188x_gpio_pdev);
+ if (err) {
+ pr_err(DRVNAME "Device addition failed\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ platform_device_put(f7188x_gpio_pdev);
+
+ return err;
+}
+
+/*
+ * Try to match a supported Fintech device by reading the (hard-wired)
+ * configuration I/O ports. If available, then register both the platform
+ * device and driver to support the GPIOs.
+ */
+
+static struct platform_driver f7188x_gpio_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = f7188x_gpio_probe,
+ .remove = f7188x_gpio_remove,
+};
+
+static int __init f7188x_gpio_init(void)
+{
+ int err;
+ struct f7188x_sio sio;
+
+ if (f7188x_find(0x2e, &sio) &&
+ f7188x_find(0x4e, &sio))
+ return -ENODEV;
+
+ err = platform_driver_register(&f7188x_gpio_driver);
+ if (!err) {
+ err = f7188x_gpio_device_add(&sio);
+ if (err)
+ platform_driver_unregister(&f7188x_gpio_driver);
+ }
+
+ return err;
+}
+subsys_initcall(f7188x_gpio_init);
+
+static void __exit f7188x_gpio_exit(void)
+{
+ platform_device_unregister(f7188x_gpio_pdev);
+ platform_driver_unregister(&f7188x_gpio_driver);
+}
+module_exit(f7188x_gpio_exit);
+
+MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71882FG and F71889F");
+MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index 7b95a4a8318..1237a73c3c9 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -18,15 +18,9 @@
*/
#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
#include <linux/io.h>
-#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_platform.h>
#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
#include <linux/module.h>
#define GEF_GPIO_DIRECT 0x00
@@ -39,28 +33,26 @@
#define GEF_GPIO_OVERRUN 0x1C
#define GEF_GPIO_MODE 0x20
-static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
+static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
+ struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
unsigned int data;
- data = ioread32be(reg);
- /* value: 0=low; 1=high */
- if (value & 0x1)
- data = data | (0x1 << offset);
+ data = ioread32be(mmchip->regs + GEF_GPIO_OUT);
+ if (value)
+ data = data | BIT(offset);
else
- data = data & ~(0x1 << offset);
-
- iowrite32be(data, reg);
+ data = data & ~BIT(offset);
+ iowrite32be(data, mmchip->regs + GEF_GPIO_OUT);
}
-
static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
unsigned int data;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data | (0x1 << offset);
+ data = data | BIT(offset);
iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
return 0;
@@ -71,11 +63,11 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
unsigned int data;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
- /* Set direction before switching to input */
- _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
+ /* Set value before switching to output */
+ gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data & ~(0x1 << offset);
+ data = data & ~BIT(offset);
iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
return 0;
@@ -83,116 +75,56 @@ static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- unsigned int data;
- int state = 0;
struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
- data = ioread32be(mmchip->regs + GEF_GPIO_IN);
- state = (int)((data >> offset) & 0x1);
-
- return state;
+ return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset));
}
-static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
- _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-}
+static const struct of_device_id gef_gpio_ids[] = {
+ {
+ .compatible = "gef,sbc610-gpio",
+ .data = (void *)19,
+ }, {
+ .compatible = "gef,sbc310-gpio",
+ .data = (void *)6,
+ }, {
+ .compatible = "ge,imp3a-gpio",
+ .data = (void *)16,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gef_gpio_ids);
-static int __init gef_gpio_init(void)
+static int __init gef_gpio_probe(struct platform_device *pdev)
{
- struct device_node *np;
- int retval;
- struct of_mm_gpio_chip *gef_gpio_chip;
-
- for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
-
- pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 19;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
-
- for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
-
- pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 6;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
-
- for_each_compatible_node(np, NULL, "ge,imp3a-gpio") {
-
- pr_debug("%s: Initialising GE GPIO\n", np->full_name);
-
- /* Allocate chip structure */
- gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
- if (!gef_gpio_chip) {
- pr_err("%s: Unable to allocate structure\n",
- np->full_name);
- continue;
- }
-
- /* Setup pointers to chip functions */
- gef_gpio_chip->gc.of_gpio_n_cells = 2;
- gef_gpio_chip->gc.ngpio = 16;
- gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
- gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
- gef_gpio_chip->gc.get = gef_gpio_get;
- gef_gpio_chip->gc.set = gef_gpio_set;
-
- /* This function adds a memory mapped GPIO chip */
- retval = of_mm_gpiochip_add(np, gef_gpio_chip);
- if (retval) {
- kfree(gef_gpio_chip);
- pr_err("%s: Unable to add GPIO\n", np->full_name);
- }
- }
+ const struct of_device_id *of_id =
+ of_match_device(gef_gpio_ids, &pdev->dev);
+ struct of_mm_gpio_chip *mmchip;
+
+ mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL);
+ if (!mmchip)
+ return -ENOMEM;
+
+ /* Setup pointers to chip functions */
+ mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data;
+ mmchip->gc.of_gpio_n_cells = 2;
+ mmchip->gc.direction_input = gef_gpio_dir_in;
+ mmchip->gc.direction_output = gef_gpio_dir_out;
+ mmchip->gc.get = gef_gpio_get;
+ mmchip->gc.set = gef_gpio_set;
+
+ /* This function adds a memory mapped GPIO chip */
+ return of_mm_gpiochip_add(pdev->dev.of_node, mmchip);
+};
- return 0;
+static struct platform_driver gef_gpio_driver = {
+ .driver = {
+ .name = "gef-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = gef_gpio_ids,
+ },
};
-arch_initcall(gef_gpio_init);
+module_platform_driver_probe(gef_gpio_driver, gef_gpio_probe);
MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 82e2e4fe599..fea8c82bb8f 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -104,6 +104,26 @@ static unsigned long bgpio_read64(void __iomem *reg)
}
#endif /* BITS_PER_LONG >= 64 */
+static void bgpio_write16be(void __iomem *reg, unsigned long data)
+{
+ iowrite16be(data, reg);
+}
+
+static unsigned long bgpio_read16be(void __iomem *reg)
+{
+ return ioread16be(reg);
+}
+
+static void bgpio_write32be(void __iomem *reg, unsigned long data)
+{
+ iowrite32be(data, reg);
+}
+
+static unsigned long bgpio_read32be(void __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
{
return 1 << pin;
@@ -119,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
+ return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
}
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -249,7 +269,8 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
static int bgpio_setup_accessors(struct device *dev,
struct bgpio_chip *bgc,
- bool be)
+ bool bit_be,
+ bool byte_be)
{
switch (bgc->bits) {
@@ -258,17 +279,33 @@ static int bgpio_setup_accessors(struct device *dev,
bgc->write_reg = bgpio_write8;
break;
case 16:
- bgc->read_reg = bgpio_read16;
- bgc->write_reg = bgpio_write16;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read16be;
+ bgc->write_reg = bgpio_write16be;
+ } else {
+ bgc->read_reg = bgpio_read16;
+ bgc->write_reg = bgpio_write16;
+ }
break;
case 32:
- bgc->read_reg = bgpio_read32;
- bgc->write_reg = bgpio_write32;
+ if (byte_be) {
+ bgc->read_reg = bgpio_read32be;
+ bgc->write_reg = bgpio_write32be;
+ } else {
+ bgc->read_reg = bgpio_read32;
+ bgc->write_reg = bgpio_write32;
+ }
break;
#if BITS_PER_LONG >= 64
case 64:
- bgc->read_reg = bgpio_read64;
- bgc->write_reg = bgpio_write64;
+ if (byte_be) {
+ dev_err(dev,
+ "64 bit big endian byte order unsupported\n");
+ return -EINVAL;
+ } else {
+ bgc->read_reg = bgpio_read64;
+ bgc->write_reg = bgpio_write64;
+ }
break;
#endif /* BITS_PER_LONG >= 64 */
default:
@@ -276,7 +313,7 @@ static int bgpio_setup_accessors(struct device *dev,
return -EINVAL;
}
- bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
+ bgc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
return 0;
}
@@ -351,13 +388,17 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc,
return 0;
}
-int bgpio_remove(struct bgpio_chip *bgc)
+static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
{
- int err = gpiochip_remove(&bgc->gc);
+ if (gpio_pin < chip->ngpio)
+ return 0;
- kfree(bgc);
+ return -EINVAL;
+}
- return err;
+int bgpio_remove(struct bgpio_chip *bgc)
+{
+ return gpiochip_remove(&bgc->gc);
}
EXPORT_SYMBOL_GPL(bgpio_remove);
@@ -380,12 +421,14 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
bgc->gc.label = dev_name(dev);
bgc->gc.base = -1;
bgc->gc.ngpio = bgc->bits;
+ bgc->gc.request = bgpio_request;
ret = bgpio_setup_io(bgc, dat, set, clr);
if (ret)
return ret;
- ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
+ ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN,
+ flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
if (ret)
return ret;
@@ -444,7 +487,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev,
return ret;
}
-static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
+static int bgpio_pdev_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *r;
@@ -454,7 +497,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout;
void __iomem *dirin;
unsigned long sz;
- unsigned long flags = 0;
+ unsigned long flags = pdev->id_entry->driver_data;
int err;
struct bgpio_chip *bgc;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
@@ -485,9 +528,6 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
if (err)
return err;
- if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"))
- flags |= BGPIOF_BIG_ENDIAN;
-
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc)
return -ENOMEM;
@@ -497,6 +537,8 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
return err;
if (pdata) {
+ if (pdata->label)
+ bgc->gc.label = pdata->label;
bgc->gc.base = pdata->base;
if (pdata->ngpio > 0)
bgc->gc.ngpio = pdata->ngpio;
@@ -507,7 +549,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
return gpiochip_add(&bgc->gc);
}
-static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
+static int bgpio_pdev_remove(struct platform_device *pdev)
{
struct bgpio_chip *bgc = platform_get_drvdata(pdev);
@@ -515,9 +557,14 @@ static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
}
static const struct platform_device_id bgpio_id_table[] = {
- { "basic-mmio-gpio", },
- { "basic-mmio-gpio-be", },
- {},
+ {
+ .name = "basic-mmio-gpio",
+ .driver_data = 0,
+ }, {
+ .name = "basic-mmio-gpio-be",
+ .driver_data = BGPIOF_BIG_ENDIAN,
+ },
+ { }
};
MODULE_DEVICE_TABLE(platform, bgpio_id_table);
@@ -527,7 +574,7 @@ static struct platform_driver bgpio_driver = {
},
.id_table = bgpio_id_table,
.probe = bgpio_pdev_probe,
- .remove = __devexit_p(bgpio_pdev_remove),
+ .remove = bgpio_pdev_remove,
};
module_platform_driver(bgpio_driver);
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
new file mode 100644
index 00000000000..3c3f515b791
--- /dev/null
+++ b/drivers/gpio/gpio-grgpio.c
@@ -0,0 +1,505 @@
+/*
+ * Driver for Aeroflex Gaisler GRGPIO General Purpose I/O cores.
+ *
+ * 2013 (c) Aeroflex Gaisler AB
+ *
+ * This driver supports the GRGPIO GPIO core available in the GRLIB VHDL
+ * IP core library.
+ *
+ * Full documentation of the GRGPIO core can be found here:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ *
+ * See "Documentation/devicetree/bindings/gpio/gpio-grgpio.txt" for
+ * information on open firmware properties.
+ *
+ * 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.
+ *
+ * Contributors: Andreas Larsson <andreas@gaisler.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/basic_mmio_gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+
+#define GRGPIO_MAX_NGPIO 32
+
+#define GRGPIO_DATA 0x00
+#define GRGPIO_OUTPUT 0x04
+#define GRGPIO_DIR 0x08
+#define GRGPIO_IMASK 0x0c
+#define GRGPIO_IPOL 0x10
+#define GRGPIO_IEDGE 0x14
+#define GRGPIO_BYPASS 0x18
+#define GRGPIO_IMAP_BASE 0x20
+
+/* Structure for an irq of the core - called an underlying irq */
+struct grgpio_uirq {
+ u8 refcnt; /* Reference counter to manage requesting/freeing of uirq */
+ u8 uirq; /* Underlying irq of the gpio driver */
+};
+
+/*
+ * Structure for an irq of a gpio line handed out by this driver. The index is
+ * used to map to the corresponding underlying irq.
+ */
+struct grgpio_lirq {
+ s8 index; /* Index into struct grgpio_priv's uirqs, or -1 */
+ u8 irq; /* irq for the gpio line */
+};
+
+struct grgpio_priv {
+ struct bgpio_chip bgc;
+ void __iomem *regs;
+ struct device *dev;
+
+ u32 imask; /* irq mask shadow register */
+
+ /*
+ * The grgpio core can have multiple "underlying" irqs. The gpio lines
+ * can be mapped to any one or none of these underlying irqs
+ * independently of each other. This driver sets up an irq domain and
+ * hands out separate irqs to each gpio line
+ */
+ struct irq_domain *domain;
+
+ /*
+ * This array contains information on each underlying irq, each
+ * irq of the grgpio core itself.
+ */
+ struct grgpio_uirq uirqs[GRGPIO_MAX_NGPIO];
+
+ /*
+ * This array contains information for each gpio line on the irqs
+ * obtains from this driver. An index value of -1 for a certain gpio
+ * line indicates that the line has no irq. Otherwise the index connects
+ * the irq to the underlying irq by pointing into the uirqs array.
+ */
+ struct grgpio_lirq lirqs[GRGPIO_MAX_NGPIO];
+};
+
+static inline struct grgpio_priv *grgpio_gc_to_priv(struct gpio_chip *gc)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return container_of(bgc, struct grgpio_priv, bgc);
+}
+
+static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
+ int val)
+{
+ struct bgpio_chip *bgc = &priv->bgc;
+ unsigned long mask = bgc->pin2mask(bgc, offset);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ if (val)
+ priv->imask |= mask;
+ else
+ priv->imask &= ~mask;
+ bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
+
+ if (offset > gc->ngpio)
+ return -ENXIO;
+
+ if (priv->lirqs[offset].index < 0)
+ return -ENXIO;
+
+ return irq_create_mapping(priv->domain, offset);
+}
+
+/* -------------------- IRQ chip functions -------------------- */
+
+static int grgpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ u32 mask = BIT(d->hwirq);
+ u32 ipol;
+ u32 iedge;
+ u32 pol;
+ u32 edge;
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_LOW:
+ pol = 0;
+ edge = 0;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ pol = mask;
+ edge = 0;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ pol = 0;
+ edge = mask;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ pol = mask;
+ edge = mask;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ ipol = priv->bgc.read_reg(priv->regs + GRGPIO_IPOL) & ~mask;
+ iedge = priv->bgc.read_reg(priv->regs + GRGPIO_IEDGE) & ~mask;
+
+ priv->bgc.write_reg(priv->regs + GRGPIO_IPOL, ipol | pol);
+ priv->bgc.write_reg(priv->regs + GRGPIO_IEDGE, iedge | edge);
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return 0;
+}
+
+static void grgpio_irq_mask(struct irq_data *d)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ int offset = d->hwirq;
+
+ grgpio_set_imask(priv, offset, 0);
+}
+
+static void grgpio_irq_unmask(struct irq_data *d)
+{
+ struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
+ int offset = d->hwirq;
+
+ grgpio_set_imask(priv, offset, 1);
+}
+
+static struct irq_chip grgpio_irq_chip = {
+ .name = "grgpio",
+ .irq_mask = grgpio_irq_mask,
+ .irq_unmask = grgpio_irq_unmask,
+ .irq_set_type = grgpio_irq_set_type,
+};
+
+static irqreturn_t grgpio_irq_handler(int irq, void *dev)
+{
+ struct grgpio_priv *priv = dev;
+ int ngpio = priv->bgc.gc.ngpio;
+ unsigned long flags;
+ int i;
+ int match = 0;
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /*
+ * For each gpio line, call its interrupt handler if it its underlying
+ * irq matches the current irq that is handled.
+ */
+ for (i = 0; i < ngpio; i++) {
+ struct grgpio_lirq *lirq = &priv->lirqs[i];
+
+ if (priv->imask & BIT(i) && lirq->index >= 0 &&
+ priv->uirqs[lirq->index].uirq == irq) {
+ generic_handle_irq(lirq->irq);
+ match = 1;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ if (!match)
+ dev_warn(priv->dev, "No gpio line matched irq %d\n", irq);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * This function will be called as a consequence of the call to
+ * irq_create_mapping in grgpio_to_irq
+ */
+static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct grgpio_priv *priv = d->host_data;
+ struct grgpio_lirq *lirq;
+ struct grgpio_uirq *uirq;
+ unsigned long flags;
+ int offset = hwirq;
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ lirq = &priv->lirqs[offset];
+ if (lirq->index < 0)
+ return -EINVAL;
+
+ dev_dbg(priv->dev, "Mapping irq %d for gpio line %d\n",
+ irq, offset);
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /* Request underlying irq if not already requested */
+ lirq->irq = irq;
+ uirq = &priv->uirqs[lirq->index];
+ if (uirq->refcnt == 0) {
+ ret = request_irq(uirq->uirq, grgpio_irq_handler, 0,
+ dev_name(priv->dev), priv);
+ if (ret) {
+ dev_err(priv->dev,
+ "Could not request underlying irq %d\n",
+ uirq->uirq);
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return ret;
+ }
+ }
+ uirq->refcnt++;
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ /* Setup irq */
+ irq_set_chip_data(irq, priv);
+ irq_set_chip_and_handler(irq, &grgpio_irq_chip,
+ handle_simple_irq);
+ irq_clear_status_flags(irq, IRQ_NOREQUEST);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+
+ return ret;
+}
+
+static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ struct grgpio_priv *priv = d->host_data;
+ int index;
+ struct grgpio_lirq *lirq;
+ struct grgpio_uirq *uirq;
+ unsigned long flags;
+ int ngpio = priv->bgc.gc.ngpio;
+ int i;
+
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ /* Free underlying irq if last user unmapped */
+ index = -1;
+ for (i = 0; i < ngpio; i++) {
+ lirq = &priv->lirqs[i];
+ if (lirq->irq == irq) {
+ grgpio_set_imask(priv, i, 0);
+ lirq->irq = 0;
+ index = lirq->index;
+ break;
+ }
+ }
+ WARN_ON(index < 0);
+
+ if (index >= 0) {
+ uirq = &priv->uirqs[lirq->index];
+ uirq->refcnt--;
+ if (uirq->refcnt == 0)
+ free_irq(uirq->uirq, priv);
+ }
+
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+}
+
+static struct irq_domain_ops grgpio_irq_domain_ops = {
+ .map = grgpio_irq_map,
+ .unmap = grgpio_irq_unmap,
+};
+
+/* ------------------------------------------------------------ */
+
+static int grgpio_probe(struct platform_device *ofdev)
+{
+ struct device_node *np = ofdev->dev.of_node;
+ void __iomem *regs;
+ struct gpio_chip *gc;
+ struct bgpio_chip *bgc;
+ struct grgpio_priv *priv;
+ struct resource *res;
+ int err;
+ u32 prop;
+ s32 *irqmap;
+ int size;
+ int i;
+
+ priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ bgc = &priv->bgc;
+ err = bgpio_init(bgc, &ofdev->dev, 4, regs + GRGPIO_DATA,
+ regs + GRGPIO_OUTPUT, NULL, regs + GRGPIO_DIR, NULL,
+ BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ if (err) {
+ dev_err(&ofdev->dev, "bgpio_init() failed\n");
+ return err;
+ }
+
+ priv->regs = regs;
+ priv->imask = bgc->read_reg(regs + GRGPIO_IMASK);
+ priv->dev = &ofdev->dev;
+
+ gc = &bgc->gc;
+ gc->of_node = np;
+ gc->owner = THIS_MODULE;
+ gc->to_irq = grgpio_to_irq;
+ gc->label = np->full_name;
+ gc->base = -1;
+
+ err = of_property_read_u32(np, "nbits", &prop);
+ if (err || prop <= 0 || prop > GRGPIO_MAX_NGPIO) {
+ gc->ngpio = GRGPIO_MAX_NGPIO;
+ dev_dbg(&ofdev->dev,
+ "No or invalid nbits property: assume %d\n", gc->ngpio);
+ } else {
+ gc->ngpio = prop;
+ }
+
+ /*
+ * The irqmap contains the index values indicating which underlying irq,
+ * if anyone, is connected to that line
+ */
+ irqmap = (s32 *)of_get_property(np, "irqmap", &size);
+ if (irqmap) {
+ if (size < gc->ngpio) {
+ dev_err(&ofdev->dev,
+ "irqmap shorter than ngpio (%d < %d)\n",
+ size, gc->ngpio);
+ return -EINVAL;
+ }
+
+ priv->domain = irq_domain_add_linear(np, gc->ngpio,
+ &grgpio_irq_domain_ops,
+ priv);
+ if (!priv->domain) {
+ dev_err(&ofdev->dev, "Could not add irq domain\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < gc->ngpio; i++) {
+ struct grgpio_lirq *lirq;
+ int ret;
+
+ lirq = &priv->lirqs[i];
+ lirq->index = irqmap[i];
+
+ if (lirq->index < 0)
+ continue;
+
+ ret = platform_get_irq(ofdev, lirq->index);
+ if (ret <= 0) {
+ /*
+ * Continue without irq functionality for that
+ * gpio line
+ */
+ dev_err(priv->dev,
+ "Failed to get irq for offset %d\n", i);
+ continue;
+ }
+ priv->uirqs[lirq->index].uirq = ret;
+ }
+ }
+
+ platform_set_drvdata(ofdev, priv);
+
+ err = gpiochip_add(gc);
+ if (err) {
+ dev_err(&ofdev->dev, "Could not add gpiochip\n");
+ return err;
+ }
+
+ dev_info(&ofdev->dev, "regs=0x%p, base=%d, ngpio=%d, irqs=%s\n",
+ priv->regs, gc->base, gc->ngpio, priv->domain ? "on" : "off");
+
+ return 0;
+}
+
+static int grgpio_remove(struct platform_device *ofdev)
+{
+ struct grgpio_priv *priv = platform_get_drvdata(ofdev);
+ unsigned long flags;
+ int i;
+ int ret = 0;
+
+ spin_lock_irqsave(&priv->bgc.lock, flags);
+
+ if (priv->domain) {
+ for (i = 0; i < GRGPIO_MAX_NGPIO; i++) {
+ if (priv->uirqs[i].refcnt != 0) {
+ ret = -EBUSY;
+ goto out;
+ }
+ }
+ }
+
+ ret = gpiochip_remove(&priv->bgc.gc);
+ if (ret)
+ goto out;
+
+ if (priv->domain)
+ irq_domain_remove(priv->domain);
+
+out:
+ spin_unlock_irqrestore(&priv->bgc.lock, flags);
+
+ return ret;
+}
+
+static const struct of_device_id grgpio_match[] = {
+ {.name = "GAISLER_GPIO"},
+ {.name = "01_01a"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, grgpio_match);
+
+static struct platform_driver grgpio_driver = {
+ .driver = {
+ .name = "grgpio",
+ .owner = THIS_MODULE,
+ .of_match_table = grgpio_match,
+ },
+ .probe = grgpio_probe,
+ .remove = grgpio_remove,
+};
+module_platform_driver(grgpio_driver);
+
+MODULE_AUTHOR("Aeroflex Gaisler AB.");
+MODULE_DESCRIPTION("Driver for Aeroflex Gaisler GRGPIO");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index d4d61796669..70304220a47 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -1,5 +1,5 @@
/*
- * Intel ICH6-10, Series 5 and 6 GPIO driver
+ * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver
*
* Copyright (C) 2010 Extreme Engineering Solutions.
*
@@ -41,18 +41,30 @@ enum GPIO_REG {
GPIO_USE_SEL = 0,
GPIO_IO_SEL,
GPIO_LVL,
+ GPO_BLINK
};
-static const u8 ichx_regs[3][3] = {
+static const u8 ichx_regs[4][3] = {
{0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */
{0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
+ {0x18, 0x18, 0x18}, /* BLINK offset */
};
static const u8 ichx_reglen[3] = {
0x30, 0x10, 0x10,
};
+static const u8 avoton_regs[4][3] = {
+ {0x00, 0x80, 0x00},
+ {0x04, 0x84, 0x00},
+ {0x08, 0x88, 0x00},
+};
+
+static const u8 avoton_reglen[3] = {
+ 0x10, 0x10, 0x00,
+};
+
#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
@@ -60,6 +72,13 @@ struct ichx_desc {
/* Max GPIO pins the chipset can have */
uint ngpio;
+ /* chipset registers */
+ const u8 (*regs)[3];
+ const u8 *reglen;
+
+ /* GPO_BLINK is available on this chipset */
+ bool have_blink;
+
/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */
bool uses_gpe0;
@@ -69,6 +88,12 @@ struct ichx_desc {
/* Some chipsets have quirks, let these use their own request/get */
int (*request)(struct gpio_chip *chip, unsigned offset);
int (*get)(struct gpio_chip *chip, unsigned offset);
+
+ /*
+ * Some chipsets don't let reading output values on GPIO_LVL register
+ * this option allows driver caching written output values
+ */
+ bool use_outlvl_cache;
};
static struct {
@@ -80,6 +105,7 @@ static struct {
struct ichx_desc *desc; /* Pointer to chipset-specific description */
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
u8 use_gpio; /* Which GPIO groups are usable */
+ int outlvl_cache[3]; /* cached output values */
} ichx_priv;
static int modparam_gpiobase = -1; /* dynamic */
@@ -97,13 +123,23 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
spin_lock_irqsave(&ichx_priv.lock, flags);
- data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ data = ichx_priv.outlvl_cache[reg_nr];
+ else
+ data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+
if (val)
data |= 1 << bit;
else
data &= ~(1 << bit);
- ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
- tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ ichx_priv.outlvl_cache[reg_nr] = data;
+
+ tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
if (verify && data != tmp)
ret = -EPERM;
@@ -121,23 +157,24 @@ static int ichx_read_bit(int reg, unsigned nr)
spin_lock_irqsave(&ichx_priv.lock, flags);
- data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
+ data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
+ ichx_priv.gpio_base);
+
+ if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
+ data = ichx_priv.outlvl_cache[reg_nr] | data;
spin_unlock_irqrestore(&ichx_priv.lock, flags);
return data & (1 << bit) ? 1 : 0;
}
-static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
+static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
{
- return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO;
+ return !!(ichx_priv.use_gpio & (1 << (nr / 32)));
}
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
- if (!ichx_gpio_check_available(gpio, nr))
- return -ENXIO;
-
/*
* Try setting pin as an input and verify it worked since many pins
* are output-only.
@@ -151,8 +188,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
- if (!ichx_gpio_check_available(gpio, nr))
- return -ENXIO;
+ /* Disable blink hardware which is available for GPIOs from 0 to 31. */
+ if (nr < 32 && ichx_priv.desc->have_blink)
+ ichx_write_bit(GPO_BLINK, nr, 0, 0);
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
@@ -169,9 +207,6 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
{
- if (!ichx_gpio_check_available(chip, nr))
- return -ENXIO;
-
return ichx_read_bit(GPIO_LVL, nr);
}
@@ -180,9 +215,6 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
unsigned long flags;
u32 data;
- if (!ichx_gpio_check_available(chip, nr))
- return -ENXIO;
-
/*
* GPI 0 - 15 need to be read from the power management registers on
* a ICH6/3100 bridge.
@@ -207,6 +239,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
{
+ if (!ichx_gpio_check_available(chip, nr))
+ return -ENXIO;
+
/*
* Note we assume the BIOS properly set a bridge's USE value. Some
* chips (eg Intel 3100) have bogus USE values though, so first see if
@@ -214,7 +249,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
* If it can't be trusted, assume that the pin can be used as a GPIO.
*/
if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
- return 1;
+ return 0;
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
}
@@ -238,7 +273,7 @@ static void ichx_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
ichx_write_bit(GPIO_LVL, nr, val, 0);
}
-static void __devinit ichx_gpiolib_setup(struct gpio_chip *chip)
+static void ichx_gpiolib_setup(struct gpio_chip *chip)
{
chip->owner = THIS_MODULE;
chip->label = DRV_NAME;
@@ -255,7 +290,7 @@ static void __devinit ichx_gpiolib_setup(struct gpio_chip *chip)
chip->direction_output = ichx_gpio_direction_output;
chip->base = modparam_gpiobase;
chip->ngpio = ichx_priv.desc->ngpio;
- chip->can_sleep = 0;
+ chip->can_sleep = false;
chip->dbg_show = NULL;
}
@@ -269,6 +304,9 @@ static struct ichx_desc ich6_desc = {
.uses_gpe0 = true,
.ngpio = 50,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* Intel 3100 */
@@ -288,32 +326,59 @@ static struct ichx_desc i3100_desc = {
.uses_gpe0 = true,
.ngpio = 50,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* ICH7 and ICH8-based */
static struct ichx_desc ich7_desc = {
.ngpio = 50,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* ICH9-based */
static struct ichx_desc ich9_desc = {
.ngpio = 61,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
static struct ichx_desc ich10_cons_desc = {
.ngpio = 61,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
static struct ichx_desc ich10_corp_desc = {
.ngpio = 72,
+ .have_blink = true,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
/* Intel 5 series, 6 series, 3400 series, and C200 series */
static struct ichx_desc intel5_desc = {
.ngpio = 76,
+ .regs = ichx_regs,
+ .reglen = ichx_reglen,
};
-static int __devinit ichx_gpio_request_regions(struct resource *res_base,
+/* Avoton */
+static struct ichx_desc avoton_desc = {
+ /* Avoton has only 59 GPIOs, but we assume the first set of register
+ * (Core) has 32 instead of 31 to keep gpio-ich compliance
+ */
+ .ngpio = 60,
+ .regs = avoton_regs,
+ .reglen = avoton_reglen,
+ .use_outlvl_cache = true,
+};
+
+static int ichx_gpio_request_regions(struct resource *res_base,
const char *name, u8 use_gpio)
{
int i;
@@ -321,11 +386,12 @@ static int __devinit ichx_gpio_request_regions(struct resource *res_base,
if (!res_base || !res_base->start || !res_base->end)
return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i)))
continue;
- if (!request_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i], name))
+ if (!request_region(
+ res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i], name))
goto request_err;
}
return 0;
@@ -335,8 +401,8 @@ request_err:
for (i--; i >= 0; i--) {
if (!(use_gpio & (1 << i)))
continue;
- release_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i]);
+ release_region(res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i]);
}
return -EBUSY;
}
@@ -345,19 +411,19 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
{
int i;
- for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
if (!(use_gpio & (1 << i)))
continue;
- release_region(res_base->start + ichx_regs[0][i],
- ichx_reglen[i]);
+ release_region(res_base->start + ichx_priv.desc->regs[0][i],
+ ichx_priv.desc->reglen[i]);
}
}
-static int __devinit ichx_gpio_probe(struct platform_device *pdev)
+static int ichx_gpio_probe(struct platform_device *pdev)
{
struct resource *res_base, *res_pm;
int err;
- struct lpc_ich_info *ich_info = pdev->dev.platform_data;
+ struct lpc_ich_info *ich_info = dev_get_platdata(&pdev->dev);
if (!ich_info)
return -ENODEV;
@@ -386,10 +452,14 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev)
case ICH_V10CONS_GPIO:
ichx_priv.desc = &ich10_cons_desc;
break;
+ case AVOTON_GPIO:
+ ichx_priv.desc = &avoton_desc;
+ break;
default:
return -ENODEV;
}
+ spin_lock_init(&ichx_priv.lock);
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
ichx_priv.use_gpio = ich_info->use_gpio;
err = ichx_gpio_request_regions(res_base, pdev->name,
@@ -442,7 +512,7 @@ add_err:
return err;
}
-static int __devexit ichx_gpio_remove(struct platform_device *pdev)
+static int ichx_gpio_remove(struct platform_device *pdev)
{
int err;
@@ -467,7 +537,7 @@ static struct platform_driver ichx_gpio_driver = {
.name = DRV_NAME,
},
.probe = ichx_gpio_probe,
- .remove = __devexit_p(ichx_gpio_remove),
+ .remove = ichx_gpio_remove,
};
module_platform_driver(ichx_gpio_driver);
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
new file mode 100644
index 00000000000..118a6bf455d
--- /dev/null
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -0,0 +1,489 @@
+/*
+ * Intel MID GPIO driver
+ *
+ * Copyright (c) 2008-2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* Supports:
+ * Moorestown platform Langwell chip.
+ * Medfield platform Penwell chip.
+ * Clovertrail platform Cloverview chip.
+ * Merrifield platform Tangier chip.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/irqdomain.h>
+
+#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0)
+#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1)
+
+/*
+ * Langwell chip has 64 pins and thus there are 2 32bit registers to control
+ * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit
+ * registers to control them, so we only define the order here instead of a
+ * structure, to get a bit offset for a pin (use GPDR as an example):
+ *
+ * nreg = ngpio / 32;
+ * reg = offset / 32;
+ * bit = offset % 32;
+ * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4;
+ *
+ * so the bit of reg_addr is to control pin offset's GPDR feature
+*/
+
+enum GPIO_REG {
+ GPLR = 0, /* pin level read-only */
+ GPDR, /* pin direction */
+ GPSR, /* pin set */
+ GPCR, /* pin clear */
+ GRER, /* rising edge detect */
+ GFER, /* falling edge detect */
+ GEDR, /* edge detect result */
+ GAFR, /* alt function */
+};
+
+/* intel_mid gpio driver data */
+struct intel_mid_gpio_ddata {
+ u16 ngpio; /* number of gpio pins */
+ u32 gplr_offset; /* offset of first GPLR register from base */
+ u32 flis_base; /* base address of FLIS registers */
+ u32 flis_len; /* length of FLIS registers */
+ u32 (*get_flis_offset)(int gpio);
+ u32 chip_irq_type; /* chip interrupt type */
+};
+
+struct intel_mid_gpio {
+ struct gpio_chip chip;
+ void __iomem *reg_base;
+ spinlock_t lock;
+ struct pci_dev *pdev;
+ struct irq_domain *domain;
+};
+
+#define to_intel_gpio_priv(chip) container_of(chip, struct intel_mid_gpio, chip)
+
+static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
+ enum GPIO_REG reg_type)
+{
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ unsigned nreg = chip->ngpio / 32;
+ u8 reg = offset / 32;
+
+ return priv->reg_base + reg_type * nreg * 4 + reg * 4;
+}
+
+static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
+ enum GPIO_REG reg_type)
+{
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ unsigned nreg = chip->ngpio / 32;
+ u8 reg = offset / 16;
+
+ return priv->reg_base + reg_type * nreg * 4 + reg * 4;
+}
+
+static int intel_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR);
+ u32 value = readl(gafr);
+ int shift = (offset % 16) << 1, af = (value >> shift) & 3;
+
+ if (af) {
+ value &= ~(3 << shift);
+ writel(value, gafr);
+ }
+ return 0;
+}
+
+static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ void __iomem *gplr = gpio_reg(chip, offset, GPLR);
+
+ return readl(gplr) & BIT(offset % 32);
+}
+
+static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ void __iomem *gpsr, *gpcr;
+
+ if (value) {
+ gpsr = gpio_reg(chip, offset, GPSR);
+ writel(BIT(offset % 32), gpsr);
+ } else {
+ gpcr = gpio_reg(chip, offset, GPCR);
+ writel(BIT(offset % 32), gpcr);
+ }
+}
+
+static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
+ u32 value;
+ unsigned long flags;
+
+ if (priv->pdev)
+ pm_runtime_get(&priv->pdev->dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ value = readl(gpdr);
+ value &= ~BIT(offset % 32);
+ writel(value, gpdr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->pdev)
+ pm_runtime_put(&priv->pdev->dev);
+
+ return 0;
+}
+
+static int intel_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
+ unsigned long flags;
+
+ intel_gpio_set(chip, offset, value);
+
+ if (priv->pdev)
+ pm_runtime_get(&priv->pdev->dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ value = readl(gpdr);
+ value |= BIT(offset % 32);
+ writel(value, gpdr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->pdev)
+ pm_runtime_put(&priv->pdev->dev);
+
+ return 0;
+}
+
+static int intel_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct intel_mid_gpio *priv = to_intel_gpio_priv(chip);
+ return irq_create_mapping(priv->domain, offset);
+}
+
+static int intel_mid_irq_type(struct irq_data *d, unsigned type)
+{
+ struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
+ u32 gpio = irqd_to_hwirq(d);
+ unsigned long flags;
+ u32 value;
+ void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);
+ void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);
+
+ if (gpio >= priv->chip.ngpio)
+ return -EINVAL;
+
+ if (priv->pdev)
+ pm_runtime_get(&priv->pdev->dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (type & IRQ_TYPE_EDGE_RISING)
+ value = readl(grer) | BIT(gpio % 32);
+ else
+ value = readl(grer) & (~BIT(gpio % 32));
+ writel(value, grer);
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ value = readl(gfer) | BIT(gpio % 32);
+ else
+ value = readl(gfer) & (~BIT(gpio % 32));
+ writel(value, gfer);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->pdev)
+ pm_runtime_put(&priv->pdev->dev);
+
+ return 0;
+}
+
+static void intel_mid_irq_unmask(struct irq_data *d)
+{
+}
+
+static void intel_mid_irq_mask(struct irq_data *d)
+{
+}
+
+static int intel_mid_irq_reqres(struct irq_data *d)
+{
+ struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) {
+ dev_err(priv->chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void intel_mid_irq_relres(struct irq_data *d)
+{
+ struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
+}
+
+static struct irq_chip intel_mid_irqchip = {
+ .name = "INTEL_MID-GPIO",
+ .irq_mask = intel_mid_irq_mask,
+ .irq_unmask = intel_mid_irq_unmask,
+ .irq_set_type = intel_mid_irq_type,
+ .irq_request_resources = intel_mid_irq_reqres,
+ .irq_release_resources = intel_mid_irq_relres,
+};
+
+static const struct intel_mid_gpio_ddata gpio_lincroft = {
+ .ngpio = 64,
+};
+
+static const struct intel_mid_gpio_ddata gpio_penwell_aon = {
+ .ngpio = 96,
+ .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
+};
+
+static const struct intel_mid_gpio_ddata gpio_penwell_core = {
+ .ngpio = 96,
+ .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
+};
+
+static const struct intel_mid_gpio_ddata gpio_cloverview_aon = {
+ .ngpio = 96,
+ .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL,
+};
+
+static const struct intel_mid_gpio_ddata gpio_cloverview_core = {
+ .ngpio = 96,
+ .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
+};
+
+static const struct intel_mid_gpio_ddata gpio_tangier = {
+ .ngpio = 192,
+ .gplr_offset = 4,
+ .flis_base = 0xff0c0000,
+ .flis_len = 0x8000,
+ .get_flis_offset = NULL,
+ .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE,
+};
+
+static const struct pci_device_id intel_gpio_ids[] = {
+ {
+ /* Lincroft */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f),
+ .driver_data = (kernel_ulong_t)&gpio_lincroft,
+ },
+ {
+ /* Penwell AON */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f),
+ .driver_data = (kernel_ulong_t)&gpio_penwell_aon,
+ },
+ {
+ /* Penwell Core */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a),
+ .driver_data = (kernel_ulong_t)&gpio_penwell_core,
+ },
+ {
+ /* Cloverview Aon */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb),
+ .driver_data = (kernel_ulong_t)&gpio_cloverview_aon,
+ },
+ {
+ /* Cloverview Core */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7),
+ .driver_data = (kernel_ulong_t)&gpio_cloverview_core,
+ },
+ {
+ /* Tangier */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x1199),
+ .driver_data = (kernel_ulong_t)&gpio_tangier,
+ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, intel_gpio_ids);
+
+static void intel_mid_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct intel_mid_gpio *priv = irq_data_get_irq_handler_data(data);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
+ u32 base, gpio, mask;
+ unsigned long pending;
+ void __iomem *gedr;
+
+ /* check GPIO controller to check which pin triggered the interrupt */
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ gedr = gpio_reg(&priv->chip, base, GEDR);
+ while ((pending = readl(gedr))) {
+ gpio = __ffs(pending);
+ mask = BIT(gpio);
+ /* Clear before handling so we can't lose an edge */
+ writel(mask, gedr);
+ generic_handle_irq(irq_find_mapping(priv->domain,
+ base + gpio));
+ }
+ }
+
+ chip->irq_eoi(data);
+}
+
+static void intel_mid_irq_init_hw(struct intel_mid_gpio *priv)
+{
+ void __iomem *reg;
+ unsigned base;
+
+ for (base = 0; base < priv->chip.ngpio; base += 32) {
+ /* Clear the rising-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GRER);
+ writel(0, reg);
+ /* Clear the falling-edge detect register */
+ reg = gpio_reg(&priv->chip, base, GFER);
+ writel(0, reg);
+ /* Clear the edge detect status register */
+ reg = gpio_reg(&priv->chip, base, GEDR);
+ writel(~0, reg);
+ }
+}
+
+static int intel_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct intel_mid_gpio *priv = d->host_data;
+
+ irq_set_chip_and_handler(irq, &intel_mid_irqchip, handle_simple_irq);
+ irq_set_chip_data(irq, priv);
+ irq_set_irq_type(irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops intel_gpio_irq_ops = {
+ .map = intel_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int intel_gpio_runtime_idle(struct device *dev)
+{
+ int err = pm_schedule_suspend(dev, 500);
+ return err ?: -EBUSY;
+}
+
+static const struct dev_pm_ops intel_gpio_pm_ops = {
+ SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle)
+};
+
+static int intel_gpio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *base;
+ struct intel_mid_gpio *priv;
+ u32 gpio_base;
+ u32 irq_base;
+ int retval;
+ struct intel_mid_gpio_ddata *ddata =
+ (struct intel_mid_gpio_ddata *)id->driver_data;
+
+ retval = pcim_enable_device(pdev);
+ if (retval)
+ return retval;
+
+ retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev));
+ if (retval) {
+ dev_err(&pdev->dev, "I/O memory mapping error\n");
+ return retval;
+ }
+
+ base = pcim_iomap_table(pdev)[1];
+
+ irq_base = readl(base);
+ gpio_base = readl(sizeof(u32) + base);
+
+ /* release the IO mapping, since we already get the info from bar1 */
+ pcim_iounmap_regions(pdev, 1 << 1);
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "can't allocate chip data\n");
+ return -ENOMEM;
+ }
+
+ priv->reg_base = pcim_iomap_table(pdev)[0];
+ priv->chip.label = dev_name(&pdev->dev);
+ priv->chip.dev = &pdev->dev;
+ priv->chip.request = intel_gpio_request;
+ priv->chip.direction_input = intel_gpio_direction_input;
+ priv->chip.direction_output = intel_gpio_direction_output;
+ priv->chip.get = intel_gpio_get;
+ priv->chip.set = intel_gpio_set;
+ priv->chip.to_irq = intel_gpio_to_irq;
+ priv->chip.base = gpio_base;
+ priv->chip.ngpio = ddata->ngpio;
+ priv->chip.can_sleep = false;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->lock);
+
+ priv->domain = irq_domain_add_simple(pdev->dev.of_node, ddata->ngpio,
+ irq_base, &intel_gpio_irq_ops, priv);
+ if (!priv->domain)
+ return -ENOMEM;
+
+ pci_set_drvdata(pdev, priv);
+ retval = gpiochip_add(&priv->chip);
+ if (retval) {
+ dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
+ return retval;
+ }
+
+ intel_mid_irq_init_hw(priv);
+
+ irq_set_handler_data(pdev->irq, priv);
+ irq_set_chained_handler(pdev->irq, intel_mid_irq_handler);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+}
+
+static struct pci_driver intel_gpio_driver = {
+ .name = "intel_mid_gpio",
+ .id_table = intel_gpio_ids,
+ .probe = intel_gpio_probe,
+ .driver = {
+ .pm = &intel_gpio_pm_ops,
+ },
+};
+
+static int __init intel_gpio_init(void)
+{
+ return pci_register_driver(&intel_gpio_driver);
+}
+
+device_initcall(intel_gpio_init);
diff --git a/drivers/gpio/gpio-iop.c b/drivers/gpio/gpio-iop.c
new file mode 100644
index 00000000000..0a5e9d3f308
--- /dev/null
+++ b/drivers/gpio/gpio-iop.c
@@ -0,0 +1,132 @@
+/*
+ * arch/arm/plat-iop/gpio.c
+ * GPIO handling for Intel IOP3xx processors.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define IOP3XX_N_GPIOS 8
+
+#define GPIO_IN 0
+#define GPIO_OUT 1
+#define GPIO_LOW 0
+#define GPIO_HIGH 1
+
+/* Memory base offset */
+static void __iomem *base;
+
+#define IOP3XX_GPIO_REG(reg) (base + (reg))
+#define IOP3XX_GPOE IOP3XX_GPIO_REG(0x0000)
+#define IOP3XX_GPID IOP3XX_GPIO_REG(0x0004)
+#define IOP3XX_GPOD IOP3XX_GPIO_REG(0x0008)
+
+static void gpio_line_config(int line, int direction)
+{
+ unsigned long flags;
+ u32 val;
+
+ local_irq_save(flags);
+ val = readl(IOP3XX_GPOE);
+ if (direction == GPIO_IN) {
+ val |= BIT(line);
+ } else if (direction == GPIO_OUT) {
+ val &= ~BIT(line);
+ }
+ writel(val, IOP3XX_GPOE);
+ local_irq_restore(flags);
+}
+
+static int gpio_line_get(int line)
+{
+ return !!(readl(IOP3XX_GPID) & BIT(line));
+}
+
+static void gpio_line_set(int line, int value)
+{
+ unsigned long flags;
+ u32 val;
+
+ local_irq_save(flags);
+ val = readl(IOP3XX_GPOD);
+ if (value == GPIO_LOW) {
+ val &= ~BIT(line);
+ } else if (value == GPIO_HIGH) {
+ val |= BIT(line);
+ }
+ writel(val, IOP3XX_GPOD);
+ local_irq_restore(flags);
+}
+
+static int iop3xx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ gpio_line_config(gpio, GPIO_IN);
+ return 0;
+}
+
+static int iop3xx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
+{
+ gpio_line_set(gpio, level);
+ gpio_line_config(gpio, GPIO_OUT);
+ return 0;
+}
+
+static int iop3xx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ return gpio_line_get(gpio);
+}
+
+static void iop3xx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ gpio_line_set(gpio, value);
+}
+
+static struct gpio_chip iop3xx_chip = {
+ .label = "iop3xx",
+ .direction_input = iop3xx_gpio_direction_input,
+ .get = iop3xx_gpio_get_value,
+ .direction_output = iop3xx_gpio_direction_output,
+ .set = iop3xx_gpio_set_value,
+ .base = 0,
+ .ngpio = IOP3XX_N_GPIOS,
+};
+
+static int iop3xx_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ return gpiochip_add(&iop3xx_chip);
+}
+
+static struct platform_driver iop3xx_gpio_driver = {
+ .driver = {
+ .name = "gpio-iop",
+ .owner = THIS_MODULE,
+ },
+ .probe = iop3xx_gpio_probe,
+};
+
+static int __init iop3xx_gpio_init(void)
+{
+ return platform_driver_register(&iop3xx_gpio_driver);
+}
+arch_initcall(iop3xx_gpio_init);
diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c
index f2f000dd70b..42852eaaf02 100644
--- a/drivers/gpio/gpio-janz-ttl.c
+++ b/drivers/gpio/gpio-janz-ttl.c
@@ -108,13 +108,13 @@ static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
spin_unlock(&mod->lock);
}
-static void __devinit ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
+static void ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val)
{
iowrite16be(reg, &mod->regs->control);
iowrite16be(val, &mod->regs->control);
}
-static void __devinit ttl_setup_device(struct ttl_module *mod)
+static void ttl_setup_device(struct ttl_module *mod)
{
/* reset the device to a known state */
iowrite16be(0x0000, &mod->regs->control);
@@ -140,7 +140,7 @@ static void __devinit ttl_setup_device(struct ttl_module *mod)
ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE);
}
-static int __devinit ttl_probe(struct platform_device *pdev)
+static int ttl_probe(struct platform_device *pdev)
{
struct janz_platform_data *pdata;
struct device *dev = &pdev->dev;
@@ -149,37 +149,24 @@ static int __devinit ttl_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(dev, "no platform data\n");
- ret = -ENXIO;
- goto out_return;
+ return -ENXIO;
}
- mod = kzalloc(sizeof(*mod), GFP_KERNEL);
- if (!mod) {
- dev_err(dev, "unable to allocate private data\n");
- ret = -ENOMEM;
- goto out_return;
- }
+ mod = devm_kzalloc(dev, sizeof(*mod), GFP_KERNEL);
+ if (!mod)
+ return -ENOMEM;
platform_set_drvdata(pdev, mod);
spin_lock_init(&mod->lock);
/* get access to the MODULbus registers for this module */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "MODULbus registers not found\n");
- ret = -ENODEV;
- goto out_free_mod;
- }
-
- mod->regs = ioremap(res->start, resource_size(res));
- if (!mod->regs) {
- dev_err(dev, "MODULbus registers not ioremap\n");
- ret = -ENOMEM;
- goto out_free_mod;
- }
+ mod->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mod->regs))
+ return PTR_ERR(mod->regs);
ttl_setup_device(mod);
@@ -198,20 +185,13 @@ static int __devinit ttl_probe(struct platform_device *pdev)
ret = gpiochip_add(gpio);
if (ret) {
dev_err(dev, "unable to add GPIO chip\n");
- goto out_iounmap_regs;
+ return ret;
}
return 0;
-
-out_iounmap_regs:
- iounmap(mod->regs);
-out_free_mod:
- kfree(mod);
-out_return:
- return ret;
}
-static int __devexit ttl_remove(struct platform_device *pdev)
+static int ttl_remove(struct platform_device *pdev)
{
struct ttl_module *mod = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -223,8 +203,6 @@ static int __devexit ttl_remove(struct platform_device *pdev)
return ret;
}
- iounmap(mod->regs);
- kfree(mod);
return 0;
}
@@ -234,7 +212,7 @@ static struct platform_driver ttl_driver = {
.owner = THIS_MODULE,
},
.probe = ttl_probe,
- .remove = __devexit_p(ttl_remove),
+ .remove = ttl_remove,
};
module_platform_driver(ttl_driver);
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
new file mode 100644
index 00000000000..1e5e51987d3
--- /dev/null
+++ b/drivers/gpio/gpio-kempld.c
@@ -0,0 +1,219 @@
+/*
+ * Kontron PLD GPIO driver
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+
+#define KEMPLD_GPIO_MAX_NUM 16
+#define KEMPLD_GPIO_MASK(x) (BIT((x) % 8))
+#define KEMPLD_GPIO_DIR_NUM(x) (0x40 + (x) / 8)
+#define KEMPLD_GPIO_LVL_NUM(x) (0x42 + (x) / 8)
+#define KEMPLD_GPIO_EVT_LVL_EDGE 0x46
+#define KEMPLD_GPIO_IEN 0x4A
+
+struct kempld_gpio_data {
+ struct gpio_chip chip;
+ struct kempld_device_data *pld;
+};
+
+/*
+ * Set or clear GPIO bit
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static void kempld_gpio_bitop(struct kempld_device_data *pld,
+ u8 reg, u8 bit, u8 val)
+{
+ u8 status;
+
+ status = kempld_read8(pld, reg);
+ if (val)
+ status |= KEMPLD_GPIO_MASK(bit);
+ else
+ status &= ~KEMPLD_GPIO_MASK(bit);
+ kempld_write8(pld, reg, status);
+}
+
+static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit)
+{
+ u8 status;
+
+ kempld_get_mutex(pld);
+ status = kempld_read8(pld, reg);
+ kempld_release_mutex(pld);
+
+ return !!(status & KEMPLD_GPIO_MASK(bit));
+}
+
+static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct kempld_gpio_data *gpio
+ = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_device_data *pld = gpio->pld;
+
+ return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
+}
+
+static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct kempld_gpio_data *gpio
+ = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_device_data *pld = gpio->pld;
+
+ kempld_get_mutex(pld);
+ kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
+ kempld_release_mutex(pld);
+}
+
+static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct kempld_gpio_data *gpio
+ = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_device_data *pld = gpio->pld;
+
+ kempld_get_mutex(pld);
+ kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+
+static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct kempld_gpio_data *gpio
+ = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_device_data *pld = gpio->pld;
+
+ kempld_get_mutex(pld);
+ kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
+ kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+
+static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct kempld_gpio_data *gpio
+ = container_of(chip, struct kempld_gpio_data, chip);
+ struct kempld_device_data *pld = gpio->pld;
+
+ return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
+}
+
+static int kempld_gpio_pincount(struct kempld_device_data *pld)
+{
+ u16 evt, evt_back;
+
+ kempld_get_mutex(pld);
+
+ /* Backup event register as it might be already initialized */
+ evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+ /* Clear event register */
+ kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000);
+ /* Read back event register */
+ evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+ /* Restore event register */
+ kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back);
+
+ kempld_release_mutex(pld);
+
+ return evt ? __ffs(evt) : 16;
+}
+
+static int kempld_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct kempld_device_data *pld = dev_get_drvdata(dev->parent);
+ struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
+ struct kempld_gpio_data *gpio;
+ struct gpio_chip *chip;
+ int ret;
+
+ if (pld->info.spec_major < 2) {
+ dev_err(dev,
+ "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n");
+ return -ENODEV;
+ }
+
+ gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+ if (gpio == NULL)
+ return -ENOMEM;
+
+ gpio->pld = pld;
+
+ platform_set_drvdata(pdev, gpio);
+
+ chip = &gpio->chip;
+ chip->label = "gpio-kempld";
+ chip->owner = THIS_MODULE;
+ chip->dev = dev;
+ chip->can_sleep = true;
+ if (pdata && pdata->gpio_base)
+ chip->base = pdata->gpio_base;
+ else
+ chip->base = -1;
+ chip->direction_input = kempld_gpio_direction_input;
+ chip->direction_output = kempld_gpio_direction_output;
+ chip->get_direction = kempld_gpio_get_direction;
+ chip->get = kempld_gpio_get;
+ chip->set = kempld_gpio_set;
+ chip->ngpio = kempld_gpio_pincount(pld);
+ if (chip->ngpio == 0) {
+ dev_err(dev, "No GPIO pins detected\n");
+ return -ENODEV;
+ }
+
+ ret = gpiochip_add(chip);
+ if (ret) {
+ dev_err(dev, "Could not register GPIO chip\n");
+ return ret;
+ }
+
+ dev_info(dev, "GPIO functionality initialized with %d pins\n",
+ chip->ngpio);
+
+ return 0;
+}
+
+static int kempld_gpio_remove(struct platform_device *pdev)
+{
+ struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&gpio->chip);
+}
+
+static struct platform_driver kempld_gpio_driver = {
+ .driver = {
+ .name = "kempld-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = kempld_gpio_probe,
+ .remove = kempld_gpio_remove,
+};
+
+module_platform_driver(kempld_gpio_driver);
+
+MODULE_DESCRIPTION("KEM PLD GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld-gpio");
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
index a3ac66ea364..464a83de0d6 100644
--- a/drivers/gpio/gpio-ks8695.c
+++ b/drivers/gpio/gpio-ks8695.c
@@ -228,7 +228,7 @@ static struct gpio_chip ks8695_gpio_chip = {
.to_irq = ks8695_gpio_to_irq,
.base = 0,
.ngpio = 16,
- .can_sleep = 0,
+ .can_sleep = false,
};
/* Register the GPIOs */
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
deleted file mode 100644
index 202a99207b7..00000000000
--- a/drivers/gpio/gpio-langwell.c
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Moorestown platform Langwell chip GPIO driver
- *
- * Copyright (c) 2008 - 2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * Moorestown platform Langwell chip.
- * Medfield platform Penwell chip.
- * Whitney point.
- */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/irqdomain.h>
-
-/*
- * Langwell chip has 64 pins and thus there are 2 32bit registers to control
- * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit
- * registers to control them, so we only define the order here instead of a
- * structure, to get a bit offset for a pin (use GPDR as an example):
- *
- * nreg = ngpio / 32;
- * reg = offset / 32;
- * bit = offset % 32;
- * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4;
- *
- * so the bit of reg_addr is to control pin offset's GPDR feature
-*/
-
-enum GPIO_REG {
- GPLR = 0, /* pin level read-only */
- GPDR, /* pin direction */
- GPSR, /* pin set */
- GPCR, /* pin clear */
- GRER, /* rising edge detect */
- GFER, /* falling edge detect */
- GEDR, /* edge detect result */
- GAFR, /* alt function */
-};
-
-struct lnw_gpio {
- struct gpio_chip chip;
- void *reg_base;
- spinlock_t lock;
- struct pci_dev *pdev;
- struct irq_domain *domain;
-};
-
-static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
- enum GPIO_REG reg_type)
-{
- struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- unsigned nreg = chip->ngpio / 32;
- u8 reg = offset / 32;
- void __iomem *ptr;
-
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
-}
-
-static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
- enum GPIO_REG reg_type)
-{
- struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- unsigned nreg = chip->ngpio / 32;
- u8 reg = offset / 16;
- void __iomem *ptr;
-
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
-}
-
-static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR);
- u32 value = readl(gafr);
- int shift = (offset % 16) << 1, af = (value >> shift) & 3;
-
- if (af) {
- value &= ~(3 << shift);
- writel(value, gafr);
- }
- return 0;
-}
-
-static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- void __iomem *gplr = gpio_reg(chip, offset, GPLR);
-
- return readl(gplr) & BIT(offset % 32);
-}
-
-static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- void __iomem *gpsr, *gpcr;
-
- if (value) {
- gpsr = gpio_reg(chip, offset, GPSR);
- writel(BIT(offset % 32), gpsr);
- } else {
- gpcr = gpio_reg(chip, offset, GPCR);
- writel(BIT(offset % 32), gpcr);
- }
-}
-
-static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
- u32 value;
- unsigned long flags;
-
- if (lnw->pdev)
- pm_runtime_get(&lnw->pdev->dev);
-
- spin_lock_irqsave(&lnw->lock, flags);
- value = readl(gpdr);
- value &= ~BIT(offset % 32);
- writel(value, gpdr);
- spin_unlock_irqrestore(&lnw->lock, flags);
-
- if (lnw->pdev)
- pm_runtime_put(&lnw->pdev->dev);
-
- return 0;
-}
-
-static int lnw_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
- unsigned long flags;
-
- lnw_gpio_set(chip, offset, value);
-
- if (lnw->pdev)
- pm_runtime_get(&lnw->pdev->dev);
-
- spin_lock_irqsave(&lnw->lock, flags);
- value = readl(gpdr);
- value |= BIT(offset % 32);
- writel(value, gpdr);
- spin_unlock_irqrestore(&lnw->lock, flags);
-
- if (lnw->pdev)
- pm_runtime_put(&lnw->pdev->dev);
-
- return 0;
-}
-
-static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- return irq_create_mapping(lnw->domain, offset);
-}
-
-static int lnw_irq_type(struct irq_data *d, unsigned type)
-{
- struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
- u32 gpio = irqd_to_hwirq(d);
- unsigned long flags;
- u32 value;
- void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
- void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);
-
- if (gpio >= lnw->chip.ngpio)
- return -EINVAL;
-
- if (lnw->pdev)
- pm_runtime_get(&lnw->pdev->dev);
-
- spin_lock_irqsave(&lnw->lock, flags);
- if (type & IRQ_TYPE_EDGE_RISING)
- value = readl(grer) | BIT(gpio % 32);
- else
- value = readl(grer) & (~BIT(gpio % 32));
- writel(value, grer);
-
- if (type & IRQ_TYPE_EDGE_FALLING)
- value = readl(gfer) | BIT(gpio % 32);
- else
- value = readl(gfer) & (~BIT(gpio % 32));
- writel(value, gfer);
- spin_unlock_irqrestore(&lnw->lock, flags);
-
- if (lnw->pdev)
- pm_runtime_put(&lnw->pdev->dev);
-
- return 0;
-}
-
-static void lnw_irq_unmask(struct irq_data *d)
-{
-}
-
-static void lnw_irq_mask(struct irq_data *d)
-{
-}
-
-static struct irq_chip lnw_irqchip = {
- .name = "LNW-GPIO",
- .irq_mask = lnw_irq_mask,
- .irq_unmask = lnw_irq_unmask,
- .irq_set_type = lnw_irq_type,
-};
-
-static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);
-
-static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
-{
- struct irq_data *data = irq_desc_get_irq_data(desc);
- struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data);
- struct irq_chip *chip = irq_data_get_irq_chip(data);
- u32 base, gpio, mask;
- unsigned long pending;
- void __iomem *gedr;
-
- /* check GPIO controller to check which pin triggered the interrupt */
- for (base = 0; base < lnw->chip.ngpio; base += 32) {
- gedr = gpio_reg(&lnw->chip, base, GEDR);
- while ((pending = readl(gedr))) {
- gpio = __ffs(pending);
- mask = BIT(gpio);
- /* Clear before handling so we can't lose an edge */
- writel(mask, gedr);
- generic_handle_irq(irq_find_mapping(lnw->domain,
- base + gpio));
- }
- }
-
- chip->irq_eoi(data);
-}
-
-static void lnw_irq_init_hw(struct lnw_gpio *lnw)
-{
- void __iomem *reg;
- unsigned base;
-
- for (base = 0; base < lnw->chip.ngpio; base += 32) {
- /* Clear the rising-edge detect register */
- reg = gpio_reg(&lnw->chip, base, GRER);
- writel(0, reg);
- /* Clear the falling-edge detect register */
- reg = gpio_reg(&lnw->chip, base, GFER);
- writel(0, reg);
- /* Clear the edge detect status register */
- reg = gpio_reg(&lnw->chip, base, GEDR);
- writel(~0, reg);
- }
-}
-
-static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct lnw_gpio *lnw = d->host_data;
-
- irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq,
- "demux");
- irq_set_chip_data(virq, lnw);
- irq_set_irq_type(virq, IRQ_TYPE_NONE);
-
- return 0;
-}
-
-static const struct irq_domain_ops lnw_gpio_irq_ops = {
- .map = lnw_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-#ifdef CONFIG_PM
-static int lnw_gpio_runtime_resume(struct device *dev)
-{
- return 0;
-}
-
-static int lnw_gpio_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-
-static int lnw_gpio_runtime_idle(struct device *dev)
-{
- int err = pm_schedule_suspend(dev, 500);
-
- if (!err)
- return 0;
-
- return -EBUSY;
-}
-
-#else
-#define lnw_gpio_runtime_suspend NULL
-#define lnw_gpio_runtime_resume NULL
-#define lnw_gpio_runtime_idle NULL
-#endif
-
-static const struct dev_pm_ops lnw_gpio_pm_ops = {
- .runtime_suspend = lnw_gpio_runtime_suspend,
- .runtime_resume = lnw_gpio_runtime_resume,
- .runtime_idle = lnw_gpio_runtime_idle,
-};
-
-static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- void *base;
- resource_size_t start, len;
- struct lnw_gpio *lnw;
- u32 gpio_base;
- int retval;
- int ngpio = id->driver_data;
-
- retval = pci_enable_device(pdev);
- if (retval)
- return retval;
-
- retval = pci_request_regions(pdev, "langwell_gpio");
- if (retval) {
- dev_err(&pdev->dev, "error requesting resources\n");
- goto err2;
- }
- /* get the gpio_base from bar1 */
- start = pci_resource_start(pdev, 1);
- len = pci_resource_len(pdev, 1);
- base = ioremap_nocache(start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar1\n");
- retval = -EFAULT;
- goto err3;
- }
- gpio_base = *((u32 *)base + 1);
- /* release the IO mapping, since we already get the info from bar1 */
- iounmap(base);
- /* get the register base from bar0 */
- start = pci_resource_start(pdev, 0);
- len = pci_resource_len(pdev, 0);
- base = devm_ioremap_nocache(&pdev->dev, start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar0\n");
- retval = -EFAULT;
- goto err3;
- }
-
- lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL);
- if (!lnw) {
- dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
- retval = -ENOMEM;
- goto err3;
- }
-
- lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
- &lnw_gpio_irq_ops, lnw);
- if (!lnw->domain) {
- retval = -ENOMEM;
- goto err3;
- }
-
- lnw->reg_base = base;
- lnw->chip.label = dev_name(&pdev->dev);
- lnw->chip.request = lnw_gpio_request;
- lnw->chip.direction_input = lnw_gpio_direction_input;
- lnw->chip.direction_output = lnw_gpio_direction_output;
- lnw->chip.get = lnw_gpio_get;
- lnw->chip.set = lnw_gpio_set;
- lnw->chip.to_irq = lnw_gpio_to_irq;
- lnw->chip.base = gpio_base;
- lnw->chip.ngpio = ngpio;
- lnw->chip.can_sleep = 0;
- lnw->pdev = pdev;
- pci_set_drvdata(pdev, lnw);
- retval = gpiochip_add(&lnw->chip);
- if (retval) {
- dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
- goto err3;
- }
-
- lnw_irq_init_hw(lnw);
-
- irq_set_handler_data(pdev->irq, lnw);
- irq_set_chained_handler(pdev->irq, lnw_irq_handler);
-
- spin_lock_init(&lnw->lock);
-
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_allow(&pdev->dev);
-
- return 0;
-
-err3:
- pci_release_regions(pdev);
-err2:
- pci_disable_device(pdev);
- return retval;
-}
-
-static struct pci_driver lnw_gpio_driver = {
- .name = "langwell_gpio",
- .id_table = lnw_gpio_ids,
- .probe = lnw_gpio_probe,
- .driver = {
- .pm = &lnw_gpio_pm_ops,
- },
-};
-
-
-static int __devinit wp_gpio_probe(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw;
- struct gpio_chip *gc;
- struct resource *rc;
- int retval = 0;
-
- rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!rc)
- return -EINVAL;
-
- lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
- if (!lnw) {
- dev_err(&pdev->dev,
- "can't allocate whitneypoint_gpio chip data\n");
- return -ENOMEM;
- }
- lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
- if (lnw->reg_base == NULL) {
- retval = -EINVAL;
- goto err_kmalloc;
- }
- spin_lock_init(&lnw->lock);
- gc = &lnw->chip;
- gc->label = dev_name(&pdev->dev);
- gc->owner = THIS_MODULE;
- gc->direction_input = lnw_gpio_direction_input;
- gc->direction_output = lnw_gpio_direction_output;
- gc->get = lnw_gpio_get;
- gc->set = lnw_gpio_set;
- gc->to_irq = NULL;
- gc->base = 0;
- gc->ngpio = 64;
- gc->can_sleep = 0;
- retval = gpiochip_add(gc);
- if (retval) {
- dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
- retval);
- goto err_ioremap;
- }
- platform_set_drvdata(pdev, lnw);
- return 0;
-err_ioremap:
- iounmap(lnw->reg_base);
-err_kmalloc:
- kfree(lnw);
- return retval;
-}
-
-static int __devexit wp_gpio_remove(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw = platform_get_drvdata(pdev);
- int err;
- err = gpiochip_remove(&lnw->chip);
- if (err)
- dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
- iounmap(lnw->reg_base);
- kfree(lnw);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-static struct platform_driver wp_gpio_driver = {
- .probe = wp_gpio_probe,
- .remove = __devexit_p(wp_gpio_remove),
- .driver = {
- .name = "wp_gpio",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init lnw_gpio_init(void)
-{
- int ret;
- ret = pci_register_driver(&lnw_gpio_driver);
- if (ret < 0)
- return ret;
- ret = platform_driver_register(&wp_gpio_driver);
- if (ret < 0)
- pci_unregister_driver(&lnw_gpio_driver);
- return ret;
-}
-
-device_initcall(lnw_gpio_init);
diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c
new file mode 100644
index 00000000000..a0341c92bcb
--- /dev/null
+++ b/drivers/gpio/gpio-lp3943.c
@@ -0,0 +1,242 @@
+/*
+ * TI/National Semiconductor LP3943 GPIO driver
+ *
+ * Copyright 2013 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/lp3943.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+enum lp3943_gpios {
+ LP3943_GPIO1,
+ LP3943_GPIO2,
+ LP3943_GPIO3,
+ LP3943_GPIO4,
+ LP3943_GPIO5,
+ LP3943_GPIO6,
+ LP3943_GPIO7,
+ LP3943_GPIO8,
+ LP3943_GPIO9,
+ LP3943_GPIO10,
+ LP3943_GPIO11,
+ LP3943_GPIO12,
+ LP3943_GPIO13,
+ LP3943_GPIO14,
+ LP3943_GPIO15,
+ LP3943_GPIO16,
+ LP3943_MAX_GPIO,
+};
+
+struct lp3943_gpio {
+ struct gpio_chip chip;
+ struct lp3943 *lp3943;
+ u16 input_mask; /* 1 = GPIO is input direction, 0 = output */
+};
+
+static inline struct lp3943_gpio *to_lp3943_gpio(struct gpio_chip *_chip)
+{
+ return container_of(_chip, struct lp3943_gpio, chip);
+}
+
+static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943 *lp3943 = lp3943_gpio->lp3943;
+
+ /* Return an error if the pin is already assigned */
+ if (test_and_set_bit(offset, &lp3943->pin_used))
+ return -EBUSY;
+
+ return 0;
+}
+
+static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ struct lp3943 *lp3943 = lp3943_gpio->lp3943;
+
+ clear_bit(offset, &lp3943->pin_used);
+}
+
+static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset,
+ u8 val)
+{
+ struct lp3943 *lp3943 = lp3943_gpio->lp3943;
+ const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
+
+ return lp3943_update_bits(lp3943, mux[offset].reg, mux[offset].mask,
+ val << mux[offset].shift);
+}
+
+static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+
+ lp3943_gpio->input_mask |= BIT(offset);
+
+ return lp3943_gpio_set_mode(lp3943_gpio, offset, LP3943_GPIO_IN);
+}
+
+static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio,
+ struct gpio_chip *chip, unsigned offset)
+{
+ u8 addr, read;
+ int err;
+
+ switch (offset) {
+ case LP3943_GPIO1 ... LP3943_GPIO8:
+ addr = LP3943_REG_GPIO_A;
+ break;
+ case LP3943_GPIO9 ... LP3943_GPIO16:
+ addr = LP3943_REG_GPIO_B;
+ offset = offset - 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = lp3943_read_byte(lp3943_gpio->lp3943, addr, &read);
+ if (err)
+ return err;
+
+ return !!(read & BIT(offset));
+}
+
+static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio,
+ struct gpio_chip *chip, unsigned offset)
+{
+ struct lp3943 *lp3943 = lp3943_gpio->lp3943;
+ const struct lp3943_reg_cfg *mux = lp3943->mux_cfg;
+ u8 read;
+ int err;
+
+ err = lp3943_read_byte(lp3943, mux[offset].reg, &read);
+ if (err)
+ return err;
+
+ read = (read & mux[offset].mask) >> mux[offset].shift;
+
+ if (read == LP3943_GPIO_OUT_HIGH)
+ return 1;
+ else if (read == LP3943_GPIO_OUT_LOW)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+
+ /*
+ * Limitation:
+ * LP3943 doesn't have the GPIO direction register. It provides
+ * only input and output status registers.
+ * So, direction info is required to handle the 'get' operation.
+ * This variable is updated whenever the direction is changed and
+ * it is used here.
+ */
+
+ if (lp3943_gpio->input_mask & BIT(offset))
+ return lp3943_get_gpio_in_status(lp3943_gpio, chip, offset);
+ else
+ return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset);
+}
+
+static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+ u8 data;
+
+ if (value)
+ data = LP3943_GPIO_OUT_HIGH;
+ else
+ data = LP3943_GPIO_OUT_LOW;
+
+ lp3943_gpio_set_mode(lp3943_gpio, offset, data);
+}
+
+static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct lp3943_gpio *lp3943_gpio = to_lp3943_gpio(chip);
+
+ lp3943_gpio_set(chip, offset, value);
+ lp3943_gpio->input_mask &= ~BIT(offset);
+
+ return 0;
+}
+
+static const struct gpio_chip lp3943_gpio_chip = {
+ .label = "lp3943",
+ .owner = THIS_MODULE,
+ .request = lp3943_gpio_request,
+ .free = lp3943_gpio_free,
+ .direction_input = lp3943_gpio_direction_input,
+ .get = lp3943_gpio_get,
+ .direction_output = lp3943_gpio_direction_output,
+ .set = lp3943_gpio_set,
+ .base = -1,
+ .ngpio = LP3943_MAX_GPIO,
+ .can_sleep = 1,
+};
+
+static int lp3943_gpio_probe(struct platform_device *pdev)
+{
+ struct lp3943 *lp3943 = dev_get_drvdata(pdev->dev.parent);
+ struct lp3943_gpio *lp3943_gpio;
+
+ lp3943_gpio = devm_kzalloc(&pdev->dev, sizeof(*lp3943_gpio),
+ GFP_KERNEL);
+ if (!lp3943_gpio)
+ return -ENOMEM;
+
+ lp3943_gpio->lp3943 = lp3943;
+ lp3943_gpio->chip = lp3943_gpio_chip;
+ lp3943_gpio->chip.dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, lp3943_gpio);
+
+ return gpiochip_add(&lp3943_gpio->chip);
+}
+
+static int lp3943_gpio_remove(struct platform_device *pdev)
+{
+ struct lp3943_gpio *lp3943_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&lp3943_gpio->chip);
+}
+
+static const struct of_device_id lp3943_gpio_of_match[] = {
+ { .compatible = "ti,lp3943-gpio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lp3943_gpio_of_match);
+
+static struct platform_driver lp3943_gpio_driver = {
+ .probe = lp3943_gpio_probe,
+ .remove = lp3943_gpio_remove,
+ .driver = {
+ .name = "lp3943-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = lp3943_gpio_of_match,
+ },
+};
+module_platform_driver(lp3943_gpio_driver);
+
+MODULE_DESCRIPTION("LP3943 GPIO driver");
+MODULE_ALIAS("platform:lp3943-gpio");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 3644e0dcb3d..225344d6640 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -21,13 +21,14 @@
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/gpio.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/platform_data/gpio-lpc32xx.h>
#include <mach/hardware.h>
#include <mach/platform.h>
-#include <mach/gpio-lpc32xx.h>
#include <mach/irqs.h>
#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000)
@@ -255,7 +256,7 @@ static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
}
/*
- * GENERIC_GPIO primitives.
+ * GPIO primitives.
*/
static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
unsigned pin)
@@ -447,7 +448,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPIO_P0_GRP,
.ngpio = LPC32XX_GPIO_P0_MAX,
.names = gpio_p0_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p0,
},
@@ -463,7 +464,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPIO_P1_GRP,
.ngpio = LPC32XX_GPIO_P1_MAX,
.names = gpio_p1_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p1,
},
@@ -478,7 +479,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPIO_P2_GRP,
.ngpio = LPC32XX_GPIO_P2_MAX,
.names = gpio_p2_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p2,
},
@@ -494,7 +495,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPIO_P3_GRP,
.ngpio = LPC32XX_GPIO_P3_MAX,
.names = gpio_p3_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p3,
},
@@ -508,7 +509,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPI_P3_GRP,
.ngpio = LPC32XX_GPI_P3_MAX,
.names = gpi_p3_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p3,
},
@@ -522,7 +523,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
.base = LPC32XX_GPO_P3_GRP,
.ngpio = LPC32XX_GPO_P3_MAX,
.names = gpo_p3_names,
- .can_sleep = 0,
+ .can_sleep = false,
},
.gpio_grp = &gpio_grp_regs_p3,
},
@@ -533,7 +534,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc,
{
/* Is this the correct bank? */
u32 bank = gpiospec->args[0];
- if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) ||
+ if ((bank >= ARRAY_SIZE(lpc32xx_gpiochip) ||
(gc != &lpc32xx_gpiochip[bank].chip)))
return -EINVAL;
@@ -542,7 +543,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc,
return gpiospec->args[1];
}
-static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev)
+static int lpc32xx_gpio_probe(struct platform_device *pdev)
{
int i;
@@ -559,7 +560,7 @@ static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev)
}
#ifdef CONFIG_OF
-static struct of_device_id lpc32xx_gpio_of_match[] __devinitdata = {
+static struct of_device_id lpc32xx_gpio_of_match[] = {
{ .compatible = "nxp,lpc3220-gpio", },
{ },
};
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
new file mode 100644
index 00000000000..2bea89b7250
--- /dev/null
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -0,0 +1,503 @@
+/*
+ * GPIO controller driver for Intel Lynxpoint PCH chipset>
+ * Copyright (c) 2012, Intel Corporation.
+ *
+ * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/irqdomain.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+
+/* LynxPoint chipset has support for 94 gpio pins */
+
+#define LP_NUM_GPIO 94
+
+/* Bitmapped register offsets */
+#define LP_ACPI_OWNED 0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */
+#define LP_GC 0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */
+#define LP_INT_STAT 0x80
+#define LP_INT_ENABLE 0x90
+
+/* Each pin has two 32 bit config registers, starting at 0x100 */
+#define LP_CONFIG1 0x100
+#define LP_CONFIG2 0x104
+
+/* LP_CONFIG1 reg bits */
+#define OUT_LVL_BIT BIT(31)
+#define IN_LVL_BIT BIT(30)
+#define TRIG_SEL_BIT BIT(4) /* 0: Edge, 1: Level */
+#define INT_INV_BIT BIT(3) /* Invert interrupt triggering */
+#define DIR_BIT BIT(2) /* 0: Output, 1: Input */
+#define USE_SEL_BIT BIT(0) /* 0: Native, 1: GPIO */
+
+/* LP_CONFIG2 reg bits */
+#define GPINDIS_BIT BIT(2) /* disable input sensing */
+#define GPIWP_BIT (BIT(0) | BIT(1)) /* weak pull options */
+
+struct lp_gpio {
+ struct gpio_chip chip;
+ struct irq_domain *domain;
+ struct platform_device *pdev;
+ spinlock_t lock;
+ unsigned long reg_base;
+};
+
+/*
+ * Lynxpoint gpios are controlled through both bitmapped registers and
+ * per gpio specific registers. The bitmapped registers are in chunks of
+ * 3 x 32bit registers to cover all 94 gpios
+ *
+ * per gpio specific registers consist of two 32bit registers per gpio
+ * (LP_CONFIG1 and LP_CONFIG2), with 94 gpios there's a total of
+ * 188 config registes.
+ *
+ * A simplified view of the register layout look like this:
+ *
+ * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31 (bitmapped registers)
+ * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63
+ * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94
+ * ...
+ * LP_INT_ENABLE[31:0] ...
+ * LP_INT_ENABLE[63:31] ...
+ * LP_INT_ENABLE[94:64] ...
+ * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers)
+ * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0
+ * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1
+ * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1
+ * LP2_CONFIG1 (gpio 2) ...
+ * LP2_CONFIG2 (gpio 2) ...
+ * ...
+ * LP94_CONFIG1 (gpio 94) ...
+ * LP94_CONFIG2 (gpio 94) ...
+ */
+
+static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
+ int reg)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ int reg_offset;
+
+ if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
+ /* per gpio specific config registers */
+ reg_offset = offset * 8;
+ else
+ /* bitmapped registers */
+ reg_offset = (offset / 32) * 4;
+
+ return lg->reg_base + reg + reg_offset;
+}
+
+static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+ unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
+ unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED);
+
+ pm_runtime_get(&lg->pdev->dev); /* should we put if failed */
+
+ /* Fail if BIOS reserved pin for ACPI use */
+ if (!(inl(acpi_use) & BIT(offset % 32))) {
+ dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset);
+ return -EBUSY;
+ }
+ /* Fail if pin is in alternate function mode (not GPIO mode) */
+ if (!(inl(reg) & USE_SEL_BIT))
+ return -ENODEV;
+
+ /* enable input sensing */
+ outl(inl(conf2) & ~GPINDIS_BIT, conf2);
+
+
+ return 0;
+}
+
+static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
+
+ /* disable input sensing */
+ outl(inl(conf2) | GPINDIS_BIT, conf2);
+
+ pm_runtime_put(&lg->pdev->dev);
+}
+
+static int lp_irq_type(struct irq_data *d, unsigned type)
+{
+ struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ u32 hwirq = irqd_to_hwirq(d);
+ unsigned long flags;
+ u32 value;
+ unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1);
+
+ if (hwirq >= lg->chip.ngpio)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lg->lock, flags);
+ value = inl(reg);
+
+ /* set both TRIG_SEL and INV bits to 0 for rising edge */
+ if (type & IRQ_TYPE_EDGE_RISING)
+ value &= ~(TRIG_SEL_BIT | INT_INV_BIT);
+
+ /* TRIG_SEL bit 0, INV bit 1 for falling edge */
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT;
+
+ /* TRIG_SEL bit 1, INV bit 0 for level low */
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT;
+
+ /* TRIG_SEL bit 1, INV bit 1 for level high */
+ if (type & IRQ_TYPE_LEVEL_HIGH)
+ value |= TRIG_SEL_BIT | INT_INV_BIT;
+
+ outl(value, reg);
+ spin_unlock_irqrestore(&lg->lock, flags);
+
+ return 0;
+}
+
+static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+ return !!(inl(reg) & IN_LVL_BIT);
+}
+
+static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lg->lock, flags);
+
+ if (value)
+ outl(inl(reg) | OUT_LVL_BIT, reg);
+ else
+ outl(inl(reg) & ~OUT_LVL_BIT, reg);
+
+ spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lg->lock, flags);
+ outl(inl(reg) | DIR_BIT, reg);
+ spin_unlock_irqrestore(&lg->lock, flags);
+
+ return 0;
+}
+
+static int lp_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
+ unsigned long flags;
+
+ lp_gpio_set(chip, offset, value);
+
+ spin_lock_irqsave(&lg->lock, flags);
+ outl(inl(reg) & ~DIR_BIT, reg);
+ spin_unlock_irqrestore(&lg->lock, flags);
+
+ return 0;
+}
+
+static int lp_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct lp_gpio *lg = container_of(chip, struct lp_gpio, chip);
+ return irq_create_mapping(lg->domain, offset);
+}
+
+static void lp_gpio_irq_handler(unsigned hwirq, struct irq_desc *desc)
+{
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct lp_gpio *lg = irq_data_get_irq_handler_data(data);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
+ u32 base, pin, mask;
+ unsigned long reg, ena, pending;
+
+ /* check from GPIO controller which pin triggered the interrupt */
+ for (base = 0; base < lg->chip.ngpio; base += 32) {
+ reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+ ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
+
+ while ((pending = (inl(reg) & inl(ena)))) {
+ unsigned irq;
+
+ pin = __ffs(pending);
+ mask = BIT(pin);
+ /* Clear before handling so we don't lose an edge */
+ outl(mask, reg);
+ irq = irq_find_mapping(lg->domain, base + pin);
+ generic_handle_irq(irq);
+ }
+ }
+ chip->irq_eoi(data);
+}
+
+static void lp_irq_unmask(struct irq_data *d)
+{
+}
+
+static void lp_irq_mask(struct irq_data *d)
+{
+}
+
+static void lp_irq_enable(struct irq_data *d)
+{
+ struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ u32 hwirq = irqd_to_hwirq(d);
+ unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lg->lock, flags);
+ outl(inl(reg) | BIT(hwirq % 32), reg);
+ spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static void lp_irq_disable(struct irq_data *d)
+{
+ struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+ u32 hwirq = irqd_to_hwirq(d);
+ unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lg->lock, flags);
+ outl(inl(reg) & ~BIT(hwirq % 32), reg);
+ spin_unlock_irqrestore(&lg->lock, flags);
+}
+
+static int lp_irq_reqres(struct irq_data *d)
+{
+ struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) {
+ dev_err(lg->chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ irqd_to_hwirq(d));
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void lp_irq_relres(struct irq_data *d)
+{
+ struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
+}
+
+static struct irq_chip lp_irqchip = {
+ .name = "LP-GPIO",
+ .irq_mask = lp_irq_mask,
+ .irq_unmask = lp_irq_unmask,
+ .irq_enable = lp_irq_enable,
+ .irq_disable = lp_irq_disable,
+ .irq_set_type = lp_irq_type,
+ .irq_request_resources = lp_irq_reqres,
+ .irq_release_resources = lp_irq_relres,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void lp_gpio_irq_init_hw(struct lp_gpio *lg)
+{
+ unsigned long reg;
+ unsigned base;
+
+ for (base = 0; base < lg->chip.ngpio; base += 32) {
+ /* disable gpio pin interrupts */
+ reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
+ outl(0, reg);
+ /* Clear interrupt status register */
+ reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
+ outl(0xffffffff, reg);
+ }
+}
+
+static int lp_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct lp_gpio *lg = d->host_data;
+
+ irq_set_chip_and_handler(irq, &lp_irqchip, handle_simple_irq);
+ irq_set_chip_data(irq, lg);
+ irq_set_irq_type(irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops lp_gpio_irq_ops = {
+ .map = lp_gpio_irq_map,
+};
+
+static int lp_gpio_probe(struct platform_device *pdev)
+{
+ struct lp_gpio *lg;
+ struct gpio_chip *gc;
+ struct resource *io_rc, *irq_rc;
+ struct device *dev = &pdev->dev;
+ unsigned long reg_len;
+ unsigned hwirq;
+ int ret = -ENODEV;
+
+ lg = devm_kzalloc(dev, sizeof(struct lp_gpio), GFP_KERNEL);
+ if (!lg)
+ return -ENOMEM;
+
+ lg->pdev = pdev;
+ platform_set_drvdata(pdev, lg);
+
+ io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!io_rc) {
+ dev_err(dev, "missing IO resources\n");
+ return -EINVAL;
+ }
+
+ lg->reg_base = io_rc->start;
+ reg_len = resource_size(io_rc);
+
+ if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) {
+ dev_err(dev, "failed requesting IO region 0x%x\n",
+ (unsigned int)lg->reg_base);
+ return -EBUSY;
+ }
+
+ spin_lock_init(&lg->lock);
+
+ gc = &lg->chip;
+ gc->label = dev_name(dev);
+ gc->owner = THIS_MODULE;
+ gc->request = lp_gpio_request;
+ gc->free = lp_gpio_free;
+ gc->direction_input = lp_gpio_direction_input;
+ gc->direction_output = lp_gpio_direction_output;
+ gc->get = lp_gpio_get;
+ gc->set = lp_gpio_set;
+ gc->base = -1;
+ gc->ngpio = LP_NUM_GPIO;
+ gc->can_sleep = false;
+ gc->dev = dev;
+
+ /* set up interrupts */
+ if (irq_rc && irq_rc->start) {
+ hwirq = irq_rc->start;
+ gc->to_irq = lp_gpio_to_irq;
+
+ lg->domain = irq_domain_add_linear(NULL, LP_NUM_GPIO,
+ &lp_gpio_irq_ops, lg);
+ if (!lg->domain)
+ return -ENXIO;
+
+ lp_gpio_irq_init_hw(lg);
+
+ irq_set_handler_data(hwirq, lg);
+ irq_set_chained_handler(hwirq, lp_gpio_irq_handler);
+ }
+
+ ret = gpiochip_add(gc);
+ if (ret) {
+ dev_err(dev, "failed adding lp-gpio chip\n");
+ return ret;
+ }
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static int lp_gpio_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int lp_gpio_runtime_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops lp_gpio_pm_ops = {
+ .runtime_suspend = lp_gpio_runtime_suspend,
+ .runtime_resume = lp_gpio_runtime_resume,
+};
+
+static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
+ { "INT33C7", 0 },
+ { "INT3437", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
+
+static int lp_gpio_remove(struct platform_device *pdev)
+{
+ struct lp_gpio *lg = platform_get_drvdata(pdev);
+ int err;
+ pm_runtime_disable(&pdev->dev);
+ err = gpiochip_remove(&lg->chip);
+ if (err)
+ dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
+ return 0;
+}
+
+static struct platform_driver lp_gpio_driver = {
+ .probe = lp_gpio_probe,
+ .remove = lp_gpio_remove,
+ .driver = {
+ .name = "lp_gpio",
+ .owner = THIS_MODULE,
+ .pm = &lp_gpio_pm_ops,
+ .acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match),
+ },
+};
+
+static int __init lp_gpio_init(void)
+{
+ return platform_driver_register(&lp_gpio_driver);
+}
+
+static void __exit lp_gpio_exit(void)
+{
+ platform_driver_unregister(&lp_gpio_driver);
+}
+
+subsys_initcall(lp_gpio_init);
+module_exit(lp_gpio_exit);
+
+MODULE_AUTHOR("Mathias Nyman (Intel)");
+MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp_gpio");
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index a5ca0ab1b37..40ab6dfb602 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -31,7 +31,7 @@ static int max7300_i2c_read(struct device *dev, unsigned int reg)
return i2c_smbus_read_byte_data(client, reg);
}
-static int __devinit max7300_probe(struct i2c_client *client,
+static int max7300_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max7301 *ts;
@@ -41,7 +41,7 @@ static int __devinit max7300_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
+ ts = devm_kzalloc(&client->dev, sizeof(struct max7301), GFP_KERNEL);
if (!ts)
return -ENOMEM;
@@ -50,12 +50,10 @@ static int __devinit max7300_probe(struct i2c_client *client,
ts->dev = &client->dev;
ret = __max730x_probe(ts);
- if (ret)
- kfree(ts);
return ret;
}
-static int __devexit max7300_remove(struct i2c_client *client)
+static int max7300_remove(struct i2c_client *client)
{
return __max730x_remove(&client->dev);
}
@@ -72,7 +70,7 @@ static struct i2c_driver max7300_driver = {
.owner = THIS_MODULE,
},
.probe = max7300_probe,
- .remove = __devexit_p(max7300_remove),
+ .remove = max7300_remove,
.id_table = max7300_id,
};
diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c
index 741acfcbe76..6e1c984a75d 100644
--- a/drivers/gpio/gpio-max7301.c
+++ b/drivers/gpio/gpio-max7301.c
@@ -50,7 +50,7 @@ static int max7301_spi_read(struct device *dev, unsigned int reg)
return word & 0xff;
}
-static int __devinit max7301_probe(struct spi_device *spi)
+static int max7301_probe(struct spi_device *spi)
{
struct max7301 *ts;
int ret;
@@ -61,7 +61,7 @@ static int __devinit max7301_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- ts = kzalloc(sizeof(struct max7301), GFP_KERNEL);
+ ts = devm_kzalloc(&spi->dev, sizeof(struct max7301), GFP_KERNEL);
if (!ts)
return -ENOMEM;
@@ -70,12 +70,10 @@ static int __devinit max7301_probe(struct spi_device *spi)
ts->dev = &spi->dev;
ret = __max730x_probe(ts);
- if (ret)
- kfree(ts);
return ret;
}
-static int __devexit max7301_remove(struct spi_device *spi)
+static int max7301_remove(struct spi_device *spi)
{
return __max730x_remove(&spi->dev);
}
@@ -92,7 +90,7 @@ static struct spi_driver max7301_driver = {
.owner = THIS_MODULE,
},
.probe = max7301_probe,
- .remove = __devexit_p(max7301_remove),
+ .remove = max7301_remove,
.id_table = max7301_id,
};
diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c
index 05e2dac60b3..0814584fcdc 100644
--- a/drivers/gpio/gpio-max730x.c
+++ b/drivers/gpio/gpio-max730x.c
@@ -160,17 +160,13 @@ static void max7301_set(struct gpio_chip *chip, unsigned offset, int value)
mutex_unlock(&ts->lock);
}
-int __devinit __max730x_probe(struct max7301 *ts)
+int __max730x_probe(struct max7301 *ts)
{
struct device *dev = ts->dev;
struct max7301_platform_data *pdata;
int i, ret;
- pdata = dev->platform_data;
- if (!pdata || !pdata->base) {
- dev_err(dev, "incorrect or missing platform data\n");
- return -EINVAL;
- }
+ pdata = dev_get_platdata(dev);
mutex_init(&ts->lock);
dev_set_drvdata(dev, ts);
@@ -178,7 +174,12 @@ int __devinit __max730x_probe(struct max7301 *ts)
/* Power up the chip and disable IRQ output */
ts->write(dev, 0x04, 0x01);
- ts->input_pullup_active = pdata->input_pullup_active;
+ if (pdata) {
+ ts->input_pullup_active = pdata->input_pullup_active;
+ ts->chip.base = pdata->base;
+ } else {
+ ts->chip.base = -1;
+ }
ts->chip.label = dev->driver->name;
ts->chip.direction_input = max7301_direction_input;
@@ -186,9 +187,8 @@ int __devinit __max730x_probe(struct max7301 *ts)
ts->chip.direction_output = max7301_direction_output;
ts->chip.set = max7301_set;
- ts->chip.base = pdata->base;
ts->chip.ngpio = PIN_NUMBER;
- ts->chip.can_sleep = 1;
+ ts->chip.can_sleep = true;
ts->chip.dev = dev;
ts->chip.owner = THIS_MODULE;
@@ -220,13 +220,12 @@ int __devinit __max730x_probe(struct max7301 *ts)
return ret;
exit_destroy:
- dev_set_drvdata(dev, NULL);
mutex_destroy(&ts->lock);
return ret;
}
EXPORT_SYMBOL_GPL(__max730x_probe);
-int __devexit __max730x_remove(struct device *dev)
+int __max730x_remove(struct device *dev)
{
struct max7301 *ts = dev_get_drvdata(dev);
int ret;
@@ -234,16 +233,13 @@ int __devexit __max730x_remove(struct device *dev)
if (ts == NULL)
return -ENODEV;
- dev_set_drvdata(dev, NULL);
-
/* Power down the chip and disable IRQ output */
ts->write(dev, 0x04, 0x00);
ret = gpiochip_remove(&ts->chip);
- if (!ret) {
+ if (!ret)
mutex_destroy(&ts->lock);
- kfree(ts);
- } else
+ else
dev_err(dev, "Failed to remove GPIO controller: %d\n", ret);
return ret;
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 9504120812a..7c36f2b0983 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -453,7 +453,7 @@ 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 = client->dev.platform_data;
+ struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
int ret;
@@ -512,7 +512,7 @@ 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 = client->dev.platform_data;
+ struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
if (pdata->irq_base && has_irq != INT_NONE)
@@ -526,7 +526,7 @@ static void max732x_irq_teardown(struct max732x_chip *chip)
}
#endif
-static int __devinit max732x_setup_gpio(struct max732x_chip *chip,
+static int max732x_setup_gpio(struct max732x_chip *chip,
const struct i2c_device_id *id,
unsigned gpio_start)
{
@@ -564,7 +564,7 @@ static int __devinit max732x_setup_gpio(struct max732x_chip *chip,
gc->set = max732x_gpio_set_value;
}
gc->get = max732x_gpio_get_value;
- gc->can_sleep = 1;
+ gc->can_sleep = true;
gc->base = gpio_start;
gc->ngpio = port;
@@ -574,7 +574,7 @@ static int __devinit max732x_setup_gpio(struct max732x_chip *chip,
return port;
}
-static int __devinit max732x_probe(struct i2c_client *client,
+static int max732x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max732x_platform_data *pdata;
@@ -583,13 +583,14 @@ static int __devinit max732x_probe(struct i2c_client *client,
uint16_t addr_a, addr_b;
int ret, nr_port;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (pdata == NULL) {
dev_dbg(&client->dev, "no platform data\n");
return -EINVAL;
}
- chip = kzalloc(sizeof(struct max732x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip),
+ GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->client = client;
@@ -621,6 +622,13 @@ static int __devinit max732x_probe(struct i2c_client *client,
goto out_failed;
}
+ if (nr_port > 8 && !chip->client_dummy) {
+ dev_err(&client->dev,
+ "Failed to allocate second group I2C device\n");
+ ret = -ENODEV;
+ goto out_failed;
+ }
+
mutex_init(&chip->lock);
max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
@@ -646,14 +654,15 @@ static int __devinit max732x_probe(struct i2c_client *client,
return 0;
out_failed:
+ if (chip->client_dummy)
+ i2c_unregister_device(chip->client_dummy);
max732x_irq_teardown(chip);
- kfree(chip);
return ret;
}
-static int __devexit max732x_remove(struct i2c_client *client)
+static int max732x_remove(struct i2c_client *client)
{
- struct max732x_platform_data *pdata = client->dev.platform_data;
+ struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
struct max732x_chip *chip = i2c_get_clientdata(client);
int ret;
@@ -680,7 +689,6 @@ static int __devexit max732x_remove(struct i2c_client *client)
if (chip->client_dummy)
i2c_unregister_device(chip->client_dummy);
- kfree(chip);
return 0;
}
@@ -690,7 +698,7 @@ static struct i2c_driver max732x_driver = {
.owner = THIS_MODULE,
},
.probe = max732x_probe,
- .remove = __devexit_p(max732x_remove),
+ .remove = max732x_remove,
.id_table = max732x_id,
};
diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c
index 2de57ce5feb..553a80a5eaf 100644
--- a/drivers/gpio/gpio-mc33880.c
+++ b/drivers/gpio/gpio-mc33880.c
@@ -80,13 +80,13 @@ static void mc33880_set(struct gpio_chip *chip, unsigned offset, int value)
mutex_unlock(&mc->lock);
}
-static int __devinit mc33880_probe(struct spi_device *spi)
+static int mc33880_probe(struct spi_device *spi)
{
struct mc33880 *mc;
struct mc33880_platform_data *pdata;
int ret;
- pdata = spi->dev.platform_data;
+ pdata = dev_get_platdata(&spi->dev);
if (!pdata || !pdata->base) {
dev_dbg(&spi->dev, "incorrect or missing platform data\n");
return -EINVAL;
@@ -101,13 +101,13 @@ static int __devinit mc33880_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- mc = kzalloc(sizeof(struct mc33880), GFP_KERNEL);
+ mc = devm_kzalloc(&spi->dev, sizeof(struct mc33880), GFP_KERNEL);
if (!mc)
return -ENOMEM;
mutex_init(&mc->lock);
- dev_set_drvdata(&spi->dev, mc);
+ spi_set_drvdata(spi, mc);
mc->spi = spi;
@@ -115,7 +115,7 @@ static int __devinit mc33880_probe(struct spi_device *spi)
mc->chip.set = mc33880_set;
mc->chip.base = pdata->base;
mc->chip.ngpio = PIN_NUMBER;
- mc->chip.can_sleep = 1;
+ mc->chip.can_sleep = true;
mc->chip.dev = &spi->dev;
mc->chip.owner = THIS_MODULE;
@@ -130,7 +130,8 @@ static int __devinit mc33880_probe(struct spi_device *spi)
ret = mc33880_write_config(mc);
if (ret) {
- printk(KERN_ERR "Failed writing to " DRIVER_NAME ": %d\n", ret);
+ dev_err(&spi->dev, "Failed writing to " DRIVER_NAME ": %d\n",
+ ret);
goto exit_destroy;
}
@@ -141,28 +142,23 @@ static int __devinit mc33880_probe(struct spi_device *spi)
return ret;
exit_destroy:
- dev_set_drvdata(&spi->dev, NULL);
mutex_destroy(&mc->lock);
- kfree(mc);
return ret;
}
-static int __devexit mc33880_remove(struct spi_device *spi)
+static int mc33880_remove(struct spi_device *spi)
{
struct mc33880 *mc;
int ret;
- mc = dev_get_drvdata(&spi->dev);
+ mc = spi_get_drvdata(spi);
if (mc == NULL)
return -ENODEV;
- dev_set_drvdata(&spi->dev, NULL);
-
ret = gpiochip_remove(&mc->chip);
- if (!ret) {
+ if (!ret)
mutex_destroy(&mc->lock);
- kfree(mc);
- } else
+ else
dev_err(&spi->dev, "Failed to remove the GPIO controller: %d\n",
ret);
@@ -175,7 +171,7 @@ static struct spi_driver mc33880_driver = {
.owner = THIS_MODULE,
},
.probe = mc33880_probe,
- .remove = __devexit_p(mc33880_remove),
+ .remove = mc33880_remove,
};
static int __init mc33880_init(void)
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
index 0ab700046a2..dce35ff00db 100644
--- a/drivers/gpio/gpio-mc9s08dz60.c
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -102,7 +102,7 @@ static int mc9s08dz60_probe(struct i2c_client *client,
mc9s->chip.dev = &client->dev;
mc9s->chip.owner = THIS_MODULE;
mc9s->chip.ngpio = GPIO_NUM;
- mc9s->chip.can_sleep = 1;
+ mc9s->chip.can_sleep = true;
mc9s->chip.get = mc9s08dz60_get_value;
mc9s->chip.set = mc9s08dz60_set_value;
mc9s->chip.direction_output = mc9s08dz60_direction_output;
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 0f425189de1..57adbc90fda 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -1,5 +1,13 @@
/*
- * MCP23S08 SPI/GPIO gpio expander driver
+ * MCP23S08 SPI/I2C GPIO gpio expander driver
+ *
+ * The inputs and outputs of the mcp23s08, mcp23s17, mcp23008 and mcp23017 are
+ * supported.
+ * For the I2C versions of the chips (mcp23008 and mcp23017) generation of
+ * interrupts is also supported.
+ * The hardware of the SPI versions of the chips (mcp23s08 and mcp23s17) is
+ * also capable of generating interrupts, but the linux driver does not
+ * support that yet.
*/
#include <linux/kernel.h>
@@ -12,6 +20,9 @@
#include <linux/spi/mcp23s08.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
+#include <linux/interrupt.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
/**
* MCP types supported by driver
@@ -32,6 +43,7 @@
#define MCP_DEFVAL 0x03
#define MCP_INTCON 0x04
#define MCP_IOCON 0x05
+# define IOCON_MIRROR (1 << 6)
# define IOCON_SEQOP (1 << 5)
# define IOCON_HAEN (1 << 3)
# define IOCON_ODR (1 << 2)
@@ -55,8 +67,14 @@ struct mcp23s08 {
u8 addr;
u16 cache[11];
+ u16 irq_rise;
+ u16 irq_fall;
+ int irq;
+ bool irq_controller;
/* lock protects the cached values */
struct mutex lock;
+ struct mutex irq_lock;
+ struct irq_domain *irq_domain;
struct gpio_chip chip;
@@ -75,9 +93,14 @@ struct mcp23s08_driver_data {
struct mcp23s08 chip[];
};
+/* This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
/*----------------------------------------------------------------------*/
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg)
{
@@ -150,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
tx[0] = mcp->addr | 0x01;
tx[1] = reg;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
return (status < 0) ? status : rx[0];
}
@@ -161,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
tx[0] = mcp->addr;
tx[1] = reg;
tx[2] = val;
- return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
+ return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
}
static int
@@ -170,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
u8 tx[2], *tmp;
int status;
- if ((n + reg) > sizeof mcp->cache)
+ if ((n + reg) > sizeof(mcp->cache))
return -EINVAL;
tx[0] = mcp->addr | 0x01;
tx[1] = reg;
tmp = (u8 *)vals;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n);
if (status >= 0) {
while (n--)
vals[n] = tmp[n]; /* expand to 16bit */
@@ -191,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
tx[0] = mcp->addr | 0x01;
tx[1] = reg << 1;
- status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
return (status < 0) ? status : (rx[0] | (rx[1] << 8));
}
@@ -203,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
tx[1] = reg << 1;
tx[2] = val;
tx[3] = val >> 8;
- return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
+ return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
}
static int
@@ -212,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
u8 tx[2];
int status;
- if ((n + reg) > sizeof mcp->cache)
+ if ((n + reg) > sizeof(mcp->cache))
return -EINVAL;
tx[0] = mcp->addr | 0x01;
tx[1] = reg << 1;
- status = spi_write_then_read(mcp->data, tx, sizeof tx,
+ status = spi_write_then_read(mcp->data, tx, sizeof(tx),
(u8 *)vals, n * 2);
if (status >= 0) {
while (n--)
@@ -314,6 +337,195 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
}
/*----------------------------------------------------------------------*/
+static irqreturn_t mcp23s08_irq(int irq, void *data)
+{
+ struct mcp23s08 *mcp = data;
+ int intcap, intf, i;
+ unsigned int child_irq;
+
+ mutex_lock(&mcp->lock);
+ intf = mcp->ops->read(mcp, MCP_INTF);
+ if (intf < 0) {
+ mutex_unlock(&mcp->lock);
+ return IRQ_HANDLED;
+ }
+
+ mcp->cache[MCP_INTF] = intf;
+
+ intcap = mcp->ops->read(mcp, MCP_INTCAP);
+ if (intcap < 0) {
+ mutex_unlock(&mcp->lock);
+ return IRQ_HANDLED;
+ }
+
+ mcp->cache[MCP_INTCAP] = intcap;
+ mutex_unlock(&mcp->lock);
+
+
+ for (i = 0; i < mcp->chip.ngpio; i++) {
+ if ((BIT(i) & mcp->cache[MCP_INTF]) &&
+ ((BIT(i) & intcap & mcp->irq_rise) ||
+ (mcp->irq_fall & ~intcap & BIT(i)))) {
+ child_irq = irq_find_mapping(mcp->irq_domain, i);
+ handle_nested_irq(child_irq);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
+
+ return irq_find_mapping(mcp->irq_domain, offset);
+}
+
+static void mcp23s08_irq_mask(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ unsigned int pos = data->hwirq;
+
+ mcp->cache[MCP_GPINTEN] &= ~BIT(pos);
+}
+
+static void mcp23s08_irq_unmask(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ unsigned int pos = data->hwirq;
+
+ mcp->cache[MCP_GPINTEN] |= BIT(pos);
+}
+
+static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ unsigned int pos = data->hwirq;
+ int status = 0;
+
+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+ mcp->cache[MCP_INTCON] &= ~BIT(pos);
+ mcp->irq_rise |= BIT(pos);
+ mcp->irq_fall |= BIT(pos);
+ } else if (type & IRQ_TYPE_EDGE_RISING) {
+ mcp->cache[MCP_INTCON] &= ~BIT(pos);
+ mcp->irq_rise |= BIT(pos);
+ mcp->irq_fall &= ~BIT(pos);
+ } else if (type & IRQ_TYPE_EDGE_FALLING) {
+ mcp->cache[MCP_INTCON] &= ~BIT(pos);
+ mcp->irq_rise &= ~BIT(pos);
+ mcp->irq_fall |= BIT(pos);
+ } else
+ return -EINVAL;
+
+ return status;
+}
+
+static void mcp23s08_irq_bus_lock(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&mcp->irq_lock);
+}
+
+static void mcp23s08_irq_bus_unlock(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&mcp->lock);
+ mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]);
+ mcp->ops->write(mcp, MCP_DEFVAL, mcp->cache[MCP_DEFVAL]);
+ mcp->ops->write(mcp, MCP_INTCON, mcp->cache[MCP_INTCON]);
+ mutex_unlock(&mcp->lock);
+ mutex_unlock(&mcp->irq_lock);
+}
+
+static int mcp23s08_irq_reqres(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+
+ if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) {
+ dev_err(mcp->chip.dev,
+ "unable to lock HW IRQ %lu for IRQ usage\n",
+ data->hwirq);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void mcp23s08_irq_relres(struct irq_data *data)
+{
+ struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+
+ gpio_unlock_as_irq(&mcp->chip, data->hwirq);
+}
+
+static struct irq_chip mcp23s08_irq_chip = {
+ .name = "gpio-mcp23xxx",
+ .irq_mask = mcp23s08_irq_mask,
+ .irq_unmask = mcp23s08_irq_unmask,
+ .irq_set_type = mcp23s08_irq_set_type,
+ .irq_bus_lock = mcp23s08_irq_bus_lock,
+ .irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
+ .irq_request_resources = mcp23s08_irq_reqres,
+ .irq_release_resources = mcp23s08_irq_relres,
+};
+
+static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
+{
+ struct gpio_chip *chip = &mcp->chip;
+ int err, irq, j;
+
+ mutex_init(&mcp->irq_lock);
+
+ mcp->irq_domain = irq_domain_add_linear(chip->of_node, chip->ngpio,
+ &irq_domain_simple_ops, mcp);
+ if (!mcp->irq_domain)
+ return -ENODEV;
+
+ err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ dev_name(chip->dev), mcp);
+ if (err != 0) {
+ dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
+ mcp->irq, err);
+ return err;
+ }
+
+ chip->to_irq = mcp23s08_gpio_to_irq;
+
+ for (j = 0; j < mcp->chip.ngpio; j++) {
+ irq = irq_create_mapping(mcp->irq_domain, j);
+ irq_set_lockdep_class(irq, &gpio_lock_class);
+ irq_set_chip_data(irq, mcp);
+ irq_set_chip(irq, &mcp23s08_irq_chip);
+ irq_set_nested_thread(irq, true);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+ }
+ return 0;
+}
+
+static void mcp23s08_irq_teardown(struct mcp23s08 *mcp)
+{
+ unsigned int irq, i;
+
+ free_irq(mcp->irq, mcp);
+
+ for (i = 0; i < mcp->chip.ngpio; i++) {
+ irq = irq_find_mapping(mcp->irq_domain, i);
+ if (irq > 0)
+ irq_dispose_mapping(irq);
+ }
+
+ irq_domain_remove(mcp->irq_domain);
+}
+
+/*----------------------------------------------------------------------*/
#ifdef CONFIG_DEBUG_FS
@@ -355,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
(mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
/* NOTE: ignoring the irq-related registers */
- seq_printf(s, "\n");
+ seq_puts(s, "\n");
}
done:
mutex_unlock(&mcp->lock);
@@ -368,10 +580,11 @@ done:
/*----------------------------------------------------------------------*/
static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
- void *data, unsigned addr,
- unsigned type, unsigned base, unsigned pullups)
+ void *data, unsigned addr, unsigned type,
+ unsigned base, unsigned pullups)
{
int status;
+ bool mirror = false;
mutex_init(&mcp->lock);
@@ -383,6 +596,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->chip.direction_output = mcp23s08_direction_output;
mcp->chip.set = mcp23s08_set;
mcp->chip.dbg_show = mcp23s08_dbg_show;
+#ifdef CONFIG_OF
+ mcp->chip.of_gpio_n_cells = 2;
+ mcp->chip.of_node = dev->of_node;
+#endif
switch (type) {
#ifdef CONFIG_SPI_MASTER
@@ -399,7 +616,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
break;
#endif /* CONFIG_SPI_MASTER */
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
case MCP_TYPE_008:
mcp->ops = &mcp23008_ops;
mcp->chip.ngpio = 8;
@@ -419,20 +636,32 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
}
mcp->chip.base = base;
- mcp->chip.can_sleep = 1;
+ mcp->chip.can_sleep = true;
mcp->chip.dev = dev;
mcp->chip.owner = THIS_MODULE;
/* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
* and MCP_IOCON.HAEN = 1, so we work with all chips.
*/
+
status = mcp->ops->read(mcp, MCP_IOCON);
if (status < 0)
goto fail;
- if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) {
+
+ mcp->irq_controller = of_property_read_bool(mcp->chip.of_node,
+ "interrupt-controller");
+ if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
+ mirror = of_property_read_bool(mcp->chip.of_node,
+ "microchip,irq-mirror");
+
+ if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
/* mcp23s17 has IOCON twice, make sure they are in sync */
status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
status |= IOCON_HAEN | (IOCON_HAEN << 8);
+ status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8));
+ if (mirror)
+ status |= IOCON_MIRROR | (IOCON_MIRROR << 8);
+
status = mcp->ops->write(mcp, MCP_IOCON, status);
if (status < 0)
goto fail;
@@ -464,6 +693,16 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
}
status = gpiochip_add(&mcp->chip);
+ if (status < 0)
+ goto fail;
+
+ if (mcp->irq && mcp->irq_controller) {
+ status = mcp23s08_irq_setup(mcp);
+ if (status) {
+ mcp23s08_irq_teardown(mcp);
+ goto fail;
+ }
+ }
fail:
if (status < 0)
dev_dbg(dev, "can't setup chip %d, --> %d\n",
@@ -473,28 +712,90 @@ fail:
/*----------------------------------------------------------------------*/
-#ifdef CONFIG_I2C
+#ifdef CONFIG_OF
+#ifdef CONFIG_SPI_MASTER
+static const struct of_device_id mcp23s08_spi_of_match[] = {
+ {
+ .compatible = "microchip,mcp23s08",
+ .data = (void *) MCP_TYPE_S08,
+ },
+ {
+ .compatible = "microchip,mcp23s17",
+ .data = (void *) MCP_TYPE_S17,
+ },
+/* NOTE: The use of the mcp prefix is deprecated and will be removed. */
+ {
+ .compatible = "mcp,mcp23s08",
+ .data = (void *) MCP_TYPE_S08,
+ },
+ {
+ .compatible = "mcp,mcp23s17",
+ .data = (void *) MCP_TYPE_S17,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match);
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+static const struct of_device_id mcp23s08_i2c_of_match[] = {
+ {
+ .compatible = "microchip,mcp23008",
+ .data = (void *) MCP_TYPE_008,
+ },
+ {
+ .compatible = "microchip,mcp23017",
+ .data = (void *) MCP_TYPE_017,
+ },
+/* NOTE: The use of the mcp prefix is deprecated and will be removed. */
+ {
+ .compatible = "mcp,mcp23008",
+ .data = (void *) MCP_TYPE_008,
+ },
+ {
+ .compatible = "mcp,mcp23017",
+ .data = (void *) MCP_TYPE_017,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
+#endif
+#endif /* CONFIG_OF */
+
-static int __devinit mcp230xx_probe(struct i2c_client *client,
+#if IS_ENABLED(CONFIG_I2C)
+
+static int mcp230xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mcp23s08_platform_data *pdata;
struct mcp23s08 *mcp;
- int status;
-
- pdata = client->dev.platform_data;
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&client->dev, "invalid or missing platform data\n");
- return -EINVAL;
+ int status, base, pullups;
+ const struct of_device_id *match;
+
+ match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
+ &client->dev);
+ pdata = dev_get_platdata(&client->dev);
+ if (match || !pdata) {
+ base = -1;
+ pullups = 0;
+ client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
+ } else {
+ if (!gpio_is_valid(pdata->base)) {
+ dev_dbg(&client->dev, "invalid platform data\n");
+ return -EINVAL;
+ }
+ base = pdata->base;
+ pullups = pdata->chip[0].pullups;
}
- mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
+ mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
if (!mcp)
return -ENOMEM;
+ mcp->irq = client->irq;
status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
- id->driver_data, pdata->base,
- pdata->chip[0].pullups);
+ id->driver_data, base, pullups);
if (status)
goto fail;
@@ -508,11 +809,14 @@ fail:
return status;
}
-static int __devexit mcp230xx_remove(struct i2c_client *client)
+static int mcp230xx_remove(struct i2c_client *client)
{
struct mcp23s08 *mcp = i2c_get_clientdata(client);
int status;
+ if (client->irq && mcp->irq_controller)
+ mcp23s08_irq_teardown(mcp);
+
status = gpiochip_remove(&mcp->chip);
if (status == 0)
kfree(mcp);
@@ -531,9 +835,10 @@ static struct i2c_driver mcp230xx_driver = {
.driver = {
.name = "mcp230xx",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mcp23s08_i2c_of_match),
},
.probe = mcp230xx_probe,
- .remove = __devexit_p(mcp230xx_remove),
+ .remove = mcp230xx_remove,
.id_table = mcp230xx_id,
};
@@ -562,53 +867,89 @@ static int mcp23s08_probe(struct spi_device *spi)
{
struct mcp23s08_platform_data *pdata;
unsigned addr;
- unsigned chips = 0;
+ int chips = 0;
struct mcp23s08_driver_data *data;
int status, type;
- unsigned base;
-
- type = spi_get_device_id(spi)->driver_data;
-
- pdata = spi->dev.platform_data;
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&spi->dev, "invalid or missing platform data\n");
- return -EINVAL;
- }
+ unsigned base = -1,
+ ngpio = 0,
+ pullups[ARRAY_SIZE(pdata->chip)];
+ const struct of_device_id *match;
+ u32 spi_present_mask = 0;
+
+ match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev);
+ if (match) {
+ type = (int)(uintptr_t)match->data;
+ status = of_property_read_u32(spi->dev.of_node,
+ "microchip,spi-present-mask", &spi_present_mask);
+ if (status) {
+ status = of_property_read_u32(spi->dev.of_node,
+ "mcp,spi-present-mask", &spi_present_mask);
+ if (status) {
+ dev_err(&spi->dev,
+ "DT has no spi-present-mask\n");
+ return -ENODEV;
+ }
+ }
+ if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) {
+ dev_err(&spi->dev, "invalid spi-present-mask\n");
+ return -ENODEV;
+ }
- for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
- if (!pdata->chip[addr].is_present)
- continue;
- chips++;
- if ((type == MCP_TYPE_S08) && (addr > 3)) {
- dev_err(&spi->dev,
- "mcp23s08 only supports address 0..3\n");
+ for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
+ pullups[addr] = 0;
+ if (spi_present_mask & (1 << addr))
+ chips++;
+ }
+ } else {
+ type = spi_get_device_id(spi)->driver_data;
+ pdata = dev_get_platdata(&spi->dev);
+ if (!pdata || !gpio_is_valid(pdata->base)) {
+ dev_dbg(&spi->dev,
+ "invalid or missing platform data\n");
return -EINVAL;
}
+
+ for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
+ if (!pdata->chip[addr].is_present)
+ continue;
+ chips++;
+ if ((type == MCP_TYPE_S08) && (addr > 3)) {
+ dev_err(&spi->dev,
+ "mcp23s08 only supports address 0..3\n");
+ return -EINVAL;
+ }
+ spi_present_mask |= 1 << addr;
+ pullups[addr] = pdata->chip[addr].pullups;
+ }
+
+ base = pdata->base;
}
+
if (!chips)
return -ENODEV;
- data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08),
+ data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08),
GFP_KERNEL);
if (!data)
return -ENOMEM;
spi_set_drvdata(spi, data);
- base = pdata->base;
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
- if (!pdata->chip[addr].is_present)
+ if (!(spi_present_mask & (1 << addr)))
continue;
chips--;
data->mcp[addr] = &data->chip[chips];
status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
0x40 | (addr << 1), type, base,
- pdata->chip[addr].pullups);
+ pullups[addr]);
if (status < 0)
goto fail;
- base += (type == MCP_TYPE_S17) ? 16 : 8;
+ if (base != -1)
+ base += (type == MCP_TYPE_S17) ? 16 : 8;
+ ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
}
- data->ngpio = base - pdata->base;
+ data->ngpio = ngpio;
/* NOTE: these chips have a relatively sane IRQ framework, with
* per-signal masking and level/edge triggering. It's not yet
@@ -668,6 +1009,7 @@ static struct spi_driver mcp23s08_driver = {
.driver = {
.name = "mcp23s08",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mcp23s08_spi_of_match),
},
};
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 6a29ee1847b..d51329d23d3 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -242,7 +242,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
gpio->dbg_show = NULL;
gpio->base = -1;
gpio->ngpio = num_port;
- gpio->can_sleep = 0;
+ gpio->can_sleep = false;
gpio->to_irq = ioh_gpio_to_irq;
}
@@ -385,7 +385,7 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
return ret;
}
-static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
+static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
unsigned int irq_start, unsigned int num)
{
struct irq_chip_generic *gc;
@@ -406,7 +406,7 @@ static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
-static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
+static int ioh_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
@@ -465,6 +465,7 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
dev_warn(&pdev->dev,
"ml_ioh_gpio: Failed to get IRQ base num\n");
chip->irq_base = -1;
+ ret = irq_base;
goto err_irq_alloc_descs;
}
chip->irq_base = irq_base;
@@ -496,8 +497,7 @@ err_irq_alloc_descs:
err_gpiochip_add:
while (--i >= 0) {
chip--;
- ret = gpiochip_remove(&chip->gpio);
- if (ret)
+ if (gpiochip_remove(&chip->gpio))
dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
}
kfree(chip_save);
@@ -517,7 +517,7 @@ err_pci_enable:
return ret;
}
-static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
+static void ioh_gpio_remove(struct pci_dev *pdev)
{
int err;
int i;
@@ -596,7 +596,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
#define ioh_gpio_resume NULL
#endif
-static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = {
+static const struct pci_device_id ioh_gpio_pcidev_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) },
{ 0, }
};
@@ -606,7 +606,7 @@ static struct pci_driver ioh_gpio_driver = {
.name = "ml_ioh_gpio",
.id_table = ioh_gpio_pcidev_id,
.probe = ioh_gpio_probe,
- .remove = __devexit_p(ioh_gpio_remove),
+ .remove = ioh_gpio_remove,
.suspend = ioh_gpio_suspend,
.resume = ioh_gpio_resume
};
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
new file mode 100644
index 00000000000..4661e181be0
--- /dev/null
+++ b/drivers/gpio/gpio-moxart.c
@@ -0,0 +1,154 @@
+/*
+ * MOXA ART SoCs GPIO driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+
+#define GPIO_DATA_OUT 0x00
+#define GPIO_DATA_IN 0x04
+#define GPIO_PIN_DIRECTION 0x08
+
+struct moxart_gpio_chip {
+ struct gpio_chip gpio;
+ void __iomem *base;
+};
+
+static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct moxart_gpio_chip, gpio);
+}
+
+static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(offset);
+}
+
+static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(offset);
+}
+
+static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ void __iomem *ioaddr = gc->base + GPIO_DATA_OUT;
+ u32 reg = readl(ioaddr);
+
+ if (value)
+ reg = reg | BIT(offset);
+ else
+ reg = reg & ~BIT(offset);
+
+ writel(reg, ioaddr);
+}
+
+static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ u32 ret = readl(gc->base + GPIO_PIN_DIRECTION);
+
+ if (ret & BIT(offset))
+ return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset));
+ else
+ return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset));
+}
+
+static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
+
+ writel(readl(ioaddr) & ~BIT(offset), ioaddr);
+ return 0;
+}
+
+static int moxart_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
+ void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
+
+ moxart_gpio_set(chip, offset, value);
+ writel(readl(ioaddr) | BIT(offset), ioaddr);
+ return 0;
+}
+
+static struct gpio_chip moxart_template_chip = {
+ .label = "moxart-gpio",
+ .request = moxart_gpio_request,
+ .free = moxart_gpio_free,
+ .direction_input = moxart_gpio_direction_input,
+ .direction_output = moxart_gpio_direction_output,
+ .set = moxart_gpio_set,
+ .get = moxart_gpio_get,
+ .ngpio = 32,
+ .owner = THIS_MODULE,
+};
+
+static int moxart_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct moxart_gpio_chip *mgc;
+ int ret;
+
+ mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL);
+ if (!mgc)
+ return -ENOMEM;
+ mgc->gpio = moxart_template_chip;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mgc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mgc->base))
+ return PTR_ERR(mgc->base);
+
+ mgc->gpio.dev = dev;
+
+ ret = gpiochip_add(&mgc->gpio);
+ if (ret) {
+ dev_err(dev, "%s: gpiochip_add failed\n",
+ dev->of_node->full_name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id moxart_gpio_match[] = {
+ { .compatible = "moxa,moxart-gpio" },
+ { }
+};
+
+static struct platform_driver moxart_gpio_driver = {
+ .driver = {
+ .name = "moxart-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = moxart_gpio_match,
+ },
+ .probe = moxart_gpio_probe,
+};
+module_platform_driver(moxart_gpio_driver);
+
+MODULE_DESCRIPTION("MOXART GPIO chip driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 2c7cef367fc..42647f26c9e 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -148,7 +148,7 @@ mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
-static int __devinit mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
+static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
{
struct mpc52xx_gpiochip *chip;
struct mpc52xx_gpio_wkup __iomem *regs;
@@ -308,7 +308,7 @@ mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
return 0;
}
-static int __devinit mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev)
+static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev)
{
struct mpc52xx_gpiochip *chip;
struct gpio_chip *gc;
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index 9ae29cc0d17..d7d6d72eba3 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/irq.h>
@@ -69,10 +70,14 @@ static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
u32 val;
struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ u32 out_mask, out_shadow;
- val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
+ out_mask = in_be32(mm->regs + GPIO_DIR);
- return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
+ val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
+ out_shadow = mpc8xxx_gc->data & out_mask;
+
+ return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
}
static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
@@ -282,17 +287,16 @@ static struct irq_chip mpc8xxx_irq_chip = {
.irq_set_type = mpc8xxx_irq_set_type,
};
-static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
+static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
if (mpc8xxx_gc->of_dev_id_data)
mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
- irq_set_chip_data(virq, h->host_data);
- irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
- irq_set_irq_type(virq, IRQ_TYPE_NONE);
+ irq_set_chip_data(irq, h->host_data);
+ irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq);
return 0;
}
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
index b3898628586..8f70ded82a2 100644
--- a/drivers/gpio/gpio-msic.c
+++ b/drivers/gpio/gpio-msic.c
@@ -256,10 +256,10 @@ static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
chip->irq_eoi(data);
}
-static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
+static int platform_msic_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct intel_msic_gpio_pdata *pdata = dev->platform_data;
+ struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev);
struct msic_gpio *mg;
int irq = platform_get_irq(pdev, 0);
int retval;
@@ -292,7 +292,7 @@ static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
mg->chip.to_irq = msic_gpio_to_irq;
mg->chip.base = pdata->gpio_base;
mg->chip.ngpio = MSIC_NUM_GPIO;
- mg->chip.can_sleep = 1;
+ mg->chip.can_sleep = true;
mg->chip.dev = dev;
mutex_init(&mg->buslock);
@@ -305,10 +305,9 @@ static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
for (i = 0; i < mg->chip.ngpio; i++) {
irq_set_chip_data(i + mg->irq_base, mg);
- irq_set_chip_and_handler_name(i + mg->irq_base,
- &msic_irqchip,
- handle_simple_irq,
- "demux");
+ irq_set_chip_and_handler(i + mg->irq_base,
+ &msic_irqchip,
+ handle_simple_irq);
}
irq_set_chained_handler(mg->irq, msic_gpio_irq_handler);
irq_set_handler_data(mg->irq, mg);
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index 52a4d4286eb..73b73969d36 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * 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
@@ -19,9 +19,11 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
-#include <mach/cpu.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+
#include <mach/msm_gpiomux.h>
-#include <mach/msm_iomap.h>
/* see 80-VA736-2 Rev C pp 695-751
**
@@ -34,10 +36,10 @@
** macros.
*/
-#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
-#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
-#define MSM_GPIO1_SHADOW_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
-#define MSM_GPIO2_SHADOW_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#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
@@ -276,16 +278,14 @@
#define MSM_GPIO_BANK(soc, bank, first, last) \
{ \
- .regs = { \
- .out = soc##_GPIO_OUT_##bank, \
- .in = soc##_GPIO_IN_##bank, \
- .int_status = soc##_GPIO_INT_STATUS_##bank, \
- .int_clear = soc##_GPIO_INT_CLEAR_##bank, \
- .int_en = soc##_GPIO_INT_EN_##bank, \
- .int_edge = soc##_GPIO_INT_EDGE_##bank, \
- .int_pos = soc##_GPIO_INT_POS_##bank, \
- .oe = soc##_GPIO_OE_##bank, \
- }, \
+ .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, \
@@ -301,39 +301,57 @@
#define MSM_GPIO_BROKEN_INT_CLEAR 1
-struct msm_gpio_regs {
- void __iomem *out;
- void __iomem *in;
- void __iomem *int_status;
- void __iomem *int_clear;
- void __iomem *int_en;
- void __iomem *int_edge;
- void __iomem *int_pos;
- void __iomem *oe;
+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;
- struct msm_gpio_regs regs;
+ 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 = readl(msm_chip->regs.out);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_OUT);
if (on)
- writel(val | mask, msm_chip->regs.out);
+ msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_OUT);
else
- writel(val & ~mask, msm_chip->regs.out);
+ msm_gpio_writel(msm_chip, val & ~mask, MSM_GPIO_OUT);
return 0;
}
@@ -342,13 +360,13 @@ 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 = readl(msm_chip->regs.in);
- pol = readl(msm_chip->regs.int_pos);
+ 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);
- writel(pol, msm_chip->regs.int_pos);
- intstat = readl(msm_chip->regs.int_status);
- val2 = readl(msm_chip->regs.in);
+ 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);
@@ -365,10 +383,11 @@ static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
/* 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 |= readl(msm_chip->regs.int_status);
+ msm_chip->int_status_copy |=
+ msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
msm_chip->int_status_copy &= ~bit;
#endif
- writel(bit, msm_chip->regs.int_clear);
+ msm_gpio_writel(msm_chip, bit, MSM_GPIO_INT_CLEAR);
msm_gpio_update_both_edge_detect(msm_chip);
return 0;
}
@@ -377,10 +396,12 @@ 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);
- writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+ 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;
}
@@ -390,11 +411,13 @@ 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);
- writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+ 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;
}
@@ -404,7 +427,7 @@ 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 (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+ 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)
@@ -450,6 +473,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x01[] = {
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),
@@ -461,6 +489,11 @@ static struct msm_gpio_chip msm_gpio_chips_msm7x30[] = {
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),
@@ -472,6 +505,11 @@ static struct msm_gpio_chip msm_gpio_chips_qsd8x50[] = {
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;
@@ -490,10 +528,10 @@ static void msm_gpio_irq_mask(struct irq_data *d)
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
- if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+ 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);
- writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+ msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
@@ -505,10 +543,10 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
spin_lock_irqsave(&msm_chip->lock, irq_flags);
/* level triggered interrupts are also latched */
- if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+ 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);
- writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+ msm_gpio_writel(msm_chip, msm_chip->int_enable[0], MSM_GPIO_INT_EN);
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
}
@@ -537,12 +575,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
unsigned val, mask = BIT(offset);
spin_lock_irqsave(&msm_chip->lock, irq_flags);
- val = readl(msm_chip->regs.int_edge);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_EDGE);
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
- writel(val | mask, msm_chip->regs.int_edge);
+ msm_gpio_writel(msm_chip, val | mask, MSM_GPIO_INT_EDGE);
__irq_set_handler_locked(d->irq, handle_edge_irq);
} else {
- writel(val & ~mask, msm_chip->regs.int_edge);
+ 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) {
@@ -550,11 +588,12 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
msm_gpio_update_both_edge_detect(msm_chip);
} else {
msm_chip->both_edge_detect &= ~mask;
- val = readl(msm_chip->regs.int_pos);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_POS);
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
- writel(val | mask, msm_chip->regs.int_pos);
+ val |= mask;
else
- writel(val & ~mask, msm_chip->regs.int_pos);
+ val &= ~mask;
+ msm_gpio_writel(msm_chip, val, MSM_GPIO_INT_POS);
}
spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
return 0;
@@ -567,7 +606,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
for (i = 0; i < msm_gpio_count; i++) {
struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
- val = readl(msm_chip->regs.int_status);
+ val = msm_gpio_readl(msm_chip, MSM_GPIO_INT_STATUS);
val &= msm_chip->int_enable[0];
while (val) {
mask = val & -val;
@@ -592,22 +631,36 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_set_type = msm_gpio_irq_set_type,
};
-static int __init msm_init_gpio(void)
+static int gpio_msm_v1_probe(struct platform_device *pdev)
{
int i, j = 0;
-
- if (cpu_is_msm7x01()) {
- msm_gpio_chips = msm_gpio_chips_msm7x01;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x01);
- } else if (cpu_is_msm7x30()) {
- msm_gpio_chips = msm_gpio_chips_msm7x30;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_msm7x30);
- } else if (cpu_is_qsd8x50()) {
- msm_gpio_chips = msm_gpio_chips_qsd8x50;
- msm_gpio_count = ARRAY_SIZE(msm_gpio_chips_qsd8x50);
- } else {
- return 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 >=
@@ -621,16 +674,42 @@ static int __init msm_init_gpio(void)
}
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);
- writel(0, msm_gpio_chips[i].regs.int_en);
+ msm_gpio_writel(&msm_gpio_chips[i], 0, MSM_GPIO_INT_EN);
gpiochip_add(&msm_gpio_chips[i].chip);
}
- irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
- irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
- irq_set_irq_wake(INT_GPIO_GROUP1, 1);
- irq_set_irq_wake(INT_GPIO_GROUP2, 2);
+ 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, 2);
return 0;
}
-postcore_initcall(msm_init_gpio);
+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",
+ .owner = THIS_MODULE,
+ },
+ .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-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index 38305beb437..a3351acd496 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -19,19 +19,21 @@
#include <linux/bitmap.h>
#include <linux/bitops.h>
+#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/module.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <linux/slab.h>
-#include <asm/mach/irq.h>
-
-#include <mach/msm_gpiomux.h>
-#include <mach/msm_iomap.h>
+#define MAX_NR_GPIO 300
/* Bits of interest in the GPIO_IN_OUT register.
*/
@@ -78,13 +80,6 @@ enum {
TARGET_PROC_NONE = 7,
};
-
-#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
-#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
-#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
-#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
-#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
-
/**
* struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
*
@@ -103,11 +98,27 @@ enum {
*/
struct msm_gpio_dev {
struct gpio_chip gpio_chip;
- DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS);
- DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS);
- DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS);
+ DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
+ DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
+ DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
+ struct irq_domain *domain;
+ int summary_irq;
+ void __iomem *msm_tlmm_base;
};
+static struct msm_gpio_dev msm_gpio;
+
+#define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \
+ (0x04 * (gpio)))
+#define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \
+ (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \
+ (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \
+ (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \
+ (0x10 * (gpio)))
+
static DEFINE_SPINLOCK(tlmm_lock);
static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
@@ -160,37 +171,29 @@ static int msm_gpio_direction_output(struct gpio_chip *chip,
static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- return msm_gpiomux_get(chip->base + offset);
+ return 0;
}
static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
{
- msm_gpiomux_put(chip->base + offset);
+ return;
}
static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return MSM_GPIO_TO_INT(chip->base + offset);
+ struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+ struct irq_domain *domain = g_dev->domain;
+
+ return irq_create_mapping(domain, offset);
}
static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
{
- return irq - MSM_GPIO_TO_INT(chip->base);
+ struct irq_data *irq_data = irq_get_irq_data(irq);
+
+ return irq_data->hwirq;
}
-static struct msm_gpio_dev msm_gpio = {
- .gpio_chip = {
- .base = 0,
- .ngpio = NR_GPIO_IRQS,
- .direction_input = msm_gpio_direction_input,
- .direction_output = msm_gpio_direction_output,
- .get = msm_gpio_get,
- .set = msm_gpio_set,
- .to_irq = msm_gpio_to_irq,
- .request = msm_gpio_request,
- .free = msm_gpio_free,
- },
-};
/* For dual-edge interrupts in software, since the hardware has no
* such support:
@@ -228,9 +231,9 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio)
if (intstat || val == val2)
return;
} while (loop_limit-- > 0);
- pr_err("dual-edge irq failed to stabilize, "
+ pr_err("%s: dual-edge irq failed to stabilize, "
"interrupts dropped. %#08x != %#08x\n",
- val, val2);
+ __func__, val, val2);
}
static void msm_gpio_irq_ack(struct irq_data *d)
@@ -249,7 +252,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
spin_lock_irqsave(&tlmm_lock, irq_flags);
writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
- clear_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+ clear_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio));
__clear_bit(gpio, msm_gpio.enabled_irqs);
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
}
@@ -261,7 +264,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
spin_lock_irqsave(&tlmm_lock, irq_flags);
__set_bit(gpio, msm_gpio.enabled_irqs);
- set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+ set_gpio_bits(BIT(INTR_RAW_STATUS_EN) | BIT(INTR_ENABLE), GPIO_INTR_CFG(gpio));
writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
}
@@ -317,10 +320,10 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_enter(chip, desc);
- for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) {
+ for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) {
if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
- generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
- i));
+ generic_handle_irq(irq_find_mapping(msm_gpio.domain,
+ i));
}
chained_irq_exit(chip, desc);
@@ -331,13 +334,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
if (on) {
- if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
- irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1);
+ if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
+ irq_set_irq_wake(msm_gpio.summary_irq, 1);
set_bit(gpio, msm_gpio.wake_irqs);
} else {
clear_bit(gpio, msm_gpio.wake_irqs);
- if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS))
- irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0);
+ if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
+ irq_set_irq_wake(msm_gpio.summary_irq, 0);
}
return 0;
@@ -352,78 +355,110 @@ static struct irq_chip msm_gpio_irq_chip = {
.irq_set_wake = msm_gpio_irq_set_wake,
};
-static int __devinit msm_gpio_probe(struct platform_device *dev)
+static struct lock_class_key msm_gpio_lock_class;
+
+static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- int i, irq, ret;
+ irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+ irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+static const struct irq_domain_ops msm_gpio_irq_domain_ops = {
+ .xlate = irq_domain_xlate_twocell,
+ .map = msm_gpio_irq_domain_map,
+};
+
+static int msm_gpio_probe(struct platform_device *pdev)
+{
+ int ret, ngpio;
+ struct resource *res;
+
+ if (of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
+ dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__);
+ return -EINVAL;
+ }
+
+ if (ngpio > MAX_NR_GPIO)
+ WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n");
+
+ bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO);
+ bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO);
+ bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(msm_gpio.msm_tlmm_base))
+ return PTR_ERR(msm_gpio.msm_tlmm_base);
+
+ msm_gpio.gpio_chip.ngpio = ngpio;
+ msm_gpio.gpio_chip.label = pdev->name;
+ msm_gpio.gpio_chip.dev = &pdev->dev;
+ msm_gpio.gpio_chip.base = 0;
+ msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input;
+ msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output;
+ msm_gpio.gpio_chip.get = msm_gpio_get;
+ msm_gpio.gpio_chip.set = msm_gpio_set;
+ msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq;
+ msm_gpio.gpio_chip.request = msm_gpio_request;
+ msm_gpio.gpio_chip.free = msm_gpio_free;
- bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
- bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS);
- bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS);
- msm_gpio.gpio_chip.label = dev->name;
ret = gpiochip_add(&msm_gpio.gpio_chip);
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret);
return ret;
+ }
- for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
- irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
- irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
+ msm_gpio.summary_irq = platform_get_irq(pdev, 0);
+ if (msm_gpio.summary_irq < 0) {
+ dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n");
+ return msm_gpio.summary_irq;
}
- irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ,
- msm_summary_irq_handler);
+ msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
+ &msm_gpio_irq_domain_ops,
+ &msm_gpio);
+ if (!msm_gpio.domain)
+ return -ENODEV;
+
+ irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler);
+
return 0;
}
-static int __devexit msm_gpio_remove(struct platform_device *dev)
+static const struct of_device_id msm_gpio_of_match[] = {
+ { .compatible = "qcom,msm-gpio", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, msm_gpio_of_match);
+
+static int msm_gpio_remove(struct platform_device *dev)
{
int ret = gpiochip_remove(&msm_gpio.gpio_chip);
if (ret < 0)
return ret;
- irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL);
+ irq_set_handler(msm_gpio.summary_irq, NULL);
return 0;
}
static struct platform_driver msm_gpio_driver = {
.probe = msm_gpio_probe,
- .remove = __devexit_p(msm_gpio_remove),
+ .remove = msm_gpio_remove,
.driver = {
.name = "msmgpio",
.owner = THIS_MODULE,
+ .of_match_table = msm_gpio_of_match,
},
};
-static struct platform_device msm_device_gpio = {
- .name = "msmgpio",
- .id = -1,
-};
-
-static int __init msm_gpio_init(void)
-{
- int rc;
-
- rc = platform_driver_register(&msm_gpio_driver);
- if (!rc) {
- rc = platform_device_register(&msm_device_gpio);
- if (rc)
- platform_driver_unregister(&msm_gpio_driver);
- }
-
- return rc;
-}
-
-static void __exit msm_gpio_exit(void)
-{
- platform_device_unregister(&msm_device_gpio);
- platform_driver_unregister(&msm_gpio_driver);
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
+module_platform_driver(msm_gpio_driver)
MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 7a874129e5d..418e3865036 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -33,6 +33,7 @@
* interrupts.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/irq.h>
@@ -41,8 +42,9 @@
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/of_device.h>
-#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/irqchip/chained_irq.h>
/*
* GPIO unit register offsets.
@@ -78,7 +80,7 @@ struct mvebu_gpio_chip {
spinlock_t lock;
void __iomem *membase;
void __iomem *percpu_membase;
- unsigned int irqbase;
+ int irqbase;
struct irq_domain *domain;
int soc_variant;
};
@@ -92,6 +94,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
return mvchip->membase + GPIO_OUT_OFF;
}
+static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
+{
+ return mvchip->membase + GPIO_BLINK_EN_OFF;
+}
+
static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
{
return mvchip->membase + GPIO_IO_CONF_OFF;
@@ -111,7 +118,7 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
case MVEBU_GPIO_SOC_VARIANT_MV78200:
return mvchip->membase + GPIO_EDGE_CAUSE_OFF;
@@ -127,7 +134,7 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
return mvchip->membase + GPIO_EDGE_MASK_OFF;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
@@ -145,7 +152,7 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
{
int cpu;
- switch(mvchip->soc_variant) {
+ switch (mvchip->soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
return mvchip->membase + GPIO_LEVEL_MASK_OFF;
case MVEBU_GPIO_SOC_VARIANT_MV78200:
@@ -163,12 +170,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
* Functions implementing the gpio_chip methods
*/
-int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
+static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
{
return pinctrl_request_gpio(chip->base + pin);
}
-void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
+static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
{
pinctrl_free_gpio(chip->base + pin);
}
@@ -206,6 +213,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
return (u >> pin) & 1;
}
+static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct mvebu_gpio_chip *mvchip =
+ container_of(chip, struct mvebu_gpio_chip, chip);
+ unsigned long flags;
+ u32 u;
+
+ spin_lock_irqsave(&mvchip->lock, flags);
+ u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
+ if (value)
+ u |= 1 << pin;
+ else
+ u &= ~(1 << pin);
+ writel_relaxed(u, mvebu_gpioreg_blink(mvchip));
+ spin_unlock_irqrestore(&mvchip->lock, flags);
+}
+
static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
struct mvebu_gpio_chip *mvchip =
@@ -244,6 +268,9 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
if (ret)
return ret;
+ mvebu_gpio_blink(chip, pin, 0);
+ mvebu_gpio_set(chip, pin, value);
+
spin_lock_irqsave(&mvchip->lock, flags);
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
u &= ~(1 << pin);
@@ -375,7 +402,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
/*
* Configure interrupt polarity.
*/
- switch(type) {
+ switch (type) {
case IRQ_TYPE_EDGE_RISING:
case IRQ_TYPE_LEVEL_HIGH:
u = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
@@ -412,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
u32 cause, type;
int i;
if (mvchip == NULL)
return;
+ chained_irq_enter(chip, desc);
+
cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
@@ -431,7 +461,7 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
if (!(cause & (1 << i)))
continue;
- type = irqd_get_trigger_type(irq_get_irq_data(irq));
+ type = irq_get_trigger_type(irq);
if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
/* Swap polarity (race with GPIO line) */
u32 polarity;
@@ -440,35 +470,83 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
polarity ^= 1 << i;
writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
}
+
generic_handle_irq(irq);
}
+
+ chained_irq_exit(chip, desc);
}
-static struct platform_device_id mvebu_gpio_ids[] = {
- {
- .name = "orion-gpio",
- }, {
- .name = "mv78200-gpio",
- }, {
- .name = "armadaxp-gpio",
- }, {
- /* sentinel */
- },
-};
-MODULE_DEVICE_TABLE(platform, mvebu_gpio_ids);
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct mvebu_gpio_chip *mvchip =
+ container_of(chip, struct mvebu_gpio_chip, chip);
+ u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
+ int i;
-static struct of_device_id mvebu_gpio_of_match[] __devinitdata = {
+ out = readl_relaxed(mvebu_gpioreg_out(mvchip));
+ io_conf = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
+ blink = readl_relaxed(mvebu_gpioreg_blink(mvchip));
+ in_pol = readl_relaxed(mvebu_gpioreg_in_pol(mvchip));
+ data_in = readl_relaxed(mvebu_gpioreg_data_in(mvchip));
+ cause = readl_relaxed(mvebu_gpioreg_edge_cause(mvchip));
+ edg_msk = readl_relaxed(mvebu_gpioreg_edge_mask(mvchip));
+ lvl_msk = readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
+
+ for (i = 0; i < chip->ngpio; i++) {
+ const char *label;
+ u32 msk;
+ bool is_out;
+
+ label = gpiochip_is_requested(chip, i);
+ if (!label)
+ continue;
+
+ msk = 1 << i;
+ is_out = !(io_conf & msk);
+
+ seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label);
+
+ if (is_out) {
+ seq_printf(s, " out %s %s\n",
+ out & msk ? "hi" : "lo",
+ blink & msk ? "(blink )" : "");
+ continue;
+ }
+
+ seq_printf(s, " in %s (act %s) - IRQ",
+ (data_in ^ in_pol) & msk ? "hi" : "lo",
+ in_pol & msk ? "lo" : "hi");
+ if (!((edg_msk | lvl_msk) & msk)) {
+ seq_printf(s, " disabled\n");
+ continue;
+ }
+ if (edg_msk & msk)
+ seq_printf(s, " edge ");
+ if (lvl_msk & msk)
+ seq_printf(s, " level");
+ seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear ");
+ }
+}
+#else
+#define mvebu_gpio_dbg_show NULL
+#endif
+
+static const struct of_device_id mvebu_gpio_of_match[] = {
{
.compatible = "marvell,orion-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_ORION,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
},
{
.compatible = "marvell,mv78200-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_MV78200,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200,
},
{
.compatible = "marvell,armadaxp-gpio",
- .data = (void*) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
},
{
/* sentinel */
@@ -476,7 +554,7 @@ static struct of_device_id mvebu_gpio_of_match[] __devinitdata = {
};
MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match);
-static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
+static int mvebu_gpio_probe(struct platform_device *pdev)
{
struct mvebu_gpio_chip *mvchip;
const struct of_device_id *match;
@@ -484,6 +562,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
struct resource *res;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
+ struct clk *clk;
unsigned int ngpios;
int soc_variant;
int i, cpu, id;
@@ -494,17 +573,9 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (! res) {
- dev_err(&pdev->dev, "Cannot get memory resource\n");
- return -ENODEV;
- }
-
mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
- if (! mvchip){
- dev_err(&pdev->dev, "Cannot allocate memory\n");
+ if (!mvchip)
return -ENOMEM;
- }
if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
dev_err(&pdev->dev, "Missing ngpios OF property\n");
@@ -517,10 +588,16 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
return id;
}
+ clk = devm_clk_get(&pdev->dev, NULL);
+ /* Not all SoCs require a clock.*/
+ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+
mvchip->soc_variant = soc_variant;
mvchip->chip.label = dev_name(&pdev->dev);
mvchip->chip.dev = &pdev->dev;
mvchip->chip.request = mvebu_gpio_request;
+ mvchip->chip.free = mvebu_gpio_free;
mvchip->chip.direction_input = mvebu_gpio_direction_input;
mvchip->chip.get = mvebu_gpio_get;
mvchip->chip.direction_output = mvebu_gpio_direction_output;
@@ -528,41 +605,30 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
mvchip->chip.to_irq = mvebu_gpio_to_irq;
mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
mvchip->chip.ngpio = ngpios;
- mvchip->chip.can_sleep = 0;
-#ifdef CONFIG_OF
+ mvchip->chip.can_sleep = false;
mvchip->chip.of_node = np;
-#endif
+ mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
spin_lock_init(&mvchip->lock);
- mvchip->membase = devm_request_and_ioremap(&pdev->dev, res);
- if (! mvchip->membase) {
- dev_err(&pdev->dev, "Cannot ioremap\n");
- kfree(mvchip->chip.label);
- return -ENOMEM;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mvchip->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mvchip->membase))
+ return PTR_ERR(mvchip->membase);
/* The Armada XP has a second range of registers for the
* per-CPU registers */
if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (! res) {
- dev_err(&pdev->dev, "Cannot get memory resource\n");
- kfree(mvchip->chip.label);
- return -ENODEV;
- }
-
- mvchip->percpu_membase = devm_request_and_ioremap(&pdev->dev, res);
- if (! mvchip->percpu_membase) {
- dev_err(&pdev->dev, "Cannot ioremap\n");
- kfree(mvchip->chip.label);
- return -ENOMEM;
- }
+ mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
+ res);
+ if (IS_ERR(mvchip->percpu_membase))
+ return PTR_ERR(mvchip->percpu_membase);
}
/*
* Mask and clear GPIO interrupts.
*/
- switch(soc_variant) {
+ switch (soc_variant) {
case MVEBU_GPIO_SOC_VARIANT_ORION:
writel_relaxed(0, mvchip->membase + GPIO_EDGE_CAUSE_OFF);
writel_relaxed(0, mvchip->membase + GPIO_EDGE_MASK_OFF);
@@ -615,15 +681,13 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
if (mvchip->irqbase < 0) {
dev_err(&pdev->dev, "no irqs\n");
- kfree(mvchip->chip.label);
- return -ENOMEM;
+ return mvchip->irqbase;
}
gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
mvchip->membase, handle_level_irq);
- if (! gc) {
+ if (!gc) {
dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
- kfree(mvchip->chip.label);
return -ENOMEM;
}
@@ -644,12 +708,12 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;
- irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE,
+ irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
/* Setup irq domain on top of the generic chip. */
- mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
- mvchip->irqbase, 0,
+ mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
+ mvchip->irqbase,
&irq_domain_simple_ops,
mvchip);
if (!mvchip->domain) {
@@ -658,7 +722,6 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
IRQ_LEVEL | IRQ_NOPROBE);
kfree(gc);
- kfree(mvchip->chip.label);
return -ENODEV;
}
@@ -672,11 +735,5 @@ static struct platform_driver mvebu_gpio_driver = {
.of_match_table = mvebu_gpio_of_match,
},
.probe = mvebu_gpio_probe,
- .id_table = mvebu_gpio_ids,
};
-
-static int __init mvebu_gpio_init(void)
-{
- return platform_driver_register(&mvebu_gpio_driver);
-}
-postcore_initcall(mvebu_gpio_init);
+module_platform_driver(mvebu_gpio_driver);
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index 80f44bb64a8..db83b3c0a44 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -19,11 +19,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -32,7 +34,6 @@
#include <linux/of_device.h>
#include <linux/module.h>
#include <asm-generic/bug.h>
-#include <asm/mach/irq.h>
enum mxc_gpio_hwtype {
IMX1_GPIO, /* runs on i.mx1 */
@@ -291,6 +292,9 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{
u32 irq_msk, irq_stat;
struct mxc_gpio_port *port;
+ struct irq_chip *chip = irq_get_chip(irq);
+
+ chained_irq_enter(chip, desc);
/* walk through all interrupt status registers */
list_for_each_entry(port, &mxc_gpio_ports, node) {
@@ -302,6 +306,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc)
if (irq_stat)
mxc_gpio_irq_handler(port, irq_stat);
}
+ chained_irq_exit(chip, desc);
}
/*
@@ -356,7 +361,7 @@ static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
IRQ_NOREQUEST, 0);
}
-static void __devinit mxc_gpio_get_hw(struct platform_device *pdev)
+static void mxc_gpio_get_hw(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxc_gpio_dt_ids, &pdev->dev);
@@ -395,7 +400,7 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
return irq_find_mapping(port->domain, offset);
}
-static int __devinit mxc_gpio_probe(struct platform_device *pdev)
+static int mxc_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct mxc_gpio_port *port;
@@ -405,34 +410,19 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
mxc_gpio_get_hw(pdev);
- port = kzalloc(sizeof(struct mxc_gpio_port), GFP_KERNEL);
+ port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores) {
- err = -ENODEV;
- goto out_kfree;
- }
-
- if (!request_mem_region(iores->start, resource_size(iores),
- pdev->name)) {
- err = -EBUSY;
- goto out_kfree;
- }
-
- port->base = ioremap(iores->start, resource_size(iores));
- if (!port->base) {
- err = -ENOMEM;
- goto out_release_mem;
- }
+ port->base = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(port->base))
+ return PTR_ERR(port->base);
port->irq_high = platform_get_irq(pdev, 1);
port->irq = platform_get_irq(pdev, 0);
- if (port->irq < 0) {
- err = -EINVAL;
- goto out_iounmap;
- }
+ if (port->irq < 0)
+ return port->irq;
/* disable the interrupt and clear the status */
writel(0, port->base + GPIO_IMR);
@@ -462,7 +452,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
port->base + GPIO_DR, NULL,
port->base + GPIO_GDIR, NULL, 0);
if (err)
- goto out_iounmap;
+ goto out_bgio;
port->bgc.gc.to_irq = mxc_gpio_to_irq;
port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
@@ -498,12 +488,7 @@ out_gpiochip_remove:
WARN_ON(gpiochip_remove(&port->bgc.gc) < 0);
out_bgpio_remove:
bgpio_remove(&port->bgc);
-out_iounmap:
- iounmap(port->base);
-out_release_mem:
- release_mem_region(iores->start, resource_size(iores));
-out_kfree:
- kfree(port);
+out_bgio:
dev_info(&pdev->dev, "%s failed with errno %d\n", __func__, err);
return err;
}
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 796fb13e481..8ffdd7d2bad 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -20,6 +20,7 @@
* MA 02110-1301, USA.
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -65,6 +66,7 @@ struct mxs_gpio_port {
struct irq_domain *domain;
struct bgpio_chip bgc;
enum mxs_gpio_id devid;
+ u32 both_edges;
};
static inline int is_imx23_gpio(struct mxs_gpio_port *port)
@@ -81,13 +83,23 @@ static inline int is_imx28_gpio(struct mxs_gpio_port *port)
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
{
+ u32 val;
u32 pin_mask = 1 << d->hwirq;
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct mxs_gpio_port *port = gc->private;
void __iomem *pin_addr;
int edge;
+ port->both_edges &= ~pin_mask;
switch (type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ val = gpio_get_value(port->bgc.gc.base + d->hwirq);
+ if (val)
+ edge = GPIO_INT_FALL_EDGE;
+ else
+ edge = GPIO_INT_RISE_EDGE;
+ port->both_edges |= pin_mask;
+ break;
case IRQ_TYPE_EDGE_RISING:
edge = GPIO_INT_RISE_EDGE;
break;
@@ -124,6 +136,23 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
return 0;
}
+static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio)
+{
+ u32 bit, val, edge;
+ void __iomem *pin_addr;
+
+ bit = 1 << gpio;
+
+ pin_addr = port->base + PINCTRL_IRQPOL(port);
+ val = readl(pin_addr);
+ edge = val & bit;
+
+ if (edge)
+ writel(bit, pin_addr + MXS_CLR);
+ else
+ writel(bit, pin_addr + MXS_SET);
+}
+
/* MXS has one interrupt *per* gpio port */
static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
{
@@ -137,6 +166,9 @@ static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc)
while (irq_stat != 0) {
int irqoffset = fls(irq_stat) - 1;
+ if (port->both_edges & (1 << irqoffset))
+ mxs_flip_edge(port, irqoffset);
+
generic_handle_irq(irq_find_mapping(port->domain, irqoffset));
irq_stat &= ~(1 << irqoffset);
}
@@ -182,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
ct->regs.mask = PINCTRL_IRQEN(port);
- irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
+ irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
+ IRQ_NOREQUEST, 0);
}
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -214,7 +247,7 @@ static const struct of_device_id mxs_gpio_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids);
-static int __devinit mxs_gpio_probe(struct platform_device *pdev)
+static int mxs_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_gpio_dt_ids, &pdev->dev);
@@ -222,7 +255,6 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
struct device_node *parent;
static void __iomem *base;
struct mxs_gpio_port *port;
- struct resource *iores = NULL;
int irq_base;
int err;
@@ -230,16 +262,10 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
if (!port)
return -ENOMEM;
- if (np) {
- port->id = of_alias_get_id(np, "gpio");
- if (port->id < 0)
- return port->id;
- port->devid = (enum mxs_gpio_id) of_id->data;
- } else {
- port->id = pdev->id;
- port->devid = pdev->id_entry->driver_data;
- }
-
+ port->id = of_alias_get_id(np, "gpio");
+ if (port->id < 0)
+ return port->id;
+ port->devid = (enum mxs_gpio_id) of_id->data;
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)
return port->irq;
@@ -249,14 +275,9 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
* share the same one
*/
if (!base) {
- if (np) {
- parent = of_get_parent(np);
- base = of_iomap(parent, 0);
- of_node_put(parent);
- } else {
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_request_and_ioremap(&pdev->dev, iores);
- }
+ parent = of_get_parent(np);
+ base = of_iomap(parent, 0);
+ of_node_put(parent);
if (!base)
return -EADDRNOTAVAIL;
}
@@ -292,7 +313,8 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port),
- port->base + PINCTRL_DOUT(port), NULL,
+ port->base + PINCTRL_DOUT(port) + MXS_SET,
+ port->base + PINCTRL_DOUT(port) + MXS_CLR,
port->base + PINCTRL_DOE(port), NULL, 0);
if (err)
goto out_irqdesc_free;
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
new file mode 100644
index 00000000000..dbb08546b9e
--- /dev/null
+++ b/drivers/gpio/gpio-octeon.c
@@ -0,0 +1,157 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium Inc.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-gpio-defs.h>
+
+#define RX_DAT 0x80
+#define TX_SET 0x88
+#define TX_CLEAR 0x90
+/*
+ * The address offset of the GPIO configuration register for a given
+ * line.
+ */
+static unsigned int bit_cfg_reg(unsigned int offset)
+{
+ /*
+ * The register stride is 8, with a discontinuity after the
+ * first 16.
+ */
+ if (offset < 16)
+ return 8 * offset;
+ else
+ return 8 * (offset - 16) + 0x100;
+}
+
+struct octeon_gpio {
+ struct gpio_chip chip;
+ u64 register_base;
+};
+
+static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+
+ cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0);
+ return 0;
+}
+
+static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ u64 mask = 1ull << offset;
+ u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR);
+ cvmx_write_csr(reg, mask);
+}
+
+static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ union cvmx_gpio_bit_cfgx cfgx;
+
+ octeon_gpio_set(chip, offset, value);
+
+ cfgx.u64 = 0;
+ cfgx.s.tx_oe = 1;
+
+ cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), cfgx.u64);
+ return 0;
+}
+
+static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+ u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT);
+
+ return ((1ull << offset) & read_bits) != 0;
+}
+
+static int octeon_gpio_probe(struct platform_device *pdev)
+{
+ struct octeon_gpio *gpio;
+ struct gpio_chip *chip;
+ struct resource *res_mem;
+ int err = 0;
+
+ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+ chip = &gpio->chip;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res_mem == NULL) {
+ dev_err(&pdev->dev, "found no memory resource\n");
+ err = -ENXIO;
+ goto out;
+ }
+ if (!devm_request_mem_region(&pdev->dev, res_mem->start,
+ resource_size(res_mem),
+ res_mem->name)) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ err = -ENXIO;
+ goto out;
+ }
+ gpio->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
+ resource_size(res_mem));
+
+ pdev->dev.platform_data = chip;
+ chip->label = "octeon-gpio";
+ chip->dev = &pdev->dev;
+ chip->owner = THIS_MODULE;
+ chip->base = 0;
+ chip->can_sleep = false;
+ chip->ngpio = 20;
+ chip->direction_input = octeon_gpio_dir_in;
+ chip->get = octeon_gpio_get;
+ chip->direction_output = octeon_gpio_dir_out;
+ chip->set = octeon_gpio_set;
+ err = gpiochip_add(chip);
+ if (err)
+ goto out;
+
+ dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n");
+out:
+ return err;
+}
+
+static int octeon_gpio_remove(struct platform_device *pdev)
+{
+ struct gpio_chip *chip = pdev->dev.platform_data;
+ return gpiochip_remove(chip);
+}
+
+static struct of_device_id octeon_gpio_match[] = {
+ {
+ .compatible = "cavium,octeon-3860-gpio",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, octeon_gpio_match);
+
+static struct platform_driver octeon_gpio_driver = {
+ .driver = {
+ .name = "octeon_gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = octeon_gpio_match,
+ },
+ .probe = octeon_gpio_probe,
+ .remove = octeon_gpio_remove,
+};
+
+module_platform_driver(octeon_gpio_driver);
+
+MODULE_DESCRIPTION("Cavium Inc. OCTEON GPIO Driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 94cbc842fbc..00f29aa1fb9 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -24,12 +24,11 @@
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/gpio.h>
+#include <linux/bitops.h>
#include <linux/platform_data/gpio-omap.h>
-#include <asm/mach/irq.h>
-
#define OFF_MODE 1
static LIST_HEAD(omap_gpio_list);
@@ -53,8 +52,6 @@ struct gpio_bank {
struct list_head node;
void __iomem *base;
u16 irq;
- int irq_base;
- struct irq_domain *domain;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
struct gpio_regs context;
@@ -65,12 +62,14 @@ struct gpio_bank {
struct gpio_chip chip;
struct clk *dbck;
u32 mod_usage;
+ u32 irq_usage;
u32 dbck_enable_mask;
bool dbck_enabled;
struct device *dev;
bool is_mpuio;
bool dbck_flag;
bool loses_context;
+ bool context_valid;
int stride;
u32 width;
int context_loss_count;
@@ -84,12 +83,21 @@ struct gpio_bank {
};
#define GPIO_INDEX(bank, gpio) (gpio % bank->width)
-#define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
+#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)
+#define LINE_USED(line, offset) (line & (BIT(offset)))
+
static int irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
{
- return gpio_irq - bank->irq_base + bank->chip.base;
+ return bank->chip.base + gpio_irq;
+}
+
+static inline struct gpio_bank *_irq_data_get_bank(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ return container_of(chip, struct gpio_bank, chip);
}
static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
@@ -98,12 +106,12 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
u32 l;
reg += bank->regs->direction;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if (is_input)
- l |= 1 << gpio;
+ l |= BIT(gpio);
else
- l &= ~(1 << gpio);
- __raw_writel(l, reg);
+ l &= ~(BIT(gpio));
+ writel_relaxed(l, reg);
bank->context.oe = l;
}
@@ -122,7 +130,7 @@ static void _set_gpio_dataout_reg(struct gpio_bank *bank, int gpio, int enable)
bank->context.dataout &= ~l;
}
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
}
/* set data out value using mask register */
@@ -132,12 +140,12 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
u32 gpio_bit = GPIO_BIT(bank, gpio);
u32 l;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if (enable)
l |= gpio_bit;
else
l &= ~gpio_bit;
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
bank->context.dataout = l;
}
@@ -145,35 +153,35 @@ static int _get_gpio_datain(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->datain;
- return (__raw_readl(reg) & (1 << offset)) != 0;
+ return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
static int _get_gpio_dataout(struct gpio_bank *bank, int offset)
{
void __iomem *reg = bank->base + bank->regs->dataout;
- return (__raw_readl(reg) & (1 << offset)) != 0;
+ return (readl_relaxed(reg) & (BIT(offset))) != 0;
}
static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
{
- int l = __raw_readl(base + reg);
+ int l = readl_relaxed(base + reg);
if (set)
l |= mask;
else
l &= ~mask;
- __raw_writel(l, base + reg);
+ writel_relaxed(l, base + reg);
}
static inline void _gpio_dbck_enable(struct gpio_bank *bank)
{
if (bank->dbck_enable_mask && !bank->dbck_enabled) {
- clk_enable(bank->dbck);
+ clk_prepare_enable(bank->dbck);
bank->dbck_enabled = true;
- __raw_writel(bank->dbck_enable_mask,
+ writel_relaxed(bank->dbck_enable_mask,
bank->base + bank->regs->debounce_en);
}
}
@@ -186,9 +194,9 @@ static inline void _gpio_dbck_disable(struct gpio_bank *bank)
* enabled but the clock is not, GPIO module seems to be unable
* to detect events and generate interrupts at least on OMAP3.
*/
- __raw_writel(0, bank->base + bank->regs->debounce_en);
+ writel_relaxed(0, bank->base + bank->regs->debounce_en);
- clk_disable(bank->dbck);
+ clk_disable_unprepare(bank->dbck);
bank->dbck_enabled = false;
}
}
@@ -221,12 +229,12 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
l = GPIO_BIT(bank, gpio);
- clk_enable(bank->dbck);
+ clk_prepare_enable(bank->dbck);
reg = bank->base + bank->regs->debounce;
- __raw_writel(debounce, reg);
+ writel_relaxed(debounce, reg);
reg = bank->base + bank->regs->debounce_en;
- val = __raw_readl(reg);
+ val = readl_relaxed(reg);
if (debounce)
val |= l;
@@ -234,8 +242,8 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
val &= ~l;
bank->dbck_enable_mask = val;
- __raw_writel(val, reg);
- clk_disable(bank->dbck);
+ writel_relaxed(val, reg);
+ clk_disable_unprepare(bank->dbck);
/*
* Enable debounce clock per module.
* This call is mandatory because in omap_gpio_request() when
@@ -251,11 +259,45 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
}
}
+/**
+ * _clear_gpio_debounce - clear debounce settings for a gpio
+ * @bank: the gpio bank we're acting upon
+ * @gpio: the gpio number on this @gpio
+ *
+ * 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 _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
+{
+ u32 gpio_bit = GPIO_BIT(bank, gpio);
+
+ if (!bank->dbck_flag)
+ return;
+
+ if (!(bank->dbck_enable_mask & gpio_bit))
+ return;
+
+ bank->dbck_enable_mask &= ~gpio_bit;
+ bank->context.debounce_en &= ~gpio_bit;
+ writel_relaxed(bank->context.debounce_en,
+ bank->base + bank->regs->debounce_en);
+
+ if (!bank->dbck_enable_mask) {
+ bank->context.debounce = 0;
+ writel_relaxed(bank->context.debounce, bank->base +
+ bank->regs->debounce);
+ clk_disable_unprepare(bank->dbck);
+ bank->dbck_enabled = false;
+ }
+}
+
static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
unsigned trigger)
{
void __iomem *base = bank->base;
- u32 gpio_bit = 1 << gpio;
+ u32 gpio_bit = BIT(gpio);
_gpio_rmw(base, bank->regs->leveldetect0, gpio_bit,
trigger & IRQ_TYPE_LEVEL_LOW);
@@ -267,18 +309,18 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
trigger & IRQ_TYPE_EDGE_FALLING);
bank->context.leveldetect0 =
- __raw_readl(bank->base + bank->regs->leveldetect0);
+ readl_relaxed(bank->base + bank->regs->leveldetect0);
bank->context.leveldetect1 =
- __raw_readl(bank->base + bank->regs->leveldetect1);
+ readl_relaxed(bank->base + bank->regs->leveldetect1);
bank->context.risingdetect =
- __raw_readl(bank->base + bank->regs->risingdetect);
+ readl_relaxed(bank->base + bank->regs->risingdetect);
bank->context.fallingdetect =
- __raw_readl(bank->base + bank->regs->fallingdetect);
+ readl_relaxed(bank->base + bank->regs->fallingdetect);
if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
bank->context.wake_en =
- __raw_readl(bank->base + bank->regs->wkup_en);
+ readl_relaxed(bank->base + bank->regs->wkup_en);
}
/* This part needs to be executed always for OMAP{34xx, 44xx} */
@@ -303,8 +345,8 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
exit:
bank->level_mask =
- __raw_readl(bank->base + bank->regs->leveldetect0) |
- __raw_readl(bank->base + bank->regs->leveldetect1);
+ readl_relaxed(bank->base + bank->regs->leveldetect0) |
+ readl_relaxed(bank->base + bank->regs->leveldetect1);
}
#ifdef CONFIG_ARCH_OMAP1
@@ -322,13 +364,13 @@ static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio)
reg += bank->regs->irqctrl;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if ((l >> gpio) & 1)
- l &= ~(1 << gpio);
+ l &= ~(BIT(gpio));
else
- l |= 1 << gpio;
+ l |= BIT(gpio);
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
}
#else
static void _toggle_gpio_edge_triggering(struct gpio_bank *bank, int gpio) {}
@@ -346,17 +388,17 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
} else if (bank->regs->irqctrl) {
reg += bank->regs->irqctrl;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if ((trigger & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
- bank->toggle_mask |= 1 << gpio;
+ bank->toggle_mask |= BIT(gpio);
if (trigger & IRQ_TYPE_EDGE_RISING)
- l |= 1 << gpio;
+ l |= BIT(gpio);
else if (trigger & IRQ_TYPE_EDGE_FALLING)
- l &= ~(1 << gpio);
+ l &= ~(BIT(gpio));
else
return -EINVAL;
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
} else if (bank->regs->edgectrl1) {
if (gpio & 0x08)
reg += bank->regs->edgectrl2;
@@ -364,28 +406,85 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio,
reg += bank->regs->edgectrl1;
gpio &= 0x07;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
l &= ~(3 << (gpio << 1));
if (trigger & IRQ_TYPE_EDGE_RISING)
l |= 2 << (gpio << 1);
if (trigger & IRQ_TYPE_EDGE_FALLING)
- l |= 1 << (gpio << 1);
+ l |= BIT(gpio << 1);
/* Enable wake-up during idle for dynamic tick */
- _gpio_rmw(base, bank->regs->wkup_en, 1 << gpio, trigger);
+ _gpio_rmw(base, bank->regs->wkup_en, BIT(gpio), trigger);
bank->context.wake_en =
- __raw_readl(bank->base + bank->regs->wkup_en);
- __raw_writel(l, reg);
+ readl_relaxed(bank->base + bank->regs->wkup_en);
+ writel_relaxed(l, reg);
}
return 0;
}
+static void _enable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+ if (bank->regs->pinctrl) {
+ void __iomem *reg = bank->base + bank->regs->pinctrl;
+
+ /* Claim the pin for MPU */
+ writel_relaxed(readl_relaxed(reg) | (BIT(offset)), reg);
+ }
+
+ if (bank->regs->ctrl && !BANK_USED(bank)) {
+ void __iomem *reg = bank->base + bank->regs->ctrl;
+ u32 ctrl;
+
+ ctrl = readl_relaxed(reg);
+ /* Module is enabled, clocks are not gated */
+ ctrl &= ~GPIO_MOD_CTRL_BIT;
+ writel_relaxed(ctrl, reg);
+ bank->context.ctrl = ctrl;
+ }
+}
+
+static void _disable_gpio_module(struct gpio_bank *bank, unsigned offset)
+{
+ void __iomem *base = bank->base;
+
+ if (bank->regs->wkup_en &&
+ !LINE_USED(bank->mod_usage, offset) &&
+ !LINE_USED(bank->irq_usage, offset)) {
+ /* Disable wake-up during idle for dynamic tick */
+ _gpio_rmw(base, bank->regs->wkup_en, BIT(offset), 0);
+ bank->context.wake_en =
+ readl_relaxed(bank->base + bank->regs->wkup_en);
+ }
+
+ if (bank->regs->ctrl && !BANK_USED(bank)) {
+ void __iomem *reg = bank->base + bank->regs->ctrl;
+ u32 ctrl;
+
+ ctrl = readl_relaxed(reg);
+ /* Module is disabled, clocks are gated */
+ ctrl |= GPIO_MOD_CTRL_BIT;
+ writel_relaxed(ctrl, reg);
+ bank->context.ctrl = ctrl;
+ }
+}
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+ void __iomem *reg = bank->base + bank->regs->direction;
+
+ return readl_relaxed(reg) & mask;
+}
+
static int gpio_irq_type(struct irq_data *d, unsigned type)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
unsigned gpio = 0;
int retval;
unsigned long flags;
+ unsigned offset;
+
+ if (!BANK_USED(bank))
+ pm_runtime_get_sync(bank->dev);
#ifdef CONFIG_ARCH_OMAP1
if (d->irq > IH_MPUIO_BASE)
@@ -393,7 +492,7 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
#endif
if (!gpio)
- gpio = irq_to_gpio(bank, d->irq);
+ gpio = irq_to_gpio(bank, d->hwirq);
if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
@@ -403,7 +502,17 @@ static int gpio_irq_type(struct irq_data *d, unsigned type)
return -EINVAL;
spin_lock_irqsave(&bank->lock, flags);
- retval = _set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), type);
+ offset = GPIO_INDEX(bank, gpio);
+ retval = _set_gpio_triggering(bank, offset, type);
+ if (!LINE_USED(bank->mod_usage, offset)) {
+ _enable_gpio_module(bank, offset);
+ _set_gpio_direction(bank, offset, 1);
+ } else if (!gpio_is_input(bank, BIT(offset))) {
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return -EINVAL;
+ }
+
+ bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -419,16 +528,16 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
void __iomem *reg = bank->base;
reg += bank->regs->irqstatus;
- __raw_writel(gpio_mask, reg);
+ writel_relaxed(gpio_mask, reg);
/* Workaround for clearing DSP GPIO interrupts to allow retention */
if (bank->regs->irqstatus2) {
reg = bank->base + bank->regs->irqstatus2;
- __raw_writel(gpio_mask, reg);
+ writel_relaxed(gpio_mask, reg);
}
/* Flush posted write for the irq status to avoid spurious interrupts */
- __raw_readl(reg);
+ readl_relaxed(reg);
}
static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
@@ -440,10 +549,10 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
{
void __iomem *reg = bank->base;
u32 l;
- u32 mask = (1 << bank->width) - 1;
+ u32 mask = (BIT(bank->width)) - 1;
reg += bank->regs->irqenable;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if (bank->regs->irqenable_inv)
l = ~l;
l &= mask;
@@ -461,7 +570,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
bank->context.irqenable1 |= gpio_mask;
} else {
reg += bank->regs->irqenable;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if (bank->regs->irqenable_inv)
l &= ~gpio_mask;
else
@@ -469,7 +578,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
bank->context.irqenable1 = l;
}
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
}
static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
@@ -483,7 +592,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
bank->context.irqenable1 &= ~gpio_mask;
} else {
reg += bank->regs->irqenable;
- l = __raw_readl(reg);
+ l = readl_relaxed(reg);
if (bank->regs->irqenable_inv)
l |= gpio_mask;
else
@@ -491,7 +600,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
bank->context.irqenable1 = l;
}
- __raw_writel(l, reg);
+ writel_relaxed(l, reg);
}
static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
@@ -527,7 +636,7 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
else
bank->context.wake_en &= ~gpio_bit;
- __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en);
+ writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -539,13 +648,14 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
_set_gpio_irqenable(bank, gpio, 0);
_clear_gpio_irqstatus(bank, gpio);
_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+ _clear_gpio_debounce(bank, gpio);
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->irq);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
return _set_gpio_wakeup(bank, gpio, enable);
}
@@ -559,35 +669,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
* If this is the first gpio_request for the bank,
* enable the bank module.
*/
- if (!bank->mod_usage)
+ if (!BANK_USED(bank))
pm_runtime_get_sync(bank->dev);
spin_lock_irqsave(&bank->lock, flags);
/* Set trigger to none. You need to enable the desired trigger with
- * request_irq() or set_irq_type().
+ * request_irq() or set_irq_type(). Only do this if the IRQ line has
+ * not already been requested.
*/
- _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
-
- if (bank->regs->pinctrl) {
- void __iomem *reg = bank->base + bank->regs->pinctrl;
-
- /* Claim the pin for MPU */
- __raw_writel(__raw_readl(reg) | (1 << offset), reg);
+ if (!LINE_USED(bank->irq_usage, offset)) {
+ _set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ _enable_gpio_module(bank, offset);
}
-
- if (bank->regs->ctrl && !bank->mod_usage) {
- void __iomem *reg = bank->base + bank->regs->ctrl;
- u32 ctrl;
-
- ctrl = __raw_readl(reg);
- /* Module is enabled, clocks are not gated */
- ctrl &= ~GPIO_MOD_CTRL_BIT;
- __raw_writel(ctrl, reg);
- bank->context.ctrl = ctrl;
- }
-
- bank->mod_usage |= 1 << offset;
-
+ bank->mod_usage |= BIT(offset);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -596,31 +690,11 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
- void __iomem *base = bank->base;
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
-
- if (bank->regs->wkup_en) {
- /* Disable wake-up during idle for dynamic tick */
- _gpio_rmw(base, bank->regs->wkup_en, 1 << offset, 0);
- bank->context.wake_en =
- __raw_readl(bank->base + bank->regs->wkup_en);
- }
-
- bank->mod_usage &= ~(1 << offset);
-
- if (bank->regs->ctrl && !bank->mod_usage) {
- void __iomem *reg = bank->base + bank->regs->ctrl;
- u32 ctrl;
-
- ctrl = __raw_readl(reg);
- /* Module is disabled, clocks are gated */
- ctrl |= GPIO_MOD_CTRL_BIT;
- __raw_writel(ctrl, reg);
- bank->context.ctrl = ctrl;
- }
-
+ bank->mod_usage &= ~(BIT(offset));
+ _disable_gpio_module(bank, offset);
_reset_gpio(bank, bank->chip.base + offset);
spin_unlock_irqrestore(&bank->lock, flags);
@@ -628,7 +702,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
* If this is the last gpio to be freed in the bank,
* disable the bank module.
*/
- if (!bank->mod_usage)
+ if (!BANK_USED(bank))
pm_runtime_put(bank->dev);
}
@@ -645,26 +719,27 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
void __iomem *isr_reg = NULL;
u32 isr;
- unsigned int gpio_irq, gpio_index;
+ unsigned int bit;
struct gpio_bank *bank;
int unmasked = 0;
- struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ struct gpio_chip *chip = irq_get_handler_data(irq);
- chained_irq_enter(chip, desc);
+ chained_irq_enter(irqchip, desc);
- bank = irq_get_handler_data(irq);
+ bank = container_of(chip, struct gpio_bank, chip);
isr_reg = bank->base + bank->regs->irqstatus;
pm_runtime_get_sync(bank->dev);
if (WARN_ON(!isr_reg))
goto exit;
- while(1) {
+ while (1) {
u32 isr_saved, level_mask = 0;
u32 enabled;
enabled = _get_gpio_irqbank_mask(bank);
- isr_saved = isr = __raw_readl(isr_reg) & enabled;
+ isr_saved = isr = readl_relaxed(isr_reg) & enabled;
if (bank->level_mask)
level_mask = bank->level_mask & enabled;
@@ -680,20 +755,15 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
configured, we could unmask GPIO bank interrupt immediately */
if (!level_mask && !unmasked) {
unmasked = 1;
- chained_irq_exit(chip, desc);
+ chained_irq_exit(irqchip, desc);
}
if (!isr)
break;
- gpio_irq = bank->irq_base;
- for (; isr != 0; isr >>= 1, gpio_irq++) {
- int gpio = irq_to_gpio(bank, gpio_irq);
-
- if (!(isr & 1))
- continue;
-
- gpio_index = GPIO_INDEX(bank, gpio);
+ while (isr) {
+ bit = __ffs(isr);
+ isr &= ~(BIT(bit));
/*
* Some chips can't respond to both rising and falling
@@ -702,10 +772,11 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
* to respond to the IRQ for the opposite direction.
* This will be indicated in the bank toggle_mask.
*/
- if (bank->toggle_mask & (1 << gpio_index))
- _toggle_gpio_edge_triggering(bank, gpio_index);
+ if (bank->toggle_mask & (BIT(bit)))
+ _toggle_gpio_edge_triggering(bank, bit);
- generic_handle_irq(gpio_irq);
+ generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
+ bit));
}
}
/* if bank has any level sensitive GPIO pin interrupt
@@ -714,33 +785,44 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
interrupt */
exit:
if (!unmasked)
- chained_irq_exit(chip, desc);
+ chained_irq_exit(irqchip, desc);
pm_runtime_put(bank->dev);
}
static void gpio_irq_shutdown(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->irq);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned long flags;
+ unsigned offset = GPIO_INDEX(bank, gpio);
spin_lock_irqsave(&bank->lock, flags);
+ gpio_unlock_as_irq(&bank->chip, offset);
+ bank->irq_usage &= ~(BIT(offset));
+ _disable_gpio_module(bank, offset);
_reset_gpio(bank, gpio);
spin_unlock_irqrestore(&bank->lock, flags);
+
+ /*
+ * If this is the last IRQ to be freed in the bank,
+ * disable the bank module.
+ */
+ if (!BANK_USED(bank))
+ pm_runtime_put(bank->dev);
}
static void gpio_ack_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->irq);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
_clear_gpio_irqstatus(bank, gpio);
}
static void gpio_mask_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->irq);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
@@ -751,8 +833,8 @@ static void gpio_mask_irq(struct irq_data *d)
static void gpio_unmask_irq(struct irq_data *d)
{
- struct gpio_bank *bank = irq_data_get_irq_chip_data(d);
- unsigned int gpio = irq_to_gpio(bank, d->irq);
+ struct gpio_bank *bank = _irq_data_get_bank(d);
+ unsigned int gpio = irq_to_gpio(bank, d->hwirq);
unsigned int irq_mask = GPIO_BIT(bank, gpio);
u32 trigger = irqd_get_trigger_type(d);
unsigned long flags;
@@ -793,7 +875,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- __raw_writel(0xffff & ~bank->context.wake_en, mask_reg);
+ writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -808,7 +890,7 @@ static int omap_mpuio_resume_noirq(struct device *dev)
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- __raw_writel(bank->context.wake_en, mask_reg);
+ writel_relaxed(bank->context.wake_en, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -846,23 +928,31 @@ static inline void mpuio_init(struct gpio_bank *bank)
/*---------------------------------------------------------------------*/
-static int gpio_input(struct gpio_chip *chip, unsigned offset)
+static int gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
struct gpio_bank *bank;
unsigned long flags;
+ void __iomem *reg;
+ int dir;
bank = container_of(chip, struct gpio_bank, chip);
+ reg = bank->base + bank->regs->direction;
spin_lock_irqsave(&bank->lock, flags);
- _set_gpio_direction(bank, offset, 1);
+ dir = !!(readl_relaxed(reg) & BIT(offset));
spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
+ return dir;
}
-static int gpio_is_input(struct gpio_bank *bank, int mask)
+static int gpio_input(struct gpio_chip *chip, unsigned offset)
{
- void __iomem *reg = bank->base + bank->regs->direction;
+ struct gpio_bank *bank;
+ unsigned long flags;
- return __raw_readl(reg) & mask;
+ bank = container_of(chip, struct gpio_bank, chip);
+ spin_lock_irqsave(&bank->lock, flags);
+ _set_gpio_direction(bank, offset, 1);
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
}
static int gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -871,7 +961,7 @@ static int gpio_get(struct gpio_chip *chip, unsigned offset)
u32 mask;
bank = container_of(chip, struct gpio_bank, chip);
- mask = (1 << offset);
+ mask = (BIT(offset));
if (gpio_is_input(bank, mask))
return _get_gpio_datain(bank, offset);
@@ -918,14 +1008,6 @@ static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&bank->lock, flags);
}
-static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
-{
- struct gpio_bank *bank;
-
- bank = container_of(chip, struct gpio_bank, chip);
- return bank->irq_base + offset;
-}
-
/*---------------------------------------------------------------------*/
static void __init omap_gpio_show_rev(struct gpio_bank *bank)
@@ -936,7 +1018,7 @@ static void __init omap_gpio_show_rev(struct gpio_bank *bank)
if (called || bank->regs->revision == USHRT_MAX)
return;
- rev = __raw_readw(bank->base + bank->regs->revision);
+ rev = readw_relaxed(bank->base + bank->regs->revision);
pr_info("OMAP GPIO hardware version %d.%d\n",
(rev >> 4) & 0x0f, rev & 0x0f);
@@ -957,27 +1039,27 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
l = 0xffff;
if (bank->is_mpuio) {
- __raw_writel(l, bank->base + bank->regs->irqenable);
+ writel_relaxed(l, bank->base + bank->regs->irqenable);
return;
}
_gpio_rmw(base, bank->regs->irqenable, l, bank->regs->irqenable_inv);
_gpio_rmw(base, bank->regs->irqstatus, l, !bank->regs->irqenable_inv);
if (bank->regs->debounce_en)
- __raw_writel(0, base + bank->regs->debounce_en);
+ writel_relaxed(0, base + bank->regs->debounce_en);
/* Save OE default value (0xffffffff) in the context */
- bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
+ bank->context.oe = readl_relaxed(bank->base + bank->regs->direction);
/* Initialize interface clk ungated, module enabled */
if (bank->regs->ctrl)
- __raw_writel(0, base + bank->regs->ctrl);
+ writel_relaxed(0, base + bank->regs->ctrl);
bank->dbck = clk_get(bank->dev, "dbclk");
if (IS_ERR(bank->dbck))
dev_err(bank->dev, "Could not get gpio dbck\n");
}
-static __devinit void
+static void
omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
unsigned int num)
{
@@ -999,17 +1081,19 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
ct->chip.irq_set_type = gpio_irq_type;
if (bank->regs->wkup_en)
- ct->chip.irq_set_wake = gpio_wake_enable,
+ ct->chip.irq_set_wake = gpio_wake_enable;
ct->regs.mask = OMAP_MPUIO_GPIO_INT / bank->stride;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
-static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
+static int omap_gpio_chip_init(struct gpio_bank *bank)
{
int j;
static int gpio;
+ int irq_base = 0;
+ int ret;
/*
* REVISIT eventually switch from OMAP-specific gpio structs
@@ -1017,12 +1101,12 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
*/
bank->chip.request = omap_gpio_request;
bank->chip.free = omap_gpio_free;
+ bank->chip.get_direction = gpio_get_direction;
bank->chip.direction_input = gpio_input;
bank->chip.get = gpio_get;
bank->chip.direction_output = gpio_output;
bank->chip.set_debounce = gpio_debounce;
bank->chip.set = gpio_set;
- bank->chip.to_irq = gpio_2irq;
if (bank->is_mpuio) {
bank->chip.label = "mpuio";
if (bank->regs->wkup_en)
@@ -1035,26 +1119,53 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
}
bank->chip.ngpio = bank->width;
- gpiochip_add(&bank->chip);
+ ret = gpiochip_add(&bank->chip);
+ if (ret) {
+ dev_err(bank->dev, "Could not register gpio chip %d\n", ret);
+ return ret;
+ }
- for (j = bank->irq_base; j < bank->irq_base + bank->width; j++) {
- irq_set_lockdep_class(j, &gpio_lock_class);
- irq_set_chip_data(j, bank);
+#ifdef CONFIG_ARCH_OMAP1
+ /*
+ * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
+ * irq_alloc_descs() since a base IRQ offset will no longer be needed.
+ */
+ irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
+ if (irq_base < 0) {
+ dev_err(bank->dev, "Couldn't allocate IRQ numbers\n");
+ return -ENODEV;
+ }
+#endif
+
+ ret = gpiochip_irqchip_add(&bank->chip, &gpio_irq_chip,
+ irq_base, gpio_irq_handler,
+ IRQ_TYPE_NONE);
+
+ if (ret) {
+ dev_err(bank->dev, "Couldn't add irqchip to gpiochip %d\n", ret);
+ ret = gpiochip_remove(&bank->chip);
+ return -ENODEV;
+ }
+
+ gpiochip_set_chained_irqchip(&bank->chip, &gpio_irq_chip,
+ bank->irq, gpio_irq_handler);
+
+ for (j = 0; j < bank->width; j++) {
+ int irq = irq_find_mapping(bank->chip.irqdomain, j);
+ irq_set_lockdep_class(irq, &gpio_lock_class);
if (bank->is_mpuio) {
- omap_mpuio_alloc_gc(bank, j, bank->width);
- } else {
- irq_set_chip(j, &gpio_irq_chip);
- irq_set_handler(j, handle_simple_irq);
- set_irq_flags(j, IRQF_VALID);
+ omap_mpuio_alloc_gc(bank, irq, bank->width);
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ set_irq_flags(irq, 0);
}
}
- irq_set_chained_handler(bank->irq, gpio_irq_handler);
- irq_set_handler_data(bank->irq, bank);
+
+ return 0;
}
static const struct of_device_id omap_gpio_match[];
-static int __devinit omap_gpio_probe(struct platform_device *pdev)
+static int omap_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
@@ -1062,15 +1173,15 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
const struct omap_gpio_platform_data *pdata;
struct resource *res;
struct gpio_bank *bank;
- int ret = 0;
+ int ret;
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
- pdata = match ? match->data : dev->platform_data;
+ pdata = match ? match->data : dev_get_platdata(dev);
if (!pdata)
return -EINVAL;
- bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL);
+ bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
if (!bank) {
dev_err(dev, "Memory alloc failed\n");
return -ENOMEM;
@@ -1084,26 +1195,27 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
bank->irq = res->start;
bank->dev = dev;
+ bank->chip.dev = dev;
bank->dbck_flag = pdata->dbck_flag;
bank->stride = pdata->bank_stride;
bank->width = pdata->bank_width;
bank->is_mpuio = pdata->is_mpuio;
bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
- bank->loses_context = pdata->loses_context;
bank->regs = pdata->regs;
#ifdef CONFIG_OF_GPIO
bank->chip.of_node = of_node_get(node);
#endif
+ if (node) {
+ if (!of_property_read_bool(node, "ti,gpio-always-on"))
+ bank->loses_context = true;
+ } else {
+ bank->loses_context = pdata->loses_context;
- bank->irq_base = irq_alloc_descs(-1, 0, bank->width, 0);
- if (bank->irq_base < 0) {
- dev_err(dev, "Couldn't allocate IRQ numbers\n");
- return -ENODEV;
+ if (bank->loses_context)
+ bank->get_context_loss_count =
+ pdata->get_context_loss_count;
}
- bank->domain = irq_domain_add_legacy(node, bank->width, bank->irq_base,
- 0, &irq_domain_simple_ops, NULL);
-
if (bank->regs->set_dataout && bank->regs->clr_dataout)
bank->set_dataout = _set_gpio_dataout_reg;
else
@@ -1113,21 +1225,10 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
/* Static mapping, never released */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (unlikely(!res)) {
- dev_err(dev, "Invalid mem resource\n");
- return -ENODEV;
- }
-
- if (!devm_request_mem_region(dev, res->start, resource_size(res),
- pdev->name)) {
- dev_err(dev, "Region already claimed\n");
- return -EBUSY;
- }
-
- bank->base = devm_ioremap(dev, res->start, resource_size(res));
- if (!bank->base) {
- dev_err(dev, "Could not ioremap\n");
- return -ENOMEM;
+ bank->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(bank->base)) {
+ irq_domain_remove(bank->chip.irqdomain);
+ return PTR_ERR(bank->base);
}
platform_set_drvdata(pdev, bank);
@@ -1140,17 +1241,18 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
mpuio_init(bank);
omap_gpio_mod_init(bank);
- omap_gpio_chip_init(bank);
- omap_gpio_show_rev(bank);
- if (bank->loses_context)
- bank->get_context_loss_count = pdata->get_context_loss_count;
+ ret = omap_gpio_chip_init(bank);
+ if (ret)
+ return ret;
+
+ omap_gpio_show_rev(bank);
pm_runtime_put(bank->dev);
list_add_tail(&bank->node, &omap_gpio_list);
- return ret;
+ return 0;
}
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -1181,11 +1283,11 @@ static int omap_gpio_runtime_suspend(struct device *dev)
*/
wake_low = bank->context.leveldetect0 & bank->context.wake_en;
if (wake_low)
- __raw_writel(wake_low | bank->context.fallingdetect,
+ writel_relaxed(wake_low | bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
if (wake_hi)
- __raw_writel(wake_hi | bank->context.risingdetect,
+ writel_relaxed(wake_hi | bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
if (!bank->enabled_non_wakeup_gpios)
@@ -1200,7 +1302,7 @@ static int omap_gpio_runtime_suspend(struct device *dev)
* non-wakeup GPIOs. Otherwise spurious IRQs will be
* generated. See OMAP2420 Errata item 1.101.
*/
- bank->saved_datain = __raw_readl(bank->base +
+ bank->saved_datain = readl_relaxed(bank->base +
bank->regs->datain);
l1 = bank->context.fallingdetect;
l2 = bank->context.risingdetect;
@@ -1208,8 +1310,8 @@ static int omap_gpio_runtime_suspend(struct device *dev)
l1 &= ~bank->enabled_non_wakeup_gpios;
l2 &= ~bank->enabled_non_wakeup_gpios;
- __raw_writel(l1, bank->base + bank->regs->fallingdetect);
- __raw_writel(l2, bank->base + bank->regs->risingdetect);
+ writel_relaxed(l1, bank->base + bank->regs->fallingdetect);
+ writel_relaxed(l2, bank->base + bank->regs->risingdetect);
bank->workaround_enabled = true;
@@ -1224,15 +1326,31 @@ update_gpio_context_count:
return 0;
}
+static void omap_gpio_init_context(struct gpio_bank *p);
+
static int omap_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_bank *bank = platform_get_drvdata(pdev);
- int context_lost_cnt_after;
u32 l = 0, gen, gen0, gen1;
unsigned long flags;
+ int c;
spin_lock_irqsave(&bank->lock, flags);
+
+ /*
+ * On the first resume during the probe, the context has not
+ * been initialised and so initialise it now. Also initialise
+ * the context loss count.
+ */
+ if (bank->loses_context && !bank->context_valid) {
+ omap_gpio_init_context(bank);
+
+ if (bank->get_context_loss_count)
+ bank->context_loss_count =
+ bank->get_context_loss_count(bank->dev);
+ }
+
_gpio_dbck_enable(bank);
/*
@@ -1241,19 +1359,22 @@ static int omap_gpio_runtime_resume(struct device *dev)
* generate a PRCM wakeup. Here we restore the
* pre-runtime_suspend() values for edge triggering.
*/
- __raw_writel(bank->context.fallingdetect,
+ writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
- __raw_writel(bank->context.risingdetect,
+ writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
- if (bank->get_context_loss_count) {
- context_lost_cnt_after =
- bank->get_context_loss_count(bank->dev);
- if (context_lost_cnt_after != bank->context_loss_count) {
+ if (bank->loses_context) {
+ if (!bank->get_context_loss_count) {
omap_gpio_restore_context(bank);
} else {
- spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
+ c = bank->get_context_loss_count(bank->dev);
+ if (c != bank->context_loss_count) {
+ omap_gpio_restore_context(bank);
+ } else {
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
+ }
}
}
@@ -1262,11 +1383,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
return 0;
}
- __raw_writel(bank->context.fallingdetect,
- bank->base + bank->regs->fallingdetect);
- __raw_writel(bank->context.risingdetect,
- bank->base + bank->regs->risingdetect);
- l = __raw_readl(bank->base + bank->regs->datain);
+ l = readl_relaxed(bank->base + bank->regs->datain);
/*
* Check if any of the non-wakeup interrupt GPIOs have changed
@@ -1296,24 +1413,24 @@ static int omap_gpio_runtime_resume(struct device *dev)
if (gen) {
u32 old0, old1;
- old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
- old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
+ old0 = readl_relaxed(bank->base + bank->regs->leveldetect0);
+ old1 = readl_relaxed(bank->base + bank->regs->leveldetect1);
if (!bank->regs->irqstatus_raw0) {
- __raw_writel(old0 | gen, bank->base +
+ writel_relaxed(old0 | gen, bank->base +
bank->regs->leveldetect0);
- __raw_writel(old1 | gen, bank->base +
+ writel_relaxed(old1 | gen, bank->base +
bank->regs->leveldetect1);
}
if (bank->regs->irqstatus_raw0) {
- __raw_writel(old0 | l, bank->base +
+ writel_relaxed(old0 | l, bank->base +
bank->regs->leveldetect0);
- __raw_writel(old1 | l, bank->base +
+ writel_relaxed(old1 | l, bank->base +
bank->regs->leveldetect1);
}
- __raw_writel(old0, bank->base + bank->regs->leveldetect0);
- __raw_writel(old1, bank->base + bank->regs->leveldetect1);
+ writel_relaxed(old0, bank->base + bank->regs->leveldetect0);
+ writel_relaxed(old1, bank->base + bank->regs->leveldetect1);
}
bank->workaround_enabled = false;
@@ -1328,7 +1445,7 @@ void omap2_gpio_prepare_for_idle(int pwr_mode)
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!bank->mod_usage || !bank->loses_context)
+ if (!BANK_USED(bank) || !bank->loses_context)
continue;
bank->power_mode = pwr_mode;
@@ -1342,7 +1459,7 @@ void omap2_gpio_resume_after_idle(void)
struct gpio_bank *bank;
list_for_each_entry(bank, &omap_gpio_list, node) {
- if (!bank->mod_usage || !bank->loses_context)
+ if (!BANK_USED(bank) || !bank->loses_context)
continue;
pm_runtime_get_sync(bank->dev);
@@ -1350,43 +1467,67 @@ void omap2_gpio_resume_after_idle(void)
}
#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_init_context(struct gpio_bank *p)
+{
+ struct omap_gpio_reg_offs *regs = p->regs;
+ void __iomem *base = p->base;
+
+ p->context.ctrl = readl_relaxed(base + regs->ctrl);
+ p->context.oe = readl_relaxed(base + regs->direction);
+ p->context.wake_en = readl_relaxed(base + regs->wkup_en);
+ p->context.leveldetect0 = readl_relaxed(base + regs->leveldetect0);
+ p->context.leveldetect1 = readl_relaxed(base + regs->leveldetect1);
+ p->context.risingdetect = readl_relaxed(base + regs->risingdetect);
+ p->context.fallingdetect = readl_relaxed(base + regs->fallingdetect);
+ p->context.irqenable1 = readl_relaxed(base + regs->irqenable);
+ p->context.irqenable2 = readl_relaxed(base + regs->irqenable2);
+
+ if (regs->set_dataout && p->regs->clr_dataout)
+ p->context.dataout = readl_relaxed(base + regs->set_dataout);
+ else
+ p->context.dataout = readl_relaxed(base + regs->dataout);
+
+ p->context_valid = true;
+}
+
static void omap_gpio_restore_context(struct gpio_bank *bank)
{
- __raw_writel(bank->context.wake_en,
+ writel_relaxed(bank->context.wake_en,
bank->base + bank->regs->wkup_en);
- __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
- __raw_writel(bank->context.leveldetect0,
+ writel_relaxed(bank->context.ctrl, bank->base + bank->regs->ctrl);
+ writel_relaxed(bank->context.leveldetect0,
bank->base + bank->regs->leveldetect0);
- __raw_writel(bank->context.leveldetect1,
+ writel_relaxed(bank->context.leveldetect1,
bank->base + bank->regs->leveldetect1);
- __raw_writel(bank->context.risingdetect,
+ writel_relaxed(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
- __raw_writel(bank->context.fallingdetect,
+ writel_relaxed(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
if (bank->regs->set_dataout && bank->regs->clr_dataout)
- __raw_writel(bank->context.dataout,
+ writel_relaxed(bank->context.dataout,
bank->base + bank->regs->set_dataout);
else
- __raw_writel(bank->context.dataout,
+ writel_relaxed(bank->context.dataout,
bank->base + bank->regs->dataout);
- __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
+ writel_relaxed(bank->context.oe, bank->base + bank->regs->direction);
if (bank->dbck_enable_mask) {
- __raw_writel(bank->context.debounce, bank->base +
+ writel_relaxed(bank->context.debounce, bank->base +
bank->regs->debounce);
- __raw_writel(bank->context.debounce_en,
+ writel_relaxed(bank->context.debounce_en,
bank->base + bank->regs->debounce_en);
}
- __raw_writel(bank->context.irqenable1,
+ writel_relaxed(bank->context.irqenable1,
bank->base + bank->regs->irqenable);
- __raw_writel(bank->context.irqenable2,
+ writel_relaxed(bank->context.irqenable2,
bank->base + bank->regs->irqenable2);
}
#endif /* CONFIG_PM_RUNTIME */
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
+static inline void omap_gpio_init_context(struct gpio_bank *p) {}
#endif
static const struct dev_pm_ops gpio_pm_ops = {
@@ -1441,19 +1582,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.fallingdetect = OMAP4_GPIO_FALLINGDETECT,
};
-const static struct omap_gpio_platform_data omap2_pdata = {
+static const struct omap_gpio_platform_data omap2_pdata = {
.regs = &omap2_gpio_regs,
.bank_width = 32,
.dbck_flag = false,
};
-const static struct omap_gpio_platform_data omap3_pdata = {
+static const struct omap_gpio_platform_data omap3_pdata = {
.regs = &omap2_gpio_regs,
.bank_width = 32,
.dbck_flag = true,
};
-const static struct omap_gpio_platform_data omap4_pdata = {
+static const struct omap_gpio_platform_data omap4_pdata = {
.regs = &omap4_gpio_regs,
.bank_width = 32,
.dbck_flag = true,
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
new file mode 100644
index 00000000000..86bdbe36206
--- /dev/null
+++ b/drivers/gpio/gpio-palmas.c
@@ -0,0 +1,239 @@
+/*
+ * TI Palma series PMIC's GPIO driver.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/palmas.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+struct palmas_gpio {
+ struct gpio_chip gpio_chip;
+ struct palmas *palmas;
+};
+
+struct palmas_device_data {
+ int ngpio;
+};
+
+static inline struct palmas_gpio *to_palmas_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct palmas_gpio, gpio_chip);
+}
+
+static int palmas_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ unsigned int val;
+ int ret;
+ unsigned int reg;
+ int gpio16 = (offset/8);
+
+ offset %= 8;
+ reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
+
+ ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
+ if (ret < 0) {
+ dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+ return ret;
+ }
+
+ if (val & BIT(offset))
+ reg = (gpio16) ? PALMAS_GPIO_DATA_OUT2 : PALMAS_GPIO_DATA_OUT;
+ else
+ reg = (gpio16) ? PALMAS_GPIO_DATA_IN2 : PALMAS_GPIO_DATA_IN;
+
+ ret = palmas_read(palmas, PALMAS_GPIO_BASE, reg, &val);
+ if (ret < 0) {
+ dev_err(gc->dev, "Reg 0x%02x read failed, %d\n", reg, ret);
+ return ret;
+ }
+ return !!(val & BIT(offset));
+}
+
+static void palmas_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+ unsigned int reg;
+ int gpio16 = (offset/8);
+
+ offset %= 8;
+ if (gpio16)
+ reg = (value) ?
+ PALMAS_GPIO_SET_DATA_OUT2 : PALMAS_GPIO_CLEAR_DATA_OUT2;
+ else
+ reg = (value) ?
+ PALMAS_GPIO_SET_DATA_OUT : PALMAS_GPIO_CLEAR_DATA_OUT;
+
+ ret = palmas_write(palmas, PALMAS_GPIO_BASE, reg, BIT(offset));
+ if (ret < 0)
+ dev_err(gc->dev, "Reg 0x%02x write failed, %d\n", reg, ret);
+}
+
+static int palmas_gpio_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+ unsigned int reg;
+ int gpio16 = (offset/8);
+
+ offset %= 8;
+ reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
+
+ /* Set the initial value */
+ palmas_gpio_set(gc, offset, value);
+
+ ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg,
+ BIT(offset), BIT(offset));
+ if (ret < 0)
+ dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+ return ret;
+}
+
+static int palmas_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+ int ret;
+ unsigned int reg;
+ int gpio16 = (offset/8);
+
+ offset %= 8;
+ reg = (gpio16) ? PALMAS_GPIO_DATA_DIR2 : PALMAS_GPIO_DATA_DIR;
+
+ ret = palmas_update_bits(palmas, PALMAS_GPIO_BASE, reg, BIT(offset), 0);
+ if (ret < 0)
+ dev_err(gc->dev, "Reg 0x%02x update failed, %d\n", reg, ret);
+ return ret;
+}
+
+static int palmas_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct palmas_gpio *pg = to_palmas_gpio(gc);
+ struct palmas *palmas = pg->palmas;
+
+ return palmas_irq_get_virq(palmas, PALMAS_GPIO_0_IRQ + offset);
+}
+
+static const struct palmas_device_data palmas_dev_data = {
+ .ngpio = 8,
+};
+
+static const struct palmas_device_data tps80036_dev_data = {
+ .ngpio = 16,
+};
+
+static const struct of_device_id of_palmas_gpio_match[] = {
+ { .compatible = "ti,palmas-gpio", .data = &palmas_dev_data,},
+ { .compatible = "ti,tps65913-gpio", .data = &palmas_dev_data,},
+ { .compatible = "ti,tps65914-gpio", .data = &palmas_dev_data,},
+ { .compatible = "ti,tps80036-gpio", .data = &tps80036_dev_data,},
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_palmas_gpio_match);
+
+static int palmas_gpio_probe(struct platform_device *pdev)
+{
+ struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
+ struct palmas_platform_data *palmas_pdata;
+ struct palmas_gpio *palmas_gpio;
+ int ret;
+ const struct of_device_id *match;
+ const struct palmas_device_data *dev_data;
+
+ match = of_match_device(of_palmas_gpio_match, &pdev->dev);
+ dev_data = match->data;
+ if (!dev_data)
+ dev_data = &palmas_dev_data;
+
+ palmas_gpio = devm_kzalloc(&pdev->dev,
+ sizeof(*palmas_gpio), GFP_KERNEL);
+ if (!palmas_gpio)
+ return -ENOMEM;
+
+ palmas_gpio->palmas = palmas;
+ palmas_gpio->gpio_chip.owner = THIS_MODULE;
+ palmas_gpio->gpio_chip.label = dev_name(&pdev->dev);
+ palmas_gpio->gpio_chip.ngpio = dev_data->ngpio;
+ palmas_gpio->gpio_chip.can_sleep = true;
+ palmas_gpio->gpio_chip.direction_input = palmas_gpio_input;
+ palmas_gpio->gpio_chip.direction_output = palmas_gpio_output;
+ palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq;
+ palmas_gpio->gpio_chip.set = palmas_gpio_set;
+ palmas_gpio->gpio_chip.get = palmas_gpio_get;
+ palmas_gpio->gpio_chip.dev = &pdev->dev;
+#ifdef CONFIG_OF_GPIO
+ palmas_gpio->gpio_chip.of_node = pdev->dev.of_node;
+#endif
+ palmas_pdata = dev_get_platdata(palmas->dev);
+ if (palmas_pdata && palmas_pdata->gpio_base)
+ palmas_gpio->gpio_chip.base = palmas_pdata->gpio_base;
+ else
+ palmas_gpio->gpio_chip.base = -1;
+
+ ret = gpiochip_add(&palmas_gpio->gpio_chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, palmas_gpio);
+ return ret;
+}
+
+static int palmas_gpio_remove(struct platform_device *pdev)
+{
+ struct palmas_gpio *palmas_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&palmas_gpio->gpio_chip);
+}
+
+static struct platform_driver palmas_gpio_driver = {
+ .driver.name = "palmas-gpio",
+ .driver.owner = THIS_MODULE,
+ .driver.of_match_table = of_palmas_gpio_match,
+ .probe = palmas_gpio_probe,
+ .remove = palmas_gpio_remove,
+};
+
+static int __init palmas_gpio_init(void)
+{
+ return platform_driver_register(&palmas_gpio_driver);
+}
+subsys_initcall(palmas_gpio_init);
+
+static void __exit palmas_gpio_exit(void)
+{
+ platform_driver_unregister(&palmas_gpio_driver);
+}
+module_exit(palmas_gpio_exit);
+
+MODULE_ALIAS("platform:palmas-gpio");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 9c693ae1795..e721a37c347 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1,5 +1,5 @@
/*
- * PCA953x 4/8/16 bit I/O ports
+ * PCA953x 4/8/16/24/40 bit I/O ports
*
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
* Copyright (C) 2007 Marvell International Ltd.
@@ -15,9 +15,8 @@
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/i2c.h>
-#include <linux/i2c/pca953x.h>
+#include <linux/platform_data/pca953x.h>
#include <linux/slab.h>
#ifdef CONFIG_OF_GPIO
#include <linux/of_platform.h>
@@ -45,6 +44,7 @@
#define PCA957X_TYPE 0x2000
static const struct i2c_device_id pca953x_id[] = {
+ { "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
{ "pca9536", 4 | PCA953X_TYPE, },
@@ -57,6 +57,7 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9557", 8 | PCA953X_TYPE, },
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
+ { "pca9698", 40 | PCA953X_TYPE, },
{ "max7310", 8 | PCA953X_TYPE, },
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
@@ -66,23 +67,28 @@ static const struct i2c_device_id pca953x_id[] = {
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
+ { "xra1202", 8 | PCA953X_TYPE },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+
struct pca953x_chip {
unsigned gpio_start;
- u32 reg_output;
- u32 reg_direction;
+ u8 reg_output[MAX_BANK];
+ u8 reg_direction[MAX_BANK];
struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ
struct mutex irq_lock;
- u32 irq_mask;
- u32 irq_stat;
- u32 irq_trig_raise;
- u32 irq_trig_fall;
- int irq_base;
+ u8 irq_mask[MAX_BANK];
+ u8 irq_stat[MAX_BANK];
+ u8 irq_trig_raise[MAX_BANK];
+ u8 irq_trig_fall[MAX_BANK];
#endif
struct i2c_client *client;
@@ -91,33 +97,73 @@ struct pca953x_chip {
int chip_type;
};
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
+{
+ return container_of(gc, struct pca953x_chip, gpio_chip);
+}
+
+static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+ int off)
+{
+ int ret;
+ int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+ int offset = off / BANK_SZ;
+
+ ret = i2c_smbus_read_byte_data(chip->client,
+ (reg << bank_shift) + offset);
+ *val = ret;
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed reading register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
+ int off)
+{
+ int ret = 0;
+ int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+ int offset = off / BANK_SZ;
+
+ ret = i2c_smbus_write_byte_data(chip->client,
+ (reg << bank_shift) + offset, val);
+
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "failed writing register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
{
int ret = 0;
if (chip->gpio_chip.ngpio <= 8)
- ret = i2c_smbus_write_byte_data(chip->client, reg, val);
- else if (chip->gpio_chip.ngpio == 24) {
- cpu_to_le32s(&val);
+ ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
+ else if (chip->gpio_chip.ngpio >= 24) {
+ int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
ret = i2c_smbus_write_i2c_block_data(chip->client,
- (reg << 2) | REG_ADDR_AI,
- 3,
- (u8 *) &val);
- }
- else {
+ (reg << bank_shift) | REG_ADDR_AI,
+ NBANK(chip), val);
+ } else {
switch (chip->chip_type) {
case PCA953X_TYPE:
ret = i2c_smbus_write_word_data(chip->client,
- reg << 1, val);
+ reg << 1, (u16) *val);
break;
case PCA957X_TYPE:
ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
- val & 0xff);
+ val[0]);
if (ret < 0)
break;
ret = i2c_smbus_write_byte_data(chip->client,
(reg << 1) + 1,
- (val & 0xff00) >> 8);
+ val[1]);
break;
}
}
@@ -130,26 +176,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
return 0;
}
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
{
int ret;
if (chip->gpio_chip.ngpio <= 8) {
ret = i2c_smbus_read_byte_data(chip->client, reg);
*val = ret;
- }
- else if (chip->gpio_chip.ngpio == 24) {
- *val = 0;
+ } else if (chip->gpio_chip.ngpio >= 24) {
+ int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
ret = i2c_smbus_read_i2c_block_data(chip->client,
- (reg << 2) | REG_ADDR_AI,
- 3,
- (u8 *) val);
- le32_to_cpus(val);
+ (reg << bank_shift) | REG_ADDR_AI,
+ NBANK(chip), val);
} else {
ret = i2c_smbus_read_word_data(chip->client, reg << 1);
- *val = ret;
+ val[0] = (u16)ret & 0xFF;
+ val[1] = (u16)ret >> 8;
}
-
if (ret < 0) {
dev_err(&chip->client->dev, "failed reading register\n");
return ret;
@@ -160,14 +204,12 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip;
- uint reg_val;
+ struct pca953x_chip *chip = to_pca(gc);
+ u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
- reg_val = chip->reg_direction | (1u << off);
+ reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -177,11 +219,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
offset = PCA957X_CFG;
break;
}
- ret = pca953x_write_reg(chip, offset, reg_val);
+ ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret)
goto exit;
- chip->reg_direction = reg_val;
+ chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0;
exit:
mutex_unlock(&chip->i2c_lock);
@@ -191,18 +233,18 @@ exit:
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
- struct pca953x_chip *chip;
- uint reg_val;
+ struct pca953x_chip *chip = to_pca(gc);
+ u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
/* set output level */
if (val)
- reg_val = chip->reg_output | (1u << off);
+ reg_val = chip->reg_output[off / BANK_SZ]
+ | (1u << (off % BANK_SZ));
else
- reg_val = chip->reg_output & ~(1u << off);
+ reg_val = chip->reg_output[off / BANK_SZ]
+ & ~(1u << (off % BANK_SZ));
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -212,14 +254,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_OUT;
break;
}
- ret = pca953x_write_reg(chip, offset, reg_val);
+ ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret)
goto exit;
- chip->reg_output = reg_val;
+ chip->reg_output[off / BANK_SZ] = reg_val;
/* then direction */
- reg_val = chip->reg_direction & ~(1u << off);
+ reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
switch (chip->chip_type) {
case PCA953X_TYPE:
offset = PCA953X_DIRECTION;
@@ -228,11 +270,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
offset = PCA957X_CFG;
break;
}
- ret = pca953x_write_reg(chip, offset, reg_val);
+ ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret)
goto exit;
- chip->reg_direction = reg_val;
+ chip->reg_direction[off / BANK_SZ] = reg_val;
ret = 0;
exit:
mutex_unlock(&chip->i2c_lock);
@@ -241,12 +283,10 @@ exit:
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
- struct pca953x_chip *chip;
+ struct pca953x_chip *chip = to_pca(gc);
u32 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -256,7 +296,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
offset = PCA957X_IN;
break;
}
- ret = pca953x_read_reg(chip, offset, &reg_val);
+ ret = pca953x_read_single(chip, offset, &reg_val, off);
mutex_unlock(&chip->i2c_lock);
if (ret < 0) {
/* NOTE: diagnostic already emitted; that's all we should
@@ -266,22 +306,22 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
return 0;
}
- return (reg_val & (1u << off)) ? 1 : 0;
+ return (reg_val & (1u << (off % BANK_SZ))) ? 1 : 0;
}
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{
- struct pca953x_chip *chip;
- u32 reg_val;
+ struct pca953x_chip *chip = to_pca(gc);
+ u8 reg_val;
int ret, offset = 0;
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
-
mutex_lock(&chip->i2c_lock);
if (val)
- reg_val = chip->reg_output | (1u << off);
+ reg_val = chip->reg_output[off / BANK_SZ]
+ | (1u << (off % BANK_SZ));
else
- reg_val = chip->reg_output & ~(1u << off);
+ reg_val = chip->reg_output[off / BANK_SZ]
+ & ~(1u << (off % BANK_SZ));
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -291,11 +331,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
offset = PCA957X_OUT;
break;
}
- ret = pca953x_write_reg(chip, offset, reg_val);
+ ret = pca953x_write_single(chip, offset, reg_val, off);
if (ret)
goto exit;
- chip->reg_output = reg_val;
+ chip->reg_output[off / BANK_SZ] = reg_val;
exit:
mutex_unlock(&chip->i2c_lock);
}
@@ -310,7 +350,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->direction_output = pca953x_gpio_direction_output;
gc->get = pca953x_gpio_get_value;
gc->set = pca953x_gpio_set_value;
- gc->can_sleep = 1;
+ gc->can_sleep = true;
gc->base = chip->gpio_start;
gc->ngpio = gpios;
@@ -321,49 +361,48 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
-static int pca953x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
-{
- struct pca953x_chip *chip;
-
- chip = container_of(gc, struct pca953x_chip, gpio_chip);
- return chip->irq_base + off;
-}
-
static void pca953x_irq_mask(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
- chip->irq_mask &= ~(1 << (d->irq - chip->irq_base));
+ chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
}
static void pca953x_irq_unmask(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
- chip->irq_mask |= 1 << (d->irq - chip->irq_base);
+ chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
}
static void pca953x_irq_bus_lock(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
mutex_lock(&chip->irq_lock);
}
static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
- u32 new_irqs;
- u32 level;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
+ u8 new_irqs;
+ int level, i;
/* Look for any newly setup interrupt */
- new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
- new_irqs &= ~chip->reg_direction;
-
- while (new_irqs) {
- level = __ffs(new_irqs);
- pca953x_gpio_direction_input(&chip->gpio_chip, level);
- new_irqs &= ~(1 << level);
+ for (i = 0; i < NBANK(chip); i++) {
+ new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
+ new_irqs &= ~chip->reg_direction[i];
+
+ while (new_irqs) {
+ level = __ffs(new_irqs);
+ pca953x_gpio_direction_input(&chip->gpio_chip,
+ level + (BANK_SZ * i));
+ new_irqs &= ~(1 << level);
+ }
}
mutex_unlock(&chip->irq_lock);
@@ -371,9 +410,10 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
- u32 level = d->irq - chip->irq_base;
- u32 mask = 1 << level;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pca953x_chip *chip = to_pca(gc);
+ int bank_nb = d->hwirq / BANK_SZ;
+ u8 mask = 1 << (d->hwirq % BANK_SZ);
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -382,14 +422,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
}
if (type & IRQ_TYPE_EDGE_FALLING)
- chip->irq_trig_fall |= mask;
+ chip->irq_trig_fall[bank_nb] |= mask;
else
- chip->irq_trig_fall &= ~mask;
+ chip->irq_trig_fall[bank_nb] &= ~mask;
if (type & IRQ_TYPE_EDGE_RISING)
- chip->irq_trig_raise |= mask;
+ chip->irq_trig_raise[bank_nb] |= mask;
else
- chip->irq_trig_raise &= ~mask;
+ chip->irq_trig_raise[bank_nb] &= ~mask;
return 0;
}
@@ -403,13 +443,13 @@ static struct irq_chip pca953x_irq_chip = {
.irq_set_type = pca953x_irq_set_type,
};
-static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
{
- u32 cur_stat;
- u32 old_stat;
- u32 pending;
- u32 trigger;
- int ret, offset = 0;
+ u8 cur_stat[MAX_BANK];
+ u8 old_stat[MAX_BANK];
+ u8 pendings = 0;
+ u8 trigger[MAX_BANK], triggers = 0;
+ int ret, i, offset = 0;
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -419,47 +459,58 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
offset = PCA957X_IN;
break;
}
- ret = pca953x_read_reg(chip, offset, &cur_stat);
+ ret = pca953x_read_regs(chip, offset, cur_stat);
if (ret)
return 0;
/* Remove output pins from the equation */
- cur_stat &= chip->reg_direction;
+ for (i = 0; i < NBANK(chip); i++)
+ cur_stat[i] &= chip->reg_direction[i];
- old_stat = chip->irq_stat;
- trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+ memcpy(old_stat, chip->irq_stat, NBANK(chip));
- if (!trigger)
+ for (i = 0; i < NBANK(chip); i++) {
+ trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
+ triggers += trigger[i];
+ }
+
+ if (!triggers)
return 0;
- chip->irq_stat = cur_stat;
+ memcpy(chip->irq_stat, cur_stat, NBANK(chip));
- pending = (old_stat & chip->irq_trig_fall) |
- (cur_stat & chip->irq_trig_raise);
- pending &= trigger;
+ for (i = 0; i < NBANK(chip); i++) {
+ pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
+ (cur_stat[i] & chip->irq_trig_raise[i]);
+ pending[i] &= trigger[i];
+ pendings += pending[i];
+ }
- return pending;
+ return pendings;
}
static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{
struct pca953x_chip *chip = devid;
- u32 pending;
- u32 level;
-
- pending = pca953x_irq_pending(chip);
-
- if (!pending)
- return IRQ_HANDLED;
-
- do {
- level = __ffs(pending);
- handle_nested_irq(level + chip->irq_base);
-
- pending &= ~(1 << level);
- } while (pending);
+ u8 pending[MAX_BANK];
+ u8 level;
+ unsigned nhandled = 0;
+ int i;
+
+ if (!pca953x_irq_pending(chip, pending))
+ return IRQ_NONE;
+
+ for (i = 0; i < NBANK(chip); i++) {
+ while (pending[i]) {
+ level = __ffs(pending[i]);
+ handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+ level + (BANK_SZ * i)));
+ pending[i] &= ~(1 << level);
+ nhandled++;
+ }
+ }
- return IRQ_HANDLED;
+ return (nhandled > 0) ? IRQ_HANDLED : IRQ_NONE;
}
static int pca953x_irq_setup(struct pca953x_chip *chip,
@@ -467,12 +518,10 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
int irq_base)
{
struct i2c_client *client = chip->client;
- int ret, offset = 0;
- u32 temporary;
+ int ret, i, offset = 0;
if (irq_base != -1
&& (id->driver_data & PCA_INT)) {
- int lvl;
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -482,65 +531,47 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN;
break;
}
- ret = pca953x_read_reg(chip, offset, &temporary);
- chip->irq_stat = temporary;
+ ret = pca953x_read_regs(chip, offset, chip->irq_stat);
if (ret)
- goto out_failed;
+ return ret;
/*
* There is no way to know which GPIO line generated the
* interrupt. We have to rely on the previous read for
* this purpose.
*/
- chip->irq_stat &= chip->reg_direction;
+ for (i = 0; i < NBANK(chip); i++)
+ chip->irq_stat[i] &= chip->reg_direction[i];
mutex_init(&chip->irq_lock);
- chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
- if (chip->irq_base < 0)
- goto out_failed;
-
- for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
- int irq = lvl + chip->irq_base;
-
- irq_clear_status_flags(irq, IRQ_NOREQUEST);
- irq_set_chip_data(irq, chip);
- irq_set_chip(irq, &pca953x_irq_chip);
- irq_set_nested_thread(irq, true);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
- }
-
- ret = request_threaded_irq(client->irq,
+ ret = devm_request_threaded_irq(&client->dev,
+ client->irq,
NULL,
pca953x_irq_handler,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+ IRQF_SHARED,
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 = pca953x_gpio_to_irq;
+ ret = gpiochip_irqchip_add(&chip->gpio_chip,
+ &pca953x_irq_chip,
+ irq_base,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&client->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
+ }
}
return 0;
-
-out_failed:
- chip->irq_base = -1;
- return ret;
}
-static void pca953x_irq_teardown(struct pca953x_chip *chip)
-{
- if (chip->irq_base != -1) {
- irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio);
- free_irq(chip->client->irq, chip);
- }
-}
#else /* CONFIG_GPIO_PCA953X_IRQ */
static int pca953x_irq_setup(struct pca953x_chip *chip,
const struct i2c_device_id *id,
@@ -553,10 +584,6 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return 0;
}
-
-static void pca953x_irq_teardown(struct pca953x_chip *chip)
-{
-}
#endif
/*
@@ -574,11 +601,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
const __be32 *val;
int size;
+ *gpio_base = -1;
+
node = client->dev.of_node;
if (node == NULL)
return;
- *gpio_base = -1;
val = of_get_property(node, "linux,gpio-base", &size);
WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
if (val) {
@@ -602,57 +630,60 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
}
#endif
-static int __devinit device_pca953x_init(struct pca953x_chip *chip, u32 invert)
+static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
{
int ret;
+ u8 val[MAX_BANK];
- ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+ ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
if (ret)
goto out;
- ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
- &chip->reg_direction);
+ ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
+ chip->reg_direction);
if (ret)
goto out;
/* set platform specific polarity inversion */
- ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+ if (invert)
+ memset(val, 0xFF, NBANK(chip));
+ else
+ memset(val, 0, NBANK(chip));
+
+ ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
out:
return ret;
}
-static int __devinit device_pca957x_init(struct pca953x_chip *chip, u32 invert)
+static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
{
int ret;
- u32 val = 0;
-
- /* Let every port in proper state, that could save power */
- pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
- pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
- pca953x_write_reg(chip, PCA957X_OUT, 0x0);
+ u8 val[MAX_BANK];
- ret = pca953x_read_reg(chip, PCA957X_IN, &val);
- if (ret)
- goto out;
- ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+ ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
if (ret)
goto out;
- ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+ ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
if (ret)
goto out;
/* set platform specific polarity inversion */
- pca953x_write_reg(chip, PCA957X_INVRT, invert);
+ if (invert)
+ memset(val, 0xFF, NBANK(chip));
+ else
+ memset(val, 0, NBANK(chip));
+ pca953x_write_regs(chip, PCA957X_INVRT, val);
/* To enable register 6, 7 to controll pull up and pull down */
- pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+ memset(val, 0x02, NBANK(chip));
+ pca953x_write_regs(chip, PCA957X_BKEN, val);
return 0;
out:
return ret;
}
-static int __devinit pca953x_probe(struct i2c_client *client,
+static int pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca953x_platform_data *pdata;
@@ -661,11 +692,12 @@ static int __devinit pca953x_probe(struct i2c_client *client,
int ret;
u32 invert = 0;
- chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (pdata) {
irq_base = pdata->irq_base;
chip->gpio_start = pdata->gpio_base;
@@ -696,15 +728,15 @@ static int __devinit pca953x_probe(struct i2c_client *client,
else
ret = device_pca957x_init(chip, invert);
if (ret)
- goto out_failed;
+ return ret;
- ret = pca953x_irq_setup(chip, id, irq_base);
+ ret = gpiochip_add(&chip->gpio_chip);
if (ret)
- goto out_failed;
+ return ret;
- ret = gpiochip_add(&chip->gpio_chip);
+ ret = pca953x_irq_setup(chip, id, irq_base);
if (ret)
- goto out_failed_irq;
+ return ret;
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
@@ -715,17 +747,11 @@ static int __devinit pca953x_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
return 0;
-
-out_failed_irq:
- pca953x_irq_teardown(chip);
-out_failed:
- kfree(chip);
- return ret;
}
static int pca953x_remove(struct i2c_client *client)
{
- struct pca953x_platform_data *pdata = client->dev.platform_data;
+ struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca953x_chip *chip = i2c_get_clientdata(client);
int ret = 0;
@@ -746,14 +772,45 @@ static int pca953x_remove(struct i2c_client *client)
return ret;
}
- pca953x_irq_teardown(chip);
- kfree(chip);
return 0;
}
+static const struct of_device_id pca953x_dt_ids[] = {
+ { .compatible = "nxp,pca9505", },
+ { .compatible = "nxp,pca9534", },
+ { .compatible = "nxp,pca9535", },
+ { .compatible = "nxp,pca9536", },
+ { .compatible = "nxp,pca9537", },
+ { .compatible = "nxp,pca9538", },
+ { .compatible = "nxp,pca9539", },
+ { .compatible = "nxp,pca9554", },
+ { .compatible = "nxp,pca9555", },
+ { .compatible = "nxp,pca9556", },
+ { .compatible = "nxp,pca9557", },
+ { .compatible = "nxp,pca9574", },
+ { .compatible = "nxp,pca9575", },
+ { .compatible = "nxp,pca9698", },
+
+ { .compatible = "maxim,max7310", },
+ { .compatible = "maxim,max7312", },
+ { .compatible = "maxim,max7313", },
+ { .compatible = "maxim,max7315", },
+
+ { .compatible = "ti,pca6107", },
+ { .compatible = "ti,tca6408", },
+ { .compatible = "ti,tca6416", },
+ { .compatible = "ti,tca6424", },
+
+ { .compatible = "exar,xra1202", },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
+
static struct i2c_driver pca953x_driver = {
.driver = {
.name = "pca953x",
+ .of_match_table = pca953x_dt_ids,
},
.probe = pca953x_probe,
.remove = pca953x_remove,
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index 16af35cd2b1..27b46751ea7 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -18,17 +18,18 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/kernel.h>
-#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c/pcf857x.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
static const struct i2c_device_id pcf857x_id[] = {
@@ -45,10 +46,32 @@ static const struct i2c_device_id pcf857x_id[] = {
{ "pca9675", 16 },
{ "max7328", 8 },
{ "max7329", 8 },
+ { "tca9554", 8 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf857x_id);
+#ifdef CONFIG_OF
+static const struct of_device_id pcf857x_of_table[] = {
+ { .compatible = "nxp,pcf8574" },
+ { .compatible = "nxp,pcf8574a" },
+ { .compatible = "nxp,pca8574" },
+ { .compatible = "nxp,pca9670" },
+ { .compatible = "nxp,pca9672" },
+ { .compatible = "nxp,pca9674" },
+ { .compatible = "nxp,pcf8575" },
+ { .compatible = "nxp,pca8575" },
+ { .compatible = "nxp,pca9671" },
+ { .compatible = "nxp,pca9673" },
+ { .compatible = "nxp,pca9675" },
+ { .compatible = "maxim,max7328" },
+ { .compatible = "maxim,max7329" },
+ { .compatible = "ti,tca9554" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcf857x_of_table);
+#endif
+
/*
* The pcf857x, pca857x, and pca967x chips only expose one read and one
* write register. Writing a "one" bit (to match the reset state) lets
@@ -65,12 +88,11 @@ struct pcf857x {
struct gpio_chip chip;
struct i2c_client *client;
struct mutex lock; /* protect 'out' */
- struct work_struct work; /* irq demux work */
struct irq_domain *irq_domain; /* for irq demux */
spinlock_t slock; /* protect irq demux */
unsigned out; /* software latch */
unsigned status; /* current status */
- int irq; /* real irq number */
+ unsigned irq_mapped; /* mapped gpio irqs */
int (*write)(struct i2c_client *client, unsigned data);
int (*read)(struct i2c_client *client);
@@ -163,48 +185,54 @@ 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 irq_create_mapping(gpio->irq_domain, offset);
+ return ret;
}
-static void pcf857x_irq_demux_work(struct work_struct *work)
+static irqreturn_t pcf857x_irq(int irq, void *data)
{
- struct pcf857x *gpio = container_of(work,
- struct pcf857x,
- work);
+ struct pcf857x *gpio = data;
unsigned long change, i, status, flags;
status = gpio->read(gpio->client);
spin_lock_irqsave(&gpio->slock, flags);
- change = gpio->status ^ status;
+ /*
+ * call the interrupt handler iff gpio is used as
+ * interrupt source, just to avoid bad irqs
+ */
+
+ change = ((gpio->status ^ status) & gpio->irq_mapped);
for_each_set_bit(i, &change, gpio->chip.ngpio)
generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
gpio->status = status;
spin_unlock_irqrestore(&gpio->slock, flags);
-}
-
-static irqreturn_t pcf857x_irq_demux(int irq, void *data)
-{
- struct pcf857x *gpio = data;
-
- /*
- * pcf857x can't read/write data here,
- * since i2c data access might go to sleep.
- */
- schedule_work(&gpio->work);
return IRQ_HANDLED;
}
-static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int virq,
+static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hw)
{
- irq_set_chip_and_handler(virq,
+ 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;
}
@@ -217,33 +245,31 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
if (gpio->irq_domain)
irq_domain_remove(gpio->irq_domain);
- if (gpio->irq)
- free_irq(gpio->irq, gpio);
}
static int pcf857x_irq_domain_init(struct pcf857x *gpio,
- struct pcf857x_platform_data *pdata,
- struct device *dev)
+ struct i2c_client *client)
{
int status;
- gpio->irq_domain = irq_domain_add_linear(dev->of_node,
+ gpio->irq_domain = irq_domain_add_linear(client->dev.of_node,
gpio->chip.ngpio,
&pcf857x_irq_domain_ops,
- NULL);
+ gpio);
if (!gpio->irq_domain)
goto fail;
/* enable real irq */
- status = request_irq(pdata->irq, pcf857x_irq_demux, 0,
- dev_name(dev), gpio);
+ 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() */
- INIT_WORK(&gpio->work, pcf857x_irq_demux_work);
gpio->chip.to_irq = pcf857x_to_irq;
- gpio->irq = pdata->irq;
return 0;
@@ -257,17 +283,21 @@ fail:
static int pcf857x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct pcf857x_platform_data *pdata;
+ struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct device_node *np = client->dev.of_node;
struct pcf857x *gpio;
+ unsigned int n_latch = 0;
int status;
- pdata = client->dev.platform_data;
- if (!pdata) {
+ if (IS_ENABLED(CONFIG_OF) && np)
+ of_property_read_u32(np, "lines-initial-states", &n_latch);
+ else if (pdata)
+ n_latch = pdata->n_latch;
+ else
dev_dbg(&client->dev, "no platform data\n");
- }
/* Allocate, initialize, and register this gpio_chip. */
- gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
+ gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
if (!gpio)
return -ENOMEM;
@@ -275,7 +305,7 @@ static int pcf857x_probe(struct i2c_client *client,
spin_lock_init(&gpio->slock);
gpio->chip.base = pdata ? pdata->gpio_base : -1;
- gpio->chip.can_sleep = 1;
+ gpio->chip.can_sleep = true;
gpio->chip.dev = &client->dev;
gpio->chip.owner = THIS_MODULE;
gpio->chip.get = pcf857x_get;
@@ -285,11 +315,11 @@ static int pcf857x_probe(struct i2c_client *client,
gpio->chip.ngpio = id->driver_data;
/* enable gpio_to_irq() if platform has settings */
- if (pdata && pdata->irq) {
- status = pcf857x_irq_domain_init(gpio, pdata, &client->dev);
+ if (client->irq) {
+ status = pcf857x_irq_domain_init(gpio, client);
if (status < 0) {
dev_err(&client->dev, "irq_domain init failed\n");
- goto fail;
+ goto fail_irq_domain;
}
}
@@ -357,26 +387,17 @@ static int pcf857x_probe(struct i2c_client *client,
* may cause transient glitching since it can't know the last value
* written (some pins may need to be driven low).
*
- * Using pdata->n_latch avoids that trouble. When left initialized
- * to zero, our software copy of the "latch" then matches the chip's
- * all-ones reset state. Otherwise it flags pins to be driven low.
+ * Using n_latch avoids that trouble. When left initialized to zero,
+ * our software copy of the "latch" then matches the chip's all-ones
+ * reset state. Otherwise it flags pins to be driven low.
*/
- gpio->out = pdata ? ~pdata->n_latch : ~0;
+ gpio->out = ~n_latch;
gpio->status = gpio->out;
status = gpiochip_add(&gpio->chip);
if (status < 0)
goto fail;
- /* NOTE: these chips can issue "some pin-changed" IRQs, which we
- * don't yet even try to use. Among other issues, the relevant
- * genirq state isn't available to modular drivers; and most irq
- * methods can't be called from sleeping contexts.
- */
-
- dev_info(&client->dev, "%s\n",
- client->irq ? " (irq ignored)" : "");
-
/* Let platform code set up the GPIOs and their users.
* Now is the first time anyone could use them.
*/
@@ -388,22 +409,24 @@ static int pcf857x_probe(struct i2c_client *client,
dev_warn(&client->dev, "setup --> %d\n", status);
}
+ dev_info(&client->dev, "probed\n");
+
return 0;
fail:
- dev_dbg(&client->dev, "probe error %d for '%s'\n",
- status, client->name);
-
- if (pdata && pdata->irq)
+ if (client->irq)
pcf857x_irq_domain_cleanup(gpio);
- kfree(gpio);
+fail_irq_domain:
+ dev_dbg(&client->dev, "probe error %d for '%s'\n",
+ status, client->name);
+
return status;
}
static int pcf857x_remove(struct i2c_client *client)
{
- struct pcf857x_platform_data *pdata = client->dev.platform_data;
+ struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pcf857x *gpio = i2c_get_clientdata(client);
int status = 0;
@@ -418,13 +441,11 @@ static int pcf857x_remove(struct i2c_client *client)
}
}
- if (pdata && pdata->irq)
+ if (client->irq)
pcf857x_irq_domain_cleanup(gpio);
status = gpiochip_remove(&gpio->chip);
- if (status == 0)
- kfree(gpio);
- else
+ if (status)
dev_err(&client->dev, "%s --> %d\n", "remove", status);
return status;
}
@@ -433,6 +454,7 @@ static struct i2c_driver pcf857x_driver = {
.driver = {
.name = "pcf857x",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pcf857x_of_table),
},
.probe = pcf857x_probe,
.remove = pcf857x_remove,
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 4ad0c4f9171..d6eac9b17db 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -20,6 +20,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/slab.h>
#define PCH_EDGE_FALLING 0
#define PCH_EDGE_RISING BIT(0)
@@ -138,9 +139,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
unsigned long flags;
spin_lock_irqsave(&chip->spinlock, flags);
- pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
- pm |= (1 << nr);
- iowrite32(pm, &chip->reg->pm);
reg_val = ioread32(&chip->reg->po);
if (val)
@@ -148,6 +146,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
else
reg_val &= ~(1 << nr);
iowrite32(reg_val, &chip->reg->po);
+
+ pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
+ pm |= (1 << nr);
+ iowrite32(pm, &chip->reg->pm);
+
spin_unlock_irqrestore(&chip->spinlock, flags);
return 0;
@@ -215,6 +218,7 @@ static void pch_gpio_setup(struct pch_gpio *chip)
struct gpio_chip *gpio = &chip->gpio;
gpio->label = dev_name(chip->dev);
+ gpio->dev = chip->dev;
gpio->owner = THIS_MODULE;
gpio->direction_input = pch_gpio_direction_input;
gpio->get = pch_gpio_get;
@@ -223,7 +227,7 @@ static void pch_gpio_setup(struct pch_gpio *chip)
gpio->dbg_show = NULL;
gpio->base = -1;
gpio->ngpio = gpio_pins[chip->ioh];
- gpio->can_sleep = 0;
+ gpio->can_sleep = false;
gpio->to_irq = pch_gpio_to_irq;
}
@@ -325,7 +329,7 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
return ret;
}
-static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
+static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
unsigned int irq_start, unsigned int num)
{
struct irq_chip_generic *gc;
@@ -345,7 +349,7 @@ static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
-static int __devinit pch_gpio_probe(struct pci_dev *pdev,
+static int pch_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
s32 ret;
@@ -423,8 +427,7 @@ end:
err_request_irq:
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
- ret = gpiochip_remove(&chip->gpio);
- if (ret)
+ if (gpiochip_remove(&chip->gpio))
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
err_gpiochip_add:
@@ -442,7 +445,7 @@ err_pci_enable:
return ret;
}
-static void __devexit pch_gpio_remove(struct pci_dev *pdev)
+static void pch_gpio_remove(struct pci_dev *pdev)
{
int err;
struct pch_gpio *chip = pci_get_drvdata(pdev);
@@ -518,7 +521,7 @@ static int pch_gpio_resume(struct pci_dev *pdev)
#endif
#define PCI_VENDOR_ID_ROHM 0x10DB
-static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
+static const struct pci_device_id pch_gpio_pcidev_id[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) },
@@ -531,7 +534,7 @@ static struct pci_driver pch_gpio_driver = {
.name = "pch_gpio",
.id_table = pch_gpio_pcidev_id,
.probe = pch_gpio_probe,
- .remove = __devexit_p(pch_gpio_remove),
+ .remove = pch_gpio_remove,
.suspend = pch_gpio_suspend,
.resume = pch_gpio_resume
};
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b4b5da4fd2c..84b49cfb81a 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -15,15 +15,15 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/bitops.h>
-#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
-#include <asm/mach/irq.h>
#define GPIODIR 0x400
#define GPIOIS 0x404
@@ -48,16 +48,9 @@ struct pl061_context_save_regs {
#endif
struct pl061_gpio {
- /* Each of the two spinlocks protects a different set of hardware
- * regiters and data structurs. This decouples the code of the IRQ from
- * the GPIO code. This also makes the case of a GPIO routine call from
- * the IRQ code simpler.
- */
- spinlock_t lock; /* GPIO registers */
+ spinlock_t lock;
void __iomem *base;
- int irq_base;
- struct irq_chip_generic *irq_gc;
struct gpio_chip gc;
#ifdef CONFIG_PM
@@ -65,6 +58,24 @@ struct pl061_gpio {
#endif
};
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void pl061_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -76,7 +87,7 @@ static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
spin_lock_irqsave(&chip->lock, flags);
gpiodir = readb(chip->base + GPIODIR);
- gpiodir &= ~(1 << offset);
+ gpiodir &= ~(BIT(offset));
writeb(gpiodir, chip->base + GPIODIR);
spin_unlock_irqrestore(&chip->lock, flags);
@@ -94,16 +105,16 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
return -EINVAL;
spin_lock_irqsave(&chip->lock, flags);
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
gpiodir = readb(chip->base + GPIODIR);
- gpiodir |= 1 << offset;
+ gpiodir |= BIT(offset);
writeb(gpiodir, chip->base + GPIODIR);
/*
* gpio value is set again, because pl061 doesn't allow to set value of
* a gpio pin before configuring it in OUT mode.
*/
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
spin_unlock_irqrestore(&chip->lock, flags);
return 0;
@@ -113,67 +124,59 @@ static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- return !!readb(chip->base + (1 << (offset + 2)));
+ return !!readb(chip->base + (BIT(offset + 2)));
}
static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- writeb(!!value << offset, chip->base + (1 << (offset + 2)));
-}
-
-static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
-{
- struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
-
- if (chip->irq_base <= 0)
- return -EINVAL;
-
- return chip->irq_base + offset;
+ writeb(!!value << offset, chip->base + (BIT(offset + 2)));
}
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = gc->private;
- int offset = d->irq - chip->irq_base;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
+ u8 bit = BIT(offset);
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
- raw_spin_lock_irqsave(&gc->lock, flags);
+ spin_lock_irqsave(&chip->lock, flags);
gpioiev = readb(chip->base + GPIOIEV);
-
gpiois = readb(chip->base + GPIOIS);
+ gpioibe = readb(chip->base + GPIOIBE);
+
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- gpiois |= 1 << offset;
+ gpiois |= bit;
if (trigger & IRQ_TYPE_LEVEL_HIGH)
- gpioiev |= 1 << offset;
+ gpioiev |= bit;
else
- gpioiev &= ~(1 << offset);
+ gpioiev &= ~bit;
} else
- gpiois &= ~(1 << offset);
- writeb(gpiois, chip->base + GPIOIS);
+ gpiois &= ~bit;
- gpioibe = readb(chip->base + GPIOIBE);
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- gpioibe |= 1 << offset;
+ /* Setting this makes GPIOEV be ignored */
+ gpioibe |= bit;
else {
- gpioibe &= ~(1 << offset);
+ gpioibe &= ~bit;
if (trigger & IRQ_TYPE_EDGE_RISING)
- gpioiev |= 1 << offset;
+ gpioiev |= bit;
else if (trigger & IRQ_TYPE_EDGE_FALLING)
- gpioiev &= ~(1 << offset);
+ gpioiev &= ~bit;
}
- writeb(gpioibe, chip->base + GPIOIBE);
+ writeb(gpiois, chip->base + GPIOIS);
+ writeb(gpioibe, chip->base + GPIOIBE);
writeb(gpioiev, chip->base + GPIOIEV);
- raw_spin_unlock_irqrestore(&gc->lock, flags);
+ spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -182,7 +185,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
{
unsigned long pending;
int offset;
- struct pl061_gpio *chip = irq_desc_get_handler_data(desc);
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
struct irq_chip *irqchip = irq_desc_get_chip(desc);
chained_irq_enter(irqchip, desc);
@@ -191,121 +195,125 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
writeb(pending, chip->base + GPIOIC);
if (pending) {
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
- generic_handle_irq(pl061_to_irq(&chip->gc, offset));
+ generic_handle_irq(irq_find_mapping(gc->irqdomain,
+ offset));
}
chained_irq_exit(irqchip, desc);
}
-static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+static void pl061_irq_mask(struct irq_data *d)
{
- struct irq_chip_type *ct;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
- chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
- chip->base, handle_simple_irq);
- chip->irq_gc->private = chip;
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) & ~mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
- ct = chip->irq_gc->chip_types;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->chip.irq_set_type = pl061_irq_type;
- ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->regs.mask = GPIOIE;
+static void pl061_irq_unmask(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+ u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
- irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
- IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) | mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
}
-static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
+static struct irq_chip pl061_irqchip = {
+ .name = "pl061",
+ .irq_mask = pl061_irq_mask,
+ .irq_unmask = pl061_irq_unmask,
+ .irq_set_type = pl061_irq_type,
+};
+
+static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
- struct pl061_platform_data *pdata;
+ struct device *dev = &adev->dev;
+ struct pl061_platform_data *pdata = dev_get_platdata(dev);
struct pl061_gpio *chip;
- int ret, irq, i;
+ int ret, irq, i, irq_base;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
- pdata = dev->dev.platform_data;
if (pdata) {
chip->gc.base = pdata->gpio_base;
- chip->irq_base = pdata->irq_base;
- } else if (dev->dev.of_node) {
- chip->gc.base = -1;
- chip->irq_base = 0;
+ irq_base = pdata->irq_base;
+ if (irq_base <= 0) {
+ dev_err(&adev->dev, "invalid IRQ base in pdata\n");
+ return -ENODEV;
+ }
} else {
- ret = -ENODEV;
- goto free_mem;
- }
-
- if (!request_mem_region(dev->res.start,
- resource_size(&dev->res), "pl061")) {
- ret = -EBUSY;
- goto free_mem;
+ chip->gc.base = -1;
+ irq_base = 0;
}
- chip->base = ioremap(dev->res.start, resource_size(&dev->res));
- if (chip->base == NULL) {
- ret = -ENOMEM;
- goto release_region;
- }
+ chip->base = devm_ioremap_resource(dev, &adev->res);
+ if (IS_ERR(chip->base))
+ return PTR_ERR(chip->base);
spin_lock_init(&chip->lock);
+ chip->gc.request = pl061_gpio_request;
+ chip->gc.free = pl061_gpio_free;
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
chip->gc.set = pl061_set_value;
- chip->gc.to_irq = pl061_to_irq;
chip->gc.ngpio = PL061_GPIO_NR;
- chip->gc.label = dev_name(&dev->dev);
- chip->gc.dev = &dev->dev;
+ chip->gc.label = dev_name(dev);
+ chip->gc.dev = dev;
chip->gc.owner = THIS_MODULE;
ret = gpiochip_add(&chip->gc);
if (ret)
- goto iounmap;
+ return ret;
/*
* irq_chip support
*/
-
- if (chip->irq_base <= 0)
- return 0;
-
- pl061_init_gc(chip, chip->irq_base);
-
writeb(0, chip->base + GPIOIE); /* disable irqs */
- irq = dev->irq[0];
+ irq = adev->irq[0];
if (irq < 0) {
- ret = -ENODEV;
- goto iounmap;
+ dev_err(&adev->dev, "invalid IRQ\n");
+ return -ENODEV;
+ }
+
+ ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
+ irq_base, handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_info(&adev->dev, "could not add irqchip\n");
+ return ret;
}
- irq_set_chained_handler(irq, pl061_irq_handler);
- irq_set_handler_data(irq, chip);
+ gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip,
+ irq, pl061_irq_handler);
for (i = 0; i < PL061_GPIO_NR; i++) {
if (pdata) {
- if (pdata->directions & (1 << i))
+ if (pdata->directions & (BIT(i)))
pl061_direction_output(&chip->gc, i,
- pdata->values & (1 << i));
+ pdata->values & (BIT(i)));
else
pl061_direction_input(&chip->gc, i);
}
}
- amba_set_drvdata(dev, chip);
+ amba_set_drvdata(adev, chip);
+ dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
+ &adev->res.start);
return 0;
-
-iounmap:
- iounmap(chip->base);
-release_region:
- release_mem_region(dev->res.start, resource_size(&dev->res));
-free_mem:
- kfree(chip);
-
- return ret;
}
#ifdef CONFIG_PM
@@ -322,7 +330,7 @@ static int pl061_suspend(struct device *dev)
chip->csave_regs.gpio_ie = readb(chip->base + GPIOIE);
for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (chip->csave_regs.gpio_dir & (1 << offset))
+ if (chip->csave_regs.gpio_dir & (BIT(offset)))
chip->csave_regs.gpio_data |=
pl061_get_value(&chip->gc, offset) << offset;
}
@@ -336,10 +344,10 @@ static int pl061_resume(struct device *dev)
int offset;
for (offset = 0; offset < PL061_GPIO_NR; offset++) {
- if (chip->csave_regs.gpio_dir & (1 << offset))
+ if (chip->csave_regs.gpio_dir & (BIT(offset)))
pl061_direction_output(&chip->gc, offset,
chip->csave_regs.gpio_data &
- (1 << offset));
+ (BIT(offset)));
else
pl061_direction_input(&chip->gc, offset);
}
@@ -385,7 +393,7 @@ static int __init pl061_gpio_init(void)
{
return amba_driver_register(&pl061_gpio_driver);
}
-subsys_initcall(pl061_gpio_init);
+module_init(pl061_gpio_init);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("PL061 GPIO driver");
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index 98d52cb3fd1..42e6e64f212 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -26,8 +27,6 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
-#include <asm/mach/irq.h>
-
#include <mach/irqs.h>
/*
@@ -86,20 +85,61 @@ struct pxa_gpio_chip {
#endif
};
-enum {
+enum pxa_gpio_type {
PXA25X_GPIO = 0,
PXA26X_GPIO,
PXA27X_GPIO,
PXA3XX_GPIO,
PXA93X_GPIO,
MMP_GPIO = 0x10,
+ MMP2_GPIO,
+};
+
+struct pxa_gpio_id {
+ enum pxa_gpio_type type;
+ int gpio_nums;
};
static DEFINE_SPINLOCK(gpio_lock);
static struct pxa_gpio_chip *pxa_gpio_chips;
-static int gpio_type;
+static enum pxa_gpio_type gpio_type;
static void __iomem *gpio_reg_base;
+static struct pxa_gpio_id pxa25x_id = {
+ .type = PXA25X_GPIO,
+ .gpio_nums = 85,
+};
+
+static struct pxa_gpio_id pxa26x_id = {
+ .type = PXA26X_GPIO,
+ .gpio_nums = 90,
+};
+
+static struct pxa_gpio_id pxa27x_id = {
+ .type = PXA27X_GPIO,
+ .gpio_nums = 121,
+};
+
+static struct pxa_gpio_id pxa3xx_id = {
+ .type = PXA3XX_GPIO,
+ .gpio_nums = 128,
+};
+
+static struct pxa_gpio_id pxa93x_id = {
+ .type = PXA93X_GPIO,
+ .gpio_nums = 192,
+};
+
+static struct pxa_gpio_id mmp_id = {
+ .type = MMP_GPIO,
+ .gpio_nums = 128,
+};
+
+static struct pxa_gpio_id mmp2_id = {
+ .type = MMP2_GPIO,
+ .gpio_nums = 192,
+};
+
#define for_each_gpio_chip(i, c) \
for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
@@ -223,7 +263,8 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- return readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset);
+ u32 gplr = readl_relaxed(gpio_chip_base(chip) + GPLR_OFFSET);
+ return !!(gplr & (1 << offset));
}
static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -250,7 +291,7 @@ static int pxa_gpio_of_xlate(struct gpio_chip *gc,
}
#endif
-static int __devinit pxa_init_gpio_chip(int gpio_end,
+static int pxa_init_gpio_chip(int gpio_end,
int (*set_wake)(unsigned int, unsigned int))
{
int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
@@ -432,47 +473,39 @@ static struct irq_chip pxa_muxed_gpio_chip = {
.irq_set_wake = pxa_gpio_set_wake,
};
-static int pxa_gpio_nums(void)
+static int pxa_gpio_nums(struct platform_device *pdev)
{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct pxa_gpio_id *pxa_id = (struct pxa_gpio_id *)id->driver_data;
int count = 0;
-#ifdef CONFIG_ARCH_PXA
- if (cpu_is_pxa25x()) {
-#ifdef CONFIG_CPU_PXA26x
- count = 89;
- gpio_type = PXA26X_GPIO;
-#elif defined(CONFIG_PXA25x)
- count = 84;
- gpio_type = PXA26X_GPIO;
-#endif /* CONFIG_CPU_PXA26x */
- } else if (cpu_is_pxa27x()) {
- count = 120;
- gpio_type = PXA27X_GPIO;
- } else if (cpu_is_pxa93x() || cpu_is_pxa95x()) {
- count = 191;
- gpio_type = PXA93X_GPIO;
- } else if (cpu_is_pxa3xx()) {
- count = 127;
- gpio_type = PXA3XX_GPIO;
- }
-#endif /* CONFIG_ARCH_PXA */
-
-#ifdef CONFIG_ARCH_MMP
- if (cpu_is_pxa168() || cpu_is_pxa910()) {
- count = 127;
- gpio_type = MMP_GPIO;
- } else if (cpu_is_mmp2()) {
- count = 191;
- gpio_type = MMP_GPIO;
+ switch (pxa_id->type) {
+ case PXA25X_GPIO:
+ case PXA26X_GPIO:
+ case PXA27X_GPIO:
+ case PXA3XX_GPIO:
+ case PXA93X_GPIO:
+ case MMP_GPIO:
+ case MMP2_GPIO:
+ gpio_type = pxa_id->type;
+ count = pxa_id->gpio_nums - 1;
+ break;
+ default:
+ count = -EINVAL;
+ break;
}
-#endif /* CONFIG_ARCH_MMP */
return count;
}
#ifdef CONFIG_OF
static struct of_device_id pxa_gpio_dt_ids[] = {
- { .compatible = "mrvl,pxa-gpio" },
- { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+ { .compatible = "intel,pxa25x-gpio", .data = &pxa25x_id, },
+ { .compatible = "intel,pxa26x-gpio", .data = &pxa26x_id, },
+ { .compatible = "intel,pxa27x-gpio", .data = &pxa27x_id, },
+ { .compatible = "intel,pxa3xx-gpio", .data = &pxa3xx_id, },
+ { .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
+ { .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
+ { .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
{}
};
@@ -490,39 +523,28 @@ const struct irq_domain_ops pxa_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
+static int pxa_gpio_probe_dt(struct platform_device *pdev)
{
- int ret, nr_banks, nr_gpios;
- struct device_node *prev, *next, *np = pdev->dev.of_node;
+ int ret = 0, nr_gpios;
+ struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+ const struct pxa_gpio_id *gpio_id;
- if (!of_id) {
+ if (!of_id || !of_id->data) {
dev_err(&pdev->dev, "Failed to find gpio controller\n");
return -EFAULT;
}
- gpio_type = (int)of_id->data;
+ gpio_id = of_id->data;
+ gpio_type = gpio_id->type;
- next = of_get_next_child(np, NULL);
- prev = next;
- if (!next) {
- dev_err(&pdev->dev, "Failed to find child gpio node\n");
- ret = -EINVAL;
- goto err;
- }
- for (nr_banks = 1; ; nr_banks++) {
- next = of_get_next_child(np, prev);
- if (!next)
- break;
- prev = next;
- }
- of_node_put(prev);
- nr_gpios = nr_banks << 5;
+ nr_gpios = gpio_id->gpio_nums;
pxa_last_gpio = nr_gpios - 1;
irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
if (irq_base < 0) {
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ ret = irq_base;
goto err;
}
domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
@@ -537,7 +559,7 @@ err:
#define pxa_gpio_probe_dt(pdev) (-1)
#endif
-static int __devinit pxa_gpio_probe(struct platform_device *pdev)
+static int pxa_gpio_probe(struct platform_device *pdev)
{
struct pxa_gpio_chip *c;
struct resource *res;
@@ -546,19 +568,18 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
int gpio, irq, ret, use_of = 0;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
- ret = pxa_gpio_probe_dt(pdev);
- if (ret < 0) {
- pxa_last_gpio = pxa_gpio_nums();
-#ifdef CONFIG_ARCH_PXA
- if (gpio_is_pxa_type(gpio_type))
- irq_base = PXA_GPIO_TO_IRQ(0);
-#endif
-#ifdef CONFIG_ARCH_MMP
- if (gpio_is_mmp_type(gpio_type))
- irq_base = MMP_GPIO_TO_IRQ(0);
-#endif
+ info = dev_get_platdata(&pdev->dev);
+ if (info) {
+ irq_base = info->irq_base;
+ if (irq_base <= 0)
+ return -EINVAL;
+ pxa_last_gpio = pxa_gpio_nums(pdev);
} else {
+ irq_base = 0;
use_of = 1;
+ ret = pxa_gpio_probe_dt(pdev);
+ if (ret < 0)
+ return -EINVAL;
}
if (!pxa_last_gpio)
@@ -595,14 +616,13 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
}
/* Initialize GPIO chips */
- info = dev_get_platdata(&pdev->dev);
pxa_init_gpio_chip(pxa_last_gpio, info ? info->gpio_set_wake : NULL);
/* clear all GPIO edge detects */
for_each_gpio_chip(gpio, c) {
writel_relaxed(0, c->regbase + GFER_OFFSET);
writel_relaxed(0, c->regbase + GRER_OFFSET);
- writel_relaxed(~0,c->regbase + GEDR_OFFSET);
+ writel_relaxed(~0, c->regbase + GEDR_OFFSET);
/* unmask GPIO edge detect for AP side */
if (gpio_is_mmp_type(gpio_type))
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
@@ -635,12 +655,24 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id gpio_id_table[] = {
+ { "pxa25x-gpio", (unsigned long)&pxa25x_id },
+ { "pxa26x-gpio", (unsigned long)&pxa26x_id },
+ { "pxa27x-gpio", (unsigned long)&pxa27x_id },
+ { "pxa3xx-gpio", (unsigned long)&pxa3xx_id },
+ { "pxa93x-gpio", (unsigned long)&pxa93x_id },
+ { "mmp-gpio", (unsigned long)&mmp_id },
+ { "mmp2-gpio", (unsigned long)&mmp2_id },
+ { },
+};
+
static struct platform_driver pxa_gpio_driver = {
.probe = pxa_gpio_probe,
.driver = {
.name = "pxa-gpio",
.of_match_table = of_match_ptr(pxa_gpio_dt_ids),
},
+ .id_table = gpio_id_table,
};
static int __init pxa_gpio_init(void)
@@ -674,7 +706,7 @@ static void pxa_gpio_resume(void)
for_each_gpio_chip(gpio, c) {
/* restore level with set/clear */
- writel_relaxed( c->saved_gplr, c->regbase + GPSR_OFFSET);
+ writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
writel_relaxed(~c->saved_gplr, c->regbase + GPCR_OFFSET);
writel_relaxed(c->saved_grer, c->regbase + GRER_OFFSET);
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 08428bf1771..562b0c4d9cc 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
- if ((offset >= 0) && (offset < 8))
+ if (offset < RC5T583_MAX_GPIO)
return rc5t583_gpio->rc5t583->irq_base +
RC5T583_IRQ_GPIO0 + offset;
return -EINVAL;
@@ -111,7 +111,7 @@ static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
}
-static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
+static int rc5t583_gpio_probe(struct platform_device *pdev)
{
struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
@@ -119,10 +119,8 @@ static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio),
GFP_KERNEL);
- if (!rc5t583_gpio) {
- dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed");
+ if (!rc5t583_gpio)
return -ENOMEM;
- }
rc5t583_gpio->gpio_chip.label = "gpio-rc5t583",
rc5t583_gpio->gpio_chip.owner = THIS_MODULE,
@@ -133,7 +131,7 @@ static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get,
rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
- rc5t583_gpio->gpio_chip.can_sleep = 1,
+ rc5t583_gpio->gpio_chip.can_sleep = true,
rc5t583_gpio->gpio_chip.dev = &pdev->dev;
rc5t583_gpio->gpio_chip.base = -1;
rc5t583_gpio->rc5t583 = rc5t583;
@@ -146,7 +144,7 @@ static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
return gpiochip_add(&rc5t583_gpio->gpio_chip);
}
-static int __devexit rc5t583_gpio_remove(struct platform_device *pdev)
+static int rc5t583_gpio_remove(struct platform_device *pdev)
{
struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
@@ -159,7 +157,7 @@ static struct platform_driver rc5t583_gpio_driver = {
.owner = THIS_MODULE,
},
.probe = rc5t583_gpio_probe,
- .remove = __devexit_p(rc5t583_gpio_remove),
+ .remove = rc5t583_gpio_remove,
};
static int __init rc5t583_gpio_init(void)
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
new file mode 100644
index 00000000000..b6ae89ea881
--- /dev/null
+++ b/drivers/gpio/gpio-rcar.c
@@ -0,0 +1,500 @@
+/*
+ * Renesas R-Car GPIO Support
+ *
+ * Copyright (C) 2013 Magnus Damm
+ *
+ * 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
+ *
+ * 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/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/gpio-rcar.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+struct gpio_rcar_priv {
+ void __iomem *base;
+ spinlock_t lock;
+ struct gpio_rcar_config config;
+ struct platform_device *pdev;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+};
+
+#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 RCAR_MAX_GPIO_PER_BANK 32
+
+static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)
+{
+ return ioread32(p->base + offs);
+}
+
+static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs,
+ u32 value)
+{
+ iowrite32(value, p->base + offs);
+}
+
+static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,
+ int bit, bool value)
+{
+ u32 tmp = gpio_rcar_read(p, offs);
+
+ if (value)
+ tmp |= BIT(bit);
+ else
+ tmp &= ~BIT(bit);
+
+ gpio_rcar_write(p, offs, tmp);
+}
+
+static void gpio_rcar_irq_disable(struct irq_data *d)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+
+ gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
+}
+
+static void gpio_rcar_irq_enable(struct irq_data *d)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+
+ gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
+}
+
+static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
+ unsigned int hwirq,
+ bool active_high_rising_edge,
+ bool level_trigger,
+ bool both)
+{
+ unsigned long flags;
+
+ /* follow steps in the GPIO documentation for
+ * "Setting Edge-Sensitive Interrupt Input Mode" and
+ * "Setting Level-Sensitive Interrupt Input Mode"
+ */
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* Configure postive or negative logic in POSNEG */
+ gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
+
+ /* Configure edge or level trigger in EDGLEVEL */
+ gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
+
+ /* Select one edge or both edges in BOTHEDGE */
+ if (p->config.has_both_edge_trigger)
+ gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
+
+ /* Select "Interrupt Input Mode" in IOINTSEL */
+ gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);
+
+ /* Write INTCLR in case of edge trigger */
+ if (!level_trigger)
+ gpio_rcar_write(p, INTCLR, BIT(hwirq));
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+ unsigned int hwirq = irqd_to_hwirq(d);
+
+ dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true,
+ false);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true,
+ false);
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
+ false);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false,
+ false);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ if (!p->config.has_both_edge_trigger)
+ return -EINVAL;
+ gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
+ true);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_rcar_priv *p = dev_id;
+ u32 pending;
+ unsigned int offset, irqs_handled = 0;
+
+ while ((pending = gpio_rcar_read(p, INTDT) &
+ gpio_rcar_read(p, INTMSK))) {
+ offset = __ffs(pending);
+ gpio_rcar_write(p, INTCLR, BIT(offset));
+ generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+ irqs_handled++;
+ }
+
+ return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline struct gpio_rcar_priv *gpio_to_priv(struct gpio_chip *chip)
+{
+ return container_of(chip, struct gpio_rcar_priv, gpio_chip);
+}
+
+static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
+ unsigned int gpio,
+ bool output)
+{
+ struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ unsigned long flags;
+
+ /* follow steps in the GPIO documentation for
+ * "Setting General Output Mode" and
+ * "Setting General Input Mode"
+ */
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* Configure postive logic in POSNEG */
+ gpio_rcar_modify_bit(p, POSNEG, gpio, false);
+
+ /* Select "General Input/Output Mode" in IOINTSEL */
+ gpio_rcar_modify_bit(p, IOINTSEL, gpio, false);
+
+ /* Select Input Mode or Output Mode in INOUTSEL */
+ gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+
+ /* Set the GPIO as an input to ensure that the next GPIO request won't
+ * drive the GPIO pin as an output.
+ */
+ gpio_rcar_config_general_input_output_mode(chip, offset, false);
+}
+
+static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ gpio_rcar_config_general_input_output_mode(chip, offset, false);
+ return 0;
+}
+
+static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
+{
+ u32 bit = BIT(offset);
+
+ /* testing on r8a7790 shows that INDT does not show correct pin state
+ * when configured as output, so use OUTDT in case of output pins */
+ if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+ else
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
+}
+
+static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct gpio_rcar_priv *p = gpio_to_priv(chip);
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->lock, flags);
+ gpio_rcar_modify_bit(p, OUTDT, offset, value);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ gpio_rcar_set(chip, offset, value);
+ gpio_rcar_config_general_input_output_mode(chip, offset, true);
+ return 0;
+}
+
+static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
+}
+
+static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct gpio_rcar_priv *p = h->host_data;
+
+ dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq);
+
+ irq_set_chip_data(irq, h->host_data);
+ irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
+ .map = gpio_rcar_irq_domain_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+struct gpio_rcar_info {
+ bool has_both_edge_trigger;
+};
+
+static const struct of_device_id gpio_rcar_of_table[] = {
+ {
+ .compatible = "renesas,gpio-r8a7790",
+ .data = (void *)&(const struct gpio_rcar_info) {
+ .has_both_edge_trigger = true,
+ },
+ }, {
+ .compatible = "renesas,gpio-r8a7791",
+ .data = (void *)&(const struct gpio_rcar_info) {
+ .has_both_edge_trigger = true,
+ },
+ }, {
+ .compatible = "renesas,gpio-rcar",
+ .data = (void *)&(const struct gpio_rcar_info) {
+ .has_both_edge_trigger = false,
+ },
+ }, {
+ /* Terminator */
+ },
+};
+
+MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);
+
+static int gpio_rcar_parse_pdata(struct gpio_rcar_priv *p)
+{
+ struct gpio_rcar_config *pdata = dev_get_platdata(&p->pdev->dev);
+ struct device_node *np = p->pdev->dev.of_node;
+ struct of_phandle_args args;
+ int ret;
+
+ if (pdata) {
+ p->config = *pdata;
+ } else if (IS_ENABLED(CONFIG_OF) && np) {
+ const struct of_device_id *match;
+ const struct gpio_rcar_info *info;
+
+ match = of_match_node(gpio_rcar_of_table, np);
+ if (!match)
+ return -EINVAL;
+
+ info = match->data;
+
+ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0,
+ &args);
+ p->config.number_of_pins = ret == 0 ? args.args[2]
+ : RCAR_MAX_GPIO_PER_BANK;
+ p->config.gpio_base = -1;
+ p->config.has_both_edge_trigger = info->has_both_edge_trigger;
+ }
+
+ if (p->config.number_of_pins == 0 ||
+ p->config.number_of_pins > RCAR_MAX_GPIO_PER_BANK) {
+ dev_warn(&p->pdev->dev,
+ "Invalid number of gpio lines %u, using %u\n",
+ p->config.number_of_pins, RCAR_MAX_GPIO_PER_BANK);
+ p->config.number_of_pins = RCAR_MAX_GPIO_PER_BANK;
+ }
+
+ return 0;
+}
+
+static int gpio_rcar_probe(struct platform_device *pdev)
+{
+ struct gpio_rcar_priv *p;
+ struct resource *io, *irq;
+ struct gpio_chip *gpio_chip;
+ struct irq_chip *irq_chip;
+ struct device *dev = &pdev->dev;
+ const char *name = dev_name(dev);
+ int ret;
+
+ p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ p->pdev = pdev;
+ spin_lock_init(&p->lock);
+
+ /* Get device configuration from DT node or platform data. */
+ ret = gpio_rcar_parse_pdata(p);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, p);
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+
+ io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!io || !irq) {
+ dev_err(dev, "missing IRQ or IOMEM\n");
+ ret = -EINVAL;
+ goto err0;
+ }
+
+ p->base = devm_ioremap_nocache(dev, io->start, resource_size(io));
+ if (!p->base) {
+ dev_err(dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto err0;
+ }
+
+ gpio_chip = &p->gpio_chip;
+ gpio_chip->request = gpio_rcar_request;
+ gpio_chip->free = gpio_rcar_free;
+ gpio_chip->direction_input = gpio_rcar_direction_input;
+ gpio_chip->get = gpio_rcar_get;
+ gpio_chip->direction_output = gpio_rcar_direction_output;
+ gpio_chip->set = gpio_rcar_set;
+ gpio_chip->to_irq = gpio_rcar_to_irq;
+ gpio_chip->label = name;
+ gpio_chip->dev = dev;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->base = p->config.gpio_base;
+ gpio_chip->ngpio = p->config.number_of_pins;
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ 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;
+
+ p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
+ p->config.number_of_pins,
+ p->config.irq_base,
+ &gpio_rcar_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ ret = -ENXIO;
+ dev_err(dev, "cannot initialize irq domain\n");
+ goto err0;
+ }
+
+ if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
+ IRQF_SHARED, name, p)) {
+ dev_err(dev, "failed to request IRQ\n");
+ ret = -ENOENT;
+ goto err1;
+ }
+
+ ret = gpiochip_add(gpio_chip);
+ if (ret) {
+ dev_err(dev, "failed to add GPIO controller\n");
+ goto err1;
+ }
+
+ dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
+
+ /* warn in case of mismatch if irq base is specified */
+ if (p->config.irq_base) {
+ ret = irq_find_mapping(p->irq_domain, 0);
+ if (p->config.irq_base != ret)
+ dev_warn(dev, "irq base mismatch (%u/%u)\n",
+ p->config.irq_base, ret);
+ }
+
+ if (p->config.pctl_name) {
+ ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
+ gpio_chip->base, gpio_chip->ngpio);
+ if (ret < 0)
+ dev_warn(dev, "failed to add pin range\n");
+ }
+
+ return 0;
+
+err1:
+ irq_domain_remove(p->irq_domain);
+err0:
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+ return ret;
+}
+
+static int gpio_rcar_remove(struct platform_device *pdev)
+{
+ struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = gpiochip_remove(&p->gpio_chip);
+ if (ret)
+ return ret;
+
+ irq_domain_remove(p->irq_domain);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver gpio_rcar_device_driver = {
+ .probe = gpio_rcar_probe,
+ .remove = gpio_rcar_remove,
+ .driver = {
+ .name = "gpio_rcar",
+ .of_match_table = of_match_ptr(gpio_rcar_of_table),
+ }
+};
+
+module_platform_driver(gpio_rcar_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas R-Car GPIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index b62d443e9a5..9fa7e53331c 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -128,30 +128,28 @@ static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
/*
* Cache the initial value of both GPIO data registers
*/
-static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
+static int rdc321x_gpio_probe(struct platform_device *pdev)
{
int err;
struct resource *r;
struct rdc321x_gpio *rdc321x_gpio_dev;
struct rdc321x_gpio_pdata *pdata;
- pdata = pdev->dev.platform_data;
+ pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
}
- rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL);
- if (!rdc321x_gpio_dev) {
- dev_err(&pdev->dev, "failed to allocate private data\n");
+ rdc321x_gpio_dev = devm_kzalloc(&pdev->dev, sizeof(struct rdc321x_gpio),
+ GFP_KERNEL);
+ if (!rdc321x_gpio_dev)
return -ENOMEM;
- }
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
- err = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
spin_lock_init(&rdc321x_gpio_dev->lock);
@@ -162,8 +160,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
if (!r) {
dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
- err = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
rdc321x_gpio_dev->reg2_ctrl_base = r->start;
@@ -187,26 +184,20 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]);
if (err)
- goto out_drvdata;
+ return err;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]);
if (err)
- goto out_drvdata;
+ return err;
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip);
-
-out_drvdata:
- platform_set_drvdata(pdev, NULL);
-out_free:
- kfree(rdc321x_gpio_dev);
- return err;
}
-static int __devexit rdc321x_gpio_remove(struct platform_device *pdev)
+static int rdc321x_gpio_remove(struct platform_device *pdev)
{
int ret;
struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev);
@@ -215,9 +206,6 @@ static int __devexit rdc321x_gpio_remove(struct platform_device *pdev)
if (ret)
dev_err(&pdev->dev, "failed to unregister chip\n");
- kfree(rdc321x_gpio_dev);
- platform_set_drvdata(pdev, NULL);
-
return ret;
}
@@ -225,7 +213,7 @@ static struct platform_driver rdc321x_gpio_driver = {
.driver.name = "rdc321x-gpio",
.driver.owner = THIS_MODULE,
.probe = rdc321x_gpio_probe,
- .remove = __devexit_p(rdc321x_gpio_remove),
+ .remove = rdc321x_gpio_remove,
};
module_platform_driver(rdc321x_gpio_driver);
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index 8ea3b33d4b4..a90be34e4d5 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -10,7 +10,7 @@
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/module.h>
-
+#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index a006f0db15a..07105ee5c9a 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -30,24 +30,19 @@
#include <asm/irq.h>
-#include <mach/hardware.h>
#include <mach/map.h>
-#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
+#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
+#include <mach/gpio-samsung.h>
+#endif
+
#include <plat/cpu.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>
-#include <plat/gpio-fns.h>
#include <plat/pm.h>
-#ifndef DEBUG_GPIO
-#define gpio_dbg(x...) do { } while (0)
-#else
-#define gpio_dbg(x...) printk(KERN_DEBUG x)
-#endif
-
int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip,
unsigned int off, samsung_gpio_pull_t pull)
{
@@ -169,28 +164,6 @@ int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip,
return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN);
}
-static int exynos_gpio_setpull(struct samsung_gpio_chip *chip,
- unsigned int off, samsung_gpio_pull_t pull)
-{
- if (pull == S3C_GPIO_PULL_UP)
- pull = 3;
-
- return samsung_gpio_setpull_updown(chip, off, pull);
-}
-
-static samsung_gpio_pull_t exynos_gpio_getpull(struct samsung_gpio_chip *chip,
- unsigned int off)
-{
- samsung_gpio_pull_t pull;
-
- pull = samsung_gpio_getpull_updown(chip, off);
-
- if (pull == 3)
- pull = S3C_GPIO_PULL_UP;
-
- return pull;
-}
-
/*
* samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration.
* @chip: The gpio chip that is being configured.
@@ -406,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip,
case 6:
shift = ((off + 1) & 7) * 4;
reg -= 4;
+ break;
default:
shift = ((off + 1) & 7) * 4;
break;
@@ -452,15 +426,6 @@ static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = {
};
#endif
-#if defined(CONFIG_ARCH_EXYNOS4) || defined(CONFIG_ARCH_EXYNOS5)
-static struct samsung_gpio_cfg exynos_gpio_cfg = {
- .set_pull = exynos_gpio_setpull,
- .get_pull = exynos_gpio_getpull,
- .set_config = samsung_gpio_setcfg_4bit,
- .get_config = samsung_gpio_getcfg_4bit,
-};
-#endif
-
#if defined(CONFIG_CPU_S5P6440) || defined(CONFIG_CPU_S5P6450)
static struct samsung_gpio_cfg s5p64x0_gpio_cfg_rbank = {
.cfg_eint = 0x3,
@@ -503,15 +468,6 @@ static struct samsung_gpio_cfg samsung_gpio_cfgs[] = {
.set_config = samsung_gpio_setcfg_2bit,
.get_config = samsung_gpio_getcfg_2bit,
},
- [8] = {
- .set_pull = exynos_gpio_setpull,
- .get_pull = exynos_gpio_getpull,
- },
- [9] = {
- .cfg_eint = 0x3,
- .set_pull = exynos_gpio_setpull,
- .get_pull = exynos_gpio_getpull,
- }
};
/*
@@ -596,10 +552,13 @@ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
unsigned long con;
con = __raw_readl(base + GPIOCON_OFF);
- con &= ~(0xf << con_4bit_shift(offset));
+ if (ourchip->bitmap_gpio_int & BIT(offset))
+ con |= 0xf << con_4bit_shift(offset);
+ else
+ con &= ~(0xf << con_4bit_shift(offset));
__raw_writel(con, base + GPIOCON_OFF);
- gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
+ pr_debug("%s: %p: CON now %08lx\n", __func__, base, con);
return 0;
}
@@ -627,7 +586,7 @@ static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
__raw_writel(con, base + GPIOCON_OFF);
__raw_writel(dat, base + GPIODAT_OFF);
- gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+ pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
return 0;
}
@@ -671,7 +630,7 @@ static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip,
con &= ~(0xf << con_4bit_shift(offset));
__raw_writel(con, regcon);
- gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
+ pr_debug("%s: %p: CON %08lx\n", __func__, base, con);
return 0;
}
@@ -706,7 +665,7 @@ static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip,
__raw_writel(con, regcon);
__raw_writel(dat, base + GPIODAT_OFF);
- gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
+ pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
return 0;
}
@@ -926,10 +885,10 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
#ifdef CONFIG_PM
if (chip->pm != NULL) {
if (!chip->pm->save || !chip->pm->resume)
- printk(KERN_ERR "gpio: %s has missing PM functions\n",
+ pr_err("gpio: %s has missing PM functions\n",
gc->label);
} else
- printk(KERN_ERR "gpio: %s has no PM function\n", gc->label);
+ pr_err("gpio: %s has no PM function\n", gc->label);
#endif
/* gpiochip_add() prints own failure message on error. */
@@ -938,67 +897,6 @@ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip)
s3c_gpiolib_track(chip);
}
-#if defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF)
-static int s3c24xx_gpio_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- unsigned int pin;
-
- if (WARN_ON(gc->of_gpio_n_cells < 3))
- return -EINVAL;
-
- if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
- return -EINVAL;
-
- if (gpiospec->args[0] > gc->ngpio)
- return -EINVAL;
-
- pin = gc->base + gpiospec->args[0];
-
- if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1])))
- pr_warn("gpio_xlate: failed to set pin function\n");
- if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff))
- pr_warn("gpio_xlate: failed to set pin pull up/down\n");
-
- if (flags)
- *flags = gpiospec->args[2] >> 16;
-
- return gpiospec->args[0];
-}
-
-static const struct of_device_id s3c24xx_gpio_dt_match[] __initdata = {
- { .compatible = "samsung,s3c24xx-gpio", },
- {}
-};
-
-static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- struct gpio_chip *gc = &chip->chip;
- u64 address;
-
- if (!of_have_populated_dt())
- return;
-
- address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
- gc->of_node = of_find_matching_node_by_address(NULL,
- s3c24xx_gpio_dt_match, address);
- if (!gc->of_node) {
- pr_info("gpio: device tree node not found for gpio controller"
- " with base address %08llx\n", address);
- return;
- }
- gc->of_gpio_n_cells = 3;
- gc->of_xlate = s3c24xx_gpio_xlate;
-}
-#else
-static __init void s3c24xx_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- return;
-}
-#endif /* defined(CONFIG_PLAT_S3C24XX) && defined(CONFIG_OF) */
-
static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
int nr_chips, void __iomem *base)
{
@@ -1023,8 +921,6 @@ static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip,
gc->direction_output = samsung_gpiolib_2bit_output;
samsung_gpiolib_add(chip);
-
- s3c24xx_gpiolib_attach_ofnode(chip, S3C24XX_PA_GPIO, i * 0x10);
}
}
@@ -1081,6 +977,8 @@ static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip
if ((base != NULL) && (chip->base == NULL))
chip->base = base + ((i) * 0x20);
+ chip->bitmap_gpio_int = 0;
+
samsung_gpiolib_add(chip);
}
}
@@ -1125,8 +1023,12 @@ int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset)
#ifdef CONFIG_PLAT_S3C24XX
static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset)
{
- if (offset < 4)
- return IRQ_EINT0 + offset;
+ if (offset < 4) {
+ if (soc_is_s3c2412())
+ return IRQ_EINT0_2412 + offset;
+ else
+ return IRQ_EINT0 + offset;
+ }
if (offset < 8)
return IRQ_EINT4 + offset - 4;
@@ -1135,7 +1037,7 @@ static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset)
}
#endif
-#ifdef CONFIG_PLAT_S3C64XX
+#ifdef CONFIG_ARCH_S3C64XX
static int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin)
{
return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO;
@@ -1155,7 +1057,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPA(0),
.owner = THIS_MODULE,
.label = "GPIOA",
- .ngpio = 24,
+ .ngpio = 27,
.direction_input = s3c24xx_gpiolib_banka_input,
.direction_output = s3c24xx_gpiolib_banka_output,
},
@@ -1164,7 +1066,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPB(0),
.owner = THIS_MODULE,
.label = "GPIOB",
- .ngpio = 16,
+ .ngpio = 11,
},
}, {
.chip = {
@@ -1209,7 +1111,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = {
.base = S3C2410_GPH(0),
.owner = THIS_MODULE,
.label = "GPIOH",
- .ngpio = 11,
+ .ngpio = 15,
},
},
/* GPIOS for the S3C2443 and later devices. */
@@ -1276,7 +1178,7 @@ struct samsung_gpio_chip s3c24xx_gpios[] = {
*/
static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = {
-#ifdef CONFIG_PLAT_S3C64XX
+#ifdef CONFIG_ARCH_S3C64XX
{
.chip = {
.base = S3C64XX_GPA(0),
@@ -1329,7 +1231,7 @@ static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = {
};
static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = {
-#ifdef CONFIG_PLAT_S3C64XX
+#ifdef CONFIG_ARCH_S3C64XX
{
.base = S3C64XX_GPH_BASE + 0x4,
.chip = {
@@ -1359,7 +1261,7 @@ static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = {
};
static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = {
-#ifdef CONFIG_PLAT_S3C64XX
+#ifdef CONFIG_ARCH_S3C64XX
{
.base = S3C64XX_GPF_BASE,
.config = &samsung_gpio_cfgs[6],
@@ -2177,854 +2079,6 @@ static struct samsung_gpio_chip s5pv210_gpios_4bit[] = {
#endif
};
-/*
- * Followings are the gpio banks in EXYNOS SoCs
- *
- * The 'config' member when left to NULL, is initialized to the default
- * structure exynos_gpio_cfg in the init function below.
- *
- * The 'base' member is also initialized in the init function below.
- * Note: The initialization of 'base' member of samsung_gpio_chip structure
- * uses the above macro and depends on the banks being listed in order here.
- */
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_1[] = {
- {
- .chip = {
- .base = EXYNOS4_GPA0(0),
- .ngpio = EXYNOS4_GPIO_A0_NR,
- .label = "GPA0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPA1(0),
- .ngpio = EXYNOS4_GPIO_A1_NR,
- .label = "GPA1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPB(0),
- .ngpio = EXYNOS4_GPIO_B_NR,
- .label = "GPB",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPC0(0),
- .ngpio = EXYNOS4_GPIO_C0_NR,
- .label = "GPC0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPC1(0),
- .ngpio = EXYNOS4_GPIO_C1_NR,
- .label = "GPC1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPD0(0),
- .ngpio = EXYNOS4_GPIO_D0_NR,
- .label = "GPD0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPD1(0),
- .ngpio = EXYNOS4_GPIO_D1_NR,
- .label = "GPD1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPE0(0),
- .ngpio = EXYNOS4_GPIO_E0_NR,
- .label = "GPE0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPE1(0),
- .ngpio = EXYNOS4_GPIO_E1_NR,
- .label = "GPE1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPE2(0),
- .ngpio = EXYNOS4_GPIO_E2_NR,
- .label = "GPE2",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPE3(0),
- .ngpio = EXYNOS4_GPIO_E3_NR,
- .label = "GPE3",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPE4(0),
- .ngpio = EXYNOS4_GPIO_E4_NR,
- .label = "GPE4",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPF0(0),
- .ngpio = EXYNOS4_GPIO_F0_NR,
- .label = "GPF0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPF1(0),
- .ngpio = EXYNOS4_GPIO_F1_NR,
- .label = "GPF1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPF2(0),
- .ngpio = EXYNOS4_GPIO_F2_NR,
- .label = "GPF2",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPF3(0),
- .ngpio = EXYNOS4_GPIO_F3_NR,
- .label = "GPF3",
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_2[] = {
- {
- .chip = {
- .base = EXYNOS4_GPJ0(0),
- .ngpio = EXYNOS4_GPIO_J0_NR,
- .label = "GPJ0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPJ1(0),
- .ngpio = EXYNOS4_GPIO_J1_NR,
- .label = "GPJ1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPK0(0),
- .ngpio = EXYNOS4_GPIO_K0_NR,
- .label = "GPK0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPK1(0),
- .ngpio = EXYNOS4_GPIO_K1_NR,
- .label = "GPK1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPK2(0),
- .ngpio = EXYNOS4_GPIO_K2_NR,
- .label = "GPK2",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPK3(0),
- .ngpio = EXYNOS4_GPIO_K3_NR,
- .label = "GPK3",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPL0(0),
- .ngpio = EXYNOS4_GPIO_L0_NR,
- .label = "GPL0",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPL1(0),
- .ngpio = EXYNOS4_GPIO_L1_NR,
- .label = "GPL1",
- },
- }, {
- .chip = {
- .base = EXYNOS4_GPL2(0),
- .ngpio = EXYNOS4_GPIO_L2_NR,
- .label = "GPL2",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY0(0),
- .ngpio = EXYNOS4_GPIO_Y0_NR,
- .label = "GPY0",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY1(0),
- .ngpio = EXYNOS4_GPIO_Y1_NR,
- .label = "GPY1",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY2(0),
- .ngpio = EXYNOS4_GPIO_Y2_NR,
- .label = "GPY2",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY3(0),
- .ngpio = EXYNOS4_GPIO_Y3_NR,
- .label = "GPY3",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY4(0),
- .ngpio = EXYNOS4_GPIO_Y4_NR,
- .label = "GPY4",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY5(0),
- .ngpio = EXYNOS4_GPIO_Y5_NR,
- .label = "GPY5",
- },
- }, {
- .config = &samsung_gpio_cfgs[8],
- .chip = {
- .base = EXYNOS4_GPY6(0),
- .ngpio = EXYNOS4_GPIO_Y6_NR,
- .label = "GPY6",
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(0),
- .chip = {
- .base = EXYNOS4_GPX0(0),
- .ngpio = EXYNOS4_GPIO_X0_NR,
- .label = "GPX0",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(8),
- .chip = {
- .base = EXYNOS4_GPX1(0),
- .ngpio = EXYNOS4_GPIO_X1_NR,
- .label = "GPX1",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(16),
- .chip = {
- .base = EXYNOS4_GPX2(0),
- .ngpio = EXYNOS4_GPIO_X2_NR,
- .label = "GPX2",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(24),
- .chip = {
- .base = EXYNOS4_GPX3(0),
- .ngpio = EXYNOS4_GPIO_X3_NR,
- .label = "GPX3",
- .to_irq = samsung_gpiolib_to_irq,
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS4
-static struct samsung_gpio_chip exynos4_gpios_3[] = {
- {
- .chip = {
- .base = EXYNOS4_GPZ(0),
- .ngpio = EXYNOS4_GPIO_Z_NR,
- .label = "GPZ",
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS5
-static struct samsung_gpio_chip exynos5_gpios_1[] = {
- {
- .chip = {
- .base = EXYNOS5_GPA0(0),
- .ngpio = EXYNOS5_GPIO_A0_NR,
- .label = "GPA0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPA1(0),
- .ngpio = EXYNOS5_GPIO_A1_NR,
- .label = "GPA1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPA2(0),
- .ngpio = EXYNOS5_GPIO_A2_NR,
- .label = "GPA2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPB0(0),
- .ngpio = EXYNOS5_GPIO_B0_NR,
- .label = "GPB0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPB1(0),
- .ngpio = EXYNOS5_GPIO_B1_NR,
- .label = "GPB1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPB2(0),
- .ngpio = EXYNOS5_GPIO_B2_NR,
- .label = "GPB2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPB3(0),
- .ngpio = EXYNOS5_GPIO_B3_NR,
- .label = "GPB3",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPC0(0),
- .ngpio = EXYNOS5_GPIO_C0_NR,
- .label = "GPC0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPC1(0),
- .ngpio = EXYNOS5_GPIO_C1_NR,
- .label = "GPC1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPC2(0),
- .ngpio = EXYNOS5_GPIO_C2_NR,
- .label = "GPC2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPC3(0),
- .ngpio = EXYNOS5_GPIO_C3_NR,
- .label = "GPC3",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPD0(0),
- .ngpio = EXYNOS5_GPIO_D0_NR,
- .label = "GPD0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPD1(0),
- .ngpio = EXYNOS5_GPIO_D1_NR,
- .label = "GPD1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY0(0),
- .ngpio = EXYNOS5_GPIO_Y0_NR,
- .label = "GPY0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY1(0),
- .ngpio = EXYNOS5_GPIO_Y1_NR,
- .label = "GPY1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY2(0),
- .ngpio = EXYNOS5_GPIO_Y2_NR,
- .label = "GPY2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY3(0),
- .ngpio = EXYNOS5_GPIO_Y3_NR,
- .label = "GPY3",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY4(0),
- .ngpio = EXYNOS5_GPIO_Y4_NR,
- .label = "GPY4",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY5(0),
- .ngpio = EXYNOS5_GPIO_Y5_NR,
- .label = "GPY5",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPY6(0),
- .ngpio = EXYNOS5_GPIO_Y6_NR,
- .label = "GPY6",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPC4(0),
- .ngpio = EXYNOS5_GPIO_C4_NR,
- .label = "GPC4",
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(0),
- .chip = {
- .base = EXYNOS5_GPX0(0),
- .ngpio = EXYNOS5_GPIO_X0_NR,
- .label = "GPX0",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(8),
- .chip = {
- .base = EXYNOS5_GPX1(0),
- .ngpio = EXYNOS5_GPIO_X1_NR,
- .label = "GPX1",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(16),
- .chip = {
- .base = EXYNOS5_GPX2(0),
- .ngpio = EXYNOS5_GPIO_X2_NR,
- .label = "GPX2",
- .to_irq = samsung_gpiolib_to_irq,
- },
- }, {
- .config = &samsung_gpio_cfgs[9],
- .irq_base = IRQ_EINT(24),
- .chip = {
- .base = EXYNOS5_GPX3(0),
- .ngpio = EXYNOS5_GPIO_X3_NR,
- .label = "GPX3",
- .to_irq = samsung_gpiolib_to_irq,
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS5
-static struct samsung_gpio_chip exynos5_gpios_2[] = {
- {
- .chip = {
- .base = EXYNOS5_GPE0(0),
- .ngpio = EXYNOS5_GPIO_E0_NR,
- .label = "GPE0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPE1(0),
- .ngpio = EXYNOS5_GPIO_E1_NR,
- .label = "GPE1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPF0(0),
- .ngpio = EXYNOS5_GPIO_F0_NR,
- .label = "GPF0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPF1(0),
- .ngpio = EXYNOS5_GPIO_F1_NR,
- .label = "GPF1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPG0(0),
- .ngpio = EXYNOS5_GPIO_G0_NR,
- .label = "GPG0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPG1(0),
- .ngpio = EXYNOS5_GPIO_G1_NR,
- .label = "GPG1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPG2(0),
- .ngpio = EXYNOS5_GPIO_G2_NR,
- .label = "GPG2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPH0(0),
- .ngpio = EXYNOS5_GPIO_H0_NR,
- .label = "GPH0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPH1(0),
- .ngpio = EXYNOS5_GPIO_H1_NR,
- .label = "GPH1",
-
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS5
-static struct samsung_gpio_chip exynos5_gpios_3[] = {
- {
- .chip = {
- .base = EXYNOS5_GPV0(0),
- .ngpio = EXYNOS5_GPIO_V0_NR,
- .label = "GPV0",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPV1(0),
- .ngpio = EXYNOS5_GPIO_V1_NR,
- .label = "GPV1",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPV2(0),
- .ngpio = EXYNOS5_GPIO_V2_NR,
- .label = "GPV2",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPV3(0),
- .ngpio = EXYNOS5_GPIO_V3_NR,
- .label = "GPV3",
- },
- }, {
- .chip = {
- .base = EXYNOS5_GPV4(0),
- .ngpio = EXYNOS5_GPIO_V4_NR,
- .label = "GPV4",
- },
- },
-};
-#endif
-
-#ifdef CONFIG_ARCH_EXYNOS5
-static struct samsung_gpio_chip exynos5_gpios_4[] = {
- {
- .chip = {
- .base = EXYNOS5_GPZ(0),
- .ngpio = EXYNOS5_GPIO_Z_NR,
- .label = "GPZ",
- },
- },
-};
-#endif
-
-
-#if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF)
-static int exynos_gpio_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- unsigned int pin;
-
- if (WARN_ON(gc->of_gpio_n_cells < 4))
- return -EINVAL;
-
- if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
- return -EINVAL;
-
- if (gpiospec->args[0] > gc->ngpio)
- return -EINVAL;
-
- pin = gc->base + gpiospec->args[0];
-
- if (s3c_gpio_cfgpin(pin, S3C_GPIO_SFN(gpiospec->args[1])))
- pr_warn("gpio_xlate: failed to set pin function\n");
- if (s3c_gpio_setpull(pin, gpiospec->args[2] & 0xffff))
- pr_warn("gpio_xlate: failed to set pin pull up/down\n");
- if (s5p_gpio_set_drvstr(pin, gpiospec->args[3]))
- pr_warn("gpio_xlate: failed to set pin drive strength\n");
-
- if (flags)
- *flags = gpiospec->args[2] >> 16;
-
- return gpiospec->args[0];
-}
-
-static const struct of_device_id exynos_gpio_dt_match[] __initdata = {
- { .compatible = "samsung,exynos4-gpio", },
- {}
-};
-
-static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- struct gpio_chip *gc = &chip->chip;
- u64 address;
-
- if (!of_have_populated_dt())
- return;
-
- address = chip->base ? base + ((u32)chip->base & 0xfff) : base + offset;
- gc->of_node = of_find_matching_node_by_address(NULL,
- exynos_gpio_dt_match, address);
- if (!gc->of_node) {
- pr_info("gpio: device tree node not found for gpio controller"
- " with base address %08llx\n", address);
- return;
- }
- gc->of_gpio_n_cells = 4;
- gc->of_xlate = exynos_gpio_xlate;
-}
-#elif defined(CONFIG_ARCH_EXYNOS)
-static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
- u64 base, u64 offset)
-{
- return;
-}
-#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
-
-static __init void exynos4_gpiolib_init(void)
-{
-#ifdef CONFIG_CPU_EXYNOS4210
- struct samsung_gpio_chip *chip;
- int i, nr_chips;
- void __iomem *gpio_base1, *gpio_base2, *gpio_base3;
- int group = 0;
- void __iomem *gpx_base;
-
-#ifdef CONFIG_PINCTRL_SAMSUNG
- /*
- * This gpio driver includes support for device tree support and
- * there are platforms using it. In order to maintain
- * compatibility with those platforms, and to allow non-dt
- * Exynos4210 platforms to use this gpiolib support, a check
- * is added to find out if there is a active pin-controller
- * driver support available. If it is available, this gpiolib
- * support is ignored and the gpiolib support available in
- * pin-controller driver is used. This is a temporary check and
- * will go away when all of the Exynos4210 platforms have
- * switched to using device tree and the pin-ctrl driver.
- */
- struct device_node *pctrl_np;
- const char *pctrl_compat = "samsung,pinctrl-exynos4210";
- pctrl_np = of_find_compatible_node(NULL, NULL, pctrl_compat);
- if (pctrl_np)
- if (of_device_is_available(pctrl_np))
- return;
-#endif
-
- /* gpio part1 */
- gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
- if (gpio_base1 == NULL) {
- pr_err("unable to ioremap for gpio_base1\n");
- goto err_ioremap1;
- }
-
- chip = exynos4_gpios_1;
- nr_chips = ARRAY_SIZE(exynos4_gpios_1);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO1, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
- nr_chips, gpio_base1);
-
- /* gpio part2 */
- gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
- if (gpio_base2 == NULL) {
- pr_err("unable to ioremap for gpio_base2\n");
- goto err_ioremap2;
- }
-
- /* need to set base address for gpx */
- chip = &exynos4_gpios_2[16];
- gpx_base = gpio_base2 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
-
- chip = exynos4_gpios_2;
- nr_chips = ARRAY_SIZE(exynos4_gpios_2);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO2, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
- nr_chips, gpio_base2);
-
- /* gpio part3 */
- gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
- if (gpio_base3 == NULL) {
- pr_err("unable to ioremap for gpio_base3\n");
- goto err_ioremap3;
- }
-
- chip = exynos4_gpios_3;
- nr_chips = ARRAY_SIZE(exynos4_gpios_3);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO3, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
- nr_chips, gpio_base3);
-
-#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
- s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
- s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
-#endif
-
- return;
-
-err_ioremap3:
- iounmap(gpio_base2);
-err_ioremap2:
- iounmap(gpio_base1);
-err_ioremap1:
- return;
-#endif /* CONFIG_CPU_EXYNOS4210 */
-}
-
-static __init void exynos5_gpiolib_init(void)
-{
-#ifdef CONFIG_SOC_EXYNOS5250
- struct samsung_gpio_chip *chip;
- int i, nr_chips;
- void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
- int group = 0;
- void __iomem *gpx_base;
-
- /* gpio part1 */
- gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
- if (gpio_base1 == NULL) {
- pr_err("unable to ioremap for gpio_base1\n");
- goto err_ioremap1;
- }
-
- /* need to set base address for gpc4 */
- exynos5_gpios_1[20].base = gpio_base1 + 0x2E0;
-
- /* need to set base address for gpx */
- chip = &exynos5_gpios_1[21];
- gpx_base = gpio_base1 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
-
- chip = exynos5_gpios_1;
- nr_chips = ARRAY_SIZE(exynos5_gpios_1);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO1, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
- nr_chips, gpio_base1);
-
- /* gpio part2 */
- gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
- if (gpio_base2 == NULL) {
- pr_err("unable to ioremap for gpio_base2\n");
- goto err_ioremap2;
- }
-
- chip = exynos5_gpios_2;
- nr_chips = ARRAY_SIZE(exynos5_gpios_2);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO2, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
- nr_chips, gpio_base2);
-
- /* gpio part3 */
- gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
- if (gpio_base3 == NULL) {
- pr_err("unable to ioremap for gpio_base3\n");
- goto err_ioremap3;
- }
-
- /* need to set base address for gpv */
- exynos5_gpios_3[0].base = gpio_base3;
- exynos5_gpios_3[1].base = gpio_base3 + 0x20;
- exynos5_gpios_3[2].base = gpio_base3 + 0x60;
- exynos5_gpios_3[3].base = gpio_base3 + 0x80;
- exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
-
- chip = exynos5_gpios_3;
- nr_chips = ARRAY_SIZE(exynos5_gpios_3);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO3, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
- nr_chips, gpio_base3);
-
- /* gpio part4 */
- gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
- if (gpio_base4 == NULL) {
- pr_err("unable to ioremap for gpio_base4\n");
- goto err_ioremap4;
- }
-
- chip = exynos5_gpios_4;
- nr_chips = ARRAY_SIZE(exynos5_gpios_4);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO4, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
- nr_chips, gpio_base4);
- return;
-
-err_ioremap4:
- iounmap(gpio_base3);
-err_ioremap3:
- iounmap(gpio_base2);
-err_ioremap2:
- iounmap(gpio_base1);
-err_ioremap1:
- return;
-
-#endif /* CONFIG_SOC_EXYNOS5250 */
-}
-
/* TODO: cleanup soc_is_* */
static __init int samsung_gpiolib_init(void)
{
@@ -3032,6 +2086,15 @@ static __init int samsung_gpiolib_init(void)
int i, nr_chips;
int group = 0;
+ /*
+ * Currently there are two drivers that can provide GPIO support for
+ * Samsung SoCs. For device tree enabled platforms, the new
+ * pinctrl-samsung driver is used, providing both GPIO and pin control
+ * interfaces. For legacy (non-DT) platforms this driver is used.
+ */
+ if (of_have_populated_dt())
+ return -ENODEV;
+
samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
if (soc_is_s3c24xx()) {
@@ -3094,10 +2157,6 @@ static __init int samsung_gpiolib_init(void)
#if defined(CONFIG_CPU_S5PV210) && defined(CONFIG_S5P_GPIO_INT)
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
#endif
- } else if (soc_is_exynos4210()) {
- exynos4_gpiolib_init();
- } else if (soc_is_exynos5250()) {
- exynos5_gpiolib_init();
} else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
return -ENODEV;
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 8707d4572a0..a9b1cd16c84 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -97,8 +97,6 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc,
u8 curr_dirs;
unsigned short offset, bit;
- sch_gpio_core_set(gc, gpio_num, val);
-
spin_lock(&gpio_lock);
offset = CGIO + gpio_num / 8;
@@ -109,6 +107,17 @@ static int sch_gpio_core_direction_out(struct gpio_chip *gc,
outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
+
+ /*
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_core_set(gc, gpio_num, val);
return 0;
}
@@ -125,13 +134,17 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
unsigned gpio_num)
{
u8 curr_dirs;
+ unsigned short offset, bit;
spin_lock(&gpio_lock);
- curr_dirs = inb(gpio_ba + RGIO);
+ offset = RGIO + gpio_num / 8;
+ bit = gpio_num % 8;
- if (!(curr_dirs & (1 << gpio_num)))
- outb(curr_dirs | (1 << gpio_num) , gpio_ba + RGIO);
+ curr_dirs = inb(gpio_ba + offset);
+
+ if (!(curr_dirs & (1 << bit)))
+ outb(curr_dirs | (1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
return 0;
@@ -139,22 +152,31 @@ static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
{
- return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
+ unsigned short offset, bit;
+
+ offset = RGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ return !!(inb(gpio_ba + offset) & (1 << bit));
}
static void sch_gpio_resume_set(struct gpio_chip *gc,
unsigned gpio_num, int val)
{
u8 curr_vals;
+ unsigned short offset, bit;
spin_lock(&gpio_lock);
- curr_vals = inb(gpio_ba + RGLV);
+ offset = RGLV + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_vals = inb(gpio_ba + offset);
if (val)
- outb(curr_vals | (1 << gpio_num), gpio_ba + RGLV);
+ outb(curr_vals | (1 << bit), gpio_ba + offset);
else
- outb((curr_vals & ~(1 << gpio_num)), gpio_ba + RGLV);
+ outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
spin_unlock(&gpio_lock);
}
@@ -163,16 +185,29 @@ static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
unsigned gpio_num, int val)
{
u8 curr_dirs;
+ unsigned short offset, bit;
- sch_gpio_resume_set(gc, gpio_num, val);
+ offset = RGIO + gpio_num / 8;
+ bit = gpio_num % 8;
spin_lock(&gpio_lock);
- curr_dirs = inb(gpio_ba + RGIO);
- if (curr_dirs & (1 << gpio_num))
- outb(curr_dirs & ~(1 << gpio_num), gpio_ba + RGIO);
+ curr_dirs = inb(gpio_ba + offset);
+ if (curr_dirs & (1 << bit))
+ outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
spin_unlock(&gpio_lock);
+
+ /*
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_resume_set(gc, gpio_num, val);
return 0;
}
@@ -185,7 +220,7 @@ static struct gpio_chip sch_gpio_resume = {
.set = sch_gpio_resume_set,
};
-static int __devinit sch_gpio_probe(struct platform_device *pdev)
+static int sch_gpio_probe(struct platform_device *pdev)
{
struct resource *res;
int err, id;
@@ -204,45 +239,41 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
gpio_ba = res->start;
switch (id) {
- case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
-
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
-
- /*
- * GPIO[6:0] enabled by default
- * GPIO7 is configured by the CMC as SLPIOVR
- * Enable GPIO[9:8] core powered gpios explicitly
- */
- outb(0x3, gpio_ba + CGEN + 1);
- /*
- * SUS_GPIO[2:0] enabled by default
- * Enable SUS_GPIO3 resume powered gpio explicitly
- */
- outb(0x8, gpio_ba + RGEN);
- break;
-
- case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
-
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
- break;
-
- case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
-
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
- break;
-
- default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ case PCI_DEVICE_ID_INTEL_SCH_LPC:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 10;
+ sch_gpio_resume.base = 10;
+ sch_gpio_resume.ngpio = 4;
+ /*
+ * GPIO[6:0] enabled by default
+ * GPIO7 is configured by the CMC as SLPIOVR
+ * Enable GPIO[9:8] core powered gpios explicitly
+ */
+ outb(0x3, gpio_ba + CGEN + 1);
+ /*
+ * SUS_GPIO[2:0] enabled by default
+ * Enable SUS_GPIO3 resume powered gpio explicitly
+ */
+ outb(0x8, gpio_ba + RGEN);
+ break;
+
+ case PCI_DEVICE_ID_INTEL_ITC_LPC:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 5;
+ sch_gpio_resume.base = 5;
+ sch_gpio_resume.ngpio = 9;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
+ sch_gpio_core.base = 0;
+ sch_gpio_core.ngpio = 21;
+ sch_gpio_resume.base = 21;
+ sch_gpio_resume.ngpio = 9;
+ break;
+
+ default:
+ err = -ENODEV;
+ goto err_sch_gpio_core;
}
sch_gpio_core.dev = &pdev->dev;
@@ -259,10 +290,8 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
return 0;
err_sch_gpio_resume:
- err = gpiochip_remove(&sch_gpio_core);
- if (err)
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", err);
+ if (gpiochip_remove(&sch_gpio_core))
+ dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
err_sch_gpio_core:
release_region(res->start, resource_size(res));
@@ -271,7 +300,7 @@ err_sch_gpio_core:
return err;
}
-static int __devexit sch_gpio_remove(struct platform_device *pdev)
+static int sch_gpio_remove(struct platform_device *pdev)
{
struct resource *res;
if (gpio_ba) {
@@ -303,7 +332,7 @@ static struct platform_driver sch_gpio_driver = {
.owner = THIS_MODULE,
},
.probe = sch_gpio_probe,
- .remove = __devexit_p(sch_gpio_remove),
+ .remove = sch_gpio_remove,
};
module_platform_driver(sch_gpio_driver);
diff --git a/drivers/gpio/gpio-sch311x.c b/drivers/gpio/gpio-sch311x.c
new file mode 100644
index 00000000000..f942b80ee40
--- /dev/null
+++ b/drivers/gpio/gpio-sch311x.c
@@ -0,0 +1,440 @@
+/*
+ * GPIO driver for the SMSC SCH311x Super-I/O chips
+ *
+ * Copyright (C) 2013 Bruno Randolf <br1@einfach.org>
+ *
+ * SuperIO functions and chip detection:
+ * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+
+#define DRV_NAME "gpio-sch311x"
+
+#define SCH311X_GPIO_CONF_OUT 0x00
+#define SCH311X_GPIO_CONF_IN 0x01
+#define SCH311X_GPIO_CONF_INVERT 0x02
+#define SCH311X_GPIO_CONF_OPEN_DRAIN 0x80
+
+#define SIO_CONFIG_KEY_ENTER 0x55
+#define SIO_CONFIG_KEY_EXIT 0xaa
+
+#define GP1 0x4b
+
+static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e };
+
+static struct platform_device *sch311x_gpio_pdev;
+
+struct sch311x_pdev_data { /* platform device data */
+ unsigned short runtime_reg; /* runtime register base address */
+};
+
+struct sch311x_gpio_block { /* one GPIO block runtime data */
+ struct gpio_chip chip;
+ unsigned short data_reg; /* from definition below */
+ unsigned short *config_regs; /* pointer to definition below */
+ unsigned short runtime_reg; /* runtime register */
+ spinlock_t lock; /* lock for this GPIO block */
+};
+
+struct sch311x_gpio_priv { /* driver private data */
+ struct sch311x_gpio_block blocks[6];
+};
+
+struct sch311x_gpio_block_def { /* register address definitions */
+ unsigned short data_reg;
+ unsigned short config_regs[8];
+ unsigned short base;
+};
+
+/* Note: some GPIOs are not available, these are marked with 0x00 */
+
+static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
+ {
+ .data_reg = 0x4b, /* GP1 */
+ .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b},
+ .base = 10,
+ },
+ {
+ .data_reg = 0x4c, /* GP2 */
+ .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32},
+ .base = 20,
+ },
+ {
+ .data_reg = 0x4d, /* GP3 */
+ .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a},
+ .base = 30,
+ },
+ {
+ .data_reg = 0x4e, /* GP4 */
+ .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73},
+ .base = 40,
+ },
+ {
+ .data_reg = 0x4f, /* GP5 */
+ .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46},
+ .base = 50,
+ },
+ {
+ .data_reg = 0x50, /* GP6 */
+ .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59},
+ .base = 60,
+ },
+};
+
+static inline struct sch311x_gpio_block *
+to_sch311x_gpio_block(struct gpio_chip *chip)
+{
+ return container_of(chip, struct sch311x_gpio_block, chip);
+}
+
+
+/*
+ * Super-IO functions
+ */
+
+static inline int sch311x_sio_enter(int sio_config_port)
+{
+ /* Don't step on other drivers' I/O space by accident. */
+ if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
+ pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
+ sio_config_port);
+ return -EBUSY;
+ }
+
+ outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
+ return 0;
+}
+
+static inline void sch311x_sio_exit(int sio_config_port)
+{
+ outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
+ release_region(sio_config_port, 2);
+}
+
+static inline int sch311x_sio_inb(int sio_config_port, int reg)
+{
+ outb(reg, sio_config_port);
+ return inb(sio_config_port + 1);
+}
+
+static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
+{
+ outb(reg, sio_config_port);
+ outb(val, sio_config_port + 1);
+}
+
+
+/*
+ * GPIO functions
+ */
+
+static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+
+ if (block->config_regs[offset] == 0) /* GPIO is not available */
+ return -ENODEV;
+
+ if (!request_region(block->runtime_reg + block->config_regs[offset],
+ 1, DRV_NAME)) {
+ dev_err(chip->dev, "Failed to request region 0x%04x.\n",
+ block->runtime_reg + block->config_regs[offset]);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+
+ if (block->config_regs[offset] == 0) /* GPIO is not available */
+ return;
+
+ release_region(block->runtime_reg + block->config_regs[offset], 1);
+}
+
+static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+ unsigned char data;
+
+ spin_lock(&block->lock);
+ data = inb(block->runtime_reg + block->data_reg);
+ spin_unlock(&block->lock);
+
+ return !!(data & BIT(offset));
+}
+
+static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
+ unsigned offset, int value)
+{
+ unsigned char data = inb(block->runtime_reg + block->data_reg);
+ if (value)
+ data |= BIT(offset);
+ else
+ data &= ~BIT(offset);
+ outb(data, block->runtime_reg + block->data_reg);
+}
+
+static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+
+ spin_lock(&block->lock);
+ __sch311x_gpio_set(block, offset, value);
+ spin_unlock(&block->lock);
+}
+
+static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+
+ spin_lock(&block->lock);
+ outb(SCH311X_GPIO_CONF_IN, block->runtime_reg +
+ block->config_regs[offset]);
+ spin_unlock(&block->lock);
+
+ return 0;
+}
+
+static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
+
+ spin_lock(&block->lock);
+
+ outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg +
+ block->config_regs[offset]);
+
+ __sch311x_gpio_set(block, offset, value);
+
+ spin_unlock(&block->lock);
+ return 0;
+}
+
+static int sch311x_gpio_probe(struct platform_device *pdev)
+{
+ struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+ struct sch311x_gpio_priv *priv;
+ struct sch311x_gpio_block *block;
+ int err, i;
+
+ /* we can register all GPIO data registers at once */
+ if (!request_region(pdata->runtime_reg + GP1, 6, DRV_NAME)) {
+ dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
+ pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
+ return -EBUSY;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+
+ for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
+ block = &priv->blocks[i];
+
+ spin_lock_init(&block->lock);
+
+ block->chip.label = DRV_NAME;
+ block->chip.owner = THIS_MODULE;
+ block->chip.request = sch311x_gpio_request;
+ block->chip.free = sch311x_gpio_free;
+ block->chip.direction_input = sch311x_gpio_direction_in;
+ block->chip.direction_output = sch311x_gpio_direction_out;
+ block->chip.get = sch311x_gpio_get;
+ block->chip.set = sch311x_gpio_set;
+ block->chip.ngpio = 8;
+ block->chip.dev = &pdev->dev;
+ block->chip.base = sch311x_gpio_blocks[i].base;
+ block->config_regs = sch311x_gpio_blocks[i].config_regs;
+ block->data_reg = sch311x_gpio_blocks[i].data_reg;
+ block->runtime_reg = pdata->runtime_reg;
+
+ err = gpiochip_add(&block->chip);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Could not register gpiochip, %d\n", err);
+ goto exit_err;
+ }
+ dev_info(&pdev->dev,
+ "SMSC SCH311x GPIO block %d registered.\n", i);
+ }
+
+ return 0;
+
+exit_err:
+ release_region(pdata->runtime_reg + GP1, 6);
+ /* release already registered chips */
+ for (--i; i >= 0; i--)
+ gpiochip_remove(&priv->blocks[i].chip);
+ return err;
+}
+
+static int sch311x_gpio_remove(struct platform_device *pdev)
+{
+ struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
+ struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
+ int err, i;
+
+ release_region(pdata->runtime_reg + GP1, 6);
+
+ for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
+ err = gpiochip_remove(&priv->blocks[i].chip);
+ if (err)
+ return err;
+ dev_info(&pdev->dev,
+ "SMSC SCH311x GPIO block %d unregistered.\n", i);
+ }
+ return 0;
+}
+
+static struct platform_driver sch311x_gpio_driver = {
+ .driver.name = DRV_NAME,
+ .driver.owner = THIS_MODULE,
+ .probe = sch311x_gpio_probe,
+ .remove = sch311x_gpio_remove,
+};
+
+
+/*
+ * Init & exit routines
+ */
+
+static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
+{
+ int err = 0, reg;
+ unsigned short base_addr;
+ unsigned char dev_id;
+
+ err = sch311x_sio_enter(sio_config_port);
+ if (err)
+ return err;
+
+ /* Check device ID. */
+ reg = sch311x_sio_inb(sio_config_port, 0x20);
+ switch (reg) {
+ case 0x7c: /* SCH3112 */
+ dev_id = 2;
+ break;
+ case 0x7d: /* SCH3114 */
+ dev_id = 4;
+ break;
+ case 0x7f: /* SCH3116 */
+ dev_id = 6;
+ break;
+ default:
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Select logical device A (runtime registers) */
+ sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
+
+ /* Check if Logical Device Register is currently active */
+ if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
+ pr_info("Seems that LDN 0x0a is not active...\n");
+
+ /* Get the base address of the runtime registers */
+ base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
+ sch311x_sio_inb(sio_config_port, 0x61);
+ if (!base_addr) {
+ pr_err("Base address not set\n");
+ err = -ENODEV;
+ goto exit;
+ }
+ *addr = base_addr;
+
+ pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
+
+exit:
+ sch311x_sio_exit(sio_config_port);
+ return err;
+}
+
+static int __init sch311x_gpio_pdev_add(const unsigned short addr)
+{
+ struct sch311x_pdev_data pdata;
+ int err;
+
+ pdata.runtime_reg = addr;
+
+ sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
+ if (!sch311x_gpio_pdev)
+ return -ENOMEM;
+
+ err = platform_device_add_data(sch311x_gpio_pdev,
+ &pdata, sizeof(pdata));
+ if (err) {
+ pr_err(DRV_NAME "Platform data allocation failed\n");
+ goto err;
+ }
+
+ err = platform_device_add(sch311x_gpio_pdev);
+ if (err) {
+ pr_err(DRV_NAME "Device addition failed\n");
+ goto err;
+ }
+ return 0;
+
+err:
+ platform_device_put(sch311x_gpio_pdev);
+ return err;
+}
+
+static int __init sch311x_gpio_init(void)
+{
+ int err, i;
+ unsigned short addr = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
+ if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
+ break;
+
+ if (!addr)
+ return -ENODEV;
+
+ err = platform_driver_register(&sch311x_gpio_driver);
+ if (err)
+ return err;
+
+ err = sch311x_gpio_pdev_add(addr);
+ if (err)
+ goto unreg_platform_driver;
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&sch311x_gpio_driver);
+ return err;
+}
+
+static void __exit sch311x_gpio_exit(void)
+{
+ platform_device_unregister(sch311x_gpio_pdev);
+ platform_driver_unregister(&sch311x_gpio_driver);
+}
+
+module_init(sch311x_gpio_init);
+module_exit(sch311x_gpio_exit);
+
+MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
+MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-sch311x");
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index e25f73130b4..7c6c518929b 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -129,7 +129,7 @@ static struct irq_domain_ops irq_domain_sdv_ops = {
.xlate = sdv_xlate,
};
-static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
+static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
struct pci_dev *pdev)
{
struct irq_chip_type *ct;
@@ -176,8 +176,10 @@ static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS,
sd->irq_base, 0, &irq_domain_sdv_ops, sd);
- if (!sd->id)
+ if (!sd->id) {
+ ret = -ENODEV;
goto out_free_irq;
+ }
return 0;
out_free_irq:
free_irq(pdev->irq, sd);
@@ -186,7 +188,7 @@ out_free_desc:
return ret;
}
-static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
+static int sdv_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
struct sdv_gpio_chip_data *sd;
@@ -212,8 +214,10 @@ static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
}
addr = pci_resource_start(pdev, GPIO_BAR);
- if (!addr)
+ if (!addr) {
+ ret = -ENODEV;
goto release_reg;
+ }
sd->gpio_pub_base = ioremap(addr, pci_resource_len(pdev, GPIO_BAR));
prop = of_get_property(pdev->dev.of_node, "intel,muxctl", &len);
@@ -270,7 +274,7 @@ static void sdv_gpio_remove(struct pci_dev *pdev)
kfree(sd);
}
-static DEFINE_PCI_DEVICE_TABLE(sdv_gpio_pci_ids) = {
+static const struct pci_device_id sdv_gpio_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
{ 0, },
};
diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c
new file mode 100644
index 00000000000..353263c85d2
--- /dev/null
+++ b/drivers/gpio/gpio-spear-spics.c
@@ -0,0 +1,208 @@
+/*
+ * SPEAr platform SPI chipselect abstraction over gpiolib
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* maximum chipselects */
+#define NUM_OF_GPIO 4
+
+/*
+ * Provision is available on some SPEAr SoCs to control ARM PL022 spi cs
+ * through system registers. This register lies outside spi (pl022)
+ * address space into system registers.
+ *
+ * It provides control for spi chip select lines so that any chipselect
+ * (out of 4 possible chipselects in pl022) can be made low to select
+ * the particular slave.
+ */
+
+/**
+ * struct spear_spics - represents spi chip select control
+ * @base: base address
+ * @perip_cfg: configuration register
+ * @sw_enable_bit: bit to enable s/w control over chipselects
+ * @cs_value_bit: bit to program high or low chipselect
+ * @cs_enable_mask: mask to select bits required to select chipselect
+ * @cs_enable_shift: bit pos of cs_enable_mask
+ * @use_count: use count of a spi controller cs lines
+ * @last_off: stores last offset caller of set_value()
+ * @chip: gpio_chip abstraction
+ */
+struct spear_spics {
+ void __iomem *base;
+ u32 perip_cfg;
+ u32 sw_enable_bit;
+ u32 cs_value_bit;
+ u32 cs_enable_mask;
+ u32 cs_enable_shift;
+ unsigned long use_count;
+ int last_off;
+ struct gpio_chip chip;
+};
+
+/* gpio framework specific routines */
+static int spics_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ return -ENXIO;
+}
+
+static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct spear_spics *spics = container_of(chip, struct spear_spics,
+ chip);
+ u32 tmp;
+
+ /* select chip select from register */
+ tmp = readl_relaxed(spics->base + spics->perip_cfg);
+ if (spics->last_off != offset) {
+ spics->last_off = offset;
+ tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift);
+ tmp |= offset << spics->cs_enable_shift;
+ }
+
+ /* toggle chip select line */
+ tmp &= ~(0x1 << spics->cs_value_bit);
+ tmp |= value << spics->cs_value_bit;
+ writel_relaxed(tmp, spics->base + spics->perip_cfg);
+}
+
+static int spics_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return -ENXIO;
+}
+
+static int spics_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ spics_set_value(chip, offset, value);
+ return 0;
+}
+
+static int spics_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct spear_spics *spics = container_of(chip, struct spear_spics,
+ chip);
+ u32 tmp;
+
+ if (!spics->use_count++) {
+ tmp = readl_relaxed(spics->base + spics->perip_cfg);
+ tmp |= 0x1 << spics->sw_enable_bit;
+ tmp |= 0x1 << spics->cs_value_bit;
+ writel_relaxed(tmp, spics->base + spics->perip_cfg);
+ }
+
+ return 0;
+}
+
+static void spics_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct spear_spics *spics = container_of(chip, struct spear_spics,
+ chip);
+ u32 tmp;
+
+ if (!--spics->use_count) {
+ tmp = readl_relaxed(spics->base + spics->perip_cfg);
+ tmp &= ~(0x1 << spics->sw_enable_bit);
+ writel_relaxed(tmp, spics->base + spics->perip_cfg);
+ }
+}
+
+static int spics_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spear_spics *spics;
+ struct resource *res;
+ int ret;
+
+ spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL);
+ if (!spics)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ spics->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(spics->base))
+ return PTR_ERR(spics->base);
+
+ if (of_property_read_u32(np, "st-spics,peripcfg-reg",
+ &spics->perip_cfg))
+ goto err_dt_data;
+ if (of_property_read_u32(np, "st-spics,sw-enable-bit",
+ &spics->sw_enable_bit))
+ goto err_dt_data;
+ if (of_property_read_u32(np, "st-spics,cs-value-bit",
+ &spics->cs_value_bit))
+ goto err_dt_data;
+ if (of_property_read_u32(np, "st-spics,cs-enable-mask",
+ &spics->cs_enable_mask))
+ goto err_dt_data;
+ if (of_property_read_u32(np, "st-spics,cs-enable-shift",
+ &spics->cs_enable_shift))
+ goto err_dt_data;
+
+ platform_set_drvdata(pdev, spics);
+
+ spics->chip.ngpio = NUM_OF_GPIO;
+ spics->chip.base = -1;
+ spics->chip.request = spics_request;
+ spics->chip.free = spics_free;
+ spics->chip.direction_input = spics_direction_input;
+ spics->chip.direction_output = spics_direction_output;
+ spics->chip.get = spics_get_value;
+ spics->chip.set = spics_set_value;
+ spics->chip.label = dev_name(&pdev->dev);
+ spics->chip.dev = &pdev->dev;
+ spics->chip.owner = THIS_MODULE;
+ spics->last_off = -1;
+
+ ret = gpiochip_add(&spics->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpio chip\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "spear spics registered\n");
+ return 0;
+
+err_dt_data:
+ dev_err(&pdev->dev, "DT probe failed\n");
+ return -EINVAL;
+}
+
+static const struct of_device_id spics_gpio_of_match[] = {
+ { .compatible = "st,spear-spics-gpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spics_gpio_of_match);
+
+static struct platform_driver spics_gpio_driver = {
+ .probe = spics_gpio_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "spear-spics-gpio",
+ .of_match_table = spics_gpio_of_match,
+ },
+};
+
+static int __init spics_gpio_init(void)
+{
+ return platform_driver_register(&spics_gpio_driver);
+}
+subsys_initcall(spics_gpio_init);
+
+MODULE_AUTHOR("Shiraz Hashim <shiraz.linux.kernel@gmail.com>");
+MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 6064fb376e1..68e3fcb1ace 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -146,7 +146,7 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */
gpio->dbg_show = NULL;
gpio->base = gpio_base;
gpio->ngpio = GSTA_NR_GPIO;
- gpio->can_sleep = 0;
+ gpio->can_sleep = false;
gpio->to_irq = gsta_gpio_to_irq;
/*
@@ -320,7 +320,7 @@ static irqreturn_t gsta_gpio_handler(int irq, void *dev_id)
return ret;
}
-static __devinit void gsta_alloc_irq_chip(struct gsta_gpio *chip)
+static void gsta_alloc_irq_chip(struct gsta_gpio *chip)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
@@ -353,7 +353,7 @@ static __devinit void gsta_alloc_irq_chip(struct gsta_gpio *chip)
}
/* The platform device used here is instantiated by the MFD device */
-static int __devinit gsta_probe(struct platform_device *dev)
+static int gsta_probe(struct platform_device *dev)
{
int i, err;
struct pci_dev *pdev;
@@ -361,7 +361,7 @@ static int __devinit gsta_probe(struct platform_device *dev)
struct gsta_gpio *chip;
struct resource *res;
- pdev = *(struct pci_dev **)(dev->dev.platform_data);
+ pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
gpio_pdata = dev_get_platdata(&pdev->dev);
if (gpio_pdata == NULL)
@@ -371,8 +371,12 @@ static int __devinit gsta_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
chip->dev = &dev->dev;
- chip->reg_base = devm_request_and_ioremap(&dev->dev, res);
+ chip->reg_base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(chip->reg_base))
+ return PTR_ERR(chip->reg_base);
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096;
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index dce34727bbf..628b5849429 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -11,7 +11,9 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/mfd/stmpe.h>
/*
@@ -21,15 +23,15 @@
enum { REG_RE, REG_FE, REG_IE };
#define CACHE_NR_REGS 3
-#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
+/* No variant has more than 24 GPIOs */
+#define CACHE_NR_BANKS (24 / 8)
struct stmpe_gpio {
struct gpio_chip chip;
struct stmpe *stmpe;
struct device *dev;
struct mutex irq_lock;
-
- int irq_base;
+ struct irq_domain *domain;
unsigned norequest_mask;
/* Caches of interrupt control registers for bus_lock */
@@ -103,7 +105,7 @@ static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
- return stmpe_gpio->irq_base + offset;
+ return irq_create_mapping(stmpe_gpio->domain, offset);
}
static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -126,13 +128,13 @@ static struct gpio_chip template_chip = {
.set = stmpe_gpio_set,
.to_irq = stmpe_gpio_to_irq,
.request = stmpe_gpio_request,
- .can_sleep = 1,
+ .can_sleep = true,
};
static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
- int offset = d->irq - stmpe_gpio->irq_base;
+ int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -199,7 +201,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
static void stmpe_gpio_irq_mask(struct irq_data *d)
{
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
- int offset = d->irq - stmpe_gpio->irq_base;
+ int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -209,7 +211,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d)
static void stmpe_gpio_irq_unmask(struct irq_data *d)
{
struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d);
- int offset = d->irq - stmpe_gpio->irq_base;
+ int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -251,8 +253,10 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
while (stat) {
int bit = __ffs(stat);
int line = bank * 8 + bit;
+ int child_irq = irq_find_mapping(stmpe_gpio->domain,
+ line);
- handle_nested_irq(stmpe_gpio->irq_base + line);
+ handle_nested_irq(child_irq);
stat &= ~(1 << bit);
}
@@ -267,43 +271,60 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- int base = stmpe_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
- irq_set_chip_data(irq, stmpe_gpio);
- irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(irq, 1);
+ struct stmpe_gpio *stmpe_gpio = d->host_data;
+
+ if (!stmpe_gpio)
+ return -EINVAL;
+
+ irq_set_chip_data(irq, stmpe_gpio);
+ irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip,
+ handle_simple_irq);
+ irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
+ set_irq_flags(irq, IRQF_VALID);
#else
- irq_set_noprobe(irq);
+ irq_set_noprobe(irq);
#endif
- }
return 0;
}
-static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
+static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
{
- int base = stmpe_gpio->irq_base;
- int irq;
-
- for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
#ifdef CONFIG_ARM
- set_irq_flags(irq, 0);
+ set_irq_flags(irq, 0);
#endif
- irq_set_chip_and_handler(irq, NULL, NULL);
- irq_set_chip_data(irq, NULL);
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
+ .unmap = stmpe_gpio_irq_unmap,
+ .map = stmpe_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
+ struct device_node *np)
+{
+ stmpe_gpio->domain = irq_domain_add_simple(np,
+ stmpe_gpio->chip.ngpio, 0,
+ &stmpe_gpio_irq_simple_ops, stmpe_gpio);
+ if (!stmpe_gpio->domain) {
+ dev_err(stmpe_gpio->dev, "failed to create irqdomain\n");
+ return -ENOSYS;
}
+
+ return 0;
}
-static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
+static int stmpe_gpio_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
+ struct device_node *np = pdev->dev.of_node;
struct stmpe_gpio_platform_data *pdata;
struct stmpe_gpio *stmpe_gpio;
int ret;
@@ -321,16 +342,21 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->dev = &pdev->dev;
stmpe_gpio->stmpe = stmpe;
- stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0;
-
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
stmpe_gpio->chip.dev = &pdev->dev;
- stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
+#ifdef CONFIG_OF
+ stmpe_gpio->chip.of_node = np;
+#endif
+ stmpe_gpio->chip.base = -1;
- if (irq >= 0)
- stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
- else
+ if (pdata)
+ stmpe_gpio->norequest_mask = pdata->norequest_mask;
+ else if (np)
+ of_property_read_u32(np, "st,norequest-mask",
+ &stmpe_gpio->norequest_mask);
+
+ if (irq < 0)
dev_info(&pdev->dev,
"device configured in no-irq mode; "
"irqs are not available\n");
@@ -340,7 +366,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
goto out_free;
if (irq >= 0) {
- ret = stmpe_gpio_irq_init(stmpe_gpio);
+ ret = stmpe_gpio_irq_init(stmpe_gpio, np);
if (ret)
goto out_disable;
@@ -348,7 +374,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_removeirq;
+ goto out_disable;
}
}
@@ -368,9 +394,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
out_freeirq:
if (irq >= 0)
free_irq(irq, stmpe_gpio);
-out_removeirq:
- if (irq >= 0)
- stmpe_gpio_irq_remove(stmpe_gpio);
out_disable:
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
out_free:
@@ -378,7 +401,7 @@ out_free:
return ret;
}
-static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
+static int stmpe_gpio_remove(struct platform_device *pdev)
{
struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
struct stmpe *stmpe = stmpe_gpio->stmpe;
@@ -398,11 +421,9 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
- if (irq >= 0) {
+ if (irq >= 0)
free_irq(irq, stmpe_gpio);
- stmpe_gpio_irq_remove(stmpe_gpio);
- }
- platform_set_drvdata(pdev, NULL);
+
kfree(stmpe_gpio);
return 0;
@@ -412,7 +433,7 @@ static struct platform_driver stmpe_gpio_driver = {
.driver.name = "stmpe-gpio",
.driver.owner = THIS_MODULE,
.probe = stmpe_gpio_probe,
- .remove = __devexit_p(stmpe_gpio_remove),
+ .remove = stmpe_gpio_remove,
};
static int __init stmpe_gpio_init(void)
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c
index 8bead0bb645..04882a911b6 100644
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -197,7 +197,7 @@ static int xway_stp_hw_init(struct xway_stp *chip)
return 0;
}
-static int __devinit xway_stp_probe(struct platform_device *pdev)
+static int xway_stp_probe(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
const __be32 *shadow, *groups, *dsl, *phy;
@@ -214,11 +214,10 @@ static int __devinit xway_stp_probe(struct platform_device *pdev)
if (!chip)
return -ENOMEM;
- chip->virt = devm_request_and_ioremap(&pdev->dev, res);
- if (!chip->virt) {
- dev_err(&pdev->dev, "failed to remap STP memory\n");
- return -ENOMEM;
- }
+ chip->virt = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(chip->virt))
+ return PTR_ERR(chip->virt);
+
chip->gc.dev = &pdev->dev;
chip->gc.label = "stp-xway";
chip->gc.direction_output = xway_stp_dir_out;
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index eb3e215d239..b51ca9f5c14 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/i2c/sx150x.h>
#define NO_UPDATE_PENDING -1
@@ -436,7 +435,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
chip->gpio_chip.set = sx150x_gpio_set;
chip->gpio_chip.to_irq = sx150x_gpio_to_irq;
chip->gpio_chip.base = pdata->gpio_base;
- chip->gpio_chip.can_sleep = 1;
+ chip->gpio_chip.can_sleep = true;
chip->gpio_chip.ngpio = chip->dev_cfg->ngpios;
if (pdata->oscio_is_gpo)
++chip->gpio_chip.ngpio;
@@ -548,7 +547,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
#endif
}
- err = request_threaded_irq(irq_summary,
+ err = devm_request_threaded_irq(&chip->client->dev,
+ irq_summary,
NULL,
sx150x_irq_thread_fn,
IRQF_SHARED | IRQF_TRIGGER_FALLING,
@@ -567,15 +567,13 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
unsigned n;
unsigned irq;
- free_irq(chip->irq_summary, chip);
-
for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
irq = chip->irq_base + n;
irq_set_chip_and_handler(irq, NULL, NULL);
}
}
-static int __devinit sx150x_probe(struct i2c_client *client,
+static int sx150x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA |
@@ -584,25 +582,26 @@ static int __devinit sx150x_probe(struct i2c_client *client,
struct sx150x_chip *chip;
int rc;
- pdata = client->dev.platform_data;
+ pdata = dev_get_platdata(&client->dev);
if (!pdata)
return -EINVAL;
if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS;
- chip = kzalloc(sizeof(struct sx150x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct sx150x_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
sx150x_init_chip(chip, client, id->driver_data, pdata);
rc = sx150x_init_hw(chip, pdata);
if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ return rc;
rc = gpiochip_add(&chip->gpio_chip);
- if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ if (rc)
+ return rc;
if (pdata->irq_summary >= 0) {
rc = sx150x_install_irq_chip(chip,
@@ -617,12 +616,10 @@ static int __devinit sx150x_probe(struct i2c_client *client,
return 0;
probe_fail_post_gpiochip_add:
WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
-probe_fail_pre_gpiochip_add:
- kfree(chip);
return rc;
}
-static int __devexit sx150x_remove(struct i2c_client *client)
+static int sx150x_remove(struct i2c_client *client)
{
struct sx150x_chip *chip;
int rc;
@@ -635,8 +632,6 @@ static int __devexit sx150x_remove(struct i2c_client *client)
if (chip->irq_summary >= 0)
sx150x_remove_irq_chip(chip);
- kfree(chip);
-
return 0;
}
@@ -646,7 +641,7 @@ static struct i2c_driver sx150x_driver = {
.owner = THIS_MODULE
},
.probe = sx150x_probe,
- .remove = __devexit_p(sx150x_remove),
+ .remove = sx150x_remove,
.id_table = sx150x_id,
};
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
new file mode 100644
index 00000000000..b50fe129774
--- /dev/null
+++ b/drivers/gpio/gpio-syscon.c
@@ -0,0 +1,191 @@
+/*
+ * SYSCON GPIO driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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/err.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define GPIO_SYSCON_FEAT_IN BIT(0)
+#define GPIO_SYSCON_FEAT_OUT BIT(1)
+#define GPIO_SYSCON_FEAT_DIR BIT(2)
+
+/* SYSCON driver is designed to use 32-bit wide registers */
+#define SYSCON_REG_SIZE (4)
+#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8)
+
+/**
+ * struct syscon_gpio_data - Configuration for the device.
+ * compatible: SYSCON driver compatible string.
+ * flags: Set of GPIO_SYSCON_FEAT_ flags:
+ * GPIO_SYSCON_FEAT_IN: GPIOs supports input,
+ * GPIO_SYSCON_FEAT_OUT: GPIOs supports output,
+ * GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction.
+ * bit_count: Number of bits used as GPIOs.
+ * dat_bit_offset: Offset (in bits) to the first GPIO bit.
+ * dir_bit_offset: Optional offset (in bits) to the first bit to switch
+ * GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
+ */
+
+struct syscon_gpio_data {
+ const char *compatible;
+ unsigned int flags;
+ unsigned int bit_count;
+ unsigned int dat_bit_offset;
+ unsigned int dir_bit_offset;
+};
+
+struct syscon_gpio_priv {
+ struct gpio_chip chip;
+ struct regmap *syscon;
+ const struct syscon_gpio_data *data;
+};
+
+static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct syscon_gpio_priv, chip);
+}
+
+static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ unsigned int val, offs = priv->data->dat_bit_offset + offset;
+ int ret;
+
+ ret = regmap_read(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
+ if (ret)
+ return ret;
+
+ return !!(val & BIT(offs % SYSCON_REG_BITS));
+}
+
+static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+ unsigned int offs = priv->data->dat_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS),
+ val ? BIT(offs % SYSCON_REG_BITS) : 0);
+}
+
+static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+
+ if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
+ unsigned int offs = priv->data->dir_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS), 0);
+ }
+
+ return 0;
+}
+
+static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
+
+ if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
+ unsigned int offs = priv->data->dir_bit_offset + offset;
+
+ regmap_update_bits(priv->syscon,
+ (offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
+ BIT(offs % SYSCON_REG_BITS),
+ BIT(offs % SYSCON_REG_BITS));
+ }
+
+ syscon_gpio_set(chip, offset, val);
+
+ return 0;
+}
+
+static const struct syscon_gpio_data clps711x_mctrl_gpio = {
+ /* ARM CLPS711X SYSFLG1 Bits 8-10 */
+ .compatible = "cirrus,clps711x-syscon1",
+ .flags = GPIO_SYSCON_FEAT_IN,
+ .bit_count = 3,
+ .dat_bit_offset = 0x40 * 8 + 8,
+};
+
+static const struct of_device_id syscon_gpio_ids[] = {
+ {
+ .compatible = "cirrus,clps711x-mctrl-gpio",
+ .data = &clps711x_mctrl_gpio,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
+
+static int syscon_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
+ struct syscon_gpio_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->data = of_id->data;
+
+ priv->syscon =
+ syscon_regmap_lookup_by_compatible(priv->data->compatible);
+ if (IS_ERR(priv->syscon))
+ return PTR_ERR(priv->syscon);
+
+ priv->chip.dev = dev;
+ priv->chip.owner = THIS_MODULE;
+ priv->chip.label = dev_name(dev);
+ priv->chip.base = -1;
+ priv->chip.ngpio = priv->data->bit_count;
+ priv->chip.get = syscon_gpio_get;
+ if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
+ priv->chip.direction_input = syscon_gpio_dir_in;
+ if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
+ priv->chip.set = syscon_gpio_set;
+ priv->chip.direction_output = syscon_gpio_dir_out;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return gpiochip_add(&priv->chip);
+}
+
+static int syscon_gpio_remove(struct platform_device *pdev)
+{
+ struct syscon_gpio_priv *priv = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&priv->chip);
+}
+
+static struct platform_driver syscon_gpio_driver = {
+ .driver = {
+ .name = "gpio-syscon",
+ .owner = THIS_MODULE,
+ .of_match_table = syscon_gpio_ids,
+ },
+ .probe = syscon_gpio_probe,
+ .remove = syscon_gpio_remove,
+};
+module_platform_driver(syscon_gpio_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("SYSCON GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c
new file mode 100644
index 00000000000..07bce97647a
--- /dev/null
+++ b/drivers/gpio/gpio-tb10x.c
@@ -0,0 +1,329 @@
+/* Abilis Systems MODULE DESCRIPTION
+ *
+ * Copyright (C) Abilis Systems 2013
+ *
+ * Authors: Sascha Leuenberger <sascha.leuenberger@abilis.com>
+ * Christian Ruppert <christian.ruppert@abilis.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/pinctrl/consumer.h>
+
+#define TB10X_GPIO_DIR_IN (0x00000000)
+#define TB10X_GPIO_DIR_OUT (0x00000001)
+#define OFFSET_TO_REG_DDR (0x00)
+#define OFFSET_TO_REG_DATA (0x04)
+#define OFFSET_TO_REG_INT_EN (0x08)
+#define OFFSET_TO_REG_CHANGE (0x0C)
+#define OFFSET_TO_REG_WRMASK (0x10)
+#define OFFSET_TO_REG_INT_TYPE (0x14)
+
+
+/**
+ * @spinlock: used for atomic read/modify/write of registers
+ * @base: register base address
+ * @domain: IRQ domain of GPIO generated interrupts managed by this controller
+ * @irq: Interrupt line of parent interrupt controller
+ * @gc: gpio_chip structure associated to this GPIO controller
+ */
+struct tb10x_gpio {
+ spinlock_t spinlock;
+ void __iomem *base;
+ struct irq_domain *domain;
+ int irq;
+ struct gpio_chip gc;
+};
+
+static inline u32 tb10x_reg_read(struct tb10x_gpio *gpio, unsigned int offs)
+{
+ return ioread32(gpio->base + offs);
+}
+
+static inline void tb10x_reg_write(struct tb10x_gpio *gpio, unsigned int offs,
+ u32 val)
+{
+ iowrite32(val, gpio->base + offs);
+}
+
+static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
+ u32 mask, u32 val)
+{
+ u32 r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio->spinlock, flags);
+
+ r = tb10x_reg_read(gpio, offs);
+ r = (r & ~mask) | (val & mask);
+
+ tb10x_reg_write(gpio, offs, r);
+
+ spin_unlock_irqrestore(&gpio->spinlock, flags);
+}
+
+static inline struct tb10x_gpio *to_tb10x_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct tb10x_gpio, gc);
+}
+
+static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+ struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ int mask = BIT(offset);
+ int val = TB10X_GPIO_DIR_IN << offset;
+
+ tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
+
+ return 0;
+}
+
+static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ int val;
+
+ val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
+
+ if (val & BIT(offset))
+ return 1;
+ else
+ return 0;
+}
+
+static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ int mask = BIT(offset);
+ int val = value << offset;
+
+ tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val);
+}
+
+static int tb10x_gpio_direction_out(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+ int mask = BIT(offset);
+ int val = TB10X_GPIO_DIR_OUT << offset;
+
+ tb10x_gpio_set(chip, offset, value);
+ tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
+
+ return 0;
+}
+
+static int tb10x_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void tb10x_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct tb10x_gpio *tb10x_gpio = to_tb10x_gpio(chip);
+
+ return irq_create_mapping(tb10x_gpio->domain, offset);
+}
+
+static int tb10x_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ if ((type & IRQF_TRIGGER_MASK) != IRQ_TYPE_EDGE_BOTH) {
+ pr_err("Only (both) edge triggered interrupts supported.\n");
+ return -EINVAL;
+ }
+
+ irqd_set_trigger_type(data, type);
+
+ return IRQ_SET_MASK_OK;
+}
+
+static irqreturn_t tb10x_gpio_irq_cascade(int irq, void *data)
+{
+ struct tb10x_gpio *tb10x_gpio = data;
+ u32 r = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_CHANGE);
+ u32 m = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_INT_EN);
+ const unsigned long bits = r & m;
+ int i;
+
+ for_each_set_bit(i, &bits, 32)
+ generic_handle_irq(irq_find_mapping(tb10x_gpio->domain, i));
+
+ return IRQ_HANDLED;
+}
+
+static int tb10x_gpio_probe(struct platform_device *pdev)
+{
+ struct tb10x_gpio *tb10x_gpio;
+ struct resource *mem;
+ struct device_node *dn = pdev->dev.of_node;
+ int ret = -EBUSY;
+ u32 ngpio;
+
+ if (!dn)
+ return -EINVAL;
+
+ if (of_property_read_u32(dn, "abilis,ngpio", &ngpio))
+ return -EINVAL;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource defined.\n");
+ return -EINVAL;
+ }
+
+ tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL);
+ if (tb10x_gpio == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&tb10x_gpio->spinlock);
+
+ tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(tb10x_gpio->base))
+ return PTR_ERR(tb10x_gpio->base);
+
+ tb10x_gpio->gc.label = of_node_full_name(dn);
+ tb10x_gpio->gc.dev = &pdev->dev;
+ tb10x_gpio->gc.owner = THIS_MODULE;
+ tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in;
+ tb10x_gpio->gc.get = tb10x_gpio_get;
+ tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out;
+ tb10x_gpio->gc.set = tb10x_gpio_set;
+ tb10x_gpio->gc.request = tb10x_gpio_request;
+ tb10x_gpio->gc.free = tb10x_gpio_free;
+ tb10x_gpio->gc.base = -1;
+ tb10x_gpio->gc.ngpio = ngpio;
+ tb10x_gpio->gc.can_sleep = false;
+
+
+ ret = gpiochip_add(&tb10x_gpio->gc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not add gpiochip.\n");
+ goto fail_gpiochip_registration;
+ }
+
+ platform_set_drvdata(pdev, tb10x_gpio);
+
+ if (of_find_property(dn, "interrupt-controller", NULL)) {
+ struct irq_chip_generic *gc;
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "No interrupt specified.\n");
+ goto fail_get_irq;
+ }
+
+ tb10x_gpio->gc.to_irq = tb10x_gpio_to_irq;
+ tb10x_gpio->irq = ret;
+
+ ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade,
+ IRQF_TRIGGER_NONE | IRQF_SHARED,
+ dev_name(&pdev->dev), tb10x_gpio);
+ if (ret != 0)
+ goto fail_request_irq;
+
+ tb10x_gpio->domain = irq_domain_add_linear(dn,
+ tb10x_gpio->gc.ngpio,
+ &irq_generic_chip_ops, NULL);
+ if (!tb10x_gpio->domain) {
+ ret = -ENOMEM;
+ goto fail_irq_domain;
+ }
+
+ ret = irq_alloc_domain_generic_chips(tb10x_gpio->domain,
+ tb10x_gpio->gc.ngpio, 1, tb10x_gpio->gc.label,
+ handle_edge_irq, IRQ_NOREQUEST, IRQ_NOPROBE,
+ IRQ_GC_INIT_MASK_CACHE);
+ if (ret)
+ goto fail_irq_domain;
+
+ gc = tb10x_gpio->domain->gc->gc[0];
+ gc->reg_base = tb10x_gpio->base;
+ gc->chip_types[0].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = tb10x_gpio_irq_set_type;
+ gc->chip_types[0].regs.ack = OFFSET_TO_REG_CHANGE;
+ gc->chip_types[0].regs.mask = OFFSET_TO_REG_INT_EN;
+ }
+
+ return 0;
+
+fail_irq_domain:
+fail_request_irq:
+fail_get_irq:
+ gpiochip_remove(&tb10x_gpio->gc);
+fail_gpiochip_registration:
+fail_ioremap:
+ return ret;
+}
+
+static int __exit tb10x_gpio_remove(struct platform_device *pdev)
+{
+ struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev);
+ int ret;
+
+ if (tb10x_gpio->gc.to_irq) {
+ irq_remove_generic_chip(tb10x_gpio->domain->gc->gc[0],
+ BIT(tb10x_gpio->gc.ngpio) - 1, 0, 0);
+ kfree(tb10x_gpio->domain->gc);
+ irq_domain_remove(tb10x_gpio->domain);
+ free_irq(tb10x_gpio->irq, tb10x_gpio);
+ }
+ ret = gpiochip_remove(&tb10x_gpio->gc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct of_device_id tb10x_gpio_dt_ids[] = {
+ { .compatible = "abilis,tb10x-gpio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tb10x_gpio_dt_ids);
+
+static struct platform_driver tb10x_gpio_driver = {
+ .probe = tb10x_gpio_probe,
+ .remove = tb10x_gpio_remove,
+ .driver = {
+ .name = "tb10x-gpio",
+ .of_match_table = tb10x_gpio_dt_ids,
+ .owner = THIS_MODULE,
+ }
+};
+
+module_platform_driver(tb10x_gpio_driver);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("tb10x gpio.");
+MODULE_VERSION("0.0.1");
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 1e48317e70f..51f7cbd9ff7 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -12,8 +12,6 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc3589x.h>
@@ -31,10 +29,6 @@ struct tc3589x_gpio {
struct tc3589x *tc3589x;
struct device *dev;
struct mutex irq_lock;
- struct irq_domain *domain;
-
- int irq_base;
-
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -95,30 +89,6 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
}
-/**
- * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
- *
- * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
- * @irq: index of the interrupt requested in the chip IRQs
- *
- * Useful for drivers to request their own IRQs.
- */
-static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio,
- int irq)
-{
- if (!tc3589x_gpio)
- return -EINVAL;
-
- return irq_create_mapping(tc3589x_gpio->domain, irq);
-}
-
-static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
-
- return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset);
-}
-
static struct gpio_chip template_chip = {
.label = "tc3589x",
.owner = THIS_MODULE,
@@ -126,13 +96,13 @@ static struct gpio_chip template_chip = {
.get = tc3589x_gpio_get,
.direction_output = tc3589x_gpio_direction_output,
.set = tc3589x_gpio_set,
- .to_irq = tc3589x_gpio_to_irq,
- .can_sleep = 1,
+ .can_sleep = true,
};
static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -159,14 +129,16 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
static void tc3589x_gpio_irq_lock(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
mutex_lock(&tc3589x_gpio->irq_lock);
}
static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
static const u8 regmap[] = {
[REG_IBE] = TC3589x_GPIOIBE0,
@@ -194,7 +166,8 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
static void tc3589x_gpio_irq_mask(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -204,7 +177,8 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
{
- struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip);
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
@@ -242,9 +216,10 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
- int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line);
+ int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
+ line);
- handle_nested_irq(virq);
+ handle_nested_irq(irq);
stat &= ~(1 << bit);
}
@@ -254,64 +229,7 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hwirq)
-{
- struct tc3589x *tc3589x_gpio = d->host_data;
-
- irq_set_chip_data(virq, tc3589x_gpio);
- irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip,
- handle_simple_irq);
- irq_set_nested_thread(virq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(virq, IRQF_VALID);
-#else
- irq_set_noprobe(virq);
-#endif
-
- return 0;
-}
-
-static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
-{
-#ifdef CONFIG_ARM
- set_irq_flags(virq, 0);
-#endif
- irq_set_chip_and_handler(virq, NULL, NULL);
- irq_set_chip_data(virq, NULL);
-}
-
-static struct irq_domain_ops tc3589x_irq_ops = {
- .map = tc3589x_gpio_irq_map,
- .unmap = tc3589x_gpio_irq_unmap,
- .xlate = irq_domain_xlate_twocell,
-};
-
-static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio,
- struct device_node *np)
-{
- int base = tc3589x_gpio->irq_base;
-
- if (base) {
- tc3589x_gpio->domain = irq_domain_add_legacy(
- NULL, tc3589x_gpio->chip.ngpio, base,
- 0, &tc3589x_irq_ops, tc3589x_gpio);
- }
- else {
- tc3589x_gpio->domain = irq_domain_add_linear(
- np, tc3589x_gpio->chip.ngpio,
- &tc3589x_irq_ops, tc3589x_gpio);
- }
-
- if (!tc3589x_gpio->domain) {
- dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
- return -ENOSYS;
- }
-
- return 0;
-}
-
-static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
+static int tc3589x_gpio_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
struct tc3589x_gpio_platform_data *pdata;
@@ -331,7 +249,8 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL);
+ tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio),
+ GFP_KERNEL);
if (!tc3589x_gpio)
return -ENOMEM;
@@ -346,33 +265,39 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1;
#ifdef CONFIG_OF_GPIO
- tc3589x_gpio->chip.of_node = np;
+ tc3589x_gpio->chip.of_node = np;
#endif
- tc3589x_gpio->irq_base = tc3589x->irq_base ?
- tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0;
-
/* Bring the GPIO module out of reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
TC3589x_RSTCTRL_GPIRST, 0);
if (ret < 0)
- goto out_free;
-
- ret = tc3589x_gpio_irq_init(tc3589x_gpio, np);
- if (ret)
- goto out_free;
+ return ret;
- ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT,
- "tc3589x-gpio", tc3589x_gpio);
+ ret = devm_request_threaded_irq(&pdev->dev,
+ irq, NULL, tc3589x_gpio_irq,
+ IRQF_ONESHOT, "tc3589x-gpio",
+ tc3589x_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
- goto out_free;
+ return ret;
}
ret = gpiochip_add(&tc3589x_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
- goto out_freeirq;
+ return ret;
+ }
+
+ ret = gpiochip_irqchip_add(&tc3589x_gpio->chip,
+ &tc3589x_gpio_irq_chip,
+ 0,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "could not connect irqchip to gpiochip\n");
+ return ret;
}
if (pdata && pdata->setup)
@@ -381,20 +306,13 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tc3589x_gpio);
return 0;
-
-out_freeirq:
- free_irq(irq, tc3589x_gpio);
-out_free:
- kfree(tc3589x_gpio);
- return ret;
}
-static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
+static int tc3589x_gpio_remove(struct platform_device *pdev)
{
struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
- int irq = platform_get_irq(pdev, 0);
int ret;
if (pdata && pdata->remove)
@@ -407,11 +325,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
return ret;
}
- free_irq(irq, tc3589x_gpio);
-
- platform_set_drvdata(pdev, NULL);
- kfree(tc3589x_gpio);
-
return 0;
}
@@ -419,7 +332,7 @@ static struct platform_driver tc3589x_gpio_driver = {
.driver.name = "tc3589x-gpio",
.driver.owner = THIS_MODULE,
.probe = tc3589x_gpio_probe,
- .remove = __devexit_p(tc3589x_gpio_remove),
+ .remove = tc3589x_gpio_remove,
};
static int __init tc3589x_gpio_init(void)
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index d982593d756..4e8fb8261a8 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -17,6 +17,7 @@
*
*/
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -26,9 +27,9 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/pinctrl/consumer.h>
-
-#include <asm/mach/irq.h>
+#include <linux/pm.h>
#define GPIO_BANK(x) ((x) >> 5)
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
@@ -64,15 +65,17 @@ struct tegra_gpio_bank {
int bank;
int irq;
spinlock_t lvl_lock[4];
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 cnf[4];
u32 out[4];
u32 oe[4];
u32 int_enb[4];
u32 int_lvl[4];
+ u32 wake_enb[4];
#endif
};
+static struct device *dev;
static struct irq_domain *irq_domain;
static void __iomem *regs;
static u32 tegra_gpio_bank_count;
@@ -109,20 +112,18 @@ static void tegra_gpio_enable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
}
-EXPORT_SYMBOL_GPL(tegra_gpio_enable);
static void tegra_gpio_disable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
}
-EXPORT_SYMBOL_GPL(tegra_gpio_disable);
-int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
{
return pinctrl_request_gpio(offset);
}
-void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
{
pinctrl_free_gpio(offset);
tegra_gpio_disable(offset);
@@ -135,6 +136,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
{
+ /* If gpio is in output mode then read from the out value */
+ if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1)
+ return (tegra_gpio_readl(GPIO_OUT(offset)) >>
+ GPIO_BIT(offset)) & 0x1;
+
return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
}
@@ -200,6 +206,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
int lvl_type;
int val;
unsigned long flags;
+ int ret;
switch (type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_RISING:
@@ -226,6 +233,12 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
+ ret = gpio_lock_as_irq(&tegra_gpio_chip, gpio);
+ if (ret) {
+ dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio);
+ return ret;
+ }
+
spin_lock_irqsave(&bank->lvl_lock[port], flags);
val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
@@ -246,6 +259,13 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
+static void tegra_gpio_irq_shutdown(struct irq_data *d)
+{
+ int gpio = d->hwirq;
+
+ gpio_unlock_as_irq(&tegra_gpio_chip, gpio);
+}
+
static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct tegra_gpio_bank *bank;
@@ -285,8 +305,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
-#ifdef CONFIG_PM
-void tegra_gpio_resume(void)
+#ifdef CONFIG_PM_SLEEP
+static int tegra_gpio_resume(struct device *dev)
{
unsigned long flags;
int b;
@@ -308,9 +328,10 @@ void tegra_gpio_resume(void)
}
local_irq_restore(flags);
+ return 0;
}
-void tegra_gpio_suspend(void)
+static int tegra_gpio_suspend(struct device *dev)
{
unsigned long flags;
int b;
@@ -327,14 +348,31 @@ void tegra_gpio_suspend(void)
bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+
+ /* Enable gpio irq for wake up source */
+ tegra_gpio_writel(bank->wake_enb[p],
+ GPIO_INT_ENB(gpio));
}
}
local_irq_restore(flags);
+ return 0;
}
-static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
+static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+ int gpio = d->hwirq;
+ u32 port, bit, mask;
+
+ port = GPIO_PORT(gpio);
+ bit = GPIO_BIT(gpio);
+ mask = BIT(bit);
+
+ if (enable)
+ bank->wake_enb[port] |= mask;
+ else
+ bank->wake_enb[port] &= ~mask;
+
return irq_set_irq_wake(bank->irq, enable);
}
#endif
@@ -345,11 +383,16 @@ static struct irq_chip tegra_gpio_irq_chip = {
.irq_mask = tegra_gpio_irq_mask,
.irq_unmask = tegra_gpio_irq_unmask,
.irq_set_type = tegra_gpio_irq_set_type,
-#ifdef CONFIG_PM
- .irq_set_wake = tegra_gpio_wake_enable,
+ .irq_shutdown = tegra_gpio_irq_shutdown,
+#ifdef CONFIG_PM_SLEEP
+ .irq_set_wake = tegra_gpio_irq_set_wake,
#endif
};
+static const struct dev_pm_ops tegra_gpio_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
+};
+
struct tegra_gpio_soc_config {
u32 bank_stride;
u32 upper_offset;
@@ -365,7 +408,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = {
.upper_offset = 0x80,
};
-static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
+static const struct of_device_id tegra_gpio_of_match[] = {
{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
{ },
@@ -376,22 +419,25 @@ static struct of_device_id tegra_gpio_of_match[] __devinitdata = {
*/
static struct lock_class_key gpio_lock_class;
-static int __devinit tegra_gpio_probe(struct platform_device *pdev)
+static int tegra_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct tegra_gpio_soc_config *config;
- int irq_base;
struct resource *res;
struct tegra_gpio_bank *bank;
+ int ret;
int gpio;
int i;
int j;
+ dev = &pdev->dev;
+
match = of_match_device(tegra_gpio_of_match, &pdev->dev);
- if (match)
- config = (struct tegra_gpio_soc_config *)match->data;
- else
- config = &tegra20_gpio_config;
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+ config = (struct tegra_gpio_soc_config *)match->data;
tegra_gpio_bank_stride = config->bank_stride;
tegra_gpio_upper_offset = config->upper_offset;
@@ -412,19 +458,14 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
tegra_gpio_banks = devm_kzalloc(&pdev->dev,
tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
GFP_KERNEL);
- if (!tegra_gpio_banks) {
- dev_err(&pdev->dev, "Couldn't allocate bank structure\n");
+ if (!tegra_gpio_banks)
return -ENODEV;
- }
- irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0);
- if (irq_base < 0) {
- dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n");
- return -ENODEV;
- }
- irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
- tegra_gpio_chip.ngpio, irq_base, 0,
+ irq_domain = irq_domain_add_linear(pdev->dev.of_node,
+ tegra_gpio_chip.ngpio,
&irq_domain_simple_ops, NULL);
+ if (!irq_domain)
+ return -ENODEV;
for (i = 0; i < tegra_gpio_bank_count; i++) {
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
@@ -439,16 +480,9 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Missing MEM resource\n");
- return -ENODEV;
- }
-
- regs = devm_request_and_ioremap(&pdev->dev, res);
- if (!regs) {
- dev_err(&pdev->dev, "Couldn't ioremap regs\n");
- return -ENODEV;
- }
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
for (i = 0; i < tegra_gpio_bank_count; i++) {
for (j = 0; j < 4; j++) {
@@ -457,14 +491,16 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev)
}
}
-#ifdef CONFIG_OF_GPIO
tegra_gpio_chip.of_node = pdev->dev.of_node;
-#endif
- gpiochip_add(&tegra_gpio_chip);
+ ret = gpiochip_add(&tegra_gpio_chip);
+ if (ret < 0) {
+ irq_domain_remove(irq_domain);
+ return ret;
+ }
for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
- int irq = irq_find_mapping(irq_domain, gpio);
+ int irq = irq_create_mapping(irq_domain, gpio);
/* No validity check; all Tegra GPIOs are valid IRQs */
bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
@@ -493,6 +529,7 @@ static struct platform_driver tegra_gpio_driver = {
.driver = {
.name = "tegra-gpio",
.owner = THIS_MODULE,
+ .pm = &tegra_gpio_pm_ops,
.of_match_table = tegra_gpio_of_match,
},
.probe = tegra_gpio_probe,
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 031c6adf5b6..efc7c129016 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d)
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
- tgpio->last_ier &= ~(1 << offset);
+ tgpio->last_ier &= ~(1UL << offset);
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
}
@@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d)
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
- tgpio->last_ier |= 1 << offset;
+ tgpio->last_ier |= 1UL << offset;
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
}
@@ -167,8 +167,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
if (ver < 3) {
ret = -EINVAL;
goto out;
- }
- else {
+ } else {
flr |= 1 << offset;
bflr |= 1 << offset;
}
@@ -222,45 +221,46 @@ static struct irq_chip timbgpio_irqchip = {
.irq_set_type = timbgpio_irq_type,
};
-static int __devinit timbgpio_probe(struct platform_device *pdev)
+static int timbgpio_probe(struct platform_device *pdev)
{
int err, i;
+ struct device *dev = &pdev->dev;
struct gpio_chip *gc;
struct timbgpio *tgpio;
struct resource *iomem;
- struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+ struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
int irq = platform_get_irq(pdev, 0);
if (!pdata || pdata->nr_pins > 32) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Invalid platform data\n");
+ return -EINVAL;
}
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Unable to get resource\n");
+ return -EINVAL;
}
- tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL);
+ tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL);
if (!tgpio) {
- err = -EINVAL;
- goto err_mem;
+ dev_err(dev, "Memory alloc failed\n");
+ return -EINVAL;
}
tgpio->irq_base = pdata->irq_base;
spin_lock_init(&tgpio->lock);
- if (!request_mem_region(iomem->start, resource_size(iomem),
- DRIVER_NAME)) {
- err = -EBUSY;
- goto err_request;
+ if (!devm_request_mem_region(dev, iomem->start, resource_size(iomem),
+ DRIVER_NAME)) {
+ dev_err(dev, "Region already claimed\n");
+ return -EBUSY;
}
- tgpio->membase = ioremap(iomem->start, resource_size(iomem));
+ tgpio->membase = devm_ioremap(dev, iomem->start, resource_size(iomem));
if (!tgpio->membase) {
- err = -ENOMEM;
- goto err_ioremap;
+ dev_err(dev, "Cannot ioremap\n");
+ return -ENOMEM;
}
gc = &tgpio->gpio;
@@ -276,11 +276,11 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
gc->dbg_show = NULL;
gc->base = pdata->gpio_base;
gc->ngpio = pdata->nr_pins;
- gc->can_sleep = 0;
+ gc->can_sleep = false;
err = gpiochip_add(gc);
if (err)
- goto err_chipadd;
+ return err;
platform_set_drvdata(pdev, tgpio);
@@ -291,8 +291,8 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
return 0;
for (i = 0; i < pdata->nr_pins; i++) {
- irq_set_chip_and_handler_name(tgpio->irq_base + i,
- &timbgpio_irqchip, handle_simple_irq, "mux");
+ irq_set_chip_and_handler(tgpio->irq_base + i,
+ &timbgpio_irqchip, handle_simple_irq);
irq_set_chip_data(tgpio->irq_base + i, tgpio);
#ifdef CONFIG_ARM
set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE);
@@ -303,25 +303,13 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
irq_set_chained_handler(irq, timbgpio_irq);
return 0;
-
-err_chipadd:
- iounmap(tgpio->membase);
-err_ioremap:
- release_mem_region(iomem->start, resource_size(iomem));
-err_request:
- kfree(tgpio);
-err_mem:
- printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err);
-
- return err;
}
-static int __devexit timbgpio_remove(struct platform_device *pdev)
+static int timbgpio_remove(struct platform_device *pdev)
{
int err;
- struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+ struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct timbgpio *tgpio = platform_get_drvdata(pdev);
- struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0);
if (irq >= 0 && tgpio->irq_base > 0) {
@@ -339,12 +327,6 @@ static int __devexit timbgpio_remove(struct platform_device *pdev)
if (err)
printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n");
- iounmap(tgpio->membase);
- release_mem_region(iomem->start, resource_size(iomem));
- kfree(tgpio);
-
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c
deleted file mode 100644
index 3fa3e2867e1..00000000000
--- a/drivers/gpio/gpio-tnetv107x.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Texas Instruments TNETV107X GPIO Controller
- *
- * Copyright (C) 2010 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-
-#include <mach/common.h>
-#include <mach/tnetv107x.h>
-
-struct tnetv107x_gpio_regs {
- u32 idver;
- u32 data_in[3];
- u32 data_out[3];
- u32 direction[3];
- u32 enable[3];
-};
-
-#define gpio_reg_index(gpio) ((gpio) >> 5)
-#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
-
-#define gpio_reg_rmw(reg, mask, val) \
- __raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg))
-
-#define gpio_reg_set_bit(reg, gpio) \
- gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio))
-
-#define gpio_reg_clear_bit(reg, gpio) \
- gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0)
-
-#define gpio_reg_get_bit(reg, gpio) \
- (__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio))
-
-#define chip2controller(chip) \
- container_of(chip, struct davinci_gpio_controller, chip)
-
-#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
-
-static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS];
-
-static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_set_bit(regs->enable, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_clear_bit(regs->enable, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-}
-
-static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- gpio_reg_set_bit(regs->direction, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- if (value)
- gpio_reg_set_bit(regs->data_out, gpio);
- else
- gpio_reg_clear_bit(regs->data_out, gpio);
-
- gpio_reg_clear_bit(regs->direction, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-
- return 0;
-}
-
-static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- int ret;
-
- ret = gpio_reg_get_bit(regs->data_in, gpio);
-
- return ret ? 1 : 0;
-}
-
-static void tnetv107x_gpio_set(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct davinci_gpio_controller *ctlr = chip2controller(chip);
- struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
- unsigned gpio = chip->base + offset;
- unsigned long flags;
-
- spin_lock_irqsave(&ctlr->lock, flags);
-
- if (value)
- gpio_reg_set_bit(regs->data_out, gpio);
- else
- gpio_reg_clear_bit(regs->data_out, gpio);
-
- spin_unlock_irqrestore(&ctlr->lock, flags);
-}
-
-static int __init tnetv107x_gpio_setup(void)
-{
- int i, base;
- unsigned ngpio;
- struct davinci_soc_info *soc_info = &davinci_soc_info;
- struct tnetv107x_gpio_regs *regs;
- struct davinci_gpio_controller *ctlr;
-
- if (soc_info->gpio_type != GPIO_TYPE_TNETV107X)
- return 0;
-
- ngpio = soc_info->gpio_num;
- if (ngpio == 0) {
- pr_err("GPIO setup: how many GPIOs?\n");
- return -EINVAL;
- }
-
- if (WARN_ON(TNETV107X_N_GPIO < ngpio))
- ngpio = TNETV107X_N_GPIO;
-
- regs = ioremap(soc_info->gpio_base, SZ_4K);
- if (WARN_ON(!regs))
- return -EINVAL;
-
- for (i = 0, base = 0; base < ngpio; i++, base += 32) {
- ctlr = &chips[i];
-
- ctlr->chip.label = "tnetv107x";
- ctlr->chip.can_sleep = 0;
- ctlr->chip.base = base;
- ctlr->chip.ngpio = ngpio - base;
- if (ctlr->chip.ngpio > 32)
- ctlr->chip.ngpio = 32;
-
- ctlr->chip.request = tnetv107x_gpio_request;
- ctlr->chip.free = tnetv107x_gpio_free;
- ctlr->chip.direction_input = tnetv107x_gpio_dir_in;
- ctlr->chip.get = tnetv107x_gpio_get;
- ctlr->chip.direction_output = tnetv107x_gpio_dir_out;
- ctlr->chip.set = tnetv107x_gpio_set;
-
- spin_lock_init(&ctlr->lock);
-
- ctlr->regs = regs;
- ctlr->set_data = &regs->data_out[i];
- ctlr->clr_data = &regs->data_out[i];
- ctlr->in_data = &regs->data_in[i];
-
- gpiochip_add(&ctlr->chip);
- }
-
- soc_info->gpio_ctlrs = chips;
- soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
- return 0;
-}
-pure_initcall(tnetv107x_gpio_setup);
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index 2526b3bb0fa..a69fbea4125 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -80,7 +80,15 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
val, mask);
}
-static int __devinit tps6586x_gpio_probe(struct platform_device *pdev)
+static int tps6586x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct tps6586x_gpio *tps6586x_gpio = to_tps6586x_gpio(gc);
+
+ return tps6586x_irq_get_virq(tps6586x_gpio->parent,
+ TPS6586X_INT_PLDO_0 + offset);
+}
+
+static int tps6586x_gpio_probe(struct platform_device *pdev)
{
struct tps6586x_platform_data *pdata;
struct tps6586x_gpio *tps6586x_gpio;
@@ -89,10 +97,8 @@ static int __devinit tps6586x_gpio_probe(struct platform_device *pdev)
pdata = dev_get_platdata(pdev->dev.parent);
tps6586x_gpio = devm_kzalloc(&pdev->dev,
sizeof(*tps6586x_gpio), GFP_KERNEL);
- if (!tps6586x_gpio) {
- dev_err(&pdev->dev, "Could not allocate tps6586x_gpio\n");
+ if (!tps6586x_gpio)
return -ENOMEM;
- }
tps6586x_gpio->parent = pdev->dev.parent;
@@ -100,12 +106,13 @@ static int __devinit tps6586x_gpio_probe(struct platform_device *pdev)
tps6586x_gpio->gpio_chip.label = pdev->name;
tps6586x_gpio->gpio_chip.dev = &pdev->dev;
tps6586x_gpio->gpio_chip.ngpio = 4;
- tps6586x_gpio->gpio_chip.can_sleep = 1;
+ tps6586x_gpio->gpio_chip.can_sleep = true;
/* FIXME: add handling of GPIOs as dedicated inputs */
tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output;
tps6586x_gpio->gpio_chip.set = tps6586x_gpio_set;
tps6586x_gpio->gpio_chip.get = tps6586x_gpio_get;
+ tps6586x_gpio->gpio_chip.to_irq = tps6586x_gpio_to_irq;
#ifdef CONFIG_OF_GPIO
tps6586x_gpio->gpio_chip.of_node = pdev->dev.parent->of_node;
@@ -126,7 +133,7 @@ static int __devinit tps6586x_gpio_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit tps6586x_gpio_remove(struct platform_device *pdev)
+static int tps6586x_gpio_remove(struct platform_device *pdev)
{
struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev);
@@ -137,7 +144,7 @@ static struct platform_driver tps6586x_gpio_driver = {
.driver.name = "tps6586x-gpio",
.driver.owner = THIS_MODULE,
.probe = tps6586x_gpio_probe,
- .remove = __devexit_p(tps6586x_gpio_remove),
+ .remove = tps6586x_gpio_remove,
};
static int __init tps6586x_gpio_init(void)
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index 11f29c82253..e2f8cda235e 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -113,7 +113,7 @@ static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev,
}
#endif
-static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
+static int tps65910_gpio_probe(struct platform_device *pdev)
{
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
@@ -123,17 +123,15 @@ static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
tps65910_gpio = devm_kzalloc(&pdev->dev,
sizeof(*tps65910_gpio), GFP_KERNEL);
- if (!tps65910_gpio) {
- dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n");
+ if (!tps65910_gpio)
return -ENOMEM;
- }
tps65910_gpio->tps65910 = tps65910;
tps65910_gpio->gpio_chip.owner = THIS_MODULE;
tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name;
- switch(tps65910_chip_id(tps65910)) {
+ switch (tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO;
break;
@@ -143,7 +141,7 @@ static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
default:
return -EINVAL;
}
- tps65910_gpio->gpio_chip.can_sleep = 1;
+ tps65910_gpio->gpio_chip.can_sleep = true;
tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input;
tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
tps65910_gpio->gpio_chip.set = tps65910_gpio_set;
@@ -188,7 +186,7 @@ skip_init:
return ret;
}
-static int __devexit tps65910_gpio_remove(struct platform_device *pdev)
+static int tps65910_gpio_remove(struct platform_device *pdev)
{
struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
@@ -199,7 +197,7 @@ static struct platform_driver tps65910_gpio_driver = {
.driver.name = "tps65910-gpio",
.driver.owner = THIS_MODULE,
.probe = tps65910_gpio_probe,
- .remove = __devexit_p(tps65910_gpio_remove),
+ .remove = tps65910_gpio_remove,
};
static int __init tps65910_gpio_init(void)
diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c
index 99106d1e2e5..59ee486cb8b 100644
--- a/drivers/gpio/gpio-tps65912.c
+++ b/drivers/gpio/gpio-tps65912.c
@@ -79,15 +79,15 @@ static struct gpio_chip template_chip = {
.direction_output = tps65912_gpio_output,
.get = tps65912_gpio_get,
.set = tps65912_gpio_set,
- .can_sleep = 1,
+ .can_sleep = true,
.ngpio = 5,
.base = -1,
};
-static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
+static int tps65912_gpio_probe(struct platform_device *pdev)
{
struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent);
- struct tps65912_board *pdata = tps65912->dev->platform_data;
+ struct tps65912_board *pdata = dev_get_platdata(tps65912->dev);
struct tps65912_gpio_data *tps65912_gpio;
int ret;
@@ -113,7 +113,7 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit tps65912_gpio_remove(struct platform_device *pdev)
+static int tps65912_gpio_remove(struct platform_device *pdev)
{
struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev);
@@ -126,7 +126,7 @@ static struct platform_driver tps65912_gpio_driver = {
.owner = THIS_MODULE,
},
.probe = tps65912_gpio_probe,
- .remove = __devexit_p(tps65912_gpio_remove),
+ .remove = tps65912_gpio_remove,
};
static int __init tps65912_gpio_init(void)
diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c
new file mode 100644
index 00000000000..3df3ebdb3e5
--- /dev/null
+++ b/drivers/gpio/gpio-ts5500.c
@@ -0,0 +1,466 @@
+/*
+ * Digital I/O driver for Technologic Systems TS-5500
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * Technologic Systems platforms have pin blocks, exposing several Digital
+ * Input/Output lines (DIO). This driver aims to support single pin blocks.
+ * In that sense, the support is not limited to the TS-5500 blocks.
+ * Actually, the following platforms have DIO support:
+ *
+ * TS-5500:
+ * Documentation: http://wiki.embeddedarm.com/wiki/TS-5500
+ * Blocks: DIO1, DIO2 and LCD port.
+ *
+ * TS-5600:
+ * Documentation: http://wiki.embeddedarm.com/wiki/TS-5600
+ * Blocks: LCD port (identical to TS-5500 LCD).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-ts5500.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* List of supported Technologic Systems platforms DIO blocks */
+enum ts5500_blocks { TS5500_DIO1, TS5500_DIO2, TS5500_LCD, TS5600_LCD };
+
+struct ts5500_priv {
+ const struct ts5500_dio *pinout;
+ struct gpio_chip gpio_chip;
+ spinlock_t lock;
+ bool strap;
+ u8 hwirq;
+};
+
+/*
+ * Hex 7D is used to control several blocks (e.g. DIO2 and LCD port).
+ * This flag ensures that the region has been requested by this driver.
+ */
+static bool hex7d_reserved;
+
+/*
+ * This structure is used to describe capabilities of DIO lines,
+ * such as available directions and connected interrupt (if any).
+ */
+struct ts5500_dio {
+ const u8 value_addr;
+ const u8 value_mask;
+ const u8 control_addr;
+ const u8 control_mask;
+ const bool no_input;
+ const bool no_output;
+ const u8 irq;
+};
+
+#define TS5500_DIO_IN_OUT(vaddr, vbit, caddr, cbit) \
+ { \
+ .value_addr = vaddr, \
+ .value_mask = BIT(vbit), \
+ .control_addr = caddr, \
+ .control_mask = BIT(cbit), \
+ }
+
+#define TS5500_DIO_IN(addr, bit) \
+ { \
+ .value_addr = addr, \
+ .value_mask = BIT(bit), \
+ .no_output = true, \
+ }
+
+#define TS5500_DIO_IN_IRQ(addr, bit, _irq) \
+ { \
+ .value_addr = addr, \
+ .value_mask = BIT(bit), \
+ .no_output = true, \
+ .irq = _irq, \
+ }
+
+#define TS5500_DIO_OUT(addr, bit) \
+ { \
+ .value_addr = addr, \
+ .value_mask = BIT(bit), \
+ .no_input = true, \
+ }
+
+/*
+ * Input/Output DIO lines are programmed in groups of 4. Their values are
+ * available through 4 consecutive bits in a value port, whereas the direction
+ * of these 4 lines is driven by only 1 bit in a control port.
+ */
+#define TS5500_DIO_GROUP(vaddr, vbitfrom, caddr, cbit) \
+ TS5500_DIO_IN_OUT(vaddr, vbitfrom + 0, caddr, cbit), \
+ TS5500_DIO_IN_OUT(vaddr, vbitfrom + 1, caddr, cbit), \
+ TS5500_DIO_IN_OUT(vaddr, vbitfrom + 2, caddr, cbit), \
+ TS5500_DIO_IN_OUT(vaddr, vbitfrom + 3, caddr, cbit)
+
+/*
+ * TS-5500 DIO1 block
+ *
+ * value control dir hw
+ * addr bit addr bit in out irq name pin offset
+ *
+ * 0x7b 0 0x7a 0 x x DIO1_0 1 0
+ * 0x7b 1 0x7a 0 x x DIO1_1 3 1
+ * 0x7b 2 0x7a 0 x x DIO1_2 5 2
+ * 0x7b 3 0x7a 0 x x DIO1_3 7 3
+ * 0x7b 4 0x7a 1 x x DIO1_4 9 4
+ * 0x7b 5 0x7a 1 x x DIO1_5 11 5
+ * 0x7b 6 0x7a 1 x x DIO1_6 13 6
+ * 0x7b 7 0x7a 1 x x DIO1_7 15 7
+ * 0x7c 0 0x7a 5 x x DIO1_8 4 8
+ * 0x7c 1 0x7a 5 x x DIO1_9 6 9
+ * 0x7c 2 0x7a 5 x x DIO1_10 8 10
+ * 0x7c 3 0x7a 5 x x DIO1_11 10 11
+ * 0x7c 4 x DIO1_12 12 12
+ * 0x7c 5 x 7 DIO1_13 14 13
+ */
+static const struct ts5500_dio ts5500_dio1[] = {
+ TS5500_DIO_GROUP(0x7b, 0, 0x7a, 0),
+ TS5500_DIO_GROUP(0x7b, 4, 0x7a, 1),
+ TS5500_DIO_GROUP(0x7c, 0, 0x7a, 5),
+ TS5500_DIO_IN(0x7c, 4),
+ TS5500_DIO_IN_IRQ(0x7c, 5, 7),
+};
+
+/*
+ * TS-5500 DIO2 block
+ *
+ * value control dir hw
+ * addr bit addr bit in out irq name pin offset
+ *
+ * 0x7e 0 0x7d 0 x x DIO2_0 1 0
+ * 0x7e 1 0x7d 0 x x DIO2_1 3 1
+ * 0x7e 2 0x7d 0 x x DIO2_2 5 2
+ * 0x7e 3 0x7d 0 x x DIO2_3 7 3
+ * 0x7e 4 0x7d 1 x x DIO2_4 9 4
+ * 0x7e 5 0x7d 1 x x DIO2_5 11 5
+ * 0x7e 6 0x7d 1 x x DIO2_6 13 6
+ * 0x7e 7 0x7d 1 x x DIO2_7 15 7
+ * 0x7f 0 0x7d 5 x x DIO2_8 4 8
+ * 0x7f 1 0x7d 5 x x DIO2_9 6 9
+ * 0x7f 2 0x7d 5 x x DIO2_10 8 10
+ * 0x7f 3 0x7d 5 x x DIO2_11 10 11
+ * 0x7f 4 x 6 DIO2_13 14 12
+ */
+static const struct ts5500_dio ts5500_dio2[] = {
+ TS5500_DIO_GROUP(0x7e, 0, 0x7d, 0),
+ TS5500_DIO_GROUP(0x7e, 4, 0x7d, 1),
+ TS5500_DIO_GROUP(0x7f, 0, 0x7d, 5),
+ TS5500_DIO_IN_IRQ(0x7f, 4, 6),
+};
+
+/*
+ * TS-5500 LCD port used as DIO block
+ * TS-5600 LCD port is identical
+ *
+ * value control dir hw
+ * addr bit addr bit in out irq name pin offset
+ *
+ * 0x72 0 0x7d 2 x x LCD_0 8 0
+ * 0x72 1 0x7d 2 x x LCD_1 7 1
+ * 0x72 2 0x7d 2 x x LCD_2 10 2
+ * 0x72 3 0x7d 2 x x LCD_3 9 3
+ * 0x72 4 0x7d 3 x x LCD_4 12 4
+ * 0x72 5 0x7d 3 x x LCD_5 11 5
+ * 0x72 6 0x7d 3 x x LCD_6 14 6
+ * 0x72 7 0x7d 3 x x LCD_7 13 7
+ * 0x73 0 x LCD_EN 5 8
+ * 0x73 6 x LCD_WR 6 9
+ * 0x73 7 x 1 LCD_RS 3 10
+ */
+static const struct ts5500_dio ts5500_lcd[] = {
+ TS5500_DIO_GROUP(0x72, 0, 0x7d, 2),
+ TS5500_DIO_GROUP(0x72, 4, 0x7d, 3),
+ TS5500_DIO_OUT(0x73, 0),
+ TS5500_DIO_IN(0x73, 6),
+ TS5500_DIO_IN_IRQ(0x73, 7, 1),
+};
+
+static inline struct ts5500_priv *ts5500_gc_to_priv(struct gpio_chip *chip)
+{
+ return container_of(chip, struct ts5500_priv, gpio_chip);
+}
+
+static inline void ts5500_set_mask(u8 mask, u8 addr)
+{
+ u8 val = inb(addr);
+ val |= mask;
+ outb(val, addr);
+}
+
+static inline void ts5500_clear_mask(u8 mask, u8 addr)
+{
+ u8 val = inb(addr);
+ val &= ~mask;
+ outb(val, addr);
+}
+
+static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ const struct ts5500_dio line = priv->pinout[offset];
+ unsigned long flags;
+
+ if (line.no_input)
+ return -ENXIO;
+
+ if (line.no_output)
+ return 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ts5500_clear_mask(line.control_mask, line.control_addr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ const struct ts5500_dio line = priv->pinout[offset];
+
+ return !!(inb(line.value_addr) & line.value_mask);
+}
+
+static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ const struct ts5500_dio line = priv->pinout[offset];
+ unsigned long flags;
+
+ if (line.no_output)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!line.no_input)
+ ts5500_set_mask(line.control_mask, line.control_addr);
+
+ if (val)
+ ts5500_set_mask(line.value_mask, line.value_addr);
+ else
+ ts5500_clear_mask(line.value_mask, line.value_addr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static void ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ const struct ts5500_dio line = priv->pinout[offset];
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (val)
+ ts5500_set_mask(line.value_mask, line.value_addr);
+ else
+ ts5500_clear_mask(line.value_mask, line.value_addr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct ts5500_priv *priv = ts5500_gc_to_priv(chip);
+ const struct ts5500_dio *block = priv->pinout;
+ const struct ts5500_dio line = block[offset];
+
+ /* Only one pin is connected to an interrupt */
+ if (line.irq)
+ return line.irq;
+
+ /* As this pin is input-only, we may strap it to another in/out pin */
+ if (priv->strap)
+ return priv->hwirq;
+
+ return -ENXIO;
+}
+
+static int ts5500_enable_irq(struct ts5500_priv *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->hwirq == 7)
+ ts5500_set_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
+ else if (priv->hwirq == 6)
+ ts5500_set_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
+ else if (priv->hwirq == 1)
+ ts5500_set_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
+ else
+ ret = -EINVAL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
+static void ts5500_disable_irq(struct ts5500_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->hwirq == 7)
+ ts5500_clear_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */
+ else if (priv->hwirq == 6)
+ ts5500_clear_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */
+ else if (priv->hwirq == 1)
+ ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */
+ else
+ dev_err(priv->gpio_chip.dev, "invalid hwirq %d\n", priv->hwirq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int ts5500_dio_probe(struct platform_device *pdev)
+{
+ enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
+ struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ const char *name = dev_name(dev);
+ struct ts5500_priv *priv;
+ struct resource *res;
+ unsigned long flags;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "missing IRQ resource\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+ priv->hwirq = res->start;
+ spin_lock_init(&priv->lock);
+
+ priv->gpio_chip.owner = THIS_MODULE;
+ priv->gpio_chip.label = name;
+ priv->gpio_chip.dev = dev;
+ priv->gpio_chip.direction_input = ts5500_gpio_input;
+ priv->gpio_chip.direction_output = ts5500_gpio_output;
+ priv->gpio_chip.get = ts5500_gpio_get;
+ priv->gpio_chip.set = ts5500_gpio_set;
+ priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
+ priv->gpio_chip.base = -1;
+ if (pdata) {
+ priv->gpio_chip.base = pdata->base;
+ priv->strap = pdata->strap;
+ }
+
+ switch (block) {
+ case TS5500_DIO1:
+ priv->pinout = ts5500_dio1;
+ priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio1);
+
+ if (!devm_request_region(dev, 0x7a, 3, name)) {
+ dev_err(dev, "failed to request %s ports\n", name);
+ return -EBUSY;
+ }
+ break;
+ case TS5500_DIO2:
+ priv->pinout = ts5500_dio2;
+ priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio2);
+
+ if (!devm_request_region(dev, 0x7e, 2, name)) {
+ dev_err(dev, "failed to request %s ports\n", name);
+ return -EBUSY;
+ }
+
+ if (hex7d_reserved)
+ break;
+
+ if (!devm_request_region(dev, 0x7d, 1, name)) {
+ dev_err(dev, "failed to request %s 7D\n", name);
+ return -EBUSY;
+ }
+
+ hex7d_reserved = true;
+ break;
+ case TS5500_LCD:
+ case TS5600_LCD:
+ priv->pinout = ts5500_lcd;
+ priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_lcd);
+
+ if (!devm_request_region(dev, 0x72, 2, name)) {
+ dev_err(dev, "failed to request %s ports\n", name);
+ return -EBUSY;
+ }
+
+ if (!hex7d_reserved) {
+ if (!devm_request_region(dev, 0x7d, 1, name)) {
+ dev_err(dev, "failed to request %s 7D\n", name);
+ return -EBUSY;
+ }
+
+ hex7d_reserved = true;
+ }
+
+ /* Ensure usage of LCD port as DIO */
+ spin_lock_irqsave(&priv->lock, flags);
+ ts5500_clear_mask(BIT(4), 0x7d);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ break;
+ }
+
+ ret = gpiochip_add(&priv->gpio_chip);
+ if (ret) {
+ dev_err(dev, "failed to register the gpio chip\n");
+ return ret;
+ }
+
+ ret = ts5500_enable_irq(priv);
+ if (ret) {
+ dev_err(dev, "invalid interrupt %d\n", priv->hwirq);
+ goto cleanup;
+ }
+
+ return 0;
+cleanup:
+ if (gpiochip_remove(&priv->gpio_chip))
+ dev_err(dev, "failed to remove gpio chip\n");
+ return ret;
+}
+
+static int ts5500_dio_remove(struct platform_device *pdev)
+{
+ struct ts5500_priv *priv = platform_get_drvdata(pdev);
+
+ ts5500_disable_irq(priv);
+ return gpiochip_remove(&priv->gpio_chip);
+}
+
+static struct platform_device_id ts5500_dio_ids[] = {
+ { "ts5500-dio1", TS5500_DIO1 },
+ { "ts5500-dio2", TS5500_DIO2 },
+ { "ts5500-dio-lcd", TS5500_LCD },
+ { "ts5600-dio-lcd", TS5600_LCD },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, ts5500_dio_ids);
+
+static struct platform_driver ts5500_dio_driver = {
+ .driver = {
+ .name = "ts5500-dio",
+ .owner = THIS_MODULE,
+ },
+ .probe = ts5500_dio_probe,
+ .remove = ts5500_dio_remove,
+ .id_table = ts5500_dio_ids,
+};
+
+module_platform_driver(ts5500_dio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Technologic Systems TS-5500 Digital I/O driver");
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c
index c5f8ca233e1..3ebb1a5ff22 100644
--- a/drivers/gpio/gpio-twl4030.c
+++ b/drivers/gpio/gpio-twl4030.c
@@ -37,7 +37,6 @@
#include <linux/i2c/twl.h>
-
/*
* The GPIO "subchip" supports 18 GPIOs which can be configured as
* inputs or outputs, with pullups or pulldowns on each pin. Each
@@ -49,11 +48,6 @@
* There are also two LED pins used sometimes as output-only GPIOs.
*/
-
-static struct gpio_chip twl_gpiochip;
-static int twl4030_gpio_base;
-static int twl4030_gpio_irq_base;
-
/* genirq interfaces are not available to modules */
#ifdef MODULE
#define is_module() true
@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base;
/* Mask for GPIO registers when aggregated into a 32-bit integer */
#define GPIO_32_MASK 0x0003ffff
-/* Data structures */
-static DEFINE_MUTEX(gpio_lock);
+struct gpio_twl4030_priv {
+ struct gpio_chip gpio_chip;
+ struct mutex mutex;
+ int irq_base;
-/* store usage of each GPIO. - each bit represents one GPIO */
-static unsigned int gpio_usage_count;
+ /* Bitfields for state caching */
+ unsigned int usage_count;
+ unsigned int direction;
+ unsigned int out_state;
+};
/*----------------------------------------------------------------------*/
+static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip)
+{
+ return container_of(chip, struct gpio_twl4030_priv, gpio_chip);
+}
+
/*
* To configure TWL4030 GPIO module registers
*/
@@ -88,11 +92,15 @@ static inline int gpio_twl4030_write(u8 address, u8 data)
/*----------------------------------------------------------------------*/
/*
- * LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB}))
+ * LED register offsets from TWL_MODULE_LED base
* PWMs A and B are dedicated to LEDs A and B, respectively.
*/
-#define TWL4030_LED_LEDEN 0x0
+#define TWL4030_LED_LEDEN_REG 0x00
+#define TWL4030_PWMAON_REG 0x01
+#define TWL4030_PWMAOFF_REG 0x02
+#define TWL4030_PWMBON_REG 0x03
+#define TWL4030_PWMBOFF_REG 0x04
/* LEDEN bits */
#define LEDEN_LEDAON BIT(0)
@@ -104,9 +112,6 @@ static inline int gpio_twl4030_write(u8 address, u8 data)
#define LEDEN_PWM_LENGTHA BIT(6)
#define LEDEN_PWM_LENGTHB BIT(7)
-#define TWL4030_PWMx_PWMxON 0x0
-#define TWL4030_PWMx_PWMxOFF 0x1
-
#define PWMxON_LENGTH BIT(7)
/*----------------------------------------------------------------------*/
@@ -125,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address)
/*----------------------------------------------------------------------*/
-static u8 cached_leden; /* protected by gpio_lock */
+static u8 cached_leden;
/* The LED lines are open drain outputs ... a FET pulls to GND, so an
* external pullup is needed. We could also expose the integrated PWM
@@ -134,19 +139,17 @@ static u8 cached_leden; /* protected by gpio_lock */
static void twl4030_led_set_value(int led, int value)
{
u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
- int status;
if (led)
mask <<= 1;
- mutex_lock(&gpio_lock);
if (value)
cached_leden &= ~mask;
else
cached_leden |= mask;
- status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
- TWL4030_LED_LEDEN);
- mutex_unlock(&gpio_lock);
+
+ WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
+ TWL4030_LED_LEDEN_REG));
}
static int twl4030_set_gpio_direction(int gpio, int is_input)
@@ -157,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0;
- mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base);
if (ret >= 0) {
if (is_input)
@@ -167,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
ret = gpio_twl4030_write(base, reg);
}
- mutex_unlock(&gpio_lock);
return ret;
}
@@ -192,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio)
u8 base = 0;
int ret = 0;
- if (unlikely((gpio >= TWL4030_GPIO_MAX)
- || !(gpio_usage_count & BIT(gpio))))
- return -EPERM;
-
base = REG_GPIODATAIN1 + d_bnk;
ret = gpio_twl4030_read(base);
if (ret > 0)
@@ -208,41 +205,42 @@ static int twl4030_get_gpio_datain(int gpio)
static int twl_request(struct gpio_chip *chip, unsigned offset)
{
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
int status = 0;
- mutex_lock(&gpio_lock);
+ mutex_lock(&priv->mutex);
/* Support the two LED outputs as output-only GPIOs. */
if (offset >= TWL4030_GPIO_MAX) {
u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT
| LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA;
- u8 module = TWL4030_MODULE_PWMA;
+ u8 reg = TWL4030_PWMAON_REG;
offset -= TWL4030_GPIO_MAX;
if (offset) {
ledclr_mask <<= 1;
- module = TWL4030_MODULE_PWMB;
+ reg = TWL4030_PWMBON_REG;
}
/* initialize PWM to always-drive */
- status = twl_i2c_write_u8(module, 0x7f,
- TWL4030_PWMx_PWMxOFF);
+ /* Configure PWM OFF register first */
+ status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1);
if (status < 0)
goto done;
- status = twl_i2c_write_u8(module, 0x7f,
- TWL4030_PWMx_PWMxON);
+
+ /* Followed by PWM ON register */
+ status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg);
if (status < 0)
goto done;
/* init LED to not-driven (high) */
- module = TWL4030_MODULE_LED;
- status = twl_i2c_read_u8(module, &cached_leden,
- TWL4030_LED_LEDEN);
+ status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden,
+ TWL4030_LED_LEDEN_REG);
if (status < 0)
goto done;
cached_leden &= ~ledclr_mask;
- status = twl_i2c_write_u8(module, cached_leden,
- TWL4030_LED_LEDEN);
+ status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
+ TWL4030_LED_LEDEN_REG);
if (status < 0)
goto done;
@@ -251,93 +249,144 @@ static int twl_request(struct gpio_chip *chip, unsigned offset)
}
/* on first use, turn GPIO module "on" */
- if (!gpio_usage_count) {
+ if (!priv->usage_count) {
struct twl4030_gpio_platform_data *pdata;
u8 value = MASK_GPIO_CTRL_GPIO_ON;
/* optionally have the first two GPIOs switch vMMC1
* and vMMC2 power supplies based on card presence.
*/
- pdata = chip->dev->platform_data;
+ pdata = dev_get_platdata(chip->dev);
if (pdata)
value |= pdata->mmc_cd & 0x03;
status = gpio_twl4030_write(REG_GPIO_CTRL, value);
}
+done:
if (!status)
- gpio_usage_count |= (0x1 << offset);
+ priv->usage_count |= BIT(offset);
-done:
- mutex_unlock(&gpio_lock);
+ mutex_unlock(&priv->mutex);
return status;
}
static void twl_free(struct gpio_chip *chip, unsigned offset)
{
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+ mutex_lock(&priv->mutex);
if (offset >= TWL4030_GPIO_MAX) {
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1);
- return;
+ goto out;
}
- mutex_lock(&gpio_lock);
-
- gpio_usage_count &= ~BIT(offset);
+ priv->usage_count &= ~BIT(offset);
/* on last use, switch off GPIO module */
- if (!gpio_usage_count)
+ if (!priv->usage_count)
gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
- mutex_unlock(&gpio_lock);
+out:
+ mutex_unlock(&priv->mutex);
}
static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
{
- return (offset < TWL4030_GPIO_MAX)
- ? twl4030_set_gpio_direction(offset, 1)
- : -EINVAL;
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ int ret;
+
+ mutex_lock(&priv->mutex);
+ if (offset < TWL4030_GPIO_MAX)
+ ret = twl4030_set_gpio_direction(offset, 1);
+ else
+ ret = -EINVAL; /* LED outputs can't be set as input */
+
+ if (!ret)
+ priv->direction &= ~BIT(offset);
+
+ mutex_unlock(&priv->mutex);
+
+ return ret;
}
static int twl_get(struct gpio_chip *chip, unsigned offset)
{
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ int ret;
int status = 0;
- if (offset < TWL4030_GPIO_MAX)
- status = twl4030_get_gpio_datain(offset);
- else if (offset == TWL4030_GPIO_MAX)
- status = cached_leden & LEDEN_LEDAON;
+ mutex_lock(&priv->mutex);
+ if (!(priv->usage_count & BIT(offset))) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (priv->direction & BIT(offset))
+ status = priv->out_state & BIT(offset);
else
- status = cached_leden & LEDEN_LEDBON;
- return (status < 0) ? 0 : status;
-}
+ status = twl4030_get_gpio_datain(offset);
-static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
-{
- if (offset < TWL4030_GPIO_MAX) {
- twl4030_set_gpio_dataout(offset, value);
- return twl4030_set_gpio_direction(offset, 0);
- } else {
- twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
- return 0;
- }
+ ret = (status <= 0) ? 0 : 1;
+out:
+ mutex_unlock(&priv->mutex);
+ return ret;
}
static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
{
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+ mutex_lock(&priv->mutex);
if (offset < TWL4030_GPIO_MAX)
twl4030_set_gpio_dataout(offset, value);
else
twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value);
+
+ if (value)
+ priv->out_state |= BIT(offset);
+ else
+ priv->out_state &= ~BIT(offset);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+ int ret = 0;
+
+ mutex_lock(&priv->mutex);
+ if (offset < TWL4030_GPIO_MAX) {
+ ret = twl4030_set_gpio_direction(offset, 0);
+ if (ret) {
+ mutex_unlock(&priv->mutex);
+ return ret;
+ }
+ }
+
+ /*
+ * LED gpios i.e. offset >= TWL4030_GPIO_MAX are always output
+ */
+
+ priv->direction |= BIT(offset);
+ mutex_unlock(&priv->mutex);
+
+ twl_set(chip, offset, value);
+
+ return ret;
}
static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX))
- ? (twl4030_gpio_irq_base + offset)
+ struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip);
+
+ return (priv->irq_base && (offset < TWL4030_GPIO_MAX))
+ ? (priv->irq_base + offset)
: -EINVAL;
}
-static struct gpio_chip twl_gpiochip = {
+static struct gpio_chip template_chip = {
.label = "twl4030",
.owner = THIS_MODULE,
.request = twl_request,
@@ -347,20 +396,20 @@ static struct gpio_chip twl_gpiochip = {
.direction_output = twl_direction_out,
.set = twl_set,
.to_irq = twl_to_irq,
- .can_sleep = 1,
+ .can_sleep = true,
};
/*----------------------------------------------------------------------*/
-static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
+static int gpio_twl4030_pulls(u32 ups, u32 downs)
{
- u8 message[6];
+ u8 message[5];
unsigned i, gpio_bit;
/* For most pins, a pulldown was enabled by default.
* We should have data that's specific to this board.
*/
- for (gpio_bit = 1, i = 1; i < 6; i++) {
+ for (gpio_bit = 1, i = 0; i < 5; i++) {
u8 bit_mask;
unsigned j;
@@ -377,18 +426,18 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs)
REG_GPIOPUPDCTR1, 5);
}
-static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
+static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
{
- u8 message[4];
+ u8 message[3];
/* 30 msec of debouncing is always used for MMC card detect,
* and is optional for everything else.
*/
- message[1] = (debounce & 0xff) | (mmc_cd & 0x03);
+ message[0] = (debounce & 0xff) | (mmc_cd & 0x03);
debounce >>= 8;
- message[2] = (debounce & 0xff);
+ message[1] = (debounce & 0xff);
debounce >>= 8;
- message[3] = (debounce & 0x03);
+ message[2] = (debounce & 0x03);
return twl_i2c_write(TWL4030_MODULE_GPIO, message,
REG_GPIO_DEBEN1, 3);
@@ -396,7 +445,8 @@ static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd)
static int gpio_twl4030_remove(struct platform_device *pdev);
-static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
+static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev,
+ struct twl4030_gpio_platform_data *pdata)
{
struct twl4030_gpio_platform_data *omap_twl_info;
@@ -404,6 +454,9 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
if (!omap_twl_info)
return NULL;
+ if (pdata)
+ *omap_twl_info = *pdata;
+
omap_twl_info->use_leds = of_property_read_bool(dev->of_node,
"ti,use-leds");
@@ -419,12 +472,18 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev)
return omap_twl_info;
}
-static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
+static int gpio_twl4030_probe(struct platform_device *pdev)
{
- struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *node = pdev->dev.of_node;
+ struct gpio_twl4030_priv *priv;
int ret, irq_base;
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
/* maybe setup IRQs */
if (is_module()) {
dev_err(&pdev->dev, "can't dispatch IRQs from modules\n");
@@ -444,15 +503,18 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- twl4030_gpio_irq_base = irq_base;
+ priv->irq_base = irq_base;
no_irqs:
- twl_gpiochip.base = -1;
- twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
- twl_gpiochip.dev = &pdev->dev;
+ priv->gpio_chip = template_chip;
+ priv->gpio_chip.base = -1;
+ priv->gpio_chip.ngpio = TWL4030_GPIO_MAX;
+ priv->gpio_chip.dev = &pdev->dev;
+
+ mutex_init(&priv->mutex);
if (node)
- pdata = of_gpio_twl4030(&pdev->dev);
+ pdata = of_gpio_twl4030(&pdev->dev, pdata);
if (pdata == NULL) {
dev_err(&pdev->dev, "Platform data is missing\n");
@@ -480,23 +542,23 @@ no_irqs:
* is (still) clear if use_leds is set.
*/
if (pdata->use_leds)
- twl_gpiochip.ngpio += 2;
+ priv->gpio_chip.ngpio += 2;
- ret = gpiochip_add(&twl_gpiochip);
+ ret = gpiochip_add(&priv->gpio_chip);
if (ret < 0) {
dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret);
- twl_gpiochip.ngpio = 0;
+ priv->gpio_chip.ngpio = 0;
gpio_twl4030_remove(pdev);
goto out;
}
- twl4030_gpio_base = twl_gpiochip.base;
+ platform_set_drvdata(pdev, priv);
if (pdata && pdata->setup) {
int status;
- status = pdata->setup(&pdev->dev,
- twl4030_gpio_base, TWL4030_GPIO_MAX);
+ status = pdata->setup(&pdev->dev, priv->gpio_chip.base,
+ TWL4030_GPIO_MAX);
if (status)
dev_dbg(&pdev->dev, "setup --> %d\n", status);
}
@@ -505,22 +567,23 @@ out:
return ret;
}
-/* Cannot use __devexit as gpio_twl4030_probe() calls us */
+/* Cannot use as gpio_twl4030_probe() calls us */
static int gpio_twl4030_remove(struct platform_device *pdev)
{
- struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+ struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev);
int status;
if (pdata && pdata->teardown) {
- status = pdata->teardown(&pdev->dev,
- twl4030_gpio_base, TWL4030_GPIO_MAX);
+ status = pdata->teardown(&pdev->dev, priv->gpio_chip.base,
+ TWL4030_GPIO_MAX);
if (status) {
dev_dbg(&pdev->dev, "teardown --> %d\n", status);
return status;
}
}
- status = gpiochip_remove(&twl_gpiochip);
+ status = gpiochip_remove(&priv->gpio_chip);
if (status < 0)
return status;
@@ -545,7 +608,7 @@ static struct platform_driver gpio_twl4030_driver = {
.driver = {
.name = "twl4030_gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(twl_gpio_match),
+ .of_match_table = twl_gpio_match,
},
.probe = gpio_twl4030_probe,
.remove = gpio_twl4030_remove,
diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c
index dd58e8b2504..0caf5cd1b47 100644
--- a/drivers/gpio/gpio-twl6040.c
+++ b/drivers/gpio/gpio-twl6040.c
@@ -77,22 +77,18 @@ static struct gpio_chip twl6040gpo_chip = {
.get = twl6040gpo_get,
.direction_output = twl6040gpo_direction_out,
.set = twl6040gpo_set,
- .can_sleep = 1,
+ .can_sleep = true,
};
/*----------------------------------------------------------------------*/
-static int __devinit gpo_twl6040_probe(struct platform_device *pdev)
+static int gpo_twl6040_probe(struct platform_device *pdev)
{
- struct twl6040_gpo_data *pdata = pdev->dev.platform_data;
struct device *twl6040_core_dev = pdev->dev.parent;
struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev);
int ret;
- if (pdata)
- twl6040gpo_chip.base = pdata->gpio_base;
- else
- twl6040gpo_chip.base = -1;
+ twl6040gpo_chip.base = -1;
if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0)
twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */
@@ -113,7 +109,7 @@ static int __devinit gpo_twl6040_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit gpo_twl6040_remove(struct platform_device *pdev)
+static int gpo_twl6040_remove(struct platform_device *pdev)
{
return gpiochip_remove(&twl6040gpo_chip);
}
diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
new file mode 100644
index 00000000000..f512da299b3
--- /dev/null
+++ b/drivers/gpio/gpio-tz1090-pdc.c
@@ -0,0 +1,243 @@
+/*
+ * Toumaz Xenif TZ1090 PDC GPIO handling.
+ *
+ * Copyright (C) 2012-2013 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+#include <asm/global_lock.h>
+
+/* Register offsets from SOC_GPIO_CONTROL0 */
+#define REG_SOC_GPIO_CONTROL0 0x00
+#define REG_SOC_GPIO_CONTROL1 0x04
+#define REG_SOC_GPIO_CONTROL2 0x08
+#define REG_SOC_GPIO_CONTROL3 0x0c
+#define REG_SOC_GPIO_STATUS 0x80
+
+/* PDC GPIOs go after normal GPIOs */
+#define GPIO_PDC_BASE 90
+#define GPIO_PDC_NGPIO 7
+
+/* Out of PDC gpios, only syswakes have irqs */
+#define GPIO_PDC_IRQ_FIRST 2
+#define GPIO_PDC_NIRQ 3
+
+/**
+ * struct tz1090_pdc_gpio - GPIO bank private data
+ * @chip: Generic GPIO chip for GPIO bank
+ * @reg: Base of registers, offset for this GPIO bank
+ * @irq: IRQ numbers for Syswake GPIOs
+ *
+ * This is the main private data for the PDC GPIO driver. It encapsulates a
+ * gpio_chip, and the callbacks for the gpio_chip can access the private data
+ * with the to_pdc() macro below.
+ */
+struct tz1090_pdc_gpio {
+ struct gpio_chip chip;
+ void __iomem *reg;
+ int irq[GPIO_PDC_NIRQ];
+};
+#define to_pdc(c) container_of(c, struct tz1090_pdc_gpio, chip)
+
+/* Register accesses into the PDC MMIO area */
+
+static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs,
+ unsigned int data)
+{
+ writel(data, priv->reg + reg_offs);
+}
+
+static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
+ unsigned int reg_offs)
+{
+ return readl(priv->reg + reg_offs);
+}
+
+/* Generic GPIO interface */
+
+static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ u32 value;
+ int lstat;
+
+ __global_lock2(lstat);
+ value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
+ value |= BIT(offset);
+ pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
+ __global_unlock2(lstat);
+
+ return 0;
+}
+
+static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset,
+ int output_value)
+{
+ struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ u32 value;
+ int lstat;
+
+ __global_lock2(lstat);
+ /* EXT_POWER doesn't seem to have an output value bit */
+ if (offset < 6) {
+ value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
+ if (output_value)
+ value |= BIT(offset);
+ else
+ value &= ~BIT(offset);
+ pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
+ }
+
+ value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
+ value &= ~BIT(offset);
+ pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
+ __global_unlock2(lstat);
+
+ return 0;
+}
+
+static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ return pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset);
+}
+
+static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int output_value)
+{
+ struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ u32 value;
+ int lstat;
+
+ /* EXT_POWER doesn't seem to have an output value bit */
+ if (offset >= 6)
+ return;
+
+ __global_lock2(lstat);
+ value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
+ if (output_value)
+ value |= BIT(offset);
+ else
+ value &= ~BIT(offset);
+ pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
+ __global_unlock2(lstat);
+}
+
+static int tz1090_pdc_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void tz1090_pdc_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_pdc_gpio *priv = to_pdc(chip);
+ unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
+ int irq;
+
+ /* only syswakes have irqs */
+ if (syswake >= GPIO_PDC_NIRQ)
+ return -EINVAL;
+
+ irq = priv->irq[syswake];
+ if (!irq)
+ return -EINVAL;
+
+ return irq;
+}
+
+static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res_regs;
+ struct tz1090_pdc_gpio *priv;
+ unsigned int i;
+
+ if (!np) {
+ dev_err(&pdev->dev, "must be instantiated via devicetree\n");
+ return -ENOENT;
+ }
+
+ res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_regs) {
+ dev_err(&pdev->dev, "cannot find registers resource\n");
+ return -ENOENT;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "unable to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ /* Ioremap the registers */
+ priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
+ res_regs->end - res_regs->start);
+ if (!priv->reg) {
+ dev_err(&pdev->dev, "unable to ioremap registers\n");
+ return -ENOMEM;
+ }
+
+ /* Set up GPIO chip */
+ priv->chip.label = "tz1090-pdc-gpio";
+ priv->chip.dev = &pdev->dev;
+ priv->chip.direction_input = tz1090_pdc_gpio_direction_input;
+ priv->chip.direction_output = tz1090_pdc_gpio_direction_output;
+ priv->chip.get = tz1090_pdc_gpio_get;
+ priv->chip.set = tz1090_pdc_gpio_set;
+ priv->chip.free = tz1090_pdc_gpio_free;
+ priv->chip.request = tz1090_pdc_gpio_request;
+ priv->chip.to_irq = tz1090_pdc_gpio_to_irq;
+ priv->chip.of_node = np;
+
+ /* GPIO numbering */
+ priv->chip.base = GPIO_PDC_BASE;
+ priv->chip.ngpio = GPIO_PDC_NGPIO;
+
+ /* Map the syswake irqs */
+ for (i = 0; i < GPIO_PDC_NIRQ; ++i)
+ priv->irq[i] = irq_of_parse_and_map(np, i);
+
+ /* Add the GPIO bank */
+ gpiochip_add(&priv->chip);
+
+ return 0;
+}
+
+static struct of_device_id tz1090_pdc_gpio_of_match[] = {
+ { .compatible = "img,tz1090-pdc-gpio" },
+ { },
+};
+
+static struct platform_driver tz1090_pdc_gpio_driver = {
+ .driver = {
+ .name = "tz1090-pdc-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = tz1090_pdc_gpio_of_match,
+ },
+ .probe = tz1090_pdc_gpio_probe,
+};
+
+static int __init tz1090_pdc_gpio_init(void)
+{
+ return platform_driver_register(&tz1090_pdc_gpio_driver);
+}
+subsys_initcall(tz1090_pdc_gpio_init);
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
new file mode 100644
index 00000000000..5246a60eff6
--- /dev/null
+++ b/drivers/gpio/gpio-tz1090.c
@@ -0,0 +1,606 @@
+/*
+ * Toumaz Xenif TZ1090 GPIO handling.
+ *
+ * Copyright (C) 2008-2013 Imagination Technologies Ltd.
+ *
+ * Based on ARM PXA code and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/syscore_ops.h>
+#include <asm/global_lock.h>
+
+/* Register offsets from bank base address */
+#define REG_GPIO_DIR 0x00
+#define REG_GPIO_IRQ_PLRT 0x20
+#define REG_GPIO_IRQ_TYPE 0x30
+#define REG_GPIO_IRQ_EN 0x40
+#define REG_GPIO_IRQ_STS 0x50
+#define REG_GPIO_BIT_EN 0x60
+#define REG_GPIO_DIN 0x70
+#define REG_GPIO_DOUT 0x80
+
+/* REG_GPIO_IRQ_PLRT */
+#define REG_GPIO_IRQ_PLRT_LOW 0
+#define REG_GPIO_IRQ_PLRT_HIGH 1
+
+/* REG_GPIO_IRQ_TYPE */
+#define REG_GPIO_IRQ_TYPE_LEVEL 0
+#define REG_GPIO_IRQ_TYPE_EDGE 1
+
+/**
+ * struct tz1090_gpio_bank - GPIO bank private data
+ * @chip: Generic GPIO chip for GPIO bank
+ * @domain: IRQ domain for GPIO bank (may be NULL)
+ * @reg: Base of registers, offset for this GPIO bank
+ * @irq: IRQ number for GPIO bank
+ * @label: Debug GPIO bank label, used for storage of chip->label
+ *
+ * This is the main private data for a GPIO bank. It encapsulates a gpio_chip,
+ * and the callbacks for the gpio_chip can access the private data with the
+ * to_bank() macro below.
+ */
+struct tz1090_gpio_bank {
+ struct gpio_chip chip;
+ struct irq_domain *domain;
+ void __iomem *reg;
+ int irq;
+ char label[16];
+};
+#define to_bank(c) container_of(c, struct tz1090_gpio_bank, chip)
+
+/**
+ * struct tz1090_gpio - Overall GPIO device private data
+ * @dev: Device (from platform device)
+ * @reg: Base of GPIO registers
+ *
+ * Represents the overall GPIO device. This structure is actually only
+ * temporary, and used during init.
+ */
+struct tz1090_gpio {
+ struct device *dev;
+ void __iomem *reg;
+};
+
+/**
+ * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank
+ * @priv: Overall GPIO device private data
+ * @node: Device tree node specific to this GPIO bank
+ * @index: Index of bank in range 0-2
+ */
+struct tz1090_gpio_bank_info {
+ struct tz1090_gpio *priv;
+ struct device_node *node;
+ unsigned int index;
+};
+
+/* Convenience register accessors */
+static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs, u32 data)
+{
+ iowrite32(data, bank->reg + reg_offs);
+}
+
+static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs)
+{
+ return ioread32(bank->reg + reg_offs);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ u32 value;
+
+ value = tz1090_gpio_read(bank, reg_offs);
+ value &= ~BIT(offset);
+ tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ int lstat;
+
+ __global_lock2(lstat);
+ _tz1090_gpio_clear_bit(bank, reg_offs, offset);
+ __global_unlock2(lstat);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ u32 value;
+
+ value = tz1090_gpio_read(bank, reg_offs);
+ value |= BIT(offset);
+ tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ int lstat;
+
+ __global_lock2(lstat);
+ _tz1090_gpio_set_bit(bank, reg_offs, offset);
+ __global_unlock2(lstat);
+}
+
+/* caller must hold LOCK2 */
+static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset,
+ bool val)
+{
+ u32 value;
+
+ value = tz1090_gpio_read(bank, reg_offs);
+ value &= ~BIT(offset);
+ if (val)
+ value |= BIT(offset);
+ tz1090_gpio_write(bank, reg_offs, value);
+}
+
+static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset,
+ bool val)
+{
+ int lstat;
+
+ __global_lock2(lstat);
+ _tz1090_gpio_mod_bit(bank, reg_offs, offset, val);
+ __global_unlock2(lstat);
+}
+
+static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank,
+ unsigned int reg_offs,
+ unsigned int offset)
+{
+ return tz1090_gpio_read(bank, reg_offs) & BIT(offset);
+}
+
+/* GPIO chip callbacks */
+
+static int tz1090_gpio_direction_input(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+ tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
+
+ return 0;
+}
+
+static int tz1090_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int output_value)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+ int lstat;
+
+ __global_lock2(lstat);
+ _tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
+ _tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset);
+ __global_unlock2(lstat);
+
+ return 0;
+}
+
+/*
+ * Return GPIO level
+ */
+static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+
+ return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
+}
+
+/*
+ * Set output GPIO level
+ */
+static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int output_value)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+
+ tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
+}
+
+static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+ int ret;
+
+ ret = pinctrl_request_gpio(chip->base + offset);
+ if (ret)
+ return ret;
+
+ tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
+ tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset);
+
+ return 0;
+}
+
+static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+
+ pinctrl_free_gpio(chip->base + offset);
+
+ tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset);
+}
+
+static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ struct tz1090_gpio_bank *bank = to_bank(chip);
+
+ if (!bank->domain)
+ return -EINVAL;
+
+ return irq_create_mapping(bank->domain, offset);
+}
+
+/* IRQ chip handlers */
+
+/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */
+static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data)
+{
+ return (struct tz1090_gpio_bank *)data->domain->host_data;
+}
+
+static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank,
+ unsigned int offset, unsigned int polarity)
+{
+ tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity);
+}
+
+static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank,
+ unsigned int offset, unsigned int type)
+{
+ tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type);
+}
+
+/* set polarity to trigger on next edge, whether rising or falling */
+static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank,
+ unsigned int offset)
+{
+ unsigned int value_p, value_i;
+ int lstat;
+
+ /*
+ * Set the GPIO's interrupt polarity to the opposite of the current
+ * input value so that the next edge triggers an interrupt.
+ */
+ __global_lock2(lstat);
+ value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN);
+ value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT);
+ value_p &= ~BIT(offset);
+ value_p |= value_i & BIT(offset);
+ tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p);
+ __global_unlock2(lstat);
+}
+
+static unsigned int gpio_startup_irq(struct irq_data *data)
+{
+ /*
+ * This warning indicates that the type of the irq hasn't been set
+ * before enabling the irq. This would normally be done by passing some
+ * trigger flags to request_irq().
+ */
+ WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE,
+ "irq type not set before enabling gpio irq %d", data->irq);
+
+ irq_gc_ack_clr_bit(data);
+ irq_gc_mask_set_bit(data);
+ return 0;
+}
+
+static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type)
+{
+ struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
+ unsigned int type;
+ unsigned int polarity;
+
+ switch (flow_type) {
+ case IRQ_TYPE_EDGE_BOTH:
+ type = REG_GPIO_IRQ_TYPE_EDGE;
+ polarity = REG_GPIO_IRQ_PLRT_LOW;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ type = REG_GPIO_IRQ_TYPE_EDGE;
+ polarity = REG_GPIO_IRQ_PLRT_HIGH;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ type = REG_GPIO_IRQ_TYPE_EDGE;
+ polarity = REG_GPIO_IRQ_PLRT_LOW;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ type = REG_GPIO_IRQ_TYPE_LEVEL;
+ polarity = REG_GPIO_IRQ_PLRT_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ type = REG_GPIO_IRQ_TYPE_LEVEL;
+ polarity = REG_GPIO_IRQ_PLRT_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tz1090_gpio_irq_type(bank, data->hwirq, type);
+ irq_setup_alt_chip(data, flow_type);
+
+ if (flow_type == IRQ_TYPE_EDGE_BOTH)
+ tz1090_gpio_irq_next_edge(bank, data->hwirq);
+ else
+ tz1090_gpio_irq_polarity(bank, data->hwirq, polarity);
+
+ return 0;
+}
+
+#ifdef CONFIG_SUSPEND
+static int gpio_set_irq_wake(struct irq_data *data, unsigned int on)
+{
+ struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
+
+#ifdef CONFIG_PM_DEBUG
+ pr_info("irq_wake irq%d state:%d\n", data->irq, on);
+#endif
+
+ /* wake on gpio block interrupt */
+ return irq_set_irq_wake(bank->irq, on);
+}
+#else
+#define gpio_set_irq_wake NULL
+#endif
+
+static void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ irq_hw_number_t hw;
+ unsigned int irq_stat, irq_no;
+ struct tz1090_gpio_bank *bank;
+ struct irq_desc *child_desc;
+
+ bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc);
+ irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) &
+ tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) &
+ tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) &
+ 0x3FFFFFFF; /* 30 bits only */
+
+ for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) {
+ if (!(irq_stat & 1))
+ continue;
+
+ irq_no = irq_linear_revmap(bank->domain, hw);
+ child_desc = irq_to_desc(irq_no);
+
+ /* Toggle edge for pin with both edges triggering enabled */
+ if (irqd_get_trigger_type(&child_desc->irq_data)
+ == IRQ_TYPE_EDGE_BOTH)
+ tz1090_gpio_irq_next_edge(bank, hw);
+
+ generic_handle_irq_desc(irq_no, child_desc);
+ }
+}
+
+static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
+{
+ struct device_node *np = info->node;
+ struct device *dev = info->priv->dev;
+ struct tz1090_gpio_bank *bank;
+ struct irq_chip_generic *gc;
+ int err;
+
+ bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
+ if (!bank) {
+ dev_err(dev, "unable to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ /* Offset the main registers to the first register in this bank */
+ bank->reg = info->priv->reg + info->index * 4;
+
+ /* Set up GPIO chip */
+ snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
+ info->index);
+ bank->chip.label = bank->label;
+ bank->chip.dev = dev;
+ bank->chip.direction_input = tz1090_gpio_direction_input;
+ bank->chip.direction_output = tz1090_gpio_direction_output;
+ bank->chip.get = tz1090_gpio_get;
+ bank->chip.set = tz1090_gpio_set;
+ bank->chip.free = tz1090_gpio_free;
+ bank->chip.request = tz1090_gpio_request;
+ bank->chip.to_irq = tz1090_gpio_to_irq;
+ bank->chip.of_node = np;
+
+ /* GPIO numbering from 0 */
+ bank->chip.base = info->index * 30;
+ bank->chip.ngpio = 30;
+
+ /* Add the GPIO bank */
+ gpiochip_add(&bank->chip);
+
+ /* Get the GPIO bank IRQ if provided */
+ bank->irq = irq_of_parse_and_map(np, 0);
+
+ /* The interrupt is optional (it may be used by another core on chip) */
+ if (bank->irq < 0) {
+ dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n",
+ info->index);
+ return 0;
+ }
+
+ dev_info(dev, "Setting up IRQs for GPIO bank %u\n",
+ info->index);
+
+ /*
+ * Initialise all interrupts to disabled so we don't get
+ * spurious ones on a dirty boot and hit the BUG_ON in the
+ * handler.
+ */
+ tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0);
+
+ /* Add a virtual IRQ for each GPIO */
+ bank->domain = irq_domain_add_linear(np,
+ bank->chip.ngpio,
+ &irq_generic_chip_ops,
+ bank);
+
+ /* Set up a generic irq chip with 2 chip types (level and edge) */
+ err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2,
+ bank->label, handle_bad_irq, 0, 0,
+ IRQ_GC_INIT_NESTED_LOCK);
+ if (err) {
+ dev_info(dev,
+ "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n",
+ info->index);
+ irq_domain_remove(bank->domain);
+ return 0;
+ }
+
+ gc = irq_get_domain_generic_chip(bank->domain, 0);
+ gc->reg_base = bank->reg;
+
+ /* level chip type */
+ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
+ gc->chip_types[0].handler = handle_level_irq;
+ gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS;
+ gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN;
+ gc->chip_types[0].chip.irq_startup = gpio_startup_irq;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type;
+ gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake;
+ gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+ /* edge chip type */
+ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
+ gc->chip_types[1].handler = handle_edge_irq;
+ gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS;
+ gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN;
+ gc->chip_types[1].chip.irq_startup = gpio_startup_irq;
+ gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit;
+ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
+ gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type;
+ gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake;
+ gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+ /* Setup chained handler for this GPIO bank */
+ irq_set_handler_data(bank->irq, bank);
+ irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler);
+
+ return 0;
+}
+
+static void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
+{
+ struct device_node *np = priv->dev->of_node;
+ struct device_node *node;
+
+ for_each_available_child_of_node(np, node) {
+ struct tz1090_gpio_bank_info info;
+ u32 addr;
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", &addr);
+ if (ret) {
+ dev_err(priv->dev, "invalid reg on %s\n",
+ node->full_name);
+ continue;
+ }
+ if (addr >= 3) {
+ dev_err(priv->dev, "index %u in %s out of range\n",
+ addr, node->full_name);
+ continue;
+ }
+
+ info.index = addr;
+ info.node = of_node_get(node);
+ info.priv = priv;
+
+ ret = tz1090_gpio_bank_probe(&info);
+ if (ret) {
+ dev_err(priv->dev, "failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
+ continue;
+ }
+ }
+}
+
+static int tz1090_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res_regs;
+ struct tz1090_gpio priv;
+
+ if (!np) {
+ dev_err(&pdev->dev, "must be instantiated via devicetree\n");
+ return -ENOENT;
+ }
+
+ res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_regs) {
+ dev_err(&pdev->dev, "cannot find registers resource\n");
+ return -ENOENT;
+ }
+
+ priv.dev = &pdev->dev;
+
+ /* Ioremap the registers */
+ priv.reg = devm_ioremap(&pdev->dev, res_regs->start,
+ res_regs->end - res_regs->start);
+ if (!priv.reg) {
+ dev_err(&pdev->dev, "unable to ioremap registers\n");
+ return -ENOMEM;
+ }
+
+ /* Look for banks */
+ tz1090_gpio_register_banks(&priv);
+
+ return 0;
+}
+
+static struct of_device_id tz1090_gpio_of_match[] = {
+ { .compatible = "img,tz1090-gpio" },
+ { },
+};
+
+static struct platform_driver tz1090_gpio_driver = {
+ .driver = {
+ .name = "tz1090-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = tz1090_gpio_of_match,
+ },
+ .probe = tz1090_gpio_probe,
+};
+
+static int __init tz1090_gpio_init(void)
+{
+ return platform_driver_register(&tz1090_gpio_driver);
+}
+subsys_initcall(tz1090_gpio_init);
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c
index 26405efe0f9..2445fe77117 100644
--- a/drivers/gpio/gpio-ucb1400.c
+++ b/drivers/gpio/gpio-ucb1400.c
@@ -12,8 +12,6 @@
#include <linux/module.h>
#include <linux/ucb1400.h>
-struct ucb1400_gpio_data *ucbdata;
-
static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
{
struct ucb1400_gpio *gpio;
@@ -47,10 +45,10 @@ static void ucb1400_gpio_set(struct gpio_chip *gc, unsigned off, int val)
static int ucb1400_gpio_probe(struct platform_device *dev)
{
- struct ucb1400_gpio *ucb = dev->dev.platform_data;
+ struct ucb1400_gpio *ucb = dev_get_platdata(&dev->dev);
int err = 0;
- if (!(ucbdata && ucbdata->gpio_offset)) {
+ if (!(ucb && ucb->gpio_offset)) {
err = -EINVAL;
goto err;
}
@@ -58,7 +56,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, ucb);
ucb->gc.label = "ucb1400_gpio";
- ucb->gc.base = ucbdata->gpio_offset;
+ ucb->gc.base = ucb->gpio_offset;
ucb->gc.ngpio = 10;
ucb->gc.owner = THIS_MODULE;
@@ -66,14 +64,14 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
ucb->gc.direction_output = ucb1400_gpio_dir_out;
ucb->gc.get = ucb1400_gpio_get;
ucb->gc.set = ucb1400_gpio_set;
- ucb->gc.can_sleep = 1;
+ ucb->gc.can_sleep = true;
err = gpiochip_add(&ucb->gc);
if (err)
goto err;
- if (ucbdata && ucbdata->gpio_setup)
- err = ucbdata->gpio_setup(&dev->dev, ucb->gc.ngpio);
+ if (ucb && ucb->gpio_setup)
+ err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err:
return err;
@@ -85,8 +83,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev)
int err = 0;
struct ucb1400_gpio *ucb = platform_get_drvdata(dev);
- if (ucbdata && ucbdata->gpio_teardown) {
- err = ucbdata->gpio_teardown(&dev->dev, ucb->gc.ngpio);
+ if (ucb && ucb->gpio_teardown) {
+ err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio);
if (err)
return err;
}
@@ -103,12 +101,8 @@ static struct platform_driver ucb1400_gpio_driver = {
},
};
-void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data)
-{
- ucbdata = data;
-}
-
module_platform_driver(ucb1400_gpio_driver);
MODULE_DESCRIPTION("Philips UCB1400 GPIO driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ucb1400_gpio");
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
new file mode 100644
index 00000000000..79e3b583671
--- /dev/null
+++ b/drivers/gpio/gpio-viperboard.c
@@ -0,0 +1,514 @@
+/*
+ * Nano River Technologies viperboard GPIO lib driver
+ *
+ * (C) 2012 by Lemonage GmbH
+ * Author: Lars Poeschel <poeschel@lemonage.de>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/viperboard.h>
+
+#define VPRBRD_GPIOA_CLK_1MHZ 0
+#define VPRBRD_GPIOA_CLK_100KHZ 1
+#define VPRBRD_GPIOA_CLK_10KHZ 2
+#define VPRBRD_GPIOA_CLK_1KHZ 3
+#define VPRBRD_GPIOA_CLK_100HZ 4
+#define VPRBRD_GPIOA_CLK_10HZ 5
+
+#define VPRBRD_GPIOA_FREQ_DEFAULT 1000
+
+#define VPRBRD_GPIOA_CMD_CONT 0x00
+#define VPRBRD_GPIOA_CMD_PULSE 0x01
+#define VPRBRD_GPIOA_CMD_PWM 0x02
+#define VPRBRD_GPIOA_CMD_SETOUT 0x03
+#define VPRBRD_GPIOA_CMD_SETIN 0x04
+#define VPRBRD_GPIOA_CMD_SETINT 0x05
+#define VPRBRD_GPIOA_CMD_GETIN 0x06
+
+#define VPRBRD_GPIOB_CMD_SETDIR 0x00
+#define VPRBRD_GPIOB_CMD_SETVAL 0x01
+
+struct vprbrd_gpioa_msg {
+ u8 cmd;
+ u8 clk;
+ u8 offset;
+ u8 t1;
+ u8 t2;
+ u8 invert;
+ u8 pwmlevel;
+ u8 outval;
+ u8 risefall;
+ u8 answer;
+ u8 __fill;
+} __packed;
+
+struct vprbrd_gpiob_msg {
+ u8 cmd;
+ u16 val;
+ u16 mask;
+} __packed;
+
+struct vprbrd_gpio {
+ struct gpio_chip gpioa; /* gpio a related things */
+ u32 gpioa_out;
+ u32 gpioa_val;
+ struct gpio_chip gpiob; /* gpio b related things */
+ u32 gpiob_out;
+ u32 gpiob_val;
+ struct vprbrd *vb;
+};
+
+/* gpioa sampling clock module parameter */
+static unsigned char gpioa_clk;
+static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT;
+module_param(gpioa_freq, uint, 0);
+MODULE_PARM_DESC(gpioa_freq,
+ "gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000");
+
+/* ----- begin of gipo a chip -------------------------------------------- */
+
+static int vprbrd_gpioa_get(struct gpio_chip *chip,
+ unsigned offset)
+{
+ int ret, answer, error = 0;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
+
+ /* if io is set to output, just return the saved value */
+ if (gpio->gpioa_out & (1 << offset))
+ return gpio->gpioa_val & (1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN;
+ gamsg->clk = 0x00;
+ gamsg->offset = offset;
+ gamsg->t1 = 0x00;
+ gamsg->t2 = 0x00;
+ gamsg->invert = 0x00;
+ gamsg->pwmlevel = 0x00;
+ gamsg->outval = 0x00;
+ gamsg->risefall = 0x00;
+ gamsg->answer = 0x00;
+ gamsg->__fill = 0x00;
+
+ ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
+ 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+ if (ret != sizeof(struct vprbrd_gpioa_msg))
+ error = -EREMOTEIO;
+
+ ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000,
+ 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+ answer = gamsg->answer & 0x01;
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpioa_msg))
+ error = -EREMOTEIO;
+
+ if (error)
+ return error;
+
+ return answer;
+}
+
+static void vprbrd_gpioa_set(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
+
+ if (gpio->gpioa_out & (1 << offset)) {
+ if (value)
+ gpio->gpioa_val |= (1 << offset);
+ else
+ gpio->gpioa_val &= ~(1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;
+ gamsg->clk = 0x00;
+ gamsg->offset = offset;
+ gamsg->t1 = 0x00;
+ gamsg->t2 = 0x00;
+ gamsg->invert = 0x00;
+ gamsg->pwmlevel = 0x00;
+ gamsg->outval = value;
+ gamsg->risefall = 0x00;
+ gamsg->answer = 0x00;
+ gamsg->__fill = 0x00;
+
+ ret = usb_control_msg(vb->usb_dev,
+ usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT,
+ 0x0000, 0x0000, gamsg,
+ sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS);
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpioa_msg))
+ dev_err(chip->dev, "usb error setting pin value\n");
+ }
+}
+
+static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
+
+ gpio->gpioa_out &= ~(1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN;
+ gamsg->clk = gpioa_clk;
+ gamsg->offset = offset;
+ gamsg->t1 = 0x00;
+ gamsg->t2 = 0x00;
+ gamsg->invert = 0x00;
+ gamsg->pwmlevel = 0x00;
+ gamsg->outval = 0x00;
+ gamsg->risefall = 0x00;
+ gamsg->answer = 0x00;
+ gamsg->__fill = 0x00;
+
+ ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
+ 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpioa_msg))
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpioa);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
+
+ gpio->gpioa_out |= (1 << offset);
+ if (value)
+ gpio->gpioa_val |= (1 << offset);
+ else
+ gpio->gpioa_val &= ~(1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;
+ gamsg->clk = 0x00;
+ gamsg->offset = offset;
+ gamsg->t1 = 0x00;
+ gamsg->t2 = 0x00;
+ gamsg->invert = 0x00;
+ gamsg->pwmlevel = 0x00;
+ gamsg->outval = value;
+ gamsg->risefall = 0x00;
+ gamsg->answer = 0x00;
+ gamsg->__fill = 0x00;
+
+ ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
+ 0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpioa_msg))
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+/* ----- end of gpio a chip ---------------------------------------------- */
+
+/* ----- begin of gipo b chip -------------------------------------------- */
+
+static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
+ unsigned dir)
+{
+ struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
+ int ret;
+
+ gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR;
+ gbmsg->val = cpu_to_be16(dir << offset);
+ gbmsg->mask = cpu_to_be16(0x0001 << offset);
+
+ ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000,
+ 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+
+ if (ret != sizeof(struct vprbrd_gpiob_msg))
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int vprbrd_gpiob_get(struct gpio_chip *chip,
+ unsigned offset)
+{
+ int ret;
+ u16 val;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
+
+ /* if io is set to output, just return the saved value */
+ if (gpio->gpiob_out & (1 << offset))
+ return gpio->gpiob_val & (1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000,
+ 0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg),
+ VPRBRD_USB_TIMEOUT_MS);
+ val = gbmsg->val;
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpiob_msg))
+ return ret;
+
+ /* cache the read values */
+ gpio->gpiob_val = be16_to_cpu(val);
+
+ return (gpio->gpiob_val >> offset) & 0x1;
+}
+
+static void vprbrd_gpiob_set(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd *vb = gpio->vb;
+ struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
+
+ if (gpio->gpiob_out & (1 << offset)) {
+ if (value)
+ gpio->gpiob_val |= (1 << offset);
+ else
+ gpio->gpiob_val &= ~(1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL;
+ gbmsg->val = cpu_to_be16(value << offset);
+ gbmsg->mask = cpu_to_be16(0x0001 << offset);
+
+ ret = usb_control_msg(vb->usb_dev,
+ usb_sndctrlpipe(vb->usb_dev, 0),
+ VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT,
+ 0x0000, 0x0000, gbmsg,
+ sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS);
+
+ mutex_unlock(&vb->lock);
+
+ if (ret != sizeof(struct vprbrd_gpiob_msg))
+ dev_err(chip->dev, "usb error setting pin value\n");
+ }
+}
+
+static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd *vb = gpio->vb;
+
+ gpio->gpiob_out &= ~(1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ ret = vprbrd_gpiob_setdir(vb, offset, 0);
+
+ mutex_unlock(&vb->lock);
+
+ if (ret)
+ dev_err(chip->dev, "usb error setting pin to input\n");
+
+ return ret;
+}
+
+static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int ret;
+ struct vprbrd_gpio *gpio =
+ container_of(chip, struct vprbrd_gpio, gpiob);
+ struct vprbrd *vb = gpio->vb;
+
+ gpio->gpiob_out |= (1 << offset);
+
+ mutex_lock(&vb->lock);
+
+ ret = vprbrd_gpiob_setdir(vb, offset, 1);
+ if (ret)
+ dev_err(chip->dev, "usb error setting pin to output\n");
+
+ mutex_unlock(&vb->lock);
+
+ vprbrd_gpiob_set(chip, offset, value);
+
+ return ret;
+}
+
+/* ----- end of gpio b chip ---------------------------------------------- */
+
+static int vprbrd_gpio_probe(struct platform_device *pdev)
+{
+ struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
+ struct vprbrd_gpio *vb_gpio;
+ int ret;
+
+ vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL);
+ if (vb_gpio == NULL)
+ return -ENOMEM;
+
+ vb_gpio->vb = vb;
+ /* registering gpio a */
+ vb_gpio->gpioa.label = "viperboard gpio a";
+ vb_gpio->gpioa.dev = &pdev->dev;
+ vb_gpio->gpioa.owner = THIS_MODULE;
+ vb_gpio->gpioa.base = -1;
+ vb_gpio->gpioa.ngpio = 16;
+ vb_gpio->gpioa.can_sleep = true;
+ vb_gpio->gpioa.set = vprbrd_gpioa_set;
+ vb_gpio->gpioa.get = vprbrd_gpioa_get;
+ vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;
+ vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;
+ ret = gpiochip_add(&vb_gpio->gpioa);
+ if (ret < 0) {
+ dev_err(vb_gpio->gpioa.dev, "could not add gpio a");
+ goto err_gpioa;
+ }
+
+ /* registering gpio b */
+ vb_gpio->gpiob.label = "viperboard gpio b";
+ vb_gpio->gpiob.dev = &pdev->dev;
+ vb_gpio->gpiob.owner = THIS_MODULE;
+ vb_gpio->gpiob.base = -1;
+ vb_gpio->gpiob.ngpio = 16;
+ vb_gpio->gpiob.can_sleep = true;
+ vb_gpio->gpiob.set = vprbrd_gpiob_set;
+ vb_gpio->gpiob.get = vprbrd_gpiob_get;
+ vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;
+ vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;
+ ret = gpiochip_add(&vb_gpio->gpiob);
+ if (ret < 0) {
+ dev_err(vb_gpio->gpiob.dev, "could not add gpio b");
+ goto err_gpiob;
+ }
+
+ platform_set_drvdata(pdev, vb_gpio);
+
+ return ret;
+
+err_gpiob:
+ if (gpiochip_remove(&vb_gpio->gpioa))
+ dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
+
+err_gpioa:
+ return ret;
+}
+
+static int vprbrd_gpio_remove(struct platform_device *pdev)
+{
+ struct vprbrd_gpio *vb_gpio = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = gpiochip_remove(&vb_gpio->gpiob);
+ if (ret == 0)
+ ret = gpiochip_remove(&vb_gpio->gpioa);
+
+ return ret;
+}
+
+static struct platform_driver vprbrd_gpio_driver = {
+ .driver.name = "viperboard-gpio",
+ .driver.owner = THIS_MODULE,
+ .probe = vprbrd_gpio_probe,
+ .remove = vprbrd_gpio_remove,
+};
+
+static int __init vprbrd_gpio_init(void)
+{
+ switch (gpioa_freq) {
+ case 1000000:
+ gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ;
+ break;
+ case 100000:
+ gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ;
+ break;
+ case 10000:
+ gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ;
+ break;
+ case 1000:
+ gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;
+ break;
+ case 100:
+ gpioa_clk = VPRBRD_GPIOA_CLK_100HZ;
+ break;
+ case 10:
+ gpioa_clk = VPRBRD_GPIOA_CLK_10HZ;
+ break;
+ default:
+ pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq);
+ gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;
+ }
+
+ return platform_driver_register(&vprbrd_gpio_driver);
+}
+subsys_initcall(vprbrd_gpio_init);
+
+static void __exit vprbrd_gpio_exit(void)
+{
+ platform_driver_unregister(&vprbrd_gpio_driver);
+}
+module_exit(vprbrd_gpio_exit);
+
+MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
+MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:viperboard-gpio");
diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c
index 82d5c20ad3c..66cbcc108e6 100644
--- a/drivers/gpio/gpio-vr41xx.c
+++ b/drivers/gpio/gpio-vr41xx.c
@@ -81,6 +81,7 @@ static DEFINE_SPINLOCK(giu_lock);
static unsigned long giu_flags;
static void __iomem *giu_base;
+static struct gpio_chip vr41xx_gpio_chip;
#define giu_read(offset) readw(giu_base + (offset))
#define giu_write(offset, value) writew((value), giu_base + (offset))
@@ -135,12 +136,31 @@ static void unmask_giuint_low(struct irq_data *d)
giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq));
}
+static unsigned int startup_giuint(struct irq_data *data)
+{
+ if (gpio_lock_as_irq(&vr41xx_gpio_chip, data->hwirq))
+ dev_err(vr41xx_gpio_chip.dev,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ data->hwirq);
+ /* Satisfy the .enable semantics by unmasking the line */
+ unmask_giuint_low(data);
+ return 0;
+}
+
+static void shutdown_giuint(struct irq_data *data)
+{
+ mask_giuint_low(data);
+ gpio_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq);
+}
+
static struct irq_chip giuint_low_irq_chip = {
.name = "GIUINTL",
.irq_ack = ack_giuint_low,
.irq_mask = mask_giuint_low,
.irq_mask_ack = mask_ack_giuint_low,
.irq_unmask = unmask_giuint_low,
+ .irq_startup = startup_giuint,
+ .irq_shutdown = shutdown_giuint,
};
static void ack_giuint_high(struct irq_data *d)
@@ -490,7 +510,7 @@ static struct gpio_chip vr41xx_gpio_chip = {
.to_irq = vr41xx_gpio_to_irq,
};
-static int __devinit giu_probe(struct platform_device *pdev)
+static int giu_probe(struct platform_device *pdev)
{
struct resource *res;
unsigned int trigger, i, pin;
@@ -552,7 +572,7 @@ static int __devinit giu_probe(struct platform_device *pdev)
return cascade_irq(irq, giu_get_irq);
}
-static int __devexit giu_remove(struct platform_device *pdev)
+static int giu_remove(struct platform_device *pdev)
{
if (giu_base) {
iounmap(giu_base);
@@ -564,7 +584,7 @@ static int __devexit giu_remove(struct platform_device *pdev)
static struct platform_driver giu_device_driver = {
.probe = giu_probe,
- .remove = __devexit_p(giu_remove),
+ .remove = giu_remove,
.driver = {
.name = "GIU",
.owner = THIS_MODULE,
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
deleted file mode 100644
index bcd8e4aa7c7..00000000000
--- a/drivers/gpio/gpio-vt8500.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* drivers/gpio/gpio-vt8500.c
- *
- * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- * Based on arch/arm/mach-vt8500/gpio.c:
- * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
- *
- * 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/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
-
-/*
- We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
- by one set of registers (although not all may be valid).
-
- Because different SoC's have different register offsets, we pass the
- register offsets as data in vt8500_gpio_dt_ids[].
-
- A value of NO_REG is used to indicate that this register is not
- supported. Only used for ->en at the moment.
-*/
-
-#define NO_REG 0xFFFF
-
-/*
- * struct vt8500_gpio_bank_regoffsets
- * @en: offset to enable register of the bank
- * @dir: offset to direction register of the bank
- * @data_out: offset to the data out register of the bank
- * @data_in: offset to the data in register of the bank
- * @ngpio: highest valid pin in this bank
- */
-
-struct vt8500_gpio_bank_regoffsets {
- unsigned int en;
- unsigned int dir;
- unsigned int data_out;
- unsigned int data_in;
- unsigned char ngpio;
-};
-
-struct vt8500_gpio_data {
- unsigned int num_banks;
- struct vt8500_gpio_bank_regoffsets banks[];
-};
-
-#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
-{ \
- .en = __en, \
- .dir = __dir, \
- .data_out = __out, \
- .data_in = __in, \
- .ngpio = __ngpio, \
-}
-
-static struct vt8500_gpio_data vt8500_data = {
- .num_banks = 7,
- .banks = {
- VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
- VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
- VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
- VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
- VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
- VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
- VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
- },
-};
-
-static struct vt8500_gpio_data wm8505_data = {
- .num_banks = 10,
- .banks = {
- VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
- VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
- VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
- VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
- VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
- VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
- VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
- VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
- VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
- VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
- },
-};
-
-/*
- * No information about which bits are valid so we just make
- * them all available until its figured out.
- */
-static struct vt8500_gpio_data wm8650_data = {
- .num_banks = 9,
- .banks = {
- VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
- VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
- VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
- VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
- VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
- VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
- VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
- VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
- VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
- },
-};
-
-struct vt8500_gpio_chip {
- struct gpio_chip chip;
-
- const struct vt8500_gpio_bank_regoffsets *regs;
- void __iomem *base;
-};
-
-
-#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
-
-static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- u32 val;
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- if (vt8500_chip->regs->en == NO_REG)
- return 0;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-
- return 0;
-}
-
-static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
- u32 val;
-
- if (vt8500_chip->regs->en == NO_REG)
- return;
-
- val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
-}
-
-static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val &= ~BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- return 0;
-}
-
-static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
-
- if (value) {
- val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- val |= BIT(offset);
- writel_relaxed(val, vt8500_chip->base +
- vt8500_chip->regs->data_out);
- }
- return 0;
-}
-
-static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >>
- offset) & 1;
-}
-
-static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
- int value)
-{
- struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
-
- u32 val = readl_relaxed(vt8500_chip->base +
- vt8500_chip->regs->data_out);
- if (value)
- val |= BIT(offset);
- else
- val &= ~BIT(offset);
-
- writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
-}
-
-static int vt8500_of_xlate(struct gpio_chip *gc,
- const struct of_phandle_args *gpiospec, u32 *flags)
-{
- /* bank if specificed in gpiospec->args[0] */
- if (flags)
- *flags = gpiospec->args[2];
-
- return gpiospec->args[1];
-}
-
-static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
- const struct vt8500_gpio_data *data)
-{
- struct vt8500_gpio_chip *vtchip;
- struct gpio_chip *chip;
- int i;
- int pin_cnt = 0;
-
- vtchip = devm_kzalloc(&pdev->dev,
- sizeof(struct vt8500_gpio_chip) * data->num_banks,
- GFP_KERNEL);
- if (!vtchip) {
- pr_err("%s: failed to allocate chip memory\n", __func__);
- return -ENOMEM;
- }
-
- for (i = 0; i < data->num_banks; i++) {
- vtchip[i].base = base;
- vtchip[i].regs = &data->banks[i];
-
- chip = &vtchip[i].chip;
-
- chip->of_xlate = vt8500_of_xlate;
- chip->of_gpio_n_cells = 3;
- chip->of_node = pdev->dev.of_node;
-
- chip->request = vt8500_gpio_request;
- chip->free = vt8500_gpio_free;
- chip->direction_input = vt8500_gpio_direction_input;
- chip->direction_output = vt8500_gpio_direction_output;
- chip->get = vt8500_gpio_get_value;
- chip->set = vt8500_gpio_set_value;
- chip->can_sleep = 0;
- chip->base = pin_cnt;
- chip->ngpio = data->banks[i].ngpio;
-
- pin_cnt += data->banks[i].ngpio;
-
- gpiochip_add(chip);
- }
- return 0;
-}
-
-static struct of_device_id vt8500_gpio_dt_ids[] = {
- { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
- { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
- { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
- { /* Sentinel */ },
-};
-
-static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
-{
- void __iomem *gpio_base;
- struct device_node *np;
- const struct of_device_id *of_id =
- of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
-
- if (!of_id) {
- dev_err(&pdev->dev, "Failed to find gpio controller\n");
- return -ENODEV;
- }
-
- np = pdev->dev.of_node;
- if (!np) {
- dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
- return -EFAULT;
- }
-
- gpio_base = of_iomap(np, 0);
- if (!gpio_base) {
- dev_err(&pdev->dev, "Unable to map GPIO registers\n");
- of_node_put(np);
- return -ENOMEM;
- }
-
- vt8500_add_chips(pdev, gpio_base, of_id->data);
-
- return 0;
-}
-
-static struct platform_driver vt8500_gpio_driver = {
- .probe = vt8500_gpio_probe,
- .driver = {
- .name = "vt8500-gpio",
- .owner = THIS_MODULE,
- .of_match_table = vt8500_gpio_dt_ids,
- },
-};
-
-module_platform_driver(vt8500_gpio_driver);
-
-MODULE_DESCRIPTION("VT8500 GPIO Driver");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 76ebfe5ff70..0fd23b6a753 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -214,12 +214,12 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
c->dbg_show = NULL;
c->base = 0;
c->ngpio = NR_VX855_GP;
- c->can_sleep = 0;
+ c->can_sleep = false;
c->names = vx855gpio_names;
}
/* This platform device is ordinarily registered by the vx855 mfd driver */
-static __devinit int vx855gpio_probe(struct platform_device *pdev)
+static int vx855gpio_probe(struct platform_device *pdev)
{
struct resource *res_gpi;
struct resource *res_gpo;
@@ -279,12 +279,11 @@ out_release:
release_region(res_gpi->start, resource_size(res_gpi));
if (vg->gpo_reserved)
release_region(res_gpi->start, resource_size(res_gpo));
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return ret;
}
-static int __devexit vx855gpio_remove(struct platform_device *pdev)
+static int vx855gpio_remove(struct platform_device *pdev)
{
struct vx855_gpio *vg = platform_get_drvdata(pdev);
struct resource *res;
@@ -301,7 +300,6 @@ static int __devexit vx855gpio_remove(struct platform_device *pdev)
release_region(res->start, resource_size(res));
}
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return 0;
}
@@ -312,7 +310,7 @@ static struct platform_driver vx855gpio_driver = {
.owner = THIS_MODULE,
},
.probe = vx855gpio_probe,
- .remove = __devexit_p(vx855gpio_remove),
+ .remove = vx855gpio_remove,
};
module_platform_driver(vx855gpio_driver);
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index b6eda35089d..b18a1a26425 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -240,13 +240,13 @@ static struct gpio_chip template_chip = {
.to_irq = wm831x_gpio_to_irq,
.set_debounce = wm831x_gpio_set_debounce,
.dbg_show = wm831x_gpio_dbg_show,
- .can_sleep = 1,
+ .can_sleep = true,
};
-static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
+static int wm831x_gpio_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
- struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+ struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
struct wm831x_gpio *wm831x_gpio;
int ret;
@@ -275,7 +275,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit wm831x_gpio_remove(struct platform_device *pdev)
+static int wm831x_gpio_remove(struct platform_device *pdev)
{
struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev);
@@ -286,7 +286,7 @@ static struct platform_driver wm831x_gpio_driver = {
.driver.name = "wm831x-gpio",
.driver.owner = THIS_MODULE,
.probe = wm831x_gpio_probe,
- .remove = __devexit_p(wm831x_gpio_remove),
+ .remove = wm831x_gpio_remove,
};
static int __init wm831x_gpio_init(void)
diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c
index fb429388939..2487f9d575d 100644
--- a/drivers/gpio/gpio-wm8350.c
+++ b/drivers/gpio/gpio-wm8350.c
@@ -106,13 +106,13 @@ static struct gpio_chip template_chip = {
.direction_output = wm8350_gpio_direction_out,
.set = wm8350_gpio_set,
.to_irq = wm8350_gpio_to_irq,
- .can_sleep = 1,
+ .can_sleep = true,
};
-static int __devinit wm8350_gpio_probe(struct platform_device *pdev)
+static int wm8350_gpio_probe(struct platform_device *pdev)
{
struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent);
- struct wm8350_platform_data *pdata = wm8350->dev->platform_data;
+ struct wm8350_platform_data *pdata = dev_get_platdata(wm8350->dev);
struct wm8350_gpio_data *wm8350_gpio;
int ret;
@@ -141,7 +141,7 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev)
return ret;
}
-static int __devexit wm8350_gpio_remove(struct platform_device *pdev)
+static int wm8350_gpio_remove(struct platform_device *pdev)
{
struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev);
@@ -152,7 +152,7 @@ static struct platform_driver wm8350_gpio_driver = {
.driver.name = "wm8350-gpio",
.driver.owner = THIS_MODULE,
.probe = wm8350_gpio_probe,
- .remove = __devexit_p(wm8350_gpio_remove),
+ .remove = wm8350_gpio_remove,
};
static int __init wm8350_gpio_init(void)
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index 1c764e779d8..d93b6b58167 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -242,13 +242,13 @@ static struct gpio_chip template_chip = {
.set = wm8994_gpio_set,
.to_irq = wm8994_gpio_to_irq,
.dbg_show = wm8994_gpio_dbg_show,
- .can_sleep = 1,
+ .can_sleep = true,
};
-static int __devinit wm8994_gpio_probe(struct platform_device *pdev)
+static int wm8994_gpio_probe(struct platform_device *pdev)
{
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
- struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
struct wm8994_gpio *wm8994_gpio;
int ret;
@@ -281,7 +281,7 @@ err:
return ret;
}
-static int __devexit wm8994_gpio_remove(struct platform_device *pdev)
+static int wm8994_gpio_remove(struct platform_device *pdev)
{
struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev);
@@ -292,7 +292,7 @@ static struct platform_driver wm8994_gpio_driver = {
.driver.name = "wm8994-gpio",
.driver.owner = THIS_MODULE,
.probe = wm8994_gpio_probe,
- .remove = __devexit_p(wm8994_gpio_remove),
+ .remove = wm8994_gpio_remove,
};
static int __init wm8994_gpio_init(void)
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 79b0fe8a725..12481867daf 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -1,7 +1,7 @@
/*
- * Xilinx gpio driver
+ * Xilinx gpio driver for xps/axi_gpio IP.
*
- * Copyright 2008 Xilinx, Inc.
+ * Copyright 2008 - 2013 Xilinx, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -12,6 +12,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -26,11 +27,31 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
+#define XGPIO_CHANNEL_OFFSET 0x8
+
+/* Read/Write access to the GPIO registers */
+#ifdef CONFIG_ARCH_ZYNQ
+# define xgpio_readreg(offset) readl(offset)
+# define xgpio_writereg(offset, val) writel(val, offset)
+#else
+# define xgpio_readreg(offset) __raw_readl(offset)
+# define xgpio_writereg(offset, val) __raw_writel(val, offset)
+#endif
+
+/**
+ * struct xgpio_instance - Stores information about GPIO device
+ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
+ * gpio_state: GPIO state shadow register
+ * gpio_dir: GPIO direction shadow register
+ * offset: GPIO channel offset
+ * gpio_lock: Lock used for synchronization
+ */
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
- u32 gpio_state; /* GPIO state shadow register */
- u32 gpio_dir; /* GPIO direction shadow register */
- spinlock_t gpio_lock; /* Lock used for synchronization */
+ u32 gpio_state;
+ u32 gpio_dir;
+ u32 offset;
+ spinlock_t gpio_lock;
};
/**
@@ -44,8 +65,12 @@ struct xgpio_instance {
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip =
+ container_of(mm_gc, struct xgpio_instance, mmchip);
- return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+ void __iomem *regs = mm_gc->regs + chip->offset;
+
+ return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
}
/**
@@ -63,15 +88,18 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
@@ -91,12 +119,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
- chip->gpio_dir |= (1 << gpio);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir |= BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -119,19 +148,21 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
/* Clear the GPIO bit in shadow register and set direction as output */
- chip->gpio_dir &= (~(1 << gpio));
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
+ chip->gpio_dir);
}
/**
@@ -159,7 +192,7 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
* driver data structure. It returns 0, if the driver is bound to the GPIO
* device, or a negative value if there is an error.
*/
-static int __devinit xgpio_of_probe(struct device_node *np)
+static int xgpio_of_probe(struct device_node *np)
{
struct xgpio_instance *chip;
int status = 0;
@@ -170,24 +203,20 @@ static int __devinit xgpio_of_probe(struct device_node *np)
return -ENOMEM;
/* Update GPIO state shadow register with default value */
- tree_info = of_get_property(np, "xlnx,dout-default", NULL);
- if (tree_info)
- chip->gpio_state = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
/* Update GPIO direction shadow register with default value */
- chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
- tree_info = of_get_property(np, "xlnx,tri-default", NULL);
- if (tree_info)
- chip->gpio_dir = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
/* Check device node and parent device node for device width */
- chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
- tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
- if (!tree_info)
- tree_info = of_get_property(np->parent,
- "xlnx,gpio-width", NULL);
- if (tree_info)
- chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,gpio-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
spin_lock_init(&chip->gpio_lock);
@@ -206,10 +235,61 @@ static int __devinit xgpio_of_probe(struct device_node *np)
np->full_name, status);
return status;
}
+
+ pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+ chip->mmchip.gc.base);
+
+ tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+ if (tree_info && be32_to_cpup(tree_info)) {
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ /* Add dual channel offset */
+ chip->offset = XGPIO_CHANNEL_OFFSET;
+
+ /* Update GPIO state shadow register with default value */
+ of_property_read_u32(np, "xlnx,dout-default-2",
+ &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
+
+ /* Update GPIO direction shadow register with default value */
+ of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
+
+ /* Check device node and parent device node for device width */
+ of_property_read_u32(np, "xlnx,gpio2-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
+
+ spin_lock_init(&chip->gpio_lock);
+
+ chip->mmchip.gc.direction_input = xgpio_dir_in;
+ chip->mmchip.gc.direction_output = xgpio_dir_out;
+ chip->mmchip.gc.get = xgpio_get;
+ chip->mmchip.gc.set = xgpio_set;
+
+ chip->mmchip.save_regs = xgpio_save_regs;
+
+ /* Call the OF gpio helper to setup and register the GPIO dev */
+ status = of_mm_gpiochip_add(np, &chip->mmchip);
+ if (status) {
+ kfree(chip);
+ pr_err("%s: error in probe function with status %d\n",
+ np->full_name, status);
+ return status;
+ }
+ pr_info("XGpio: %s: dual channel registered, base is %d\n",
+ np->full_name, chip->mmchip.gc.base);
+ }
+
return 0;
}
-static struct of_device_id xgpio_of_match[] __devinitdata = {
+static const struct of_device_id xgpio_of_match[] = {
{ .compatible = "xlnx,xps-gpio-1.00.a", },
{ /* end of list */ },
};
diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c
new file mode 100644
index 00000000000..7081304d679
--- /dev/null
+++ b/drivers/gpio/gpio-xtensa.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2013 TangoTec Ltd.
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the Xtensa LX4 GPIO32 Option
+ *
+ * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
+ *
+ * GPIO32 is a standard optional extension to the Xtensa architecture core that
+ * provides preconfigured output and input ports for intra SoC signaling. The
+ * GPIO32 option is implemented as 32bit Tensilica Instruction Extension (TIE)
+ * output state called EXPSTATE, and 32bit input wire called IMPWIRE. This
+ * driver treats input and output states as two distinct devices.
+ *
+ * Access to GPIO32 specific instructions is controlled by the CPENABLE
+ * (Coprocessor Enable Bits) register. By default Xtensa Linux startup code
+ * disables access to all coprocessors. This driver sets the CPENABLE bit
+ * corresponding to GPIO32 before any GPIO32 specific instruction, and restores
+ * CPENABLE state after that.
+ *
+ * This driver is currently incompatible with SMP. The GPIO32 extension is not
+ * guaranteed to be available in all cores. Moreover, each core controls a
+ * different set of IO wires. A theoretical SMP aware version of this driver
+ * would need to have a per core workqueue to do the actual GPIO manipulation.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+
+#include <asm/coprocessor.h> /* CPENABLE read/write macros */
+
+#ifndef XCHAL_CP_ID_XTIOP
+#error GPIO32 option is not enabled for your xtensa core variant
+#endif
+
+#if XCHAL_HAVE_CP
+
+static inline unsigned long enable_cp(unsigned long *cpenable)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ RSR_CPENABLE(*cpenable);
+ WSR_CPENABLE(*cpenable | BIT(XCHAL_CP_ID_XTIOP));
+
+ return flags;
+}
+
+static inline void disable_cp(unsigned long flags, unsigned long cpenable)
+{
+ WSR_CPENABLE(cpenable);
+ local_irq_restore(flags);
+}
+
+#else
+
+static inline unsigned long enable_cp(unsigned long *cpenable)
+{
+ *cpenable = 0; /* avoid uninitialized value warning */
+ return 0;
+}
+
+static inline void disable_cp(unsigned long flags, unsigned long cpenable)
+{
+}
+
+#endif /* XCHAL_HAVE_CP */
+
+static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ return 1; /* input only */
+}
+
+static int xtensa_impwire_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ unsigned long flags, saved_cpenable;
+ u32 impwire;
+
+ flags = enable_cp(&saved_cpenable);
+ __asm__ __volatile__("read_impwire %0" : "=a" (impwire));
+ disable_cp(flags, saved_cpenable);
+
+ return !!(impwire & BIT(offset));
+}
+
+static void xtensa_impwire_set_value(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ BUG(); /* output only; should never be called */
+}
+
+static int xtensa_expstate_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ return 0; /* output only */
+}
+
+static int xtensa_expstate_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ unsigned long flags, saved_cpenable;
+ u32 expstate;
+
+ flags = enable_cp(&saved_cpenable);
+ __asm__ __volatile__("rur.expstate %0" : "=a" (expstate));
+ disable_cp(flags, saved_cpenable);
+
+ return !!(expstate & BIT(offset));
+}
+
+static void xtensa_expstate_set_value(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ unsigned long flags, saved_cpenable;
+ u32 mask = BIT(offset);
+ u32 val = value ? BIT(offset) : 0;
+
+ flags = enable_cp(&saved_cpenable);
+ __asm__ __volatile__("wrmsk_expstate %0, %1"
+ :: "a" (val), "a" (mask));
+ disable_cp(flags, saved_cpenable);
+}
+
+static struct gpio_chip impwire_chip = {
+ .label = "impwire",
+ .base = -1,
+ .ngpio = 32,
+ .get_direction = xtensa_impwire_get_direction,
+ .get = xtensa_impwire_get_value,
+ .set = xtensa_impwire_set_value,
+};
+
+static struct gpio_chip expstate_chip = {
+ .label = "expstate",
+ .base = -1,
+ .ngpio = 32,
+ .get_direction = xtensa_expstate_get_direction,
+ .get = xtensa_expstate_get_value,
+ .set = xtensa_expstate_set_value,
+};
+
+static int xtensa_gpio_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = gpiochip_add(&impwire_chip);
+ if (ret)
+ return ret;
+ return gpiochip_add(&expstate_chip);
+}
+
+static struct platform_driver xtensa_gpio_driver = {
+ .driver = {
+ .name = "xtensa-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = xtensa_gpio_probe,
+};
+
+static int __init xtensa_gpio_init(void)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_simple("xtensa-gpio", 0, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ return platform_driver_register(&xtensa_gpio_driver);
+}
+device_initcall(xtensa_gpio_init);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Xtensa LX4 GPIO32 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
new file mode 100644
index 00000000000..54e54e4cc6c
--- /dev/null
+++ b/drivers/gpio/gpio-zevio.c
@@ -0,0 +1,224 @@
+/*
+ * GPIO controller in LSI ZEVIO SoCs.
+ *
+ * Author: Fabian Vogt <fabian@ritter-vogt.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+/*
+ * Memory layout:
+ * This chip has four gpio sections, each controls 8 GPIOs.
+ * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10.
+ * Disclaimer: Reverse engineered!
+ * For more information refer to:
+ * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
+ *
+ * 0x00-0x3F: Section 0
+ * +0x00: Masked interrupt status (read-only)
+ * +0x04: R: Interrupt status W: Reset interrupt status
+ * +0x08: R: Interrupt mask W: Mask interrupt
+ * +0x0C: W: Unmask interrupt (write-only)
+ * +0x10: Direction: I/O=1/0
+ * +0x14: Output
+ * +0x18: Input (read-only)
+ * +0x20: R: Level interrupt W: Set as level interrupt
+ * 0x40-0x7F: Section 1
+ * 0x80-0xBF: Section 2
+ * 0xC0-0xFF: Section 3
+ */
+
+#define ZEVIO_GPIO_SECTION_SIZE 0x40
+
+/* Offsets to various registers */
+#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00
+#define ZEVIO_GPIO_INT_STATUS 0x04
+#define ZEVIO_GPIO_INT_UNMASK 0x08
+#define ZEVIO_GPIO_INT_MASK 0x0C
+#define ZEVIO_GPIO_DIRECTION 0x10
+#define ZEVIO_GPIO_OUTPUT 0x14
+#define ZEVIO_GPIO_INPUT 0x18
+#define ZEVIO_GPIO_INT_STICKY 0x20
+
+#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
+ struct zevio_gpio, chip)
+
+/* Bit number of GPIO in its section */
+#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
+
+struct zevio_gpio {
+ spinlock_t lock;
+ struct of_mm_gpio_chip chip;
+};
+
+static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
+ unsigned port_offset)
+{
+ unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
+ return readl(IOMEM(c->chip.regs + section_offset + port_offset));
+}
+
+static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
+ unsigned port_offset, u32 val)
+{
+ unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
+ writel(val, IOMEM(c->chip.regs + section_offset + port_offset));
+}
+
+/* Functions for struct gpio_chip */
+static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val, dir;
+
+ spin_lock(&controller->lock);
+ dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ if (dir & BIT(ZEVIO_GPIO_BIT(pin)))
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
+ else
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ spin_unlock(&controller->lock);
+
+ return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
+}
+
+static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ if (value)
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ else
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
+ spin_unlock(&controller->lock);
+}
+
+static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
+
+ spin_unlock(&controller->lock);
+
+ return 0;
+}
+
+static int zevio_gpio_direction_output(struct gpio_chip *chip,
+ unsigned pin, int value)
+{
+ struct zevio_gpio *controller = to_zevio_gpio(chip);
+ u32 val;
+
+ spin_lock(&controller->lock);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
+ if (value)
+ val |= BIT(ZEVIO_GPIO_BIT(pin));
+ else
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
+ val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
+ val &= ~BIT(ZEVIO_GPIO_BIT(pin));
+ zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
+
+ spin_unlock(&controller->lock);
+
+ return 0;
+}
+
+static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ /*
+ * TODO: Implement IRQs.
+ * Not implemented yet due to weird lockups
+ */
+
+ return -ENXIO;
+}
+
+static struct gpio_chip zevio_gpio_chip = {
+ .direction_input = zevio_gpio_direction_input,
+ .direction_output = zevio_gpio_direction_output,
+ .set = zevio_gpio_set,
+ .get = zevio_gpio_get,
+ .to_irq = zevio_gpio_to_irq,
+ .base = 0,
+ .owner = THIS_MODULE,
+ .ngpio = 32,
+ .of_gpio_n_cells = 2,
+};
+
+/* Initialization */
+static int zevio_gpio_probe(struct platform_device *pdev)
+{
+ struct zevio_gpio *controller;
+ int status, i;
+
+ controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return -ENOMEM;
+
+ /* Copy our reference */
+ controller->chip.gc = zevio_gpio_chip;
+ controller->chip.gc.dev = &pdev->dev;
+
+ status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
+ if (status) {
+ dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
+ return status;
+ }
+
+ spin_lock_init(&controller->lock);
+
+ /* Disable interrupts, they only cause errors */
+ for (i = 0; i < controller->chip.gc.ngpio; i += 8)
+ zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
+
+ dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
+
+ return 0;
+}
+
+static const struct of_device_id zevio_gpio_of_match[] = {
+ { .compatible = "lsi,zevio-gpio", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, zevio_gpio_of_match);
+
+static struct platform_driver zevio_gpio_driver = {
+ .driver = {
+ .name = "gpio-zevio",
+ .owner = THIS_MODULE,
+ .of_match_table = zevio_gpio_of_match,
+ },
+ .probe = zevio_gpio_probe,
+};
+module_platform_driver(zevio_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>");
+MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver");
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
new file mode 100644
index 00000000000..4a987917c18
--- /dev/null
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -0,0 +1,556 @@
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012, Intel Corporation
+ * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
+ * Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include "gpiolib.h"
+
+struct acpi_gpio_event {
+ struct list_head node;
+ acpi_handle handle;
+ unsigned int pin;
+ unsigned int irq;
+};
+
+struct acpi_gpio_connection {
+ struct list_head node;
+ struct gpio_desc *desc;
+};
+
+struct acpi_gpio_chip {
+ /*
+ * ACPICA requires that the first field of the context parameter
+ * passed to acpi_install_address_space_handler() is large enough
+ * to hold struct acpi_connection_info.
+ */
+ struct acpi_connection_info conn_info;
+ struct list_head conns;
+ struct mutex conn_lock;
+ struct gpio_chip *chip;
+ struct list_head events;
+};
+
+static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
+{
+ if (!gc->dev)
+ return false;
+
+ return ACPI_HANDLE(gc->dev) == data;
+}
+
+/**
+ * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
+ * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
+ * @pin: ACPI GPIO pin number (0-based, controller-relative)
+ *
+ * Returns GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
+ * error value
+ */
+
+static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
+{
+ struct gpio_chip *chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return ERR_PTR(-ENODEV);
+
+ chip = gpiochip_find(handle, acpi_gpiochip_find);
+ if (!chip)
+ return ERR_PTR(-ENODEV);
+
+ if (pin < 0 || pin > chip->ngpio)
+ return ERR_PTR(-EINVAL);
+
+ return gpiochip_get_desc(chip, pin);
+}
+
+static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
+{
+ struct acpi_gpio_event *event = data;
+
+ acpi_evaluate_object(event->handle, NULL, NULL, NULL);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
+{
+ struct acpi_gpio_event *event = data;
+
+ acpi_execute_simple_method(event->handle, NULL, event->pin);
+
+ return IRQ_HANDLED;
+}
+
+static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
+{
+ /* The address of this function is used as a key. */
+}
+
+static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
+ void *context)
+{
+ struct acpi_gpio_chip *acpi_gpio = context;
+ struct gpio_chip *chip = acpi_gpio->chip;
+ struct acpi_resource_gpio *agpio;
+ acpi_handle handle, evt_handle;
+ struct acpi_gpio_event *event;
+ irq_handler_t handler = NULL;
+ struct gpio_desc *desc;
+ unsigned long irqflags;
+ int ret, pin, irq;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return AE_OK;
+
+ agpio = &ares->data.gpio;
+ if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
+ return AE_OK;
+
+ handle = ACPI_HANDLE(chip->dev);
+ pin = agpio->pin_table[0];
+
+ if (pin <= 255) {
+ char ev_name[5];
+ sprintf(ev_name, "_%c%02X",
+ agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
+ pin);
+ if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
+ handler = acpi_gpio_irq_handler;
+ }
+ if (!handler) {
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
+ handler = acpi_gpio_irq_handler_evt;
+ }
+ if (!handler)
+ return AE_BAD_PARAMETER;
+
+ desc = gpiochip_get_desc(chip, pin);
+ if (IS_ERR(desc)) {
+ dev_err(chip->dev, "Failed to get GPIO descriptor\n");
+ return AE_ERROR;
+ }
+
+ ret = gpiochip_request_own_desc(desc, "ACPI:Event");
+ if (ret) {
+ dev_err(chip->dev, "Failed to request GPIO\n");
+ return AE_ERROR;
+ }
+
+ gpiod_direction_input(desc);
+
+ ret = gpiod_lock_as_irq(desc);
+ if (ret) {
+ dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
+ goto fail_free_desc;
+ }
+
+ irq = gpiod_to_irq(desc);
+ if (irq < 0) {
+ dev_err(chip->dev, "Failed to translate GPIO to IRQ\n");
+ goto fail_unlock_irq;
+ }
+
+ irqflags = IRQF_ONESHOT;
+ if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
+ if (agpio->polarity == ACPI_ACTIVE_HIGH)
+ irqflags |= IRQF_TRIGGER_HIGH;
+ else
+ irqflags |= IRQF_TRIGGER_LOW;
+ } else {
+ switch (agpio->polarity) {
+ case ACPI_ACTIVE_HIGH:
+ irqflags |= IRQF_TRIGGER_RISING;
+ break;
+ case ACPI_ACTIVE_LOW:
+ irqflags |= IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ irqflags |= IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING;
+ break;
+ }
+ }
+
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
+ if (!event)
+ goto fail_unlock_irq;
+
+ event->handle = evt_handle;
+ event->irq = irq;
+ event->pin = pin;
+
+ ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
+ "ACPI:Event", event);
+ if (ret) {
+ dev_err(chip->dev, "Failed to setup interrupt handler for %d\n",
+ event->irq);
+ goto fail_free_event;
+ }
+
+ list_add_tail(&event->node, &acpi_gpio->events);
+ return AE_OK;
+
+fail_free_event:
+ kfree(event);
+fail_unlock_irq:
+ gpiod_unlock_as_irq(desc);
+fail_free_desc:
+ gpiochip_free_own_desc(desc);
+
+ return AE_ERROR;
+}
+
+/**
+ * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
+ * @acpi_gpio: ACPI GPIO chip
+ *
+ * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
+ * handled by ACPI event methods which need to be called from the GPIO
+ * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
+ * gpio pins have acpi event methods and assigns interrupt handlers that calls
+ * the acpi event methods for those pins.
+ */
+static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
+{
+ struct gpio_chip *chip = acpi_gpio->chip;
+
+ if (!chip->to_irq)
+ return;
+
+ INIT_LIST_HEAD(&acpi_gpio->events);
+ acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI",
+ acpi_gpiochip_request_interrupt, acpi_gpio);
+}
+
+/**
+ * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
+ * @acpi_gpio: ACPI GPIO chip
+ *
+ * Free interrupts associated with GPIO ACPI event method for the given
+ * GPIO chip.
+ */
+static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
+{
+ struct acpi_gpio_event *event, *ep;
+ struct gpio_chip *chip = acpi_gpio->chip;
+
+ if (!chip->to_irq)
+ return;
+
+ list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
+ struct gpio_desc *desc;
+
+ free_irq(event->irq, event);
+ desc = gpiochip_get_desc(chip, event->pin);
+ if (WARN_ON(IS_ERR(desc)))
+ continue;
+ gpiod_unlock_as_irq(desc);
+ gpiochip_free_own_desc(desc);
+ list_del(&event->node);
+ kfree(event);
+ }
+}
+
+struct acpi_gpio_lookup {
+ struct acpi_gpio_info info;
+ int index;
+ struct gpio_desc *desc;
+ int n;
+};
+
+static int acpi_find_gpio(struct acpi_resource *ares, void *data)
+{
+ struct acpi_gpio_lookup *lookup = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return 1;
+
+ if (lookup->n++ == lookup->index && !lookup->desc) {
+ const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+
+ lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
+ agpio->pin_table[0]);
+ lookup->info.gpioint =
+ agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
+ }
+
+ return 1;
+}
+
+/**
+ * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
+ * @dev: pointer to a device to get GPIO from
+ * @index: index of GpioIo/GpioInt resource (starting from %0)
+ * @info: info pointer to fill in (optional)
+ *
+ * Function goes through ACPI resources for @dev and based on @index looks
+ * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
+ * and returns it. @index matches GpioIo/GpioInt resources only so if there
+ * are total %3 GPIO resources, the index goes from %0 to %2.
+ *
+ * If the GPIO cannot be translated or there is an error an ERR_PTR is
+ * returned.
+ *
+ * Note: if the GPIO resource has multiple entries in the pin list, this
+ * function only returns the first.
+ */
+struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+ struct acpi_gpio_info *info)
+{
+ struct acpi_gpio_lookup lookup;
+ struct list_head resource_list;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ int ret;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle || acpi_bus_get_device(handle, &adev))
+ return ERR_PTR(-ENODEV);
+
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.index = index;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
+ &lookup);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ if (lookup.desc && info)
+ *info = lookup.info;
+
+ return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
+}
+
+static acpi_status
+acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, u64 *value, void *handler_context,
+ void *region_context)
+{
+ struct acpi_gpio_chip *achip = region_context;
+ struct gpio_chip *chip = achip->chip;
+ struct acpi_resource_gpio *agpio;
+ struct acpi_resource *ares;
+ acpi_status status;
+ bool pull_up;
+ int i;
+
+ status = acpi_buffer_to_resource(achip->conn_info.connection,
+ achip->conn_info.length, &ares);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
+ ACPI_FREE(ares);
+ return AE_BAD_PARAMETER;
+ }
+
+ agpio = &ares->data.gpio;
+ pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
+
+ if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
+ function == ACPI_WRITE)) {
+ ACPI_FREE(ares);
+ return AE_BAD_PARAMETER;
+ }
+
+ for (i = 0; i < agpio->pin_table_length; i++) {
+ unsigned pin = agpio->pin_table[i];
+ struct acpi_gpio_connection *conn;
+ struct gpio_desc *desc;
+ bool found;
+
+ desc = gpiochip_get_desc(chip, pin);
+ if (IS_ERR(desc)) {
+ status = AE_ERROR;
+ goto out;
+ }
+
+ mutex_lock(&achip->conn_lock);
+
+ found = false;
+ list_for_each_entry(conn, &achip->conns, node) {
+ if (conn->desc == desc) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ int ret;
+
+ ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
+ if (ret) {
+ status = AE_ERROR;
+ mutex_unlock(&achip->conn_lock);
+ goto out;
+ }
+
+ switch (agpio->io_restriction) {
+ case ACPI_IO_RESTRICT_INPUT:
+ gpiod_direction_input(desc);
+ break;
+ case ACPI_IO_RESTRICT_OUTPUT:
+ /*
+ * ACPI GPIO resources don't contain an
+ * initial value for the GPIO. Therefore we
+ * deduce that value from the pull field
+ * instead. If the pin is pulled up we
+ * assume default to be high, otherwise
+ * low.
+ */
+ gpiod_direction_output(desc, pull_up);
+ break;
+ default:
+ /*
+ * Assume that the BIOS has configured the
+ * direction and pull accordingly.
+ */
+ break;
+ }
+
+ conn = kzalloc(sizeof(*conn), GFP_KERNEL);
+ if (!conn) {
+ status = AE_NO_MEMORY;
+ gpiochip_free_own_desc(desc);
+ mutex_unlock(&achip->conn_lock);
+ goto out;
+ }
+
+ conn->desc = desc;
+ list_add_tail(&conn->node, &achip->conns);
+ }
+
+ mutex_unlock(&achip->conn_lock);
+
+ if (function == ACPI_WRITE)
+ gpiod_set_raw_value_cansleep(desc,
+ !!((1 << i) & *value));
+ else
+ *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
+ }
+
+out:
+ ACPI_FREE(ares);
+ return status;
+}
+
+static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
+{
+ struct gpio_chip *chip = achip->chip;
+ acpi_handle handle = ACPI_HANDLE(chip->dev);
+ acpi_status status;
+
+ INIT_LIST_HEAD(&achip->conns);
+ mutex_init(&achip->conn_lock);
+ status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+ acpi_gpio_adr_space_handler,
+ NULL, achip);
+ if (ACPI_FAILURE(status))
+ dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n");
+}
+
+static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
+{
+ struct gpio_chip *chip = achip->chip;
+ acpi_handle handle = ACPI_HANDLE(chip->dev);
+ struct acpi_gpio_connection *conn, *tmp;
+ acpi_status status;
+
+ status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
+ acpi_gpio_adr_space_handler);
+ if (ACPI_FAILURE(status)) {
+ dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n");
+ return;
+ }
+
+ list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
+ gpiochip_free_own_desc(conn->desc);
+ list_del(&conn->node);
+ kfree(conn);
+ }
+}
+
+void acpi_gpiochip_add(struct gpio_chip *chip)
+{
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip || !chip->dev)
+ return;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
+ if (!acpi_gpio) {
+ dev_err(chip->dev,
+ "Failed to allocate memory for ACPI GPIO chip\n");
+ return;
+ }
+
+ acpi_gpio->chip = chip;
+
+ status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
+ if (ACPI_FAILURE(status)) {
+ dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
+ kfree(acpi_gpio);
+ return;
+ }
+
+ acpi_gpiochip_request_interrupts(acpi_gpio);
+ acpi_gpiochip_request_regions(acpi_gpio);
+}
+
+void acpi_gpiochip_remove(struct gpio_chip *chip)
+{
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip || !chip->dev)
+ return;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
+ return;
+ }
+
+ acpi_gpiochip_free_regions(acpi_gpio);
+ acpi_gpiochip_free_interrupts(acpi_gpio);
+
+ acpi_detach_data(handle, acpi_gpio_chip_dh);
+ kfree(acpi_gpio);
+}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index f1a45997aea..af7e25c9a9a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -12,21 +12,25 @@
*/
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
+struct gpio_desc;
+
/* Private data structure for of_gpiochip_find_and_xlate */
struct gg_data {
enum of_gpio_flags *flags;
struct of_phandle_args gpiospec;
- int out_gpio;
+ struct gpio_desc *out_gpio;
};
/* Private function for resolving node pointer to gpio_chip */
@@ -44,28 +48,31 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
if (ret < 0)
return false;
- gg_data->out_gpio = ret + gc->base;
+ gg_data->out_gpio = gpiochip_get_desc(gc, ret);
return true;
}
/**
- * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
+ * of_get_named_gpiod_flags() - Get a GPIO descriptor and flags for GPIO API
* @np: device node to get GPIO from
* @propname: property name containing gpio specifier(s)
* @index: index of the GPIO
* @flags: a flags pointer to fill in
*
- * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
* value on the error condition. If @flags is not NULL the function also fills
* in flags for the GPIO.
*/
-int of_get_named_gpio_flags(struct device_node *np, const char *propname,
- int index, enum of_gpio_flags *flags)
+struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+ const char *propname, int index, enum of_gpio_flags *flags)
{
/* Return -EPROBE_DEFER to support probe() functions to be called
* later when the GPIO actually becomes available
*/
- struct gg_data gg_data = { .flags = flags, .out_gpio = -EPROBE_DEFER };
+ struct gg_data gg_data = {
+ .flags = flags,
+ .out_gpio = ERR_PTR(-EPROBE_DEFER)
+ };
int ret;
/* .of_xlate might decide to not fill in the flags, so clear it. */
@@ -75,52 +82,33 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
&gg_data.gpiospec);
if (ret) {
- pr_debug("%s: can't parse gpios property\n", __func__);
- return ret;
+ pr_debug("%s: can't parse gpios property of node '%s[%d]'\n",
+ __func__, np->full_name, index);
+ return ERR_PTR(ret);
}
gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
of_node_put(gg_data.gpiospec.np);
- pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio);
+ pr_debug("%s exited with status %d\n", __func__,
+ PTR_ERR_OR_ZERO(gg_data.out_gpio));
return gg_data.out_gpio;
}
-EXPORT_SYMBOL(of_get_named_gpio_flags);
+EXPORT_SYMBOL(of_get_named_gpiod_flags);
-/**
- * of_gpio_named_count - Count GPIOs for a device
- * @np: device node to count GPIOs for
- * @propname: property name containing gpio specifier(s)
- *
- * The function returns the count of GPIOs specified for a node.
- *
- * Note that the empty GPIO specifiers counts too. For example,
- *
- * gpios = <0
- * &pio1 1 2
- * 0
- * &pio2 3 4>;
- *
- * defines four GPIOs (so this function will return 4), two of which
- * are not specified.
- */
-unsigned int of_gpio_named_count(struct device_node *np, const char* propname)
+int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
+ int index, enum of_gpio_flags *flags)
{
- unsigned int cnt = 0;
-
- do {
- int ret;
+ struct gpio_desc *desc;
- ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
- cnt, NULL);
- /* A hole in the gpios = <> counts anyway. */
- if (ret < 0 && ret != -EEXIST)
- break;
- } while (++cnt);
+ desc = of_get_named_gpiod_flags(np, list_name, index, flags);
- return cnt;
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+ else
+ return desc_to_gpio(desc);
}
-EXPORT_SYMBOL(of_gpio_named_count);
+EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
@@ -216,6 +204,89 @@ err0:
}
EXPORT_SYMBOL(of_mm_gpiochip_add);
+#ifdef CONFIG_PINCTRL
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
+{
+ struct device_node *np = chip->of_node;
+ struct of_phandle_args pinspec;
+ struct pinctrl_dev *pctldev;
+ int index = 0, ret;
+ const char *name;
+ static const char group_names_propname[] = "gpio-ranges-group-names";
+ struct property *group_names;
+
+ if (!np)
+ return;
+
+ group_names = of_find_property(np, group_names_propname, NULL);
+
+ for (;; index++) {
+ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+ index, &pinspec);
+ if (ret)
+ break;
+
+ pctldev = of_pinctrl_get(pinspec.np);
+ if (!pctldev)
+ break;
+
+ if (pinspec.args[2]) {
+ if (group_names) {
+ ret = of_property_read_string_index(np,
+ group_names_propname,
+ index, &name);
+ if (strlen(name)) {
+ pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n",
+ np->full_name);
+ break;
+ }
+ }
+ /* npins != 0: linear range */
+ ret = gpiochip_add_pin_range(chip,
+ pinctrl_dev_get_devname(pctldev),
+ pinspec.args[0],
+ pinspec.args[1],
+ pinspec.args[2]);
+ if (ret)
+ break;
+ } else {
+ /* npins == 0: special range */
+ if (pinspec.args[1]) {
+ pr_err("%s: Illegal gpio-range format.\n",
+ np->full_name);
+ break;
+ }
+
+ if (!group_names) {
+ pr_err("%s: GPIO group range requested but no %s property.\n",
+ np->full_name, group_names_propname);
+ break;
+ }
+
+ ret = of_property_read_string_index(np,
+ group_names_propname,
+ index, &name);
+ if (ret)
+ break;
+
+ if (!strlen(name)) {
+ pr_err("%s: Group name of GPIO group range cannot be the empty string.\n",
+ np->full_name);
+ break;
+ }
+
+ ret = gpiochip_add_pingroup_range(chip, pctldev,
+ pinspec.args[0], name);
+ if (ret)
+ break;
+ }
+ }
+}
+
+#else
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
+#endif
+
void of_gpiochip_add(struct gpio_chip *chip)
{
if ((!chip->of_node) && (chip->dev))
@@ -229,11 +300,14 @@ void of_gpiochip_add(struct gpio_chip *chip)
chip->of_xlate = of_gpio_simple_xlate;
}
+ of_gpiochip_add_pin_range(chip);
of_node_get(chip->of_node);
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
+ gpiochip_remove_pin_ranges(chip);
+
if (chip->of_node)
of_node_put(chip->of_node);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5d6c71edc73..2ebc9071e35 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3,6 +3,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/debugfs.h>
@@ -11,20 +12,19 @@
#include <linux/of_gpio.h>
#include <linux/idr.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/driver.h>
+
+#include "gpiolib.h"
#define CREATE_TRACE_POINTS
#include <trace/events/gpio.h>
-/* Optional implementation infrastructure for GPIO interfaces.
- *
- * Platforms may want to use this if they tend to use very many GPIOs
- * that aren't part of a System-On-Chip core; or across I2C/SPI/etc.
+/* Implementation infrastructure for GPIO interfaces.
*
- * When kernel footprint or instruction count is an issue, simpler
- * implementations may be preferred. The GPIO programming interface
- * allows for inlining speed-critical get/set operations for common
- * cases, so that access to SOC-integrated GPIOs can sometimes cost
- * only an instruction or two per bit.
+ * The GPIO programming interface allows for inlining speed-critical
+ * get/set operations for common cases, so that access to SOC-integrated
+ * GPIOs can sometimes cost only an instruction or two per bit.
*/
@@ -52,14 +52,14 @@ struct gpio_desc {
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
-#define FLAG_RESERVED 2
-#define FLAG_EXPORT 3 /* protected by sysfs_lock */
-#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
-#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
-#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
-#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
-#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
-#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
+#define FLAG_EXPORT 2 /* protected by sysfs_lock */
+#define FLAG_SYSFS 3 /* exported via /sys/class/gpio/control */
+#define FLAG_TRIG_FALL 4 /* trigger on falling edge */
+#define FLAG_TRIG_RISE 5 /* trigger on rising edge */
+#define FLAG_ACTIVE_LOW 6 /* value has active low */
+#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
+#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
+#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
#define ID_SHIFT 16 /* add new flags before this one */
@@ -72,10 +72,70 @@ struct gpio_desc {
};
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
+#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
+
+static DEFINE_MUTEX(gpio_lookup_lock);
+static LIST_HEAD(gpio_lookup_list);
+static LIST_HEAD(gpio_chips);
+
#ifdef CONFIG_GPIO_SYSFS
static DEFINE_IDR(dirent_idr);
#endif
+static int gpiod_request(struct gpio_desc *desc, const char *label);
+static void gpiod_free(struct gpio_desc *desc);
+
+/* With descriptor prefix */
+
+#ifdef CONFIG_DEBUG_FS
+#define gpiod_emerg(desc, fmt, ...) \
+ pr_emerg("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
+ ##__VA_ARGS__)
+#define gpiod_crit(desc, fmt, ...) \
+ pr_crit("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_err(desc, fmt, ...) \
+ pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_warn(desc, fmt, ...) \
+ pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_info(desc, fmt, ...) \
+ pr_info("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?", \
+ ##__VA_ARGS__)
+#define gpiod_dbg(desc, fmt, ...) \
+ pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), desc->label ? : "?",\
+ ##__VA_ARGS__)
+#else
+#define gpiod_emerg(desc, fmt, ...) \
+ pr_emerg("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#define gpiod_crit(desc, fmt, ...) \
+ pr_crit("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#define gpiod_err(desc, fmt, ...) \
+ pr_err("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#define gpiod_warn(desc, fmt, ...) \
+ pr_warn("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#define gpiod_info(desc, fmt, ...) \
+ pr_info("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#define gpiod_dbg(desc, fmt, ...) \
+ pr_debug("gpio-%d: " fmt, desc_to_gpio(desc), ##__VA_ARGS__)
+#endif
+
+/* With chip prefix */
+
+#define chip_emerg(chip, fmt, ...) \
+ pr_emerg("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_crit(chip, fmt, ...) \
+ pr_crit("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_err(chip, fmt, ...) \
+ pr_err("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_warn(chip, fmt, ...) \
+ pr_warn("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_info(chip, fmt, ...) \
+ pr_info("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+#define chip_dbg(chip, fmt, ...) \
+ pr_debug("GPIO chip %s: " fmt, chip->label, ##__VA_ARGS__)
+
static inline void desc_set_label(struct gpio_desc *d, const char *label)
{
#ifdef CONFIG_DEBUG_FS
@@ -83,6 +143,51 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
#endif
}
+/*
+ * Return the GPIO number of the passed descriptor relative to its chip
+ */
+static int gpio_chip_hwgpio(const struct gpio_desc *desc)
+{
+ return desc - &desc->chip->desc[0];
+}
+
+/**
+ * Convert a GPIO number to its descriptor
+ */
+struct gpio_desc *gpio_to_desc(unsigned gpio)
+{
+ if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
+ return NULL;
+ else
+ return &gpio_desc[gpio];
+}
+EXPORT_SYMBOL_GPL(gpio_to_desc);
+
+/**
+ * Get the GPIO descriptor corresponding to the given hw number for this chip.
+ */
+struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
+ u16 hwnum)
+{
+ if (hwnum >= chip->ngpio)
+ return ERR_PTR(-EINVAL);
+
+ return &chip->desc[hwnum];
+}
+EXPORT_SYMBOL_GPL(gpiochip_get_desc);
+
+/**
+ * Convert a GPIO descriptor to the integer namespace.
+ * This should disappear in the future but is needed since we still
+ * use GPIO numbers for error messages and sysfs nodes
+ */
+int desc_to_gpio(const struct gpio_desc *desc)
+{
+ return desc - &gpio_desc[0];
+}
+EXPORT_SYMBOL_GPL(desc_to_gpio);
+
+
/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
* when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when
@@ -94,15 +199,16 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
* only "legal" in the sense that (old) code using it won't break yet,
* but instead only triggers a WARN() stack dump.
*/
-static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
+static int gpio_ensure_requested(struct gpio_desc *desc)
{
const struct gpio_chip *chip = desc->chip;
- const int gpio = chip->base + offset;
+ const int gpio = desc_to_gpio(desc);
if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0,
"autorequest GPIO-%d\n", gpio)) {
if (!try_module_get(chip->owner)) {
- pr_err("GPIO-%d: module can't be gotten \n", gpio);
+ gpiod_err(desc, "%s: module can't be gotten\n",
+ __func__);
clear_bit(FLAG_REQUESTED, &desc->flags);
/* lose */
return -EIO;
@@ -115,81 +221,75 @@ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
return 0;
}
-/* caller holds gpio_lock *OR* gpio is marked as requested */
-struct gpio_chip *gpio_to_chip(unsigned gpio)
+/**
+ * gpiod_to_chip - Return the GPIO chip to which a GPIO descriptor belongs
+ * @desc: descriptor to return the chip of
+ */
+struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
{
- return gpio_desc[gpio].chip;
+ return desc ? desc->chip : NULL;
}
+EXPORT_SYMBOL_GPL(gpiod_to_chip);
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base(int ngpio)
{
- int i;
- int spare = 0;
- int base = -ENOSPC;
-
- for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) {
- struct gpio_desc *desc = &gpio_desc[i];
- struct gpio_chip *chip = desc->chip;
+ struct gpio_chip *chip;
+ int base = ARCH_NR_GPIOS - ngpio;
- if (!chip && !test_bit(FLAG_RESERVED, &desc->flags)) {
- spare++;
- if (spare == ngpio) {
- base = i;
- break;
- }
- } else {
- spare = 0;
- if (chip)
- i -= chip->ngpio - 1;
- }
+ list_for_each_entry_reverse(chip, &gpio_chips, list) {
+ /* found a free space? */
+ if (chip->base + chip->ngpio <= base)
+ break;
+ else
+ /* nope, check the space right before the chip */
+ base = chip->base - ngpio;
}
- if (gpio_is_valid(base))
+ if (gpio_is_valid(base)) {
pr_debug("%s: found new base at %d\n", __func__, base);
- return base;
+ return base;
+ } else {
+ pr_err("%s: cannot find free range\n", __func__);
+ return -ENOSPC;
+ }
}
/**
- * gpiochip_reserve() - reserve range of gpios to use with platform code only
- * @start: starting gpio number
- * @ngpio: number of gpios to reserve
- * Context: platform init, potentially before irqs or kmalloc will work
+ * gpiod_get_direction - return the current direction of a GPIO
+ * @desc: GPIO to get the direction of
+ *
+ * Return GPIOF_DIR_IN or GPIOF_DIR_OUT, or an error code in case of error.
*
- * Returns a negative errno if any gpio within the range is already reserved
- * or registered, else returns zero as a success code. Use this function
- * to mark a range of gpios as unavailable for dynamic gpio number allocation,
- * for example because its driver support is not yet loaded.
+ * This function may sleep if gpiod_cansleep() is true.
*/
-int __init gpiochip_reserve(int start, int ngpio)
+int gpiod_get_direction(const struct gpio_desc *desc)
{
- int ret = 0;
- unsigned long flags;
- int i;
-
- if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
- return -EINVAL;
-
- spin_lock_irqsave(&gpio_lock, flags);
+ struct gpio_chip *chip;
+ unsigned offset;
+ int status = -EINVAL;
- for (i = start; i < start + ngpio; i++) {
- struct gpio_desc *desc = &gpio_desc[i];
+ chip = gpiod_to_chip(desc);
+ offset = gpio_chip_hwgpio(desc);
- if (desc->chip || test_bit(FLAG_RESERVED, &desc->flags)) {
- ret = -EBUSY;
- goto err;
- }
+ if (!chip->get_direction)
+ return status;
- set_bit(FLAG_RESERVED, &desc->flags);
+ status = chip->get_direction(chip, offset);
+ if (status > 0) {
+ /* GPIOF_DIR_IN, or other positive */
+ status = 1;
+ /* FLAG_IS_OUT is just a cache of the result of get_direction(),
+ * so it does not affect constness per se */
+ clear_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
}
-
- pr_debug("%s: reserved gpios from %d to %d\n",
- __func__, start, start + ngpio - 1);
-err:
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- return ret;
+ if (status == 0) {
+ /* GPIOF_DIR_OUT */
+ set_bit(FLAG_IS_OUT, &((struct gpio_desc *)desc)->flags);
+ }
+ return status;
}
+EXPORT_SYMBOL_GPL(gpiod_get_direction);
#ifdef CONFIG_GPIO_SYSFS
@@ -227,12 +327,14 @@ static ssize_t gpio_direction_show(struct device *dev,
mutex_lock(&sysfs_lock);
- if (!test_bit(FLAG_EXPORT, &desc->flags))
+ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
status = -EIO;
- else
+ } else {
+ gpiod_get_direction(desc);
status = sprintf(buf, "%s\n",
test_bit(FLAG_IS_OUT, &desc->flags)
? "out" : "in");
+ }
mutex_unlock(&sysfs_lock);
return status;
@@ -241,8 +343,7 @@ static ssize_t gpio_direction_show(struct device *dev,
static ssize_t gpio_direction_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- unsigned gpio = desc - gpio_desc;
+ struct gpio_desc *desc = dev_get_drvdata(dev);
ssize_t status;
mutex_lock(&sysfs_lock);
@@ -250,11 +351,11 @@ static ssize_t gpio_direction_store(struct device *dev,
if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
else if (sysfs_streq(buf, "high"))
- status = gpio_direction_output(gpio, 1);
+ status = gpiod_direction_output_raw(desc, 1);
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
- status = gpio_direction_output(gpio, 0);
+ status = gpiod_direction_output_raw(desc, 0);
else if (sysfs_streq(buf, "in"))
- status = gpio_direction_input(gpio);
+ status = gpiod_direction_input(desc);
else
status = -EINVAL;
@@ -268,23 +369,15 @@ static /* const */ DEVICE_ATTR(direction, 0644,
static ssize_t gpio_value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- unsigned gpio = desc - gpio_desc;
+ struct gpio_desc *desc = dev_get_drvdata(dev);
ssize_t status;
mutex_lock(&sysfs_lock);
- if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+ if (!test_bit(FLAG_EXPORT, &desc->flags))
status = -EIO;
- } else {
- int value;
-
- value = !!gpio_get_value_cansleep(gpio);
- if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
- value = !value;
-
- status = sprintf(buf, "%d\n", value);
- }
+ else
+ status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
mutex_unlock(&sysfs_lock);
return status;
@@ -293,8 +386,7 @@ static ssize_t gpio_value_show(struct device *dev,
static ssize_t gpio_value_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
- const struct gpio_desc *desc = dev_get_drvdata(dev);
- unsigned gpio = desc - gpio_desc;
+ struct gpio_desc *desc = dev_get_drvdata(dev);
ssize_t status;
mutex_lock(&sysfs_lock);
@@ -306,11 +398,9 @@ static ssize_t gpio_value_store(struct device *dev,
else {
long value;
- status = strict_strtol(buf, 0, &value);
+ status = kstrtol(buf, 0, &value);
if (status == 0) {
- if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
- value = !value;
- gpio_set_value_cansleep(gpio, value != 0);
+ gpiod_set_value_cansleep(desc, value);
status = size;
}
}
@@ -324,7 +414,7 @@ static const DEVICE_ATTR(value, 0644,
static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
{
- struct sysfs_dirent *value_sd = priv;
+ struct kernfs_node *value_sd = priv;
sysfs_notify_dirent(value_sd);
return IRQ_HANDLED;
@@ -333,14 +423,14 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
unsigned long gpio_flags)
{
- struct sysfs_dirent *value_sd;
+ struct kernfs_node *value_sd;
unsigned long irq_flags;
int ret, irq, id;
if ((desc->flags & GPIO_TRIGGER_MASK) == gpio_flags)
return 0;
- irq = gpio_to_irq(desc - gpio_desc);
+ irq = gpiod_to_irq(desc);
if (irq < 0)
return -EIO;
@@ -352,6 +442,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
desc->flags &= ~GPIO_TRIGGER_MASK;
if (!gpio_flags) {
+ gpiod_unlock_as_irq(desc);
ret = 0;
goto free_id;
}
@@ -365,21 +456,16 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (!value_sd) {
- value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
+ value_sd = sysfs_get_dirent(dev->kobj.sd, "value");
if (!value_sd) {
ret = -ENODEV;
goto err_out;
}
- do {
- ret = -ENOMEM;
- if (idr_pre_get(&dirent_idr, GFP_KERNEL))
- ret = idr_get_new_above(&dirent_idr, value_sd,
- 1, &id);
- } while (ret == -EAGAIN);
-
- if (ret)
+ ret = idr_alloc(&dirent_idr, value_sd, 1, 0, GFP_KERNEL);
+ if (ret < 0)
goto free_sd;
+ id = ret;
desc->flags &= GPIO_FLAGS_MASK;
desc->flags |= (unsigned long)id << ID_SHIFT;
@@ -395,6 +481,12 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
if (ret < 0)
goto free_id;
+ ret = gpiod_lock_as_irq(desc);
+ if (ret < 0) {
+ gpiod_warn(desc, "failed to flag the GPIO for IRQ\n");
+ goto free_id;
+ }
+
desc->flags |= gpio_flags;
return 0;
@@ -532,7 +624,7 @@ static ssize_t gpio_active_low_store(struct device *dev,
} else {
long value;
- status = strict_strtol(buf, 0, &value);
+ status = kstrtol(buf, 0, &value);
if (status == 0)
status = sysfs_set_active_low(desc, dev, value != 0);
}
@@ -610,27 +702,37 @@ static ssize_t export_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t len)
{
- long gpio;
- int status;
+ long gpio;
+ struct gpio_desc *desc;
+ int status;
- status = strict_strtol(buf, 0, &gpio);
+ status = kstrtol(buf, 0, &gpio);
if (status < 0)
goto done;
+ desc = gpio_to_desc(gpio);
+ /* reject invalid GPIOs */
+ if (!desc) {
+ pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
+ return -EINVAL;
+ }
+
/* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so
* they may be undone on its behalf too.
*/
- status = gpio_request(gpio, "sysfs");
- if (status < 0)
+ status = gpiod_request(desc, "sysfs");
+ if (status < 0) {
+ if (status == -EPROBE_DEFER)
+ status = -ENODEV;
goto done;
-
- status = gpio_export(gpio, true);
+ }
+ status = gpiod_export(desc, true);
if (status < 0)
- gpio_free(gpio);
+ gpiod_free(desc);
else
- set_bit(FLAG_SYSFS, &gpio_desc[gpio].flags);
+ set_bit(FLAG_SYSFS, &desc->flags);
done:
if (status)
@@ -642,26 +744,30 @@ static ssize_t unexport_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t len)
{
- long gpio;
- int status;
+ long gpio;
+ struct gpio_desc *desc;
+ int status;
- status = strict_strtol(buf, 0, &gpio);
+ status = kstrtol(buf, 0, &gpio);
if (status < 0)
goto done;
- status = -EINVAL;
-
+ desc = gpio_to_desc(gpio);
/* reject bogus commands (gpio_unexport ignores them) */
- if (!gpio_is_valid(gpio))
- goto done;
+ if (!desc) {
+ pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
+ return -EINVAL;
+ }
+
+ status = -EINVAL;
/* No extra locking here; FLAG_SYSFS just signifies that the
* request and export were done by on behalf of userspace, so
* they may be undone on its behalf too.
*/
- if (test_and_clear_bit(FLAG_SYSFS, &gpio_desc[gpio].flags)) {
+ if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
status = 0;
- gpio_free(gpio);
+ gpiod_free(desc);
}
done:
if (status)
@@ -684,7 +790,7 @@ static struct class gpio_class = {
/**
- * gpio_export - export a GPIO through sysfs
+ * gpiod_export - export a GPIO through sysfs
* @gpio: gpio to make available, already requested
* @direction_may_change: true if userspace may change gpio direction
* Context: arch_initcall or later
@@ -698,12 +804,13 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-int gpio_export(unsigned gpio, bool direction_may_change)
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
{
unsigned long flags;
- struct gpio_desc *desc;
- int status = -EINVAL;
+ int status;
const char *ioname = NULL;
+ struct device *dev;
+ int offset;
/* can't export until sysfs is available ... */
if (!gpio_class.p) {
@@ -711,70 +818,78 @@ int gpio_export(unsigned gpio, bool direction_may_change)
return -ENOENT;
}
- if (!gpio_is_valid(gpio))
- goto done;
+ if (!desc) {
+ pr_debug("%s: invalid gpio descriptor\n", __func__);
+ return -EINVAL;
+ }
mutex_lock(&sysfs_lock);
spin_lock_irqsave(&gpio_lock, flags);
- desc = &gpio_desc[gpio];
- if (test_bit(FLAG_REQUESTED, &desc->flags)
- && !test_bit(FLAG_EXPORT, &desc->flags)) {
- status = 0;
- if (!desc->chip->direction_input
- || !desc->chip->direction_output)
- direction_may_change = false;
+ if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
+ test_bit(FLAG_EXPORT, &desc->flags)) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)\n",
+ __func__,
+ test_bit(FLAG_REQUESTED, &desc->flags),
+ test_bit(FLAG_EXPORT, &desc->flags));
+ status = -EPERM;
+ goto fail_unlock;
}
+
+ if (!desc->chip->direction_input || !desc->chip->direction_output)
+ direction_may_change = false;
spin_unlock_irqrestore(&gpio_lock, flags);
- if (desc->chip->names && desc->chip->names[gpio - desc->chip->base])
- ioname = desc->chip->names[gpio - desc->chip->base];
+ offset = gpio_chip_hwgpio(desc);
+ if (desc->chip->names && desc->chip->names[offset])
+ ioname = desc->chip->names[offset];
- if (status == 0) {
- struct device *dev;
-
- dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
- desc, ioname ? ioname : "gpio%u", gpio);
- if (!IS_ERR(dev)) {
- status = sysfs_create_group(&dev->kobj,
- &gpio_attr_group);
-
- if (!status && direction_may_change)
- status = device_create_file(dev,
- &dev_attr_direction);
-
- if (!status && gpio_to_irq(gpio) >= 0
- && (direction_may_change
- || !test_bit(FLAG_IS_OUT,
- &desc->flags)))
- status = device_create_file(dev,
- &dev_attr_edge);
-
- if (status != 0)
- device_unregister(dev);
- } else
- status = PTR_ERR(dev);
- if (status == 0)
- set_bit(FLAG_EXPORT, &desc->flags);
+ dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
+ desc, ioname ? ioname : "gpio%u",
+ desc_to_gpio(desc));
+ if (IS_ERR(dev)) {
+ status = PTR_ERR(dev);
+ goto fail_unlock;
}
- mutex_unlock(&sysfs_lock);
-
-done:
+ status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
if (status)
- pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+ goto fail_unregister_device;
+
+ if (direction_may_change) {
+ status = device_create_file(dev, &dev_attr_direction);
+ if (status)
+ goto fail_unregister_device;
+ }
+
+ if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
+ !test_bit(FLAG_IS_OUT, &desc->flags))) {
+ status = device_create_file(dev, &dev_attr_edge);
+ if (status)
+ goto fail_unregister_device;
+ }
+
+ set_bit(FLAG_EXPORT, &desc->flags);
+ mutex_unlock(&sysfs_lock);
+ return 0;
+fail_unregister_device:
+ device_unregister(dev);
+fail_unlock:
+ mutex_unlock(&sysfs_lock);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_export);
+EXPORT_SYMBOL_GPL(gpiod_export);
-static int match_export(struct device *dev, void *data)
+static int match_export(struct device *dev, const void *data)
{
return dev_get_drvdata(dev) == data;
}
/**
- * gpio_export_link - create a sysfs link to an exported GPIO node
+ * gpiod_export_link - create a sysfs link to an exported GPIO node
* @dev: device under which to create symlink
* @name: name of the symlink
* @gpio: gpio to create symlink to, already exported
@@ -784,18 +899,18 @@ static int match_export(struct device *dev, void *data)
*
* Returns zero on success, else an error.
*/
-int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
+int gpiod_export_link(struct device *dev, const char *name,
+ struct gpio_desc *desc)
{
- struct gpio_desc *desc;
int status = -EINVAL;
- if (!gpio_is_valid(gpio))
- goto done;
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
mutex_lock(&sysfs_lock);
- desc = &gpio_desc[gpio];
-
if (test_bit(FLAG_EXPORT, &desc->flags)) {
struct device *tdev;
@@ -810,17 +925,15 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
mutex_unlock(&sysfs_lock);
-done:
if (status)
- pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_export_link);
-
+EXPORT_SYMBOL_GPL(gpiod_export_link);
/**
- * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value
+ * gpiod_sysfs_set_active_low - set the polarity of gpio sysfs value
* @gpio: gpio to change
* @value: non-zero to use active low, i.e. inverted values
*
@@ -831,19 +944,18 @@ EXPORT_SYMBOL_GPL(gpio_export_link);
*
* Returns zero on success, else an error.
*/
-int gpio_sysfs_set_active_low(unsigned gpio, int value)
+int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
{
- struct gpio_desc *desc;
struct device *dev = NULL;
int status = -EINVAL;
- if (!gpio_is_valid(gpio))
- goto done;
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
mutex_lock(&sysfs_lock);
- desc = &gpio_desc[gpio];
-
if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export);
if (dev == NULL) {
@@ -857,35 +969,31 @@ int gpio_sysfs_set_active_low(unsigned gpio, int value)
unlock:
mutex_unlock(&sysfs_lock);
-done:
if (status)
- pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
+EXPORT_SYMBOL_GPL(gpiod_sysfs_set_active_low);
/**
- * gpio_unexport - reverse effect of gpio_export()
+ * gpiod_unexport - reverse effect of gpio_export()
* @gpio: gpio to make unavailable
*
* This is implicit on gpio_free().
*/
-void gpio_unexport(unsigned gpio)
+void gpiod_unexport(struct gpio_desc *desc)
{
- struct gpio_desc *desc;
int status = 0;
struct device *dev = NULL;
- if (!gpio_is_valid(gpio)) {
- status = -EINVAL;
- goto done;
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return;
}
mutex_lock(&sysfs_lock);
- desc = &gpio_desc[gpio];
-
if (test_bit(FLAG_EXPORT, &desc->flags)) {
dev = class_find_device(&gpio_class, NULL, desc, match_export);
@@ -897,15 +1005,16 @@ void gpio_unexport(unsigned gpio)
}
mutex_unlock(&sysfs_lock);
+
if (dev) {
device_unregister(dev);
put_device(dev);
}
-done:
+
if (status)
- pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
}
-EXPORT_SYMBOL_GPL(gpio_unexport);
+EXPORT_SYMBOL_GPL(gpiod_unexport);
static int gpiochip_export(struct gpio_chip *chip)
{
@@ -937,13 +1046,12 @@ static int gpiochip_export(struct gpio_chip *chip)
unsigned gpio;
spin_lock_irqsave(&gpio_lock, flags);
- gpio = chip->base;
- while (gpio_desc[gpio].chip == chip)
- gpio_desc[gpio++].chip = NULL;
+ gpio = 0;
+ while (gpio < chip->ngpio)
+ chip->desc[gpio++].chip = NULL;
spin_unlock_irqrestore(&gpio_lock, flags);
- pr_debug("%s: chip %s status %d\n", __func__,
- chip->label, status);
+ chip_dbg(chip, "%s: status %d\n", __func__, status);
}
return status;
@@ -959,22 +1067,21 @@ static void gpiochip_unexport(struct gpio_chip *chip)
if (dev) {
put_device(dev);
device_unregister(dev);
- chip->exported = 0;
+ chip->exported = false;
status = 0;
} else
status = -ENODEV;
mutex_unlock(&sysfs_lock);
if (status)
- pr_debug("%s: chip %s status %d\n", __func__,
- chip->label, status);
+ chip_dbg(chip, "%s: status %d\n", __func__, status);
}
static int __init gpiolib_sysfs_init(void)
{
int status;
unsigned long flags;
- unsigned gpio;
+ struct gpio_chip *chip;
status = class_register(&gpio_class);
if (status < 0)
@@ -987,10 +1094,7 @@ static int __init gpiolib_sysfs_init(void)
* registered, and so arch_initcall() can always gpio_export().
*/
spin_lock_irqsave(&gpio_lock, flags);
- for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
- struct gpio_chip *chip;
-
- chip = gpio_desc[gpio].chip;
+ list_for_each_entry(chip, &gpio_chips, list) {
if (!chip || chip->exported)
continue;
@@ -1017,6 +1121,43 @@ static inline void gpiochip_unexport(struct gpio_chip *chip)
#endif /* CONFIG_GPIO_SYSFS */
+/*
+ * Add a new chip to the global chips list, keeping the list of chips sorted
+ * by base order.
+ *
+ * Return -EBUSY if the new chip overlaps with some other chip's integer
+ * space.
+ */
+static int gpiochip_add_to_list(struct gpio_chip *chip)
+{
+ struct list_head *pos = &gpio_chips;
+ struct gpio_chip *_chip;
+ int err = 0;
+
+ /* find where to insert our chip */
+ list_for_each(pos, &gpio_chips) {
+ _chip = list_entry(pos, struct gpio_chip, list);
+ /* shall we insert before _chip? */
+ if (_chip->base >= chip->base + chip->ngpio)
+ break;
+ }
+
+ /* are we stepping on the chip right before? */
+ if (pos != &gpio_chips && pos->prev != &gpio_chips) {
+ _chip = list_entry(pos->prev, struct gpio_chip, list);
+ if (_chip->base + _chip->ngpio > chip->base) {
+ dev_err(chip->dev,
+ "GPIO integer space overlap, cannot add chip\n");
+ err = -EBUSY;
+ }
+ }
+
+ if (!err)
+ list_add_tail(&chip->list, pos);
+
+ return err;
+}
+
/**
* gpiochip_add() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
@@ -1058,34 +1199,37 @@ int gpiochip_add(struct gpio_chip *chip)
chip->base = base;
}
- /* these GPIO numbers must not be managed by another gpio_chip */
- for (id = base; id < base + chip->ngpio; id++) {
- if (gpio_desc[id].chip != NULL) {
- status = -EBUSY;
- break;
- }
- }
+ status = gpiochip_add_to_list(chip);
+
if (status == 0) {
- for (id = base; id < base + chip->ngpio; id++) {
- gpio_desc[id].chip = chip;
+ chip->desc = &gpio_desc[chip->base];
+
+ for (id = 0; id < chip->ngpio; id++) {
+ struct gpio_desc *desc = &chip->desc[id];
+ desc->chip = chip;
/* REVISIT: most hardware initializes GPIOs as
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
+ * and in case chip->get_direction is not set,
* we may expose the wrong direction in sysfs.
*/
- gpio_desc[id].flags = !chip->direction_input
+ desc->flags = !chip->direction_input
? (1 << FLAG_IS_OUT)
: 0;
}
}
- of_gpiochip_add(chip);
-
-unlock:
spin_unlock_irqrestore(&gpio_lock, flags);
+#ifdef CONFIG_PINCTRL
+ INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
+ of_gpiochip_add(chip);
+ acpi_gpiochip_add(chip);
+
if (status)
goto fail;
@@ -1093,20 +1237,26 @@ unlock:
if (status)
goto fail;
- pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
+ pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
return 0;
+
+unlock:
+ spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
- pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
+ pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
return status;
}
EXPORT_SYMBOL_GPL(gpiochip_add);
+/* Forward-declaration */
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+
/**
* gpiochip_remove() - unregister a gpio_chip
* @chip: the chip to unregister
@@ -1119,19 +1269,25 @@ int gpiochip_remove(struct gpio_chip *chip)
int status = 0;
unsigned id;
+ acpi_gpiochip_remove(chip);
+
spin_lock_irqsave(&gpio_lock, flags);
+ gpiochip_irqchip_remove(chip);
+ gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
- for (id = chip->base; id < chip->base + chip->ngpio; id++) {
- if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
+ for (id = 0; id < chip->ngpio; id++) {
+ if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
status = -EBUSY;
break;
}
}
if (status == 0) {
- for (id = chip->base; id < chip->base + chip->ngpio; id++)
- gpio_desc[id].chip = NULL;
+ for (id = 0; id < chip->ngpio; id++)
+ chip->desc[id].chip = NULL;
+
+ list_del(&chip->list);
}
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1158,49 +1314,397 @@ struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip,
void *data))
{
- struct gpio_chip *chip = NULL;
+ struct gpio_chip *chip;
unsigned long flags;
- int i;
spin_lock_irqsave(&gpio_lock, flags);
- for (i = 0; i < ARCH_NR_GPIOS; i++) {
- if (!gpio_desc[i].chip)
- continue;
-
- if (match(gpio_desc[i].chip, data)) {
- chip = gpio_desc[i].chip;
+ list_for_each_entry(chip, &gpio_chips, list)
+ if (match(chip, data))
break;
- }
- }
+
+ /* No match? */
+ if (&chip->list == &gpio_chips)
+ chip = NULL;
spin_unlock_irqrestore(&gpio_lock, flags);
return chip;
}
EXPORT_SYMBOL_GPL(gpiochip_find);
+static int gpiochip_match_name(struct gpio_chip *chip, void *data)
+{
+ const char *name = data;
+
+ return !strcmp(chip->label, name);
+}
+
+static struct gpio_chip *find_chip_by_name(const char *name)
+{
+ return gpiochip_find((void *)name, gpiochip_match_name);
+}
+
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+
+/*
+ * The following is irqchip helper code for gpiochips.
+ */
+
+/**
+ * gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
+ * @gpiochip: the gpiochip to add the irqchip to
+ * @irqchip: the irqchip to add to the gpiochip
+ * @parent_irq: the irq number corresponding to the parent IRQ for this
+ * chained irqchip
+ * @parent_handler: the parent interrupt handler for the accumulated IRQ
+ * coming out of the gpiochip
+ */
+void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ int parent_irq,
+ irq_flow_handler_t parent_handler)
+{
+ if (gpiochip->can_sleep) {
+ chip_err(gpiochip, "you cannot have chained interrupts on a chip that may sleep\n");
+ return;
+ }
+
+ irq_set_chained_handler(parent_irq, parent_handler);
+ /*
+ * The parent irqchip is already using the chip_data for this
+ * irqchip, so our callbacks simply use the handler_data.
+ */
+ irq_set_handler_data(parent_irq, gpiochip);
+}
+EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpiochip_irq_lock_class;
+
+/**
+ * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
+ * @d: the irqdomain used by this irqchip
+ * @irq: the global irq number used by this GPIO irqchip irq
+ * @hwirq: the local IRQ/GPIO line offset on this gpiochip
+ *
+ * This function will set up the mapping for a certain IRQ line on a
+ * gpiochip by assigning the gpiochip as chip data, and using the irqchip
+ * stored inside the gpiochip.
+ */
+static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct gpio_chip *chip = d->host_data;
+
+ irq_set_chip_data(irq, chip);
+ irq_set_lockdep_class(irq, &gpiochip_irq_lock_class);
+ irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+ /* Chips that can sleep need nested thread handlers */
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+ /*
+ * No set-up of the hardware will happen if IRQ_TYPE_NONE
+ * is passed as default type.
+ */
+ if (chip->irq_default_type != IRQ_TYPE_NONE)
+ irq_set_irq_type(irq, chip->irq_default_type);
+
+ return 0;
+}
+
+static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
+{
+ struct gpio_chip *chip = d->host_data;
+
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, 0);
+#endif
+ if (chip->can_sleep)
+ irq_set_nested_thread(irq, 0);
+ irq_set_chip_and_handler(irq, NULL, NULL);
+ irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops gpiochip_domain_ops = {
+ .map = gpiochip_irq_map,
+ .unmap = gpiochip_irq_unmap,
+ /* Virtually all GPIO irqchips are twocell:ed */
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static int gpiochip_irq_reqres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ if (gpio_lock_as_irq(chip, d->hwirq)) {
+ chip_err(chip,
+ "unable to lock HW IRQ %lu for IRQ\n",
+ d->hwirq);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void gpiochip_irq_relres(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+ gpio_unlock_as_irq(chip, d->hwirq);
+}
+
+static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_find_mapping(chip->irqdomain, offset);
+}
+
+/**
+ * gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
+ * @gpiochip: the gpiochip to remove the irqchip from
+ *
+ * This is called only from gpiochip_remove()
+ */
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
+{
+ unsigned int offset;
+
+ /* Remove all IRQ mappings and delete the domain */
+ if (gpiochip->irqdomain) {
+ for (offset = 0; offset < gpiochip->ngpio; offset++)
+ irq_dispose_mapping(gpiochip->irq_base + offset);
+ irq_domain_remove(gpiochip->irqdomain);
+ }
+
+ if (gpiochip->irqchip) {
+ gpiochip->irqchip->irq_request_resources = NULL;
+ gpiochip->irqchip->irq_release_resources = NULL;
+ gpiochip->irqchip = NULL;
+ }
+}
+
+/**
+ * gpiochip_irqchip_add() - adds an irqchip to a gpiochip
+ * @gpiochip: the gpiochip to add the irqchip to
+ * @irqchip: the irqchip to add to the gpiochip
+ * @first_irq: if not dynamically assigned, the base (first) IRQ to
+ * allocate gpiochip irqs from
+ * @handler: the irq handler to use (often a predefined irq core function)
+ * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
+ * to have the core avoid setting up any default type in the hardware.
+ *
+ * This function closely associates a certain irqchip with a certain
+ * gpiochip, providing an irq domain to translate the local IRQs to
+ * global irqs in the gpiolib core, and making sure that the gpiochip
+ * is passed as chip data to all related functions. Driver callbacks
+ * need to use container_of() to get their local state containers back
+ * from the gpiochip passed as chip data. An irqdomain will be stored
+ * in the gpiochip that shall be used by the driver to handle IRQ number
+ * translation. The gpiochip will need to be initialized and registered
+ * before calling this function.
+ *
+ * This function will handle two cell:ed simple IRQs and assumes all
+ * the pins on the gpiochip can generate a unique IRQ. Everything else
+ * need to be open coded.
+ */
+int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type)
+{
+ struct device_node *of_node;
+ unsigned int offset;
+ unsigned irq_base = 0;
+
+ if (!gpiochip || !irqchip)
+ return -EINVAL;
+
+ if (!gpiochip->dev) {
+ pr_err("missing gpiochip .dev parent pointer\n");
+ return -EINVAL;
+ }
+ of_node = gpiochip->dev->of_node;
+#ifdef CONFIG_OF_GPIO
+ /*
+ * If the gpiochip has an assigned OF node this takes precendence
+ * FIXME: get rid of this and use gpiochip->dev->of_node everywhere
+ */
+ if (gpiochip->of_node)
+ of_node = gpiochip->of_node;
+#endif
+ gpiochip->irqchip = irqchip;
+ gpiochip->irq_handler = handler;
+ gpiochip->irq_default_type = type;
+ gpiochip->to_irq = gpiochip_to_irq;
+ gpiochip->irqdomain = irq_domain_add_simple(of_node,
+ gpiochip->ngpio, first_irq,
+ &gpiochip_domain_ops, gpiochip);
+ if (!gpiochip->irqdomain) {
+ gpiochip->irqchip = NULL;
+ return -EINVAL;
+ }
+ irqchip->irq_request_resources = gpiochip_irq_reqres;
+ irqchip->irq_release_resources = gpiochip_irq_relres;
+
+ /*
+ * Prepare the mapping since the irqchip shall be orthogonal to
+ * any gpiochip calls. If the first_irq was zero, this is
+ * necessary to allocate descriptors for all IRQs.
+ */
+ for (offset = 0; offset < gpiochip->ngpio; offset++) {
+ irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
+ if (offset == 0)
+ /*
+ * Store the base into the gpiochip to be used when
+ * unmapping the irqs.
+ */
+ gpiochip->irq_base = irq_base;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
+
+#else /* CONFIG_GPIOLIB_IRQCHIP */
+
+static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
+
+#endif /* CONFIG_GPIOLIB_IRQCHIP */
+
+#ifdef CONFIG_PINCTRL
+
+/**
+ * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping
+ * @chip: the gpiochip to add the range for
+ * @pinctrl: the dev_name() of the pin controller to map to
+ * @gpio_offset: the start offset in the current gpio_chip number space
+ * @pin_group: name of the pin group inside the pin controller
+ */
+int gpiochip_add_pingroup_range(struct gpio_chip *chip,
+ struct pinctrl_dev *pctldev,
+ unsigned int gpio_offset, const char *pin_group)
+{
+ struct gpio_pin_range *pin_range;
+ int ret;
+
+ pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
+ if (!pin_range) {
+ chip_err(chip, "failed to allocate pin ranges\n");
+ return -ENOMEM;
+ }
+
+ /* Use local offset as range ID */
+ pin_range->range.id = gpio_offset;
+ pin_range->range.gc = chip;
+ pin_range->range.name = chip->label;
+ pin_range->range.base = chip->base + gpio_offset;
+ pin_range->pctldev = pctldev;
+
+ ret = pinctrl_get_group_pins(pctldev, pin_group,
+ &pin_range->range.pins,
+ &pin_range->range.npins);
+ if (ret < 0) {
+ kfree(pin_range);
+ return ret;
+ }
+
+ pinctrl_add_gpio_range(pctldev, &pin_range->range);
+
+ chip_dbg(chip, "created GPIO range %d->%d ==> %s PINGRP %s\n",
+ gpio_offset, gpio_offset + pin_range->range.npins - 1,
+ pinctrl_dev_get_devname(pctldev), pin_group);
+
+ list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
+
+/**
+ * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
+ * @chip: the gpiochip to add the range for
+ * @pinctrl_name: the dev_name() of the pin controller to map to
+ * @gpio_offset: the start offset in the current gpio_chip number space
+ * @pin_offset: the start offset in the pin controller number space
+ * @npins: the number of pins from the offset of each pin space (GPIO and
+ * pin controller) to accumulate in this range
+ */
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins)
+{
+ struct gpio_pin_range *pin_range;
+ int ret;
+
+ pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
+ if (!pin_range) {
+ chip_err(chip, "failed to allocate pin ranges\n");
+ return -ENOMEM;
+ }
+
+ /* Use local offset as range ID */
+ pin_range->range.id = gpio_offset;
+ pin_range->range.gc = chip;
+ pin_range->range.name = chip->label;
+ pin_range->range.base = chip->base + gpio_offset;
+ pin_range->range.pin_base = pin_offset;
+ pin_range->range.npins = npins;
+ pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
+ &pin_range->range);
+ if (IS_ERR(pin_range->pctldev)) {
+ ret = PTR_ERR(pin_range->pctldev);
+ chip_err(chip, "could not create pin range\n");
+ kfree(pin_range);
+ return ret;
+ }
+ chip_dbg(chip, "created GPIO range %d->%d ==> %s PIN %d->%d\n",
+ gpio_offset, gpio_offset + npins - 1,
+ pinctl_name,
+ pin_offset, pin_offset + npins - 1);
+
+ list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+/**
+ * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
+ * @chip: the chip to remove all the mappings for
+ */
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+ struct gpio_pin_range *pin_range, *tmp;
+
+ list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
+ list_del(&pin_range->node);
+ pinctrl_remove_gpio_range(pin_range->pctldev,
+ &pin_range->range);
+ kfree(pin_range);
+ }
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
+
+#endif /* CONFIG_PINCTRL */
+
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls.
*/
-int gpio_request(unsigned gpio, const char *label)
+static int __gpiod_request(struct gpio_desc *desc, const char *label)
{
- struct gpio_desc *desc;
- struct gpio_chip *chip;
- int status = -EPROBE_DEFER;
+ struct gpio_chip *chip = desc->chip;
+ int status;
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
- if (!gpio_is_valid(gpio))
- goto done;
- desc = &gpio_desc[gpio];
- chip = desc->chip;
- if (chip == NULL)
- goto done;
-
- if (!try_module_get(chip->owner))
- goto done;
-
/* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
*/
@@ -1210,68 +1714,108 @@ int gpio_request(unsigned gpio, const char *label)
status = 0;
} else {
status = -EBUSY;
- module_put(chip->owner);
goto done;
}
if (chip->request) {
/* chip->request may sleep */
spin_unlock_irqrestore(&gpio_lock, flags);
- status = chip->request(chip, gpio - chip->base);
+ status = chip->request(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags);
if (status < 0) {
desc_set_label(desc, NULL);
- module_put(chip->owner);
clear_bit(FLAG_REQUESTED, &desc->flags);
+ goto done;
}
}
+ if (chip->get_direction) {
+ /* chip->get_direction may sleep */
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_get_direction(desc);
+ spin_lock_irqsave(&gpio_lock, flags);
+ }
+done:
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return status;
+}
+
+static int gpiod_request(struct gpio_desc *desc, const char *label)
+{
+ int status = -EPROBE_DEFER;
+ struct gpio_chip *chip;
+
+ if (!desc) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+
+ chip = desc->chip;
+ if (!chip)
+ goto done;
+
+ if (try_module_get(chip->owner)) {
+ status = __gpiod_request(desc, label);
+ if (status < 0)
+ module_put(chip->owner);
+ }
done:
if (status)
- pr_debug("gpio_request: gpio-%d (%s) status %d\n",
- gpio, label ? : "?", status);
- spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+
return status;
}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ return gpiod_request(gpio_to_desc(gpio), label);
+}
EXPORT_SYMBOL_GPL(gpio_request);
-void gpio_free(unsigned gpio)
+static bool __gpiod_free(struct gpio_desc *desc)
{
+ bool ret = false;
unsigned long flags;
- struct gpio_desc *desc;
struct gpio_chip *chip;
might_sleep();
- if (!gpio_is_valid(gpio)) {
- WARN_ON(extra_checks);
- return;
- }
-
- gpio_unexport(gpio);
+ gpiod_unexport(desc);
spin_lock_irqsave(&gpio_lock, flags);
- desc = &gpio_desc[gpio];
chip = desc->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
if (chip->free) {
spin_unlock_irqrestore(&gpio_lock, flags);
might_sleep_if(chip->can_sleep);
- chip->free(chip, gpio - chip->base);
+ chip->free(chip, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags);
}
desc_set_label(desc, NULL);
- module_put(desc->chip->owner);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
- } else
- WARN_ON(extra_checks);
+ ret = true;
+ }
spin_unlock_irqrestore(&gpio_lock, flags);
+ return ret;
+}
+
+static void gpiod_free(struct gpio_desc *desc)
+{
+ if (desc && __gpiod_free(desc))
+ module_put(desc->chip->owner);
+ else
+ WARN_ON(extra_checks);
+}
+
+void gpio_free(unsigned gpio)
+{
+ gpiod_free(gpio_to_desc(gpio));
}
EXPORT_SYMBOL_GPL(gpio_free);
@@ -1283,29 +1827,32 @@ EXPORT_SYMBOL_GPL(gpio_free);
*/
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
{
+ struct gpio_desc *desc;
int err;
- err = gpio_request(gpio, label);
+ desc = gpio_to_desc(gpio);
+
+ err = gpiod_request(desc, label);
if (err)
return err;
if (flags & GPIOF_OPEN_DRAIN)
- set_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags);
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
if (flags & GPIOF_OPEN_SOURCE)
- set_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags);
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
if (flags & GPIOF_DIR_IN)
- err = gpio_direction_input(gpio);
+ err = gpiod_direction_input(desc);
else
- err = gpio_direction_output(gpio,
+ err = gpiod_direction_output_raw(desc,
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err)
goto free_gpio;
if (flags & GPIOF_EXPORT) {
- err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE);
+ err = gpiod_export(desc, flags & GPIOF_EXPORT_CHANGEABLE);
if (err)
goto free_gpio;
}
@@ -1313,7 +1860,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
return 0;
free_gpio:
- gpio_free(gpio);
+ gpiod_free(desc);
return err;
}
EXPORT_SYMBOL_GPL(gpio_request_one);
@@ -1368,20 +1915,54 @@ EXPORT_SYMBOL_GPL(gpio_free_array);
*/
const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
{
- unsigned gpio = chip->base + offset;
+ struct gpio_desc *desc;
- if (!gpio_is_valid(gpio) || gpio_desc[gpio].chip != chip)
+ if (!GPIO_OFFSET_VALID(chip, offset))
return NULL;
- if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
+
+ desc = &chip->desc[offset];
+
+ if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
return NULL;
#ifdef CONFIG_DEBUG_FS
- return gpio_desc[gpio].label;
+ return desc->label;
#else
return "?";
#endif
}
EXPORT_SYMBOL_GPL(gpiochip_is_requested);
+/**
+ * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor
+ * @desc: GPIO descriptor to request
+ * @label: label for the GPIO
+ *
+ * Function allows GPIO chip drivers to request and use their own GPIO
+ * descriptors via gpiolib API. Difference to gpiod_request() is that this
+ * function will not increase reference count of the GPIO chip module. This
+ * allows the GPIO chip module to be unloaded as needed (we assume that the
+ * GPIO chip driver handles freeing the GPIOs it has requested).
+ */
+int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
+{
+ if (!desc || !desc->chip)
+ return -EINVAL;
+
+ return __gpiod_request(desc, label);
+}
+
+/**
+ * gpiochip_free_own_desc - Free GPIO requested by the chip driver
+ * @desc: GPIO descriptor to free
+ *
+ * Function frees the given GPIO requested previously with
+ * gpiochip_request_own_desc().
+ */
+void gpiochip_free_own_desc(struct gpio_desc *desc)
+{
+ if (desc)
+ __gpiod_free(desc);
+}
/* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled.
@@ -1392,24 +1973,38 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
* rely on gpio_request() having been called beforehand.
*/
-int gpio_direction_input(unsigned gpio)
+/**
+ * gpiod_direction_input - set the GPIO direction to input
+ * @desc: GPIO to set to input
+ *
+ * Set the direction of the passed GPIO to input, such as gpiod_get_value() can
+ * be called safely on it.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_input(struct gpio_desc *desc)
{
unsigned long flags;
struct gpio_chip *chip;
- struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
+ int offset;
- spin_lock_irqsave(&gpio_lock, flags);
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
- if (!gpio_is_valid(gpio))
- goto fail;
chip = desc->chip;
- if (!chip || !chip->get || !chip->direction_input)
- goto fail;
- gpio -= chip->base;
- if (gpio >= chip->ngpio)
- goto fail;
- status = gpio_ensure_requested(desc, gpio);
+ if (!chip->get || !chip->direction_input) {
+ gpiod_warn(desc,
+ "%s: missing get() or direction_input() operations\n",
+ __func__);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ status = gpio_ensure_requested(desc);
if (status < 0)
goto fail;
@@ -1419,11 +2014,12 @@ int gpio_direction_input(unsigned gpio)
might_sleep_if(chip->can_sleep);
+ offset = gpio_chip_hwgpio(desc);
if (status) {
- status = chip->request(chip, gpio);
+ status = chip->request(chip, offset);
if (status < 0) {
- pr_debug("GPIO-%d: chip request fail, %d\n",
- chip->base + gpio, status);
+ gpiod_dbg(desc, "%s: chip request fail, %d\n",
+ __func__, status);
/* and it's not available to anyone else ...
* gpio_request() is the fully clean solution.
*/
@@ -1431,48 +2027,55 @@ int gpio_direction_input(unsigned gpio)
}
}
- status = chip->direction_input(chip, gpio);
+ status = chip->direction_input(chip, offset);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
- trace_gpio_direction(chip->base + gpio, 1, status);
+ trace_gpio_direction(desc_to_gpio(desc), 1, status);
lose:
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
- pr_debug("%s: gpio-%d status %d\n",
- __func__, gpio, status);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_direction_input);
+EXPORT_SYMBOL_GPL(gpiod_direction_input);
-int gpio_direction_output(unsigned gpio, int value)
+static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
unsigned long flags;
struct gpio_chip *chip;
- struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
+ int offset;
+
+ /* GPIOs used for IRQs shall not be set as output */
+ if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
+ gpiod_err(desc,
+ "%s: tried to set a GPIO tied to an IRQ as output\n",
+ __func__);
+ return -EIO;
+ }
/* Open drain pin should not be driven to 1 */
if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
- return gpio_direction_input(gpio);
+ return gpiod_direction_input(desc);
/* Open source pin should not be driven to 0 */
if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
- return gpio_direction_input(gpio);
+ return gpiod_direction_input(desc);
+
+ chip = desc->chip;
+ if (!chip->set || !chip->direction_output) {
+ gpiod_warn(desc,
+ "%s: missing set() or direction_output() operations\n",
+ __func__);
+ return -EIO;
+ }
spin_lock_irqsave(&gpio_lock, flags);
- if (!gpio_is_valid(gpio))
- goto fail;
- chip = desc->chip;
- if (!chip || !chip->set || !chip->direction_output)
- goto fail;
- gpio -= chip->base;
- if (gpio >= chip->ngpio)
- goto fail;
- status = gpio_ensure_requested(desc, gpio);
+ status = gpio_ensure_requested(desc);
if (status < 0)
goto fail;
@@ -1482,11 +2085,12 @@ int gpio_direction_output(unsigned gpio, int value)
might_sleep_if(chip->can_sleep);
+ offset = gpio_chip_hwgpio(desc);
if (status) {
- status = chip->request(chip, gpio);
+ status = chip->request(chip, offset);
if (status < 0) {
- pr_debug("GPIO-%d: chip request fail, %d\n",
- chip->base + gpio, status);
+ gpiod_dbg(desc, "%s: chip request fail, %d\n",
+ __func__, status);
/* and it's not available to anyone else ...
* gpio_request() is the fully clean solution.
*/
@@ -1494,45 +2098,96 @@ int gpio_direction_output(unsigned gpio, int value)
}
}
- status = chip->direction_output(chip, gpio, value);
+ status = chip->direction_output(chip, offset, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
- trace_gpio_value(chip->base + gpio, 0, value);
- trace_gpio_direction(chip->base + gpio, 0, status);
+ trace_gpio_value(desc_to_gpio(desc), 0, value);
+ trace_gpio_direction(desc_to_gpio(desc), 0, status);
lose:
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
- pr_debug("%s: gpio-%d status %d\n",
- __func__, gpio, status);
+ gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_direction_output);
/**
- * gpio_set_debounce - sets @debounce time for a @gpio
+ * gpiod_direction_output_raw - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as raw value on the physical line without regard for the ACTIVE_LOW status.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
+{
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+ return _gpiod_direction_output_raw(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
+
+/**
+ * gpiod_direction_output - set the GPIO direction to output
+ * @desc: GPIO to set to output
+ * @value: initial output value of the GPIO
+ *
+ * Set the direction of the passed GPIO to output, such as gpiod_set_value() can
+ * be called safely on it. The initial value of the output must be specified
+ * as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_direction_output(struct gpio_desc *desc, int value)
+{
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+ return _gpiod_direction_output_raw(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_direction_output);
+
+/**
+ * gpiod_set_debounce - sets @debounce time for a @gpio
* @gpio: the gpio to set debounce time
* @debounce: debounce time is microseconds
+ *
+ * returns -ENOTSUPP if the controller does not support setting
+ * debounce.
*/
-int gpio_set_debounce(unsigned gpio, unsigned debounce)
+int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
{
unsigned long flags;
struct gpio_chip *chip;
- struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
+ int offset;
- spin_lock_irqsave(&gpio_lock, flags);
+ if (!desc || !desc->chip) {
+ pr_warn("%s: invalid GPIO\n", __func__);
+ return -EINVAL;
+ }
- if (!gpio_is_valid(gpio))
- goto fail;
chip = desc->chip;
- if (!chip || !chip->set || !chip->set_debounce)
- goto fail;
- gpio -= chip->base;
- if (gpio >= chip->ngpio)
- goto fail;
- status = gpio_ensure_requested(desc, gpio);
+ if (!chip->set || !chip->set_debounce) {
+ gpiod_dbg(desc,
+ "%s: missing set() or set_debounce() operations\n",
+ __func__);
+ return -ENOTSUPP;
+ }
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ status = gpio_ensure_requested(desc);
if (status < 0)
goto fail;
@@ -1542,17 +2197,29 @@ int gpio_set_debounce(unsigned gpio, unsigned debounce)
might_sleep_if(chip->can_sleep);
- return chip->set_debounce(chip, gpio, debounce);
+ offset = gpio_chip_hwgpio(desc);
+ return chip->set_debounce(chip, offset, debounce);
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
- pr_debug("%s: gpio-%d status %d\n",
- __func__, gpio, status);
+ gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
-EXPORT_SYMBOL_GPL(gpio_set_debounce);
+EXPORT_SYMBOL_GPL(gpiod_set_debounce);
+
+/**
+ * gpiod_is_active_low - test whether a GPIO is active-low or not
+ * @desc: the gpio descriptor to test
+ *
+ * Returns 1 if the GPIO is active-low, 0 otherwise.
+ */
+int gpiod_is_active_low(const struct gpio_desc *desc)
+{
+ return test_bit(FLAG_ACTIVE_LOW, &desc->flags);
+}
+EXPORT_SYMBOL_GPL(gpiod_is_active_low);
/* I/O calls are only valid after configuration completed; the relevant
* "is this a valid GPIO" error checks should already have been done.
@@ -1576,178 +2243,616 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
* that the GPIO was actually requested.
*/
+static bool _gpiod_get_raw_value(const struct gpio_desc *desc)
+{
+ struct gpio_chip *chip;
+ bool value;
+ int offset;
+
+ chip = desc->chip;
+ offset = gpio_chip_hwgpio(desc);
+ value = chip->get ? chip->get(chip, offset) : false;
+ trace_gpio_value(desc_to_gpio(desc), 1, value);
+ return value;
+}
+
/**
- * __gpio_get_value() - return a gpio's value
- * @gpio: gpio whose value will be returned
- * Context: any
+ * gpiod_get_raw_value() - return a gpio's raw value
+ * @desc: gpio whose value will be returned
*
- * This is used directly or indirectly to implement gpio_get_value().
- * It returns the zero or nonzero value provided by the associated
- * gpio_chip.get() method; or zero if no such method is provided.
+ * Return the GPIO's raw value, i.e. the value of the physical line disregarding
+ * its ACTIVE_LOW status.
+ *
+ * This function should be called from contexts where we cannot sleep, and will
+ * complain if the GPIO chip functions potentially sleep.
*/
-int __gpio_get_value(unsigned gpio)
+int gpiod_get_raw_value(const struct gpio_desc *desc)
{
- struct gpio_chip *chip;
- int value;
+ if (!desc)
+ return 0;
+ /* Should be using gpio_get_value_cansleep() */
+ WARN_ON(desc->chip->can_sleep);
+ return _gpiod_get_raw_value(desc);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_value);
- chip = gpio_to_chip(gpio);
+/**
+ * gpiod_get_value() - return a gpio's value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
+ * account.
+ *
+ * This function should be called from contexts where we cannot sleep, and will
+ * complain if the GPIO chip functions potentially sleep.
+ */
+int gpiod_get_value(const struct gpio_desc *desc)
+{
+ int value;
+ if (!desc)
+ return 0;
/* Should be using gpio_get_value_cansleep() */
- WARN_ON(chip->can_sleep);
- value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
- trace_gpio_value(gpio, 1, value);
+ WARN_ON(desc->chip->can_sleep);
+
+ value = _gpiod_get_raw_value(desc);
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+
return value;
}
-EXPORT_SYMBOL_GPL(__gpio_get_value);
+EXPORT_SYMBOL_GPL(gpiod_get_value);
/*
* _gpio_set_open_drain_value() - Set the open drain gpio's value.
- * @gpio: Gpio whose state need to be set.
- * @chip: Gpio chip.
+ * @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/
-static void _gpio_set_open_drain_value(unsigned gpio,
- struct gpio_chip *chip, int value)
+static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
{
int err = 0;
+ struct gpio_chip *chip = desc->chip;
+ int offset = gpio_chip_hwgpio(desc);
+
if (value) {
- err = chip->direction_input(chip, gpio - chip->base);
+ err = chip->direction_input(chip, offset);
if (!err)
- clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ clear_bit(FLAG_IS_OUT, &desc->flags);
} else {
- err = chip->direction_output(chip, gpio - chip->base, 0);
+ err = chip->direction_output(chip, offset, 0);
if (!err)
- set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ set_bit(FLAG_IS_OUT, &desc->flags);
}
- trace_gpio_direction(gpio, value, err);
+ trace_gpio_direction(desc_to_gpio(desc), value, err);
if (err < 0)
- pr_err("%s: Error in set_value for open drain gpio%d err %d\n",
- __func__, gpio, err);
+ gpiod_err(desc,
+ "%s: Error in set_value for open drain err %d\n",
+ __func__, err);
}
/*
- * _gpio_set_open_source() - Set the open source gpio's value.
- * @gpio: Gpio whose state need to be set.
- * @chip: Gpio chip.
+ * _gpio_set_open_source_value() - Set the open source gpio's value.
+ * @desc: gpio descriptor whose state need to be set.
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
*/
-static void _gpio_set_open_source_value(unsigned gpio,
- struct gpio_chip *chip, int value)
+static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
{
int err = 0;
+ struct gpio_chip *chip = desc->chip;
+ int offset = gpio_chip_hwgpio(desc);
+
if (value) {
- err = chip->direction_output(chip, gpio - chip->base, 1);
+ err = chip->direction_output(chip, offset, 1);
if (!err)
- set_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ set_bit(FLAG_IS_OUT, &desc->flags);
} else {
- err = chip->direction_input(chip, gpio - chip->base);
+ err = chip->direction_input(chip, offset);
if (!err)
- clear_bit(FLAG_IS_OUT, &gpio_desc[gpio].flags);
+ clear_bit(FLAG_IS_OUT, &desc->flags);
}
- trace_gpio_direction(gpio, !value, err);
+ trace_gpio_direction(desc_to_gpio(desc), !value, err);
if (err < 0)
- pr_err("%s: Error in set_value for open source gpio%d err %d\n",
- __func__, gpio, err);
+ gpiod_err(desc,
+ "%s: Error in set_value for open source err %d\n",
+ __func__, err);
}
+static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
+{
+ struct gpio_chip *chip;
+
+ chip = desc->chip;
+ trace_gpio_value(desc_to_gpio(desc), 0, value);
+ if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+ _gpio_set_open_drain_value(desc, value);
+ else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+ _gpio_set_open_source_value(desc, value);
+ else
+ chip->set(chip, gpio_chip_hwgpio(desc), value);
+}
/**
- * __gpio_set_value() - assign a gpio's value
- * @gpio: gpio whose value will be assigned
+ * gpiod_set_raw_value() - assign a gpio's raw value
+ * @desc: gpio whose value will be assigned
* @value: value to assign
- * Context: any
*
- * This is used directly or indirectly to implement gpio_set_value().
- * It invokes the associated gpio_chip.set() method.
+ * Set the raw value of the GPIO, i.e. the value of its physical line without
+ * regard for its ACTIVE_LOW status.
+ *
+ * This function should be called from contexts where we cannot sleep, and will
+ * complain if the GPIO chip functions potentially sleep.
*/
-void __gpio_set_value(unsigned gpio, int value)
+void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
- struct gpio_chip *chip;
+ if (!desc)
+ return;
+ /* Should be using gpio_set_value_cansleep() */
+ WARN_ON(desc->chip->can_sleep);
+ _gpiod_set_raw_value(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_raw_value);
- chip = gpio_to_chip(gpio);
+/**
+ * gpiod_set_value() - assign a gpio's value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account
+ *
+ * This function should be called from contexts where we cannot sleep, and will
+ * complain if the GPIO chip functions potentially sleep.
+ */
+void gpiod_set_value(struct gpio_desc *desc, int value)
+{
+ if (!desc)
+ return;
/* Should be using gpio_set_value_cansleep() */
- WARN_ON(chip->can_sleep);
- trace_gpio_value(gpio, 0, value);
- if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
- _gpio_set_open_drain_value(gpio, chip, value);
- else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
- _gpio_set_open_source_value(gpio, chip, value);
- else
- chip->set(chip, gpio - chip->base, value);
+ WARN_ON(desc->chip->can_sleep);
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+ _gpiod_set_raw_value(desc, value);
}
-EXPORT_SYMBOL_GPL(__gpio_set_value);
+EXPORT_SYMBOL_GPL(gpiod_set_value);
/**
- * __gpio_cansleep() - report whether gpio value access will sleep
- * @gpio: gpio in question
- * Context: any
+ * gpiod_cansleep() - report whether gpio value access may sleep
+ * @desc: gpio to check
*
- * This is used directly or indirectly to implement gpio_cansleep(). It
- * returns nonzero if access reading or writing the GPIO value can sleep.
*/
-int __gpio_cansleep(unsigned gpio)
+int gpiod_cansleep(const struct gpio_desc *desc)
{
- struct gpio_chip *chip;
+ if (!desc)
+ return 0;
+ return desc->chip->can_sleep;
+}
+EXPORT_SYMBOL_GPL(gpiod_cansleep);
- /* only call this on GPIOs that are valid! */
- chip = gpio_to_chip(gpio);
+/**
+ * gpiod_to_irq() - return the IRQ corresponding to a GPIO
+ * @desc: gpio whose IRQ will be returned (already requested)
+ *
+ * Return the IRQ corresponding to the passed GPIO, or an error code in case of
+ * error.
+ */
+int gpiod_to_irq(const struct gpio_desc *desc)
+{
+ struct gpio_chip *chip;
+ int offset;
- return chip->can_sleep;
+ if (!desc)
+ return -EINVAL;
+ chip = desc->chip;
+ offset = gpio_chip_hwgpio(desc);
+ return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
}
-EXPORT_SYMBOL_GPL(__gpio_cansleep);
+EXPORT_SYMBOL_GPL(gpiod_to_irq);
/**
- * __gpio_to_irq() - return the IRQ corresponding to a GPIO
- * @gpio: gpio whose IRQ will be returned (already requested)
- * Context: any
+ * gpiod_lock_as_irq() - lock a GPIO to be used as IRQ
+ * @gpio: the GPIO line to lock as used for IRQ
*
- * This is used directly or indirectly to implement gpio_to_irq().
- * It returns the number of the IRQ signaled by this (input) GPIO,
- * or a negative errno.
+ * This is used directly by GPIO drivers that want to lock down
+ * a certain GPIO line to be used for IRQs.
*/
-int __gpio_to_irq(unsigned gpio)
+int gpiod_lock_as_irq(struct gpio_desc *desc)
{
- struct gpio_chip *chip;
+ if (!desc)
+ return -EINVAL;
+
+ if (test_bit(FLAG_IS_OUT, &desc->flags)) {
+ gpiod_err(desc,
+ "%s: tried to flag a GPIO set as output for IRQ\n",
+ __func__);
+ return -EIO;
+ }
- chip = gpio_to_chip(gpio);
- return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+ set_bit(FLAG_USED_AS_IRQ, &desc->flags);
+ return 0;
}
-EXPORT_SYMBOL_GPL(__gpio_to_irq);
+EXPORT_SYMBOL_GPL(gpiod_lock_as_irq);
+int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset));
+}
+EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
+/**
+ * gpiod_unlock_as_irq() - unlock a GPIO used as IRQ
+ * @gpio: the GPIO line to unlock from IRQ usage
+ *
+ * This is used directly by GPIO drivers that want to indicate
+ * that a certain GPIO is no longer used exclusively for IRQ.
+ */
+void gpiod_unlock_as_irq(struct gpio_desc *desc)
+{
+ if (!desc)
+ return;
+
+ clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
+}
+EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq);
+
+void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
+{
+ return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset));
+}
+EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
-/* There's no value in making it easy to inline GPIO calls that may sleep.
- * Common examples include ones connected to I2C or SPI chips.
+/**
+ * gpiod_get_raw_value_cansleep() - return a gpio's raw value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's raw value, i.e. the value of the physical line disregarding
+ * its ACTIVE_LOW status.
+ *
+ * This function is to be called from contexts that can sleep.
*/
+int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
+{
+ might_sleep_if(extra_checks);
+ if (!desc)
+ return 0;
+ return _gpiod_get_raw_value(desc);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_raw_value_cansleep);
-int gpio_get_value_cansleep(unsigned gpio)
+/**
+ * gpiod_get_value_cansleep() - return a gpio's value
+ * @desc: gpio whose value will be returned
+ *
+ * Return the GPIO's logical value, i.e. taking the ACTIVE_LOW status into
+ * account.
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+int gpiod_get_value_cansleep(const struct gpio_desc *desc)
{
- struct gpio_chip *chip;
int value;
might_sleep_if(extra_checks);
- chip = gpio_to_chip(gpio);
- value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
- trace_gpio_value(gpio, 1, value);
+ if (!desc)
+ return 0;
+
+ value = _gpiod_get_raw_value(desc);
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+
return value;
}
-EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
+EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
-void gpio_set_value_cansleep(unsigned gpio, int value)
+/**
+ * gpiod_set_raw_value_cansleep() - assign a gpio's raw value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the raw value of the GPIO, i.e. the value of its physical line without
+ * regard for its ACTIVE_LOW status.
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
{
- struct gpio_chip *chip;
+ might_sleep_if(extra_checks);
+ if (!desc)
+ return;
+ _gpiod_set_raw_value(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep);
+/**
+ * gpiod_set_value_cansleep() - assign a gpio's value
+ * @desc: gpio whose value will be assigned
+ * @value: value to assign
+ *
+ * Set the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
+ * account
+ *
+ * This function is to be called from contexts that can sleep.
+ */
+void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
+{
might_sleep_if(extra_checks);
- chip = gpio_to_chip(gpio);
- trace_gpio_value(gpio, 0, value);
- if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
- _gpio_set_open_drain_value(gpio, chip, value);
- else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
- _gpio_set_open_source_value(gpio, chip, value);
- else
- chip->set(chip, gpio - chip->base, value);
+ if (!desc)
+ return;
+
+ if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+ value = !value;
+ _gpiod_set_raw_value(desc, value);
+}
+EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
+
+/**
+ * gpiod_add_lookup_table() - register GPIO device consumers
+ * @table: table of consumers to register
+ */
+void gpiod_add_lookup_table(struct gpiod_lookup_table *table)
+{
+ mutex_lock(&gpio_lookup_lock);
+
+ list_add_tail(&table->list, &gpio_lookup_list);
+
+ mutex_unlock(&gpio_lookup_lock);
+}
+
+static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
+ unsigned int idx,
+ enum gpio_lookup_flags *flags)
+{
+ static const char *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++) {
+ if (con_id)
+ snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]);
+ else
+ snprintf(prop_name, 32, "%s", suffixes[i]);
+
+ desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
+ &of_flags);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
+ *flags |= GPIO_ACTIVE_LOW;
+
+ return desc;
+}
+
+static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
+ unsigned int idx,
+ enum gpio_lookup_flags *flags)
+{
+ struct acpi_gpio_info info;
+ struct gpio_desc *desc;
+
+ desc = acpi_get_gpiod_by_index(dev, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+
+ if (info.gpioint && info.active_low)
+ *flags |= GPIO_ACTIVE_LOW;
+
+ return desc;
+}
+
+static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
+{
+ const char *dev_id = dev ? dev_name(dev) : NULL;
+ struct gpiod_lookup_table *table;
+
+ mutex_lock(&gpio_lookup_lock);
+
+ list_for_each_entry(table, &gpio_lookup_list, list) {
+ if (table->dev_id && dev_id) {
+ /*
+ * Valid strings on both ends, must be identical to have
+ * a match
+ */
+ if (!strcmp(table->dev_id, dev_id))
+ goto found;
+ } else {
+ /*
+ * One of the pointers is NULL, so both must be to have
+ * a match
+ */
+ if (dev_id == table->dev_id)
+ goto found;
+ }
+ }
+ table = NULL;
+
+found:
+ mutex_unlock(&gpio_lookup_lock);
+ return table;
+}
+
+static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
+ unsigned int idx,
+ enum gpio_lookup_flags *flags)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENOENT);
+ struct gpiod_lookup_table *table;
+ struct gpiod_lookup *p;
+
+ table = gpiod_find_lookup_table(dev);
+ if (!table)
+ return desc;
+
+ for (p = &table->table[0]; p->chip_label; p++) {
+ struct gpio_chip *chip;
+
+ /* idx must always match exactly */
+ if (p->idx != idx)
+ continue;
+
+ /* If the lookup entry has a con_id, require exact match */
+ if (p->con_id && (!con_id || strcmp(p->con_id, con_id)))
+ continue;
+
+ chip = find_chip_by_name(p->chip_label);
+
+ if (!chip) {
+ dev_err(dev, "cannot find GPIO chip %s\n",
+ p->chip_label);
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (chip->ngpio <= p->chip_hwnum) {
+ dev_err(dev,
+ "requested GPIO %d is out of range [0..%d] for chip %s\n",
+ idx, chip->ngpio, chip->label);
+ return ERR_PTR(-EINVAL);
+ }
+
+ desc = gpiochip_get_desc(chip, p->chip_hwnum);
+ *flags = p->flags;
+
+ return desc;
+ }
+
+ return desc;
+}
+
+/**
+ * gpiod_get - obtain a GPIO for a given GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ *
+ * Return the GPIO descriptor corresponding to the function con_id of device
+ * dev, -ENOENT if no GPIO has been assigned to the requested function, or
+ * another IS_ERR() code if an error occured while trying to acquire the GPIO.
+ */
+struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id)
+{
+ return gpiod_get_index(dev, con_id, 0);
+}
+EXPORT_SYMBOL_GPL(gpiod_get);
+
+/**
+ * gpiod_get_optional - obtain an optional GPIO for a given GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ *
+ * This is equivalent to gpiod_get(), except that when no GPIO was assigned to
+ * the requested function it will return NULL. This is convenient for drivers
+ * that need to handle optional GPIOs.
+ */
+struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
+ const char *con_id)
+{
+ return gpiod_get_index_optional(dev, con_id, 0);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_optional);
+
+/**
+ * gpiod_get_index - obtain a GPIO from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ *
+ * This variant of gpiod_get() allows to access GPIOs other than the first
+ * defined one for functions that define several GPIOs.
+ *
+ * Return a valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the
+ * requested function and/or index, or another IS_ERR() code if an error
+ * occured while trying to acquire the GPIO.
+ */
+struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
+ const char *con_id,
+ unsigned int idx)
+{
+ struct gpio_desc *desc = NULL;
+ int status;
+ enum gpio_lookup_flags flags = 0;
+
+ 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, &flags);
+ } 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, &flags);
+ }
+
+ /*
+ * Either we are not using DT or ACPI, or their lookup did not return
+ * a result. In that case, use platform lookup as a fallback.
+ */
+ if (!desc || desc == ERR_PTR(-ENOENT)) {
+ dev_dbg(dev, "using lookup tables for GPIO lookup");
+ desc = gpiod_find(dev, con_id, idx, &flags);
+ }
+
+ if (IS_ERR(desc)) {
+ dev_dbg(dev, "lookup for GPIO %s failed\n", con_id);
+ return desc;
+ }
+
+ status = gpiod_request(desc, con_id);
+
+ if (status < 0)
+ return ERR_PTR(status);
+
+ if (flags & GPIO_ACTIVE_LOW)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+ if (flags & GPIO_OPEN_DRAIN)
+ set_bit(FLAG_OPEN_DRAIN, &desc->flags);
+ if (flags & GPIO_OPEN_SOURCE)
+ set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+
+ return desc;
}
-EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
+EXPORT_SYMBOL_GPL(gpiod_get_index);
+/**
+ * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
+ * function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ *
+ * This is equivalent to gpiod_get_index(), except that when no GPIO with the
+ * specified index was assigned to the requested function it will return NULL.
+ * This is convenient for drivers that need to handle optional GPIOs.
+ */
+struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index)
+{
+ struct gpio_desc *desc;
+
+ desc = gpiod_get_index(dev, con_id, index);
+ if (IS_ERR(desc)) {
+ if (PTR_ERR(desc) == -ENOENT)
+ return NULL;
+ }
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_index_optional);
+
+/**
+ * gpiod_put - dispose of a GPIO descriptor
+ * @desc: GPIO descriptor to dispose of
+ *
+ * No descriptor can be used after gpiod_put() has been called on it.
+ */
+void gpiod_put(struct gpio_desc *desc)
+{
+ gpiod_free(desc);
+}
+EXPORT_SYMBOL_GPL(gpiod_put);
#ifdef CONFIG_DEBUG_FS
@@ -1755,66 +2860,59 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
unsigned i;
unsigned gpio = chip->base;
- struct gpio_desc *gdesc = &gpio_desc[gpio];
+ struct gpio_desc *gdesc = &chip->desc[0];
int is_out;
+ int is_irq;
for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
continue;
+ gpiod_get_direction(gdesc);
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
- seq_printf(s, " gpio-%-3d (%-20.20s) %s %s",
+ is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
+ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s",
gpio, gdesc->label,
is_out ? "out" : "in ",
chip->get
? (chip->get(chip, i) ? "hi" : "lo")
- : "? ");
+ : "? ",
+ is_irq ? "IRQ" : " ");
seq_printf(s, "\n");
}
}
static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
{
+ unsigned long flags;
struct gpio_chip *chip = NULL;
- unsigned int gpio;
- void *ret = NULL;
- loff_t index = 0;
-
- /* REVISIT this isn't locked against gpio_chip removal ... */
-
- for (gpio = 0; gpio_is_valid(gpio); gpio++) {
- if (gpio_desc[gpio].chip == chip)
- continue;
+ loff_t index = *pos;
- chip = gpio_desc[gpio].chip;
- if (!chip)
- continue;
+ s->private = "";
- if (index++ >= *pos) {
- ret = chip;
- break;
+ spin_lock_irqsave(&gpio_lock, flags);
+ list_for_each_entry(chip, &gpio_chips, list)
+ if (index-- == 0) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return chip;
}
- }
-
- s->private = "";
+ spin_unlock_irqrestore(&gpio_lock, flags);
- return ret;
+ return NULL;
}
static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
+ unsigned long flags;
struct gpio_chip *chip = v;
- unsigned int gpio;
void *ret = NULL;
- /* skip GPIOs provided by the current chip */
- for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
- chip = gpio_desc[gpio].chip;
- if (chip) {
- ret = chip;
- break;
- }
- }
+ spin_lock_irqsave(&gpio_lock, flags);
+ if (list_is_last(&chip->list, &gpio_chips))
+ ret = NULL;
+ else
+ ret = list_entry(chip->list.next, struct gpio_chip, list);
+ spin_unlock_irqrestore(&gpio_lock, flags);
s->private = "\n";
++*pos;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
new file mode 100644
index 00000000000..1a4103dd38d
--- /dev/null
+++ b/drivers/gpio/gpiolib.h
@@ -0,0 +1,54 @@
+/*
+ * Internal GPIO functions.
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef GPIOLIB_H
+#define GPIOLIB_H
+
+#include <linux/err.h>
+#include <linux/device.h>
+
+enum of_gpio_flags;
+
+/**
+ * struct acpi_gpio_info - ACPI GPIO specific information
+ * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
+ * @active_low: in case of @gpioint, the pin is active low
+ */
+struct acpi_gpio_info {
+ bool gpioint;
+ bool active_low;
+};
+
+#ifdef CONFIG_ACPI
+void acpi_gpiochip_add(struct gpio_chip *chip);
+void acpi_gpiochip_remove(struct gpio_chip *chip);
+
+struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+ struct acpi_gpio_info *info);
+#else
+static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
+static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
+
+static inline struct gpio_desc *
+acpi_get_gpiod_by_index(struct device *dev, int index,
+ struct acpi_gpio_info *info)
+{
+ return ERR_PTR(-ENOSYS);
+}
+#endif
+
+int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
+void gpiochip_free_own_desc(struct gpio_desc *desc);
+
+struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+ const char *list_name, int index, enum of_gpio_flags *flags);
+
+#endif /* GPIOLIB_H */