mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
This is the bulk of GPIO changes for v4.4:
GPIO core: - Define and handle flags for open drain/open collector and open source/open emitter, also know as "single-ended" configurations. - Generic request/free operations that handle calling out to the (optional) pin control backend. - Some refactoring related to an ABI change that did not happen, yet provide useful. - Added a real-time compliance checklist. Many GPIO chips have irqchips, and need to think this over with the RT patches going upstream. - Restructure, fix and clean up Kconfig menus a bit. New drivers: - New driver for AMD Promony. - New driver for ACCES 104-IDIO-16, a port-mapped I/O card, ISA-style. Very retro. Subdriver changes: - OMAP changes to handle real time requirements. - Handle trigger types for edge and level IRQs on PL061 properly. As this hardware is very common it needs to set a proper example for others to follow. - Some container_of() cleanups. - Delete the unused MSM driver in favor of the driver that is embedded inside the pin control driver. - Cleanup of the ath79 GPIO driver used by many, many OpenWRT router targets. - A consolidated IT87xx driver replacing the earlier very specific IT8761e driver. - Handle the TI TCA9539 in the PCA953x driver. Also handle ACPI devices in this subdriver. - Drop xilinx arch dependencies as these FPGAs seem to profilate over a few different architectures. MIPS and ARM come to mind. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJWNz3qAAoJEEEQszewGV1zKlAP/R+mVoQHyfDFurChDzuWQjZK T4eDiFGTHr/MUDP9I0jINF400SfEm3ajm3aoPvKc6fA2d7oLNB7TzyUxjDsQV4h8 NsCJ9IYD9xYgF6SDovPYPZ6SkRJYimDrwjD/DUSR8ijisVzJwYCyEGznelWKnQMo Fcw4kOTMrW0034ZT4nGH4kSgIzNAMcecazaaqLisniYZ/4Ozk1CQsrBK1gCO/kr8 Hh3N/mN4TBvOyIuD7lmN5PnWuJo641rplcWErjxUZYvqEddSfAnpasfAcXMkZ4gM jOK+l7VIycxOAn+EJwqjyVPJ0gDPPaMwB836gogzNraO2SYd/R2JvyI2zyTogmdW MNwsKwP2b/ma/h0A/JBDFmcMiJwA2QHHgylLrB+vfWAP9o2nJv++Op1/q8ktVR+1 EgEk9StVvnYqC86DJhYbUbMmX7TorRwPoUo/5Z6C/viyZzOagZge0vYKYTQS99Pq B+2aH7pMPLooAdU/cyYy8J20mxQ4RaHoy+TCe0RMRhxnRi9CnnnYNHbZDVdHISpr OSfZKSM40DbAAs7UNxIgPXM1qSzia23tgzZEdh5qwQtZBTC6fWr/1xOrTpFW2wY6 VxqgP/OX23BzJQE4YDnOHLIj8GX0MLqXr7pl2+KBcHO9xvPS6Qj8fFsLEVatCwX0 Caify6KIbbgMWcVmut/6 =LDCr -----END PGP SIGNATURE----- Merge tag 'gpio-v4.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "Here is the bulk of GPIO changes for the v4.4 development cycle. The only changes hitting outside drivers/gpio are in the pin control subsystem and these seem to have settled nicely in linux-next. Development mistakes and catfights are nicely documented in the reverts as you can see. The outcome of the ABI fight is that we're working on a chardev ABI for GPIO now, where hope to show results for the v4.5 kernel. Summary of changes: GPIO core: - Define and handle flags for open drain/open collector and open source/open emitter, also know as "single-ended" configurations. - Generic request/free operations that handle calling out to the (optional) pin control backend. - Some refactoring related to an ABI change that did not happen, yet provide useful. - Added a real-time compliance checklist. Many GPIO chips have irqchips, and need to think this over with the RT patches going upstream. - Restructure, fix and clean up Kconfig menus a bit. New drivers: - New driver for AMD Promony. - New driver for ACCES 104-IDIO-16, a port-mapped I/O card, ISA-style. Very retro. Subdriver changes: - OMAP changes to handle real time requirements. - Handle trigger types for edge and level IRQs on PL061 properly. As this hardware is very common it needs to set a proper example for others to follow. - Some container_of() cleanups. - Delete the unused MSM driver in favor of the driver that is embedded inside the pin control driver. - Cleanup of the ath79 GPIO driver used by many, many OpenWRT router targets. - A consolidated IT87xx driver replacing the earlier very specific IT8761e driver. - Handle the TI TCA9539 in the PCA953x driver. Also handle ACPI devices in this subdriver. - Drop xilinx arch dependencies as these FPGAs seem to profilate over a few different architectures. MIPS and ARM come to mind" * tag 'gpio-v4.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (57 commits) gpio: fix up SPI submenu gpio: drop surplus I2C dependencies gpio: drop surplus X86 dependencies gpio: dt-bindings: document the official use of "ngpios" gpio: MAINTAINERS: Add an entry for the ATH79 GPIO driver gpio / ACPI: Allow shared GPIO event to be read via operation region gpio: group port-mapped I/O drivers in a menu gpio: Add ACCES 104-IDIO-16 driver maintainer entry gpio: zynq: Document interrupt-controller DT binding gpio: xilinx: Drop architecture dependencies gpio: generic: Revert to old error handling in bgpio_map gpio: add a real time compliance notes Revert "gpio: add a real time compliance checklist" gpio: Add GPIO support for the ACCES 104-IDIO-16 gpio: driver for AMD Promontory gpio: xlp: Convert to use gpiolib irqchip helpers gpio: add a real time compliance checklist gpio/xilinx: enable for MIPS gpiolib: Add and use OF_GPIO_SINGLE_ENDED flag gpiolib: Split GPIO flags parsing and GPIO configuration ...
This commit is contained in:
commit
e86328c489
@ -1,26 +0,0 @@
|
||||
MSM GPIO controller bindings
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
- "qcom,msm-gpio" for MSM controllers
|
||||
- #gpio-cells : Should be two.
|
||||
- first cell is the pin number
|
||||
- second cell is used to specify optional parameters (unused)
|
||||
- gpio-controller : Marks the device node as a GPIO controller.
|
||||
- #interrupt-cells : Should be 2.
|
||||
- interrupt-controller: Mark the device node as an interrupt controller
|
||||
- interrupts : Specify the TLMM summary interrupt number
|
||||
- ngpio : Specify the number of MSM GPIOs
|
||||
|
||||
Example:
|
||||
|
||||
msmgpio: gpio@fd510000 {
|
||||
compatible = "qcom,msm-gpio";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0xfd510000 0x4000>;
|
||||
interrupts = <0 208 0>;
|
||||
ngpio = <150>;
|
||||
};
|
@ -24,6 +24,7 @@ Required properties:
|
||||
ti,tca6408
|
||||
ti,tca6416
|
||||
ti,tca6424
|
||||
ti,tca9539
|
||||
exar,xra1202
|
||||
|
||||
Example:
|
||||
|
@ -12,6 +12,13 @@ Required properties:
|
||||
- interrupts : Interrupt specifier (see interrupt bindings for
|
||||
details)
|
||||
- interrupt-parent : Must be core interrupt controller
|
||||
- interrupt-controller : Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells : Should be 2. The first cell is the GPIO number.
|
||||
The second cell bits[3:0] is used to specify trigger type and level flags:
|
||||
1 = low-to-high edge triggered.
|
||||
2 = high-to-low edge triggered.
|
||||
4 = active high level-sensitive.
|
||||
8 = active low level-sensitive.
|
||||
- reg : Address and length of the register set for the device
|
||||
|
||||
Example:
|
||||
@ -22,5 +29,7 @@ Example:
|
||||
gpio-controller;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 20 4>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0xe000a000 0x1000>;
|
||||
};
|
||||
|
@ -54,9 +54,13 @@ only uses one.
|
||||
|
||||
gpio-specifier may encode: bank, pin position inside the bank,
|
||||
whether pin is open-drain and whether pin is logically inverted.
|
||||
|
||||
Exact meaning of each specifier cell is controller specific, and must
|
||||
be documented in the device tree binding for the device. Use the macros
|
||||
defined in include/dt-bindings/gpio/gpio.h whenever possible:
|
||||
be documented in the device tree binding for the device.
|
||||
|
||||
Most controllers are however specifying a generic flag bitfield
|
||||
in the last cell, so for these, use the macros defined in
|
||||
include/dt-bindings/gpio/gpio.h whenever possible:
|
||||
|
||||
Example of a node using GPIOs:
|
||||
|
||||
@ -67,6 +71,15 @@ Example of a node using GPIOs:
|
||||
GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes
|
||||
GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
|
||||
|
||||
Optional standard bitfield specifiers for the last cell:
|
||||
|
||||
- Bit 0: 0 means active high, 1 means active low
|
||||
- Bit 1: 1 means single-ended wiring, see:
|
||||
https://en.wikipedia.org/wiki/Single-ended_triode
|
||||
When used with active-low, this means open drain/collector, see:
|
||||
https://en.wikipedia.org/wiki/Open_collector
|
||||
When used with active-high, this means open source/emitter
|
||||
|
||||
1.1) GPIO specifier best practices
|
||||
----------------------------------
|
||||
|
||||
@ -118,6 +131,30 @@ Every GPIO controller node must contain both an empty "gpio-controller"
|
||||
property, and a #gpio-cells integer property, which indicates the number of
|
||||
cells in a gpio-specifier.
|
||||
|
||||
Optionally, a GPIO controller may have a "ngpios" property. This property
|
||||
indicates the number of in-use slots of available slots for GPIOs. The
|
||||
typical example is something like this: the hardware register is 32 bits
|
||||
wide, but only 18 of the bits have a physical counterpart. The driver is
|
||||
generally written so that all 32 bits can be used, but the IP block is reused
|
||||
in a lot of designs, some using all 32 bits, some using 18 and some using
|
||||
12. In this case, setting "ngpios = <18>;" informs the driver that only the
|
||||
first 18 GPIOs, at local offset 0 .. 17, are in use.
|
||||
|
||||
If these GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an
|
||||
additional bitmask is needed to specify which GPIOs are actually in use,
|
||||
and which are dummies. The bindings for this case has not yet been
|
||||
specified, but should be specified if/when such hardware appears.
|
||||
|
||||
Example:
|
||||
|
||||
gpio-controller@00000000 {
|
||||
compatible = "foo";
|
||||
reg = <0x00000000 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <18>;
|
||||
}
|
||||
|
||||
The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism
|
||||
providing automatic GPIO request and configuration as part of the
|
||||
gpio-controller's driver probe function.
|
||||
|
@ -62,6 +62,11 @@ Any debugfs dump method should normally ignore signals which haven't been
|
||||
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
|
||||
NULL or the label associated with that GPIO when it was requested.
|
||||
|
||||
RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
|
||||
(like PM runtime) in its gpio_chip implementation (.get/.set and direction
|
||||
control callbacks) if it is expected to call GPIO APIs from atomic context
|
||||
on -RT (inside hard IRQ handlers and similar contexts). Normally this should
|
||||
not be required.
|
||||
|
||||
GPIO drivers providing IRQs
|
||||
---------------------------
|
||||
@ -73,6 +78,13 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using
|
||||
the header <linux/irq.h>. So basically such a driver is utilizing two sub-
|
||||
systems simultaneously: gpio and irq.
|
||||
|
||||
RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
|
||||
(like PM runtime) as part of its irq_chip implementation on -RT.
|
||||
- spinlock_t should be replaced with raw_spinlock_t [1].
|
||||
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
|
||||
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
|
||||
on an irqchip. Create the callbacks if needed [2].
|
||||
|
||||
GPIO irqchips usually fall in one of two categories:
|
||||
|
||||
* CHAINED GPIO irqchips: these are usually the type that is embedded on
|
||||
@ -93,6 +105,38 @@ GPIO irqchips usually fall in one of two categories:
|
||||
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
|
||||
struct gpio_chip, as everything happens directly in the callbacks.
|
||||
|
||||
RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
|
||||
As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
|
||||
in chained IRQ handler.
|
||||
if required (and if it can't be converted to the nested threaded GPIO irqchip)
|
||||
- chained IRQ handler can be converted to generic irq handler and this way
|
||||
it will be threaded IRQ handler on -RT and hard IRQ handler on non-RT
|
||||
(for example, see [3]).
|
||||
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
|
||||
so IRQ core will complain if it will be called from IRQ handler wich is forced
|
||||
thread. The "fake?" raw lock can be used to W/A this problem:
|
||||
|
||||
raw_spinlock_t wa_lock;
|
||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
unsigned long wa_lock_flags;
|
||||
raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit));
|
||||
raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
|
||||
|
||||
* GENERIC CHAINED GPIO irqchips: these are the same as "CHAINED GPIO irqchips",
|
||||
but chained IRQ handlers are not used. Instead GPIO IRQs dispatching is
|
||||
performed by generic IRQ handler which is configured using request_irq().
|
||||
The GPIO irqchip will then end up calling something like this sequence in
|
||||
its interrupt handler:
|
||||
|
||||
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
|
||||
for each detected GPIO IRQ
|
||||
generic_handle_irq(...);
|
||||
|
||||
RT_FULL: Such kind of handlers will be forced threaded on -RT, as result IRQ
|
||||
core will complain that generic_handle_irq() is called with IRQ enabled and
|
||||
the same W/A as for "CHAINED GPIO irqchips" can be applied.
|
||||
|
||||
* NESTED THREADED GPIO irqchips: these are off-chip GPIO expanders and any
|
||||
other GPIO irqchip residing on the other side of a sleeping bus. Of course
|
||||
such drivers that need slow bus traffic to read out IRQ status and similar,
|
||||
@ -133,6 +177,13 @@ To use the helpers please keep the following in mind:
|
||||
the irqchip can initialize. E.g. .dev and .can_sleep shall be set up
|
||||
properly.
|
||||
|
||||
- Nominally set all handlers to handle_bad_irq() in the setup call and pass
|
||||
handle_bad_irq() as flow handler parameter in gpiochip_irqchip_add() if it is
|
||||
expected for GPIO driver that irqchip .set_type() callback have to be called
|
||||
before using/enabling GPIO IRQ. Then set the handler to handle_level_irq()
|
||||
and/or handle_edge_irq() in the irqchip .set_type() callback depending on
|
||||
what your controller supports.
|
||||
|
||||
It is legal for any IRQ consumer to request an IRQ from any irqchip no matter
|
||||
if that is a combined GPIO+IRQ driver. The basic premise is that gpio_chip and
|
||||
irq_chip are orthogonal, and offering their services independent of each
|
||||
@ -169,6 +220,31 @@ When implementing an irqchip inside a GPIO driver, these two functions should
|
||||
typically be called in the .startup() and .shutdown() callbacks from the
|
||||
irqchip.
|
||||
|
||||
Real-Time compliance for GPIO IRQ chips
|
||||
---------------------------------------
|
||||
|
||||
Any provider of irqchips needs to be carefully tailored to support Real Time
|
||||
preemption. It is desireable that all irqchips in the GPIO subsystem keep this
|
||||
in mind and does the proper testing to assure they are real time-enabled.
|
||||
So, pay attention on above " RT_FULL:" notes, please.
|
||||
The following is a checklist to follow when preparing a driver for real
|
||||
time-compliance:
|
||||
|
||||
- ensure spinlock_t is not used as part irq_chip implementation;
|
||||
- ensure that sleepable APIs are not used as part irq_chip implementation.
|
||||
If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
|
||||
and .irq_bus_unlock() callbacks;
|
||||
- Chained GPIO irqchips: ensure spinlock_t or any sleepable APIs are not used
|
||||
from chained IRQ handler;
|
||||
- Generic chained GPIO irqchips: take care about generic_handle_irq() calls and
|
||||
apply corresponding W/A;
|
||||
- Chained GPIO irqchips: get rid of chained IRQ handler and use generic irq
|
||||
handler if possible :)
|
||||
- regmap_mmio: Sry, but you are in trouble :( if MMIO regmap is used as for
|
||||
GPIO IRQ chip implementation;
|
||||
- Test your driver with the appropriate in-kernel real time test cases for both
|
||||
level and edge IRQs.
|
||||
|
||||
|
||||
Requesting self-owned GPIO pins
|
||||
-------------------------------
|
||||
@ -190,3 +266,7 @@ gpiochip_free_own_desc().
|
||||
These functions must be used with care since they do not affect module use
|
||||
count. Do not use the functions to request gpio descriptors not owned by the
|
||||
calling driver.
|
||||
|
||||
[1] http://www.spinics.net/lists/linux-omap/msg120425.html
|
||||
[2] https://lkml.org/lkml/2015/9/25/494
|
||||
[3] https://lkml.org/lkml/2015/9/25/495
|
||||
|
14
MAINTAINERS
14
MAINTAINERS
@ -240,6 +240,12 @@ L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
F: drivers/hwmon/abituguru3.c
|
||||
|
||||
ACCES 104-IDIO-16 GPIO DRIVER
|
||||
M: "William Breathitt Gray" <vilhelm.gray@gmail.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-104-idio-16.c
|
||||
|
||||
ACENIC DRIVER
|
||||
M: Jes Sorensen <jes@trained-monkey.org>
|
||||
L: linux-acenic@sunsite.dk
|
||||
@ -1780,6 +1786,14 @@ S: Supported
|
||||
F: Documentation/aoe/
|
||||
F: drivers/block/aoe/
|
||||
|
||||
ATHEROS 71XX/9XXX GPIO DRIVER
|
||||
M: Alban Bedel <albeu@free.fr>
|
||||
W: https://github.com/AlbanBedel/linux
|
||||
T: git git://github.com/AlbanBedel/linux
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-ath79.c
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-ath79.txt
|
||||
|
||||
ATHEROS ATH GENERIC UTILITIES
|
||||
M: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
|
@ -119,6 +119,13 @@ config GPIO_ALTERA
|
||||
|
||||
If driver is built as a module it will be called gpio-altera.
|
||||
|
||||
config GPIO_AMDPT
|
||||
tristate "AMD Promontory GPIO support"
|
||||
depends on ACPI
|
||||
help
|
||||
driver for GPIO functionality on Promontory IOHub
|
||||
Require ACPI ASL code to enumerate as a platform device.
|
||||
|
||||
config GPIO_BCM_KONA
|
||||
bool "Broadcom Kona GPIO"
|
||||
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
||||
@ -176,16 +183,6 @@ config GPIO_ETRAXFS
|
||||
help
|
||||
Say yes here to support the GPIO controller on Axis ETRAX FS SoCs.
|
||||
|
||||
config GPIO_F7188X
|
||||
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
|
||||
depends on X86
|
||||
help
|
||||
This option enables support for GPIOs found on Fintek Super-I/O
|
||||
chips F71869, F71869A, F71882FG and F71889F.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called f7188x-gpio.
|
||||
|
||||
config GPIO_GE_FPGA
|
||||
bool "GE FPGA based GPIO"
|
||||
depends on GE_FPGA
|
||||
@ -235,12 +232,6 @@ config GPIO_IOP
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config GPIO_IT8761E
|
||||
tristate "IT8761E GPIO support"
|
||||
depends on X86 # unconditional access to IO space.
|
||||
help
|
||||
Say yes here to support GPIO functionality of IT8761E super I/O chip.
|
||||
|
||||
config GPIO_LOONGSON
|
||||
bool "Loongson-2/3 GPIO support"
|
||||
depends on CPU_LOONGSON2 || CPU_LOONGSON3
|
||||
@ -297,14 +288,6 @@ config GPIO_MPC8XXX
|
||||
Say Y here if you're going to use hardware that connects to the
|
||||
MPC512x/831x/834x/837x/8572/8610 GPIOs.
|
||||
|
||||
config GPIO_MSM_V2
|
||||
tristate "Qualcomm MSM GPIO v2"
|
||||
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
|
||||
selected for GPIO, and are controlled by this driver.
|
||||
|
||||
config GPIO_MVEBU
|
||||
def_bool y
|
||||
depends on PLAT_ORION
|
||||
@ -368,42 +351,6 @@ config GPIO_SAMSUNG
|
||||
Legacy GPIO support. Use only for platforms without support for
|
||||
pinctrl.
|
||||
|
||||
config GPIO_SCH
|
||||
tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
|
||||
depends on PCI && X86
|
||||
select MFD_CORE
|
||||
select LPC_SCH
|
||||
help
|
||||
Say yes here to support GPIO interface on Intel Poulsbo SCH,
|
||||
Intel Tunnel Creek processor, Intel Centerton processor or
|
||||
Intel Quark X1000 SoC.
|
||||
|
||||
The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
|
||||
powered by the core power rail and are turned off during sleep
|
||||
modes (S3 and higher). The remaining four GPIOs are powered by
|
||||
the Intel SCH suspend power supply. These GPIOs remain
|
||||
active during S3. The suspend powered GPIOs can be used to wake the
|
||||
system from the Suspend-to-RAM state.
|
||||
|
||||
The Intel Tunnel Creek processor has 5 GPIOs powered by the
|
||||
core power rail and 9 from suspend power supply.
|
||||
|
||||
The Intel Centerton processor has a total of 30 GPIO pins.
|
||||
Twenty-one are powered by the core power rail and 9 from the
|
||||
suspend power supply.
|
||||
|
||||
The Intel Quark X1000 SoC has 2 GPIOs powered by the core
|
||||
power well and 6 from the suspend power well.
|
||||
|
||||
config GPIO_SCH311X
|
||||
tristate "SMSC SCH311x SuperI/O GPIO"
|
||||
help
|
||||
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
|
||||
@ -440,15 +387,6 @@ config GPIO_TB10X
|
||||
select GENERIC_IRQ_CHIP
|
||||
select OF_GPIO
|
||||
|
||||
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
|
||||
@ -508,13 +446,13 @@ config GPIO_XGENE_SB
|
||||
|
||||
config GPIO_XILINX
|
||||
tristate "Xilinx GPIO support"
|
||||
depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86)
|
||||
depends on OF_GPIO
|
||||
help
|
||||
Say yes here to support the Xilinx FPGA GPIO device
|
||||
|
||||
config GPIO_XLP
|
||||
tristate "Netlogic XLP GPIO support"
|
||||
depends on CPU_XLP
|
||||
depends on CPU_XLP && OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This driver provides support for GPIO interface on Netlogic XLP MIPS64
|
||||
@ -545,6 +483,87 @@ config GPIO_ZYNQ
|
||||
help
|
||||
Say yes here to support Xilinx Zynq GPIO controller.
|
||||
|
||||
config GPIO_ZX
|
||||
bool "ZTE ZX GPIO support"
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support the GPIO device on ZTE ZX SoCs.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Port-mapped I/O GPIO drivers"
|
||||
depends on X86 # Unconditional I/O space access
|
||||
|
||||
config GPIO_104_IDIO_16
|
||||
tristate "ACCES 104-IDIO-16 GPIO support"
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDIO-16 family.
|
||||
|
||||
config GPIO_F7188X
|
||||
tristate "F71869, F71869A, F71882FG and F71889F GPIO support"
|
||||
help
|
||||
This option enables support for GPIOs found on Fintek Super-I/O
|
||||
chips F71869, F71869A, F71882FG and F71889F.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called f7188x-gpio.
|
||||
|
||||
config GPIO_IT87
|
||||
tristate "IT87xx GPIO support"
|
||||
help
|
||||
Say yes here to support GPIO functionality of IT87xx Super I/O chips.
|
||||
|
||||
This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and
|
||||
supports the IT8761E Super I/O chip as well.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gpio_it87
|
||||
|
||||
config GPIO_SCH
|
||||
tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
|
||||
depends on PCI
|
||||
select MFD_CORE
|
||||
select LPC_SCH
|
||||
help
|
||||
Say yes here to support GPIO interface on Intel Poulsbo SCH,
|
||||
Intel Tunnel Creek processor, Intel Centerton processor or
|
||||
Intel Quark X1000 SoC.
|
||||
|
||||
The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
|
||||
powered by the core power rail and are turned off during sleep
|
||||
modes (S3 and higher). The remaining four GPIOs are powered by
|
||||
the Intel SCH suspend power supply. These GPIOs remain
|
||||
active during S3. The suspend powered GPIOs can be used to wake the
|
||||
system from the Suspend-to-RAM state.
|
||||
|
||||
The Intel Tunnel Creek processor has 5 GPIOs powered by the
|
||||
core power rail and 9 from suspend power supply.
|
||||
|
||||
The Intel Centerton processor has a total of 30 GPIO pins.
|
||||
Twenty-one are powered by the core power rail and 9 from the
|
||||
suspend power supply.
|
||||
|
||||
The Intel Quark X1000 SoC has 2 GPIOs powered by the core
|
||||
power well and 6 from the suspend power well.
|
||||
|
||||
config GPIO_SCH311X
|
||||
tristate "SMSC SCH311x SuperI/O GPIO"
|
||||
help
|
||||
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_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.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "I2C GPIO expanders"
|
||||
@ -552,7 +571,6 @@ menu "I2C GPIO expanders"
|
||||
|
||||
config GPIO_ADP5588
|
||||
tristate "ADP5588 I2C GPIO expander"
|
||||
depends on I2C
|
||||
help
|
||||
This option enables support for 18 GPIOs found
|
||||
on Analog Devices ADP5588 GPIO Expanders.
|
||||
@ -566,7 +584,7 @@ config GPIO_ADP5588_IRQ
|
||||
|
||||
config GPIO_ADNP
|
||||
tristate "Avionic Design N-bit GPIO expander"
|
||||
depends on I2C && OF_GPIO
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
This option enables support for N GPIOs found on Avionic Design
|
||||
@ -578,14 +596,12 @@ config GPIO_ADNP
|
||||
|
||||
config GPIO_MAX7300
|
||||
tristate "Maxim MAX7300 GPIO expander"
|
||||
depends on I2C
|
||||
select GPIO_MAX730X
|
||||
help
|
||||
GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
|
||||
|
||||
config GPIO_MAX732X
|
||||
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to support the MAX7319, MAX7320-7327 series of I2C
|
||||
Port Expanders. Each IO port on these chips has a fixed role of
|
||||
@ -618,7 +634,6 @@ config GPIO_MC9S08DZ60
|
||||
|
||||
config GPIO_PCA953X
|
||||
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
|
||||
SMBus I/O expanders, made mostly by NXP or TI. Compatible
|
||||
@ -646,7 +661,6 @@ config GPIO_PCA953X_IRQ
|
||||
|
||||
config GPIO_PCF857X
|
||||
tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
|
||||
depends on I2C
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
@ -976,7 +990,7 @@ menu "SPI GPIO expanders"
|
||||
|
||||
config GPIO_74X164
|
||||
tristate "74x164 serial-in/parallel-out 8-bits shift register"
|
||||
depends on SPI_MASTER && OF
|
||||
depends on OF
|
||||
help
|
||||
Driver for 74x164 compatible serial-in/parallel-out 8-outputs
|
||||
shift registers. This driver can be used to provide access
|
||||
@ -984,33 +998,29 @@ config GPIO_74X164
|
||||
|
||||
config GPIO_MAX7301
|
||||
tristate "Maxim MAX7301 GPIO expander"
|
||||
depends on SPI_MASTER
|
||||
select GPIO_MAX730X
|
||||
help
|
||||
GPIO driver for Maxim MAX7301 SPI-based GPIO expander.
|
||||
|
||||
config GPIO_MC33880
|
||||
tristate "Freescale MC33880 high-side/low-side switch"
|
||||
help
|
||||
SPI driver for Freescale MC33880 high-side/low-side switch.
|
||||
This provides GPIO interface supporting inputs and outputs.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "SPI or I2C GPIO expanders"
|
||||
depends on (SPI_MASTER && !I2C) || I2C
|
||||
|
||||
config GPIO_MCP23S08
|
||||
tristate "Microchip MCP23xxx I/O expander"
|
||||
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"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
SPI driver for Freescale MC33880 high-side/low-side switch.
|
||||
This provides GPIO interface supporting inputs and outputs.
|
||||
|
||||
config GPIO_ZX
|
||||
bool "ZTE ZX GPIO support"
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support the GPIO device on ZTE ZX SoCs.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "USB GPIO expanders"
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
|
||||
|
||||
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
|
||||
obj-$(CONFIG_GPIO_74X164) += gpio-74x164.o
|
||||
obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
|
||||
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
|
||||
@ -19,6 +20,7 @@ obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
|
||||
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
|
||||
obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
|
||||
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
|
||||
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
|
||||
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
|
||||
obj-$(CONFIG_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
@ -40,7 +42,7 @@ 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_IT87) += gpio-it87.o
|
||||
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
|
||||
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
|
||||
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
|
||||
@ -64,7 +66,6 @@ obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o
|
||||
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
|
||||
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
|
||||
obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
|
||||
obj-$(CONFIG_GPIO_MSM_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
|
||||
|
216
drivers/gpio/gpio-104-idio-16.c
Normal file
216
drivers/gpio/gpio-104-idio-16.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* GPIO driver for the ACCES 104-IDIO-16 family
|
||||
* Copyright (C) 2015 William Breathitt Gray
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
static unsigned idio_16_base;
|
||||
module_param(idio_16_base, uint, 0);
|
||||
MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address");
|
||||
|
||||
/**
|
||||
* struct idio_16_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @lock: synchronization lock to prevent gpio_set race conditions
|
||||
* @base: base port address of the GPIO device
|
||||
* @extent: extent of port address region of the GPIO device
|
||||
* @out_state: output bits state
|
||||
*/
|
||||
struct idio_16_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
unsigned base;
|
||||
unsigned extent;
|
||||
unsigned out_state;
|
||||
};
|
||||
|
||||
static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
if (offset > 15)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idio_16_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
chip->set(chip, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct idio_16_gpio *to_idio16gpio(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct idio_16_gpio, chip);
|
||||
}
|
||||
|
||||
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
|
||||
const unsigned BIT_MASK = 1U << (offset-16);
|
||||
|
||||
if (offset < 16)
|
||||
return -EINVAL;
|
||||
|
||||
if (offset < 24)
|
||||
return !!(inb(idio16gpio->base + 1) & BIT_MASK);
|
||||
|
||||
return !!(inb(idio16gpio->base + 5) & (BIT_MASK>>8));
|
||||
}
|
||||
|
||||
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = to_idio16gpio(chip);
|
||||
const unsigned BIT_MASK = 1U << offset;
|
||||
unsigned long flags;
|
||||
|
||||
if (offset > 15)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&idio16gpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
idio16gpio->out_state |= BIT_MASK;
|
||||
else
|
||||
idio16gpio->out_state &= ~BIT_MASK;
|
||||
|
||||
if (offset > 7)
|
||||
outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
|
||||
else
|
||||
outb(idio16gpio->out_state, idio16gpio->base);
|
||||
|
||||
spin_unlock_irqrestore(&idio16gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int __init idio_16_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct idio_16_gpio *idio16gpio;
|
||||
int err;
|
||||
|
||||
const unsigned BASE = idio_16_base;
|
||||
const unsigned EXTENT = 8;
|
||||
const char *const NAME = dev_name(dev);
|
||||
|
||||
idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
|
||||
if (!idio16gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!request_region(BASE, EXTENT, NAME)) {
|
||||
dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
|
||||
NAME, BASE, BASE + EXTENT);
|
||||
err = -EBUSY;
|
||||
goto err_lock_io_port;
|
||||
}
|
||||
|
||||
idio16gpio->chip.label = NAME;
|
||||
idio16gpio->chip.dev = dev;
|
||||
idio16gpio->chip.owner = THIS_MODULE;
|
||||
idio16gpio->chip.base = -1;
|
||||
idio16gpio->chip.ngpio = 32;
|
||||
idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
|
||||
idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
|
||||
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
||||
idio16gpio->chip.get = idio_16_gpio_get;
|
||||
idio16gpio->chip.set = idio_16_gpio_set;
|
||||
idio16gpio->base = BASE;
|
||||
idio16gpio->extent = EXTENT;
|
||||
idio16gpio->out_state = 0xFFFF;
|
||||
|
||||
spin_lock_init(&idio16gpio->lock);
|
||||
|
||||
dev_set_drvdata(dev, idio16gpio);
|
||||
|
||||
err = gpiochip_add(&idio16gpio->chip);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
goto err_gpio_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_gpio_register:
|
||||
release_region(BASE, EXTENT);
|
||||
err_lock_io_port:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int idio_16_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&idio16gpio->chip);
|
||||
release_region(idio16gpio->base, idio16gpio->extent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device *idio_16_device;
|
||||
|
||||
static struct platform_driver idio_16_driver = {
|
||||
.driver = {
|
||||
.name = "104-idio-16"
|
||||
},
|
||||
.remove = idio_16_remove
|
||||
};
|
||||
|
||||
static void __exit idio_16_exit(void)
|
||||
{
|
||||
platform_device_unregister(idio_16_device);
|
||||
platform_driver_unregister(&idio_16_driver);
|
||||
}
|
||||
|
||||
static int __init idio_16_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1);
|
||||
if (!idio_16_device)
|
||||
return -ENOMEM;
|
||||
|
||||
err = platform_device_add(idio_16_device);
|
||||
if (err)
|
||||
goto err_platform_device;
|
||||
|
||||
err = platform_driver_probe(&idio_16_driver, idio_16_probe);
|
||||
if (err)
|
||||
goto err_platform_driver;
|
||||
|
||||
return 0;
|
||||
|
||||
err_platform_driver:
|
||||
platform_device_del(idio_16_device);
|
||||
err_platform_device:
|
||||
platform_device_put(idio_16_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
module_init(idio_16_init);
|
||||
module_exit(idio_16_exit);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -42,6 +42,11 @@ struct altera_gpio_chip {
|
||||
int mapped_irq;
|
||||
};
|
||||
|
||||
static struct altera_gpio_chip *to_altera(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct altera_gpio_chip, mmchip.gc);
|
||||
}
|
||||
|
||||
static void altera_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc;
|
||||
@ -49,7 +54,7 @@ static void altera_gpio_irq_unmask(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
u32 intmask;
|
||||
|
||||
altera_gc = irq_data_get_irq_chip_data(d);
|
||||
altera_gc = to_altera(irq_data_get_irq_chip_data(d));
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
|
||||
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
@ -67,7 +72,7 @@ static void altera_gpio_irq_mask(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
u32 intmask;
|
||||
|
||||
altera_gc = irq_data_get_irq_chip_data(d);
|
||||
altera_gc = to_altera(irq_data_get_irq_chip_data(d));
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
|
||||
spin_lock_irqsave(&altera_gc->gpio_lock, flags);
|
||||
@ -87,7 +92,7 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc;
|
||||
|
||||
altera_gc = irq_data_get_irq_chip_data(d);
|
||||
altera_gc = to_altera(irq_data_get_irq_chip_data(d));
|
||||
|
||||
if (type == IRQ_TYPE_NONE)
|
||||
return 0;
|
||||
@ -210,7 +215,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
|
||||
unsigned long status;
|
||||
int i;
|
||||
|
||||
altera_gc = irq_desc_get_handler_data(desc);
|
||||
altera_gc = to_altera(irq_desc_get_handler_data(desc));
|
||||
chip = irq_desc_get_chip(desc);
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
irqdomain = altera_gc->mmchip.gc.irqdomain;
|
||||
@ -239,7 +244,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
||||
unsigned long status;
|
||||
int i;
|
||||
|
||||
altera_gc = irq_desc_get_handler_data(desc);
|
||||
altera_gc = to_altera(irq_desc_get_handler_data(desc));
|
||||
chip = irq_desc_get_chip(desc);
|
||||
mm_gc = &altera_gc->mmchip;
|
||||
irqdomain = altera_gc->mmchip.gc.irqdomain;
|
||||
|
261
drivers/gpio/gpio-amdpt.c
Normal file
261
drivers/gpio/gpio-amdpt.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* AMD Promontory GPIO driver
|
||||
*
|
||||
* Copyright (C) 2015 ASMedia Technology Inc.
|
||||
* Author: YD Tseng <yd_tseng@asmedia.com.tw>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define PT_TOTAL_GPIO 8
|
||||
|
||||
/* PCI-E MMIO register offsets */
|
||||
#define PT_DIRECTION_REG 0x00
|
||||
#define PT_INPUTDATA_REG 0x04
|
||||
#define PT_OUTPUTDATA_REG 0x08
|
||||
#define PT_CLOCKRATE_REG 0x0C
|
||||
#define PT_SYNC_REG 0x28
|
||||
|
||||
struct pt_gpio_chip {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *reg_base;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define to_pt_gpio(c) container_of(c, struct pt_gpio_chip, gc)
|
||||
|
||||
static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 using_pins;
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_request offset=%x\n", offset);
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
|
||||
if (using_pins & BIT(offset)) {
|
||||
dev_warn(gc->dev, "PT GPIO pin %x reconfigured\n",
|
||||
offset);
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 using_pins;
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
|
||||
using_pins &= ~BIT(offset);
|
||||
writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_free offset=%x\n", offset);
|
||||
}
|
||||
|
||||
static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_set_value offset=%x, value=%x\n",
|
||||
offset, value);
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
|
||||
data &= ~BIT(offset);
|
||||
if (value)
|
||||
data |= BIT(offset);
|
||||
writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
|
||||
|
||||
/* configure as output */
|
||||
if (data & BIT(offset))
|
||||
data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
|
||||
else /* configure as input */
|
||||
data = readl(pt_gpio->reg_base + PT_INPUTDATA_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
|
||||
data >>= offset;
|
||||
data &= 1;
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_get_value offset=%x, value=%x\n",
|
||||
offset, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_dirction_input offset=%x\n", offset);
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
|
||||
data &= ~BIT(offset);
|
||||
writel(data, pt_gpio->reg_base + PT_DIRECTION_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = to_pt_gpio(gc);
|
||||
unsigned long flags;
|
||||
u32 data;
|
||||
|
||||
dev_dbg(gc->dev, "pt_gpio_direction_output offset=%x, value=%x\n",
|
||||
offset, value);
|
||||
|
||||
spin_lock_irqsave(&pt_gpio->lock, flags);
|
||||
|
||||
data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
|
||||
if (value)
|
||||
data |= BIT(offset);
|
||||
else
|
||||
data &= ~BIT(offset);
|
||||
writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG);
|
||||
|
||||
data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
|
||||
data |= BIT(offset);
|
||||
writel(data, pt_gpio->reg_base + PT_DIRECTION_REG);
|
||||
|
||||
spin_unlock_irqrestore(&pt_gpio->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pt_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct acpi_device *acpi_dev;
|
||||
acpi_handle handle = ACPI_HANDLE(dev);
|
||||
struct pt_gpio_chip *pt_gpio;
|
||||
struct resource *res_mem;
|
||||
int ret = 0;
|
||||
|
||||
if (acpi_bus_get_device(handle, &acpi_dev)) {
|
||||
dev_err(dev, "PT GPIO device node not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pt_gpio = devm_kzalloc(dev, sizeof(struct pt_gpio_chip), GFP_KERNEL);
|
||||
if (!pt_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res_mem) {
|
||||
dev_err(&pdev->dev, "Failed to get MMIO resource for PT GPIO.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pt_gpio->reg_base = devm_ioremap_resource(dev, res_mem);
|
||||
if (IS_ERR(pt_gpio->reg_base)) {
|
||||
dev_err(&pdev->dev, "Failed to map MMIO resource for PT GPIO.\n");
|
||||
return PTR_ERR(pt_gpio->reg_base);
|
||||
}
|
||||
|
||||
spin_lock_init(&pt_gpio->lock);
|
||||
|
||||
pt_gpio->gc.label = pdev->name;
|
||||
pt_gpio->gc.owner = THIS_MODULE;
|
||||
pt_gpio->gc.dev = dev;
|
||||
pt_gpio->gc.request = pt_gpio_request;
|
||||
pt_gpio->gc.free = pt_gpio_free;
|
||||
pt_gpio->gc.direction_input = pt_gpio_direction_input;
|
||||
pt_gpio->gc.direction_output = pt_gpio_direction_output;
|
||||
pt_gpio->gc.get = pt_gpio_get_value;
|
||||
pt_gpio->gc.set = pt_gpio_set_value;
|
||||
pt_gpio->gc.base = -1;
|
||||
pt_gpio->gc.ngpio = PT_TOTAL_GPIO;
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
pt_gpio->gc.of_node = pdev->dev.of_node;
|
||||
#endif
|
||||
ret = gpiochip_add(&pt_gpio->gc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register GPIO lib\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pt_gpio);
|
||||
|
||||
/* initialize register setting */
|
||||
writel(0, pt_gpio->reg_base + PT_SYNC_REG);
|
||||
writel(0, pt_gpio->reg_base + PT_CLOCKRATE_REG);
|
||||
|
||||
dev_dbg(&pdev->dev, "PT GPIO driver loaded\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pt_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev);
|
||||
|
||||
gpiochip_remove(&pt_gpio->gc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id pt_gpio_acpi_match[] = {
|
||||
{ "AMDF030", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match);
|
||||
|
||||
static struct platform_driver pt_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "pt-gpio",
|
||||
.acpi_match_table = ACPI_PTR(pt_gpio_acpi_match),
|
||||
},
|
||||
.probe = pt_gpio_probe,
|
||||
.remove = pt_gpio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pt_gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("YD Tseng <yd_tseng@asmedia.com.tw>");
|
||||
MODULE_DESCRIPTION("AMD Promontory GPIO Driver");
|
@ -118,6 +118,8 @@ static int arizona_gpio_probe(struct platform_device *pdev)
|
||||
case WM5110:
|
||||
case WM8280:
|
||||
case WM8997:
|
||||
case WM8998:
|
||||
case WM1814:
|
||||
arizona_gpio->gpio_chip.ngpio = 5;
|
||||
break;
|
||||
default:
|
||||
|
@ -12,61 +12,51 @@
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_data/gpio-ath79.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <asm/mach-ath79/ar71xx_regs.h>
|
||||
|
||||
static void __iomem *ath79_gpio_base;
|
||||
static u32 ath79_gpio_count;
|
||||
static DEFINE_SPINLOCK(ath79_gpio_lock);
|
||||
struct ath79_gpio_ctrl {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static void __ath79_gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
|
||||
if (value)
|
||||
__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
|
||||
}
|
||||
|
||||
static int __ath79_gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
|
||||
}
|
||||
|
||||
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return __ath79_gpio_get_value(offset);
|
||||
}
|
||||
#define to_ath79_gpio_ctrl(c) container_of(c, struct ath79_gpio_ctrl, chip)
|
||||
|
||||
static void ath79_gpio_set_value(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
unsigned gpio, int value)
|
||||
{
|
||||
__ath79_gpio_set_value(offset, value);
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
|
||||
if (value)
|
||||
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(BIT(gpio), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
}
|
||||
|
||||
static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
|
||||
return (__raw_readl(ctrl->base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
|
||||
}
|
||||
|
||||
static int ath79_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -74,35 +64,37 @@ static int ath79_gpio_direction_input(struct gpio_chip *chip,
|
||||
static int ath79_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
if (value)
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) | BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -110,25 +102,26 @@ static int ar934x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
void __iomem *base = ath79_gpio_base;
|
||||
struct ath79_gpio_ctrl *ctrl = to_ath79_gpio_ctrl(chip);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ath79_gpio_lock, flags);
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
|
||||
if (value)
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_SET);
|
||||
else
|
||||
__raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
|
||||
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
|
||||
|
||||
__raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
|
||||
base + AR71XX_GPIO_REG_OE);
|
||||
__raw_writel(
|
||||
__raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & BIT(offset),
|
||||
ctrl->base + AR71XX_GPIO_REG_OE);
|
||||
|
||||
spin_unlock_irqrestore(&ath79_gpio_lock, flags);
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip ath79_gpio_chip = {
|
||||
static const struct gpio_chip ath79_gpio_chip = {
|
||||
.label = "ath79",
|
||||
.get = ath79_gpio_get_value,
|
||||
.set = ath79_gpio_set_value,
|
||||
@ -147,10 +140,16 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ath79_gpio_ctrl *ctrl;
|
||||
struct resource *res;
|
||||
u32 ath79_gpio_count;
|
||||
bool oe_inverted;
|
||||
int err;
|
||||
|
||||
ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
if (np) {
|
||||
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
|
||||
if (err) {
|
||||
@ -171,19 +170,21 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ath79_gpio_base = devm_ioremap_nocache(
|
||||
ctrl->base = devm_ioremap_nocache(
|
||||
&pdev->dev, res->start, resource_size(res));
|
||||
if (!ath79_gpio_base)
|
||||
if (!ctrl->base)
|
||||
return -ENOMEM;
|
||||
|
||||
ath79_gpio_chip.dev = &pdev->dev;
|
||||
ath79_gpio_chip.ngpio = ath79_gpio_count;
|
||||
spin_lock_init(&ctrl->lock);
|
||||
memcpy(&ctrl->chip, &ath79_gpio_chip, sizeof(ctrl->chip));
|
||||
ctrl->chip.dev = &pdev->dev;
|
||||
ctrl->chip.ngpio = ath79_gpio_count;
|
||||
if (oe_inverted) {
|
||||
ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
|
||||
ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
|
||||
ctrl->chip.direction_input = ar934x_gpio_direction_input;
|
||||
ctrl->chip.direction_output = ar934x_gpio_direction_output;
|
||||
}
|
||||
|
||||
err = gpiochip_add(&ath79_gpio_chip);
|
||||
err = gpiochip_add(&ctrl->chip);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"cannot add AR71xx GPIO chip, error=%d", err);
|
||||
|
@ -176,6 +176,11 @@ static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
|
||||
.rw_intr_pins = ARTPEC3_rw_intr_pins,
|
||||
};
|
||||
|
||||
static struct etraxfs_gpio_chip *to_etraxfs(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct etraxfs_gpio_chip, bgc.gc);
|
||||
}
|
||||
|
||||
static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
|
||||
{
|
||||
return gc->label[0] - 'A';
|
||||
@ -220,7 +225,8 @@ static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
|
||||
|
||||
static void etraxfs_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
@ -229,7 +235,8 @@ static void etraxfs_gpio_irq_ack(struct irq_data *d)
|
||||
|
||||
static void etraxfs_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
@ -241,7 +248,8 @@ static void etraxfs_gpio_irq_mask(struct irq_data *d)
|
||||
|
||||
static void etraxfs_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
@ -253,7 +261,8 @@ static void etraxfs_gpio_irq_unmask(struct irq_data *d)
|
||||
|
||||
static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
u32 cfg;
|
||||
@ -289,7 +298,8 @@ static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
|
||||
static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
int ret = -EBUSY;
|
||||
@ -319,7 +329,8 @@ out:
|
||||
|
||||
static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
|
||||
{
|
||||
struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct etraxfs_gpio_chip *chip =
|
||||
to_etraxfs(irq_data_get_irq_chip_data(d));
|
||||
struct etraxfs_gpio_block *block = chip->block;
|
||||
unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
|
||||
|
||||
|
@ -579,40 +579,20 @@ EXPORT_SYMBOL_GPL(bgpio_init);
|
||||
|
||||
static void __iomem *bgpio_map(struct platform_device *pdev,
|
||||
const char *name,
|
||||
resource_size_t sane_sz,
|
||||
int *err)
|
||||
resource_size_t sane_sz)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *r;
|
||||
resource_size_t start;
|
||||
resource_size_t sz;
|
||||
void __iomem *ret;
|
||||
|
||||
*err = 0;
|
||||
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
sz = resource_size(r);
|
||||
if (sz != sane_sz) {
|
||||
*err = -EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (sz != sane_sz)
|
||||
return IOMEM_ERR_PTR(-EINVAL);
|
||||
|
||||
start = r->start;
|
||||
if (!devm_request_mem_region(dev, start, sz, r->name)) {
|
||||
*err = -EBUSY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = devm_ioremap(dev, start, sz);
|
||||
if (!ret) {
|
||||
*err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return devm_ioremap_resource(&pdev->dev, r);
|
||||
}
|
||||
|
||||
static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||
@ -636,25 +616,25 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||
|
||||
sz = resource_size(r);
|
||||
|
||||
dat = bgpio_map(pdev, "dat", sz, &err);
|
||||
if (!dat)
|
||||
return err ? err : -EINVAL;
|
||||
dat = bgpio_map(pdev, "dat", sz);
|
||||
if (IS_ERR(dat))
|
||||
return PTR_ERR(dat);
|
||||
|
||||
set = bgpio_map(pdev, "set", sz, &err);
|
||||
if (err)
|
||||
return err;
|
||||
set = bgpio_map(pdev, "set", sz);
|
||||
if (IS_ERR(set))
|
||||
return PTR_ERR(set);
|
||||
|
||||
clr = bgpio_map(pdev, "clr", sz, &err);
|
||||
if (err)
|
||||
return err;
|
||||
clr = bgpio_map(pdev, "clr", sz);
|
||||
if (IS_ERR(clr))
|
||||
return PTR_ERR(clr);
|
||||
|
||||
dirout = bgpio_map(pdev, "dirout", sz, &err);
|
||||
if (err)
|
||||
return err;
|
||||
dirout = bgpio_map(pdev, "dirout", sz);
|
||||
if (IS_ERR(dirout))
|
||||
return PTR_ERR(dirout);
|
||||
|
||||
dirin = bgpio_map(pdev, "dirin", sz, &err);
|
||||
if (err)
|
||||
return err;
|
||||
dirin = bgpio_map(pdev, "dirin", sz);
|
||||
if (IS_ERR(dirin))
|
||||
return PTR_ERR(dirin);
|
||||
|
||||
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
|
||||
if (!bgc)
|
||||
|
411
drivers/gpio/gpio-it87.c
Normal file
411
drivers/gpio/gpio-it87.c
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* GPIO interface for IT87xx Super I/O chips
|
||||
*
|
||||
* Author: Diego Elio Pettenò <flameeyes@flameeyes.eu>
|
||||
*
|
||||
* Based on it87_wdt.c by Oliver Schuster
|
||||
* gpio-it8761e.c by Denis Turischev
|
||||
* gpio-stmpe.c by Rabin Vincent
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
/* Chip Id numbers */
|
||||
#define NO_DEV_ID 0xffff
|
||||
#define IT8728_ID 0x8728
|
||||
#define IT8732_ID 0x8732
|
||||
#define IT8761_ID 0x8761
|
||||
|
||||
/* IO Ports */
|
||||
#define REG 0x2e
|
||||
#define VAL 0x2f
|
||||
|
||||
/* Logical device Numbers LDN */
|
||||
#define GPIO 0x07
|
||||
|
||||
/* Configuration Registers and Functions */
|
||||
#define LDNREG 0x07
|
||||
#define CHIPID 0x20
|
||||
#define CHIPREV 0x22
|
||||
|
||||
/**
|
||||
* struct it87_gpio - it87-specific GPIO chip
|
||||
* @chip the underlying gpio_chip structure
|
||||
* @lock a lock to avoid races between operations
|
||||
* @io_base base address for gpio ports
|
||||
* @io_size size of the port rage starting from io_base.
|
||||
* @output_base Super I/O register address for Output Enable register
|
||||
* @simple_base Super I/O 'Simple I/O' Enable register
|
||||
* @simple_size Super IO 'Simple I/O' Enable register size; this is
|
||||
* required because IT87xx chips might only provide Simple I/O
|
||||
* switches on a subset of lines, whereas the others keep the
|
||||
* same status all time.
|
||||
*/
|
||||
struct it87_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
u16 io_base;
|
||||
u16 io_size;
|
||||
u8 output_base;
|
||||
u8 simple_base;
|
||||
u8 simple_size;
|
||||
};
|
||||
|
||||
static struct it87_gpio it87_gpio_chip = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock),
|
||||
};
|
||||
|
||||
static inline struct it87_gpio *to_it87_gpio(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct it87_gpio, chip);
|
||||
}
|
||||
|
||||
/* Superio chip access functions; copied from wdt_it87 */
|
||||
|
||||
static inline int superio_enter(void)
|
||||
{
|
||||
/*
|
||||
* Try to reserve REG and REG + 1 for exclusive access.
|
||||
*/
|
||||
if (!request_muxed_region(REG, 2, KBUILD_MODNAME))
|
||||
return -EBUSY;
|
||||
|
||||
outb(0x87, REG);
|
||||
outb(0x01, REG);
|
||||
outb(0x55, REG);
|
||||
outb(0x55, REG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void superio_exit(void)
|
||||
{
|
||||
outb(0x02, REG);
|
||||
outb(0x02, VAL);
|
||||
release_region(REG, 2);
|
||||
}
|
||||
|
||||
static inline void superio_select(int ldn)
|
||||
{
|
||||
outb(LDNREG, REG);
|
||||
outb(ldn, VAL);
|
||||
}
|
||||
|
||||
static inline int superio_inb(int reg)
|
||||
{
|
||||
outb(reg, REG);
|
||||
return inb(VAL);
|
||||
}
|
||||
|
||||
static inline void superio_outb(int val, int reg)
|
||||
{
|
||||
outb(reg, REG);
|
||||
outb(val, VAL);
|
||||
}
|
||||
|
||||
static inline int superio_inw(int reg)
|
||||
{
|
||||
int val;
|
||||
|
||||
outb(reg++, REG);
|
||||
val = inb(VAL) << 8;
|
||||
outb(reg, REG);
|
||||
val |= inb(VAL);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void superio_outw(int val, int reg)
|
||||
{
|
||||
outb(reg++, REG);
|
||||
outb(val >> 8, VAL);
|
||||
outb(reg, REG);
|
||||
outb(val, VAL);
|
||||
}
|
||||
|
||||
static inline void superio_set_mask(int mask, int reg)
|
||||
{
|
||||
u8 curr_val = superio_inb(reg);
|
||||
u8 new_val = curr_val | mask;
|
||||
|
||||
if (curr_val != new_val)
|
||||
superio_outb(new_val, reg);
|
||||
}
|
||||
|
||||
static inline void superio_clear_mask(int mask, int reg)
|
||||
{
|
||||
u8 curr_val = superio_inb(reg);
|
||||
u8 new_val = curr_val & ~mask;
|
||||
|
||||
if (curr_val != new_val)
|
||||
superio_outb(new_val, reg);
|
||||
}
|
||||
|
||||
static int it87_gpio_request(struct gpio_chip *chip, unsigned gpio_num)
|
||||
{
|
||||
u8 mask, group;
|
||||
int rc = 0;
|
||||
struct it87_gpio *it87_gpio = to_it87_gpio(chip);
|
||||
|
||||
mask = 1 << (gpio_num % 8);
|
||||
group = (gpio_num / 8);
|
||||
|
||||
spin_lock(&it87_gpio->lock);
|
||||
|
||||
rc = superio_enter();
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
/* not all the IT87xx chips support Simple I/O and not all of
|
||||
* them allow all the lines to be set/unset to Simple I/O.
|
||||
*/
|
||||
if (group < it87_gpio->simple_size)
|
||||
superio_set_mask(mask, group + it87_gpio->simple_base);
|
||||
|
||||
/* clear output enable, setting the pin to input, as all the
|
||||
* newly-exported GPIO interfaces are set to input.
|
||||
*/
|
||||
superio_clear_mask(mask, group + it87_gpio->output_base);
|
||||
|
||||
superio_exit();
|
||||
|
||||
exit:
|
||||
spin_unlock(&it87_gpio->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int it87_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
|
||||
{
|
||||
u16 reg;
|
||||
u8 mask;
|
||||
struct it87_gpio *it87_gpio = to_it87_gpio(chip);
|
||||
|
||||
mask = 1 << (gpio_num % 8);
|
||||
reg = (gpio_num / 8) + it87_gpio->io_base;
|
||||
|
||||
return !!(inb(reg) & mask);
|
||||
}
|
||||
|
||||
static int it87_gpio_direction_in(struct gpio_chip *chip, unsigned gpio_num)
|
||||
{
|
||||
u8 mask, group;
|
||||
int rc = 0;
|
||||
struct it87_gpio *it87_gpio = to_it87_gpio(chip);
|
||||
|
||||
mask = 1 << (gpio_num % 8);
|
||||
group = (gpio_num / 8);
|
||||
|
||||
spin_lock(&it87_gpio->lock);
|
||||
|
||||
rc = superio_enter();
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
/* clear the output enable bit */
|
||||
superio_clear_mask(mask, group + it87_gpio->output_base);
|
||||
|
||||
superio_exit();
|
||||
|
||||
exit:
|
||||
spin_unlock(&it87_gpio->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void it87_gpio_set(struct gpio_chip *chip,
|
||||
unsigned gpio_num, int val)
|
||||
{
|
||||
u8 mask, curr_vals;
|
||||
u16 reg;
|
||||
struct it87_gpio *it87_gpio = to_it87_gpio(chip);
|
||||
|
||||
mask = 1 << (gpio_num % 8);
|
||||
reg = (gpio_num / 8) + it87_gpio->io_base;
|
||||
|
||||
curr_vals = inb(reg);
|
||||
if (val)
|
||||
outb(curr_vals | mask, reg);
|
||||
else
|
||||
outb(curr_vals & ~mask, reg);
|
||||
}
|
||||
|
||||
static int it87_gpio_direction_out(struct gpio_chip *chip,
|
||||
unsigned gpio_num, int val)
|
||||
{
|
||||
u8 mask, group;
|
||||
int rc = 0;
|
||||
struct it87_gpio *it87_gpio = to_it87_gpio(chip);
|
||||
|
||||
mask = 1 << (gpio_num % 8);
|
||||
group = (gpio_num / 8);
|
||||
|
||||
spin_lock(&it87_gpio->lock);
|
||||
|
||||
rc = superio_enter();
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
/* set the output enable bit */
|
||||
superio_set_mask(mask, group + it87_gpio->output_base);
|
||||
|
||||
it87_gpio_set(chip, gpio_num, val);
|
||||
|
||||
superio_exit();
|
||||
|
||||
exit:
|
||||
spin_unlock(&it87_gpio->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct gpio_chip it87_template_chip = {
|
||||
.label = KBUILD_MODNAME,
|
||||
.owner = THIS_MODULE,
|
||||
.request = it87_gpio_request,
|
||||
.get = it87_gpio_get,
|
||||
.direction_input = it87_gpio_direction_in,
|
||||
.set = it87_gpio_set,
|
||||
.direction_output = it87_gpio_direction_out,
|
||||
.base = -1
|
||||
};
|
||||
|
||||
static int __init it87_gpio_init(void)
|
||||
{
|
||||
int rc = 0, i;
|
||||
u16 chip_type;
|
||||
u8 chip_rev, gpio_ba_reg;
|
||||
char *labels, **labels_table;
|
||||
|
||||
struct it87_gpio *it87_gpio = &it87_gpio_chip;
|
||||
|
||||
rc = superio_enter();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
chip_type = superio_inw(CHIPID);
|
||||
chip_rev = superio_inb(CHIPREV) & 0x0f;
|
||||
superio_exit();
|
||||
|
||||
it87_gpio->chip = it87_template_chip;
|
||||
|
||||
switch (chip_type) {
|
||||
case IT8728_ID:
|
||||
case IT8732_ID:
|
||||
gpio_ba_reg = 0x62;
|
||||
it87_gpio->io_size = 8;
|
||||
it87_gpio->output_base = 0xc8;
|
||||
it87_gpio->simple_base = 0xc0;
|
||||
it87_gpio->simple_size = 5;
|
||||
it87_gpio->chip.ngpio = 64;
|
||||
break;
|
||||
case IT8761_ID:
|
||||
gpio_ba_reg = 0x60;
|
||||
it87_gpio->io_size = 4;
|
||||
it87_gpio->output_base = 0xf0;
|
||||
it87_gpio->simple_size = 0;
|
||||
it87_gpio->chip.ngpio = 16;
|
||||
break;
|
||||
case NO_DEV_ID:
|
||||
pr_err("no device\n");
|
||||
return -ENODEV;
|
||||
default:
|
||||
pr_err("Unknown Chip found, Chip %04x Revision %x\n",
|
||||
chip_type, chip_rev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = superio_enter();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
superio_select(GPIO);
|
||||
|
||||
/* fetch GPIO base address */
|
||||
it87_gpio->io_base = superio_inw(gpio_ba_reg);
|
||||
|
||||
superio_exit();
|
||||
|
||||
pr_info("Found Chip IT%04x rev %x. %u GPIO lines starting at %04xh\n",
|
||||
chip_type, chip_rev, it87_gpio->chip.ngpio,
|
||||
it87_gpio->io_base);
|
||||
|
||||
if (!request_region(it87_gpio->io_base, it87_gpio->io_size,
|
||||
KBUILD_MODNAME))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set up aliases for the GPIO connection.
|
||||
*
|
||||
* ITE documentation for recent chips such as the IT8728F
|
||||
* refers to the GPIO lines as GPxy, with a coordinates system
|
||||
* where x is the GPIO group (starting from 1) and y is the
|
||||
* bit within the group.
|
||||
*
|
||||
* By creating these aliases, we make it easier to understand
|
||||
* to which GPIO pin we're referring to.
|
||||
*/
|
||||
labels = kcalloc(it87_gpio->chip.ngpio, sizeof("it87_gpXY"),
|
||||
GFP_KERNEL);
|
||||
labels_table = kcalloc(it87_gpio->chip.ngpio, sizeof(const char *),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!labels || !labels_table) {
|
||||
rc = -ENOMEM;
|
||||
goto labels_free;
|
||||
}
|
||||
|
||||
for (i = 0; i < it87_gpio->chip.ngpio; i++) {
|
||||
char *label = &labels[i * sizeof("it87_gpXY")];
|
||||
|
||||
sprintf(label, "it87_gp%u%u", 1+(i/8), i%8);
|
||||
labels_table[i] = label;
|
||||
}
|
||||
|
||||
it87_gpio->chip.names = (const char *const*)labels_table;
|
||||
|
||||
rc = gpiochip_add(&it87_gpio->chip);
|
||||
if (rc)
|
||||
goto labels_free;
|
||||
|
||||
return 0;
|
||||
|
||||
labels_free:
|
||||
kfree(labels_table);
|
||||
kfree(labels);
|
||||
release_region(it87_gpio->io_base, it87_gpio->io_size);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit it87_gpio_exit(void)
|
||||
{
|
||||
struct it87_gpio *it87_gpio = &it87_gpio_chip;
|
||||
|
||||
gpiochip_remove(&it87_gpio->chip);
|
||||
release_region(it87_gpio->io_base, it87_gpio->io_size);
|
||||
kfree(it87_gpio->chip.names[0]);
|
||||
kfree(it87_gpio->chip.names);
|
||||
}
|
||||
|
||||
module_init(it87_gpio_init);
|
||||
module_exit(it87_gpio_exit);
|
||||
|
||||
MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>");
|
||||
MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips");
|
||||
MODULE_LICENSE("GPL");
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
* GPIO interface for IT8761E Super I/O chip
|
||||
*
|
||||
* Author: Denis Turischev <denis@compulab.co.il>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#define SIO_CHIP_ID 0x8761
|
||||
#define CHIP_ID_HIGH_BYTE 0x20
|
||||
#define CHIP_ID_LOW_BYTE 0x21
|
||||
|
||||
static u8 ports[2] = { 0x2e, 0x4e };
|
||||
static u8 port;
|
||||
|
||||
static DEFINE_SPINLOCK(sio_lock);
|
||||
|
||||
#define GPIO_NAME "it8761-gpio"
|
||||
#define GPIO_BA_HIGH_BYTE 0x60
|
||||
#define GPIO_BA_LOW_BYTE 0x61
|
||||
#define GPIO_IOSIZE 4
|
||||
#define GPIO1X_IO 0xf0
|
||||
#define GPIO2X_IO 0xf1
|
||||
|
||||
static u16 gpio_ba;
|
||||
|
||||
static u8 read_reg(u8 addr, u8 port)
|
||||
{
|
||||
outb(addr, port);
|
||||
return inb(port + 1);
|
||||
}
|
||||
|
||||
static void write_reg(u8 data, u8 addr, u8 port)
|
||||
{
|
||||
outb(addr, port);
|
||||
outb(data, port + 1);
|
||||
}
|
||||
|
||||
static void enter_conf_mode(u8 port)
|
||||
{
|
||||
outb(0x87, port);
|
||||
outb(0x61, port);
|
||||
outb(0x55, port);
|
||||
outb((port == 0x2e) ? 0x55 : 0xaa, port);
|
||||
}
|
||||
|
||||
static void exit_conf_mode(u8 port)
|
||||
{
|
||||
outb(0x2, port);
|
||||
outb(0x2, port + 1);
|
||||
}
|
||||
|
||||
static void enter_gpio_mode(u8 port)
|
||||
{
|
||||
write_reg(0x2, 0x7, port);
|
||||
}
|
||||
|
||||
static int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
|
||||
{
|
||||
u16 reg;
|
||||
u8 bit;
|
||||
|
||||
bit = gpio_num % 8;
|
||||
reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
|
||||
|
||||
return !!(inb(reg) & (1 << bit));
|
||||
}
|
||||
|
||||
static int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
|
||||
{
|
||||
u8 curr_dirs;
|
||||
u8 io_reg, bit;
|
||||
|
||||
bit = gpio_num % 8;
|
||||
io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
|
||||
|
||||
spin_lock(&sio_lock);
|
||||
|
||||
enter_conf_mode(port);
|
||||
enter_gpio_mode(port);
|
||||
|
||||
curr_dirs = read_reg(io_reg, port);
|
||||
|
||||
if (curr_dirs & (1 << bit))
|
||||
write_reg(curr_dirs & ~(1 << bit), io_reg, port);
|
||||
|
||||
exit_conf_mode(port);
|
||||
|
||||
spin_unlock(&sio_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void it8761e_gpio_set(struct gpio_chip *gc,
|
||||
unsigned gpio_num, int val)
|
||||
{
|
||||
u8 curr_vals, bit;
|
||||
u16 reg;
|
||||
|
||||
bit = gpio_num % 8;
|
||||
reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
|
||||
|
||||
spin_lock(&sio_lock);
|
||||
|
||||
curr_vals = inb(reg);
|
||||
if (val)
|
||||
outb(curr_vals | (1 << bit), reg);
|
||||
else
|
||||
outb(curr_vals & ~(1 << bit), reg);
|
||||
|
||||
spin_unlock(&sio_lock);
|
||||
}
|
||||
|
||||
static int it8761e_gpio_direction_out(struct gpio_chip *gc,
|
||||
unsigned gpio_num, int val)
|
||||
{
|
||||
u8 curr_dirs, io_reg, bit;
|
||||
|
||||
bit = gpio_num % 8;
|
||||
io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
|
||||
|
||||
it8761e_gpio_set(gc, gpio_num, val);
|
||||
|
||||
spin_lock(&sio_lock);
|
||||
|
||||
enter_conf_mode(port);
|
||||
enter_gpio_mode(port);
|
||||
|
||||
curr_dirs = read_reg(io_reg, port);
|
||||
|
||||
if (!(curr_dirs & (1 << bit)))
|
||||
write_reg(curr_dirs | (1 << bit), io_reg, port);
|
||||
|
||||
exit_conf_mode(port);
|
||||
|
||||
spin_unlock(&sio_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip it8761e_gpio_chip = {
|
||||
.label = GPIO_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.get = it8761e_gpio_get,
|
||||
.direction_input = it8761e_gpio_direction_in,
|
||||
.set = it8761e_gpio_set,
|
||||
.direction_output = it8761e_gpio_direction_out,
|
||||
};
|
||||
|
||||
static int __init it8761e_gpio_init(void)
|
||||
{
|
||||
int i, id, err;
|
||||
|
||||
/* chip and port detection */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
spin_lock(&sio_lock);
|
||||
enter_conf_mode(ports[i]);
|
||||
|
||||
id = (read_reg(CHIP_ID_HIGH_BYTE, ports[i]) << 8) +
|
||||
read_reg(CHIP_ID_LOW_BYTE, ports[i]);
|
||||
|
||||
exit_conf_mode(ports[i]);
|
||||
spin_unlock(&sio_lock);
|
||||
|
||||
if (id == SIO_CHIP_ID) {
|
||||
port = ports[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!port)
|
||||
return -ENODEV;
|
||||
|
||||
/* fetch GPIO base address */
|
||||
enter_conf_mode(port);
|
||||
enter_gpio_mode(port);
|
||||
gpio_ba = (read_reg(GPIO_BA_HIGH_BYTE, port) << 8) +
|
||||
read_reg(GPIO_BA_LOW_BYTE, port);
|
||||
exit_conf_mode(port);
|
||||
|
||||
if (!request_region(gpio_ba, GPIO_IOSIZE, GPIO_NAME))
|
||||
return -EBUSY;
|
||||
|
||||
it8761e_gpio_chip.base = -1;
|
||||
it8761e_gpio_chip.ngpio = 16;
|
||||
|
||||
err = gpiochip_add(&it8761e_gpio_chip);
|
||||
if (err < 0)
|
||||
goto gpiochip_add_err;
|
||||
|
||||
return 0;
|
||||
|
||||
gpiochip_add_err:
|
||||
release_region(gpio_ba, GPIO_IOSIZE);
|
||||
gpio_ba = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit it8761e_gpio_exit(void)
|
||||
{
|
||||
if (gpio_ba) {
|
||||
gpiochip_remove(&it8761e_gpio_chip);
|
||||
release_region(gpio_ba, GPIO_IOSIZE);
|
||||
gpio_ba = 0;
|
||||
}
|
||||
}
|
||||
module_init(it8761e_gpio_init);
|
||||
module_exit(it8761e_gpio_exit);
|
||||
|
||||
MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
|
||||
MODULE_DESCRIPTION("GPIO interface for IT8761E Super I/O chip");
|
||||
MODULE_LICENSE("GPL");
|
@ -36,16 +36,6 @@ static inline struct lpc18xx_gpio_chip *to_lpc18xx_gpio(struct gpio_chip *chip)
|
||||
return container_of(chip, struct lpc18xx_gpio_chip, gpio);
|
||||
}
|
||||
|
||||
static int lpc18xx_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(offset);
|
||||
}
|
||||
|
||||
static void lpc18xx_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(offset);
|
||||
}
|
||||
|
||||
static void lpc18xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct lpc18xx_gpio_chip *gc = to_lpc18xx_gpio(chip);
|
||||
@ -95,8 +85,8 @@ static int lpc18xx_gpio_direction_output(struct gpio_chip *chip,
|
||||
|
||||
static struct gpio_chip lpc18xx_chip = {
|
||||
.label = "lpc18xx/43xx-gpio",
|
||||
.request = lpc18xx_gpio_request,
|
||||
.free = lpc18xx_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.direction_input = lpc18xx_gpio_direction_input,
|
||||
.direction_output = lpc18xx_gpio_direction_output,
|
||||
.set = lpc18xx_gpio_set,
|
||||
|
@ -236,7 +236,6 @@ int __max730x_remove(struct device *dev)
|
||||
ts->write(dev, 0x04, 0x00);
|
||||
gpiochip_remove(&ts->chip);
|
||||
mutex_destroy(&ts->lock);
|
||||
kfree(ts);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__max730x_remove);
|
||||
|
@ -29,16 +29,6 @@
|
||||
#define GPIO_DATA_IN 0x04
|
||||
#define GPIO_PIN_DIRECTION 0x08
|
||||
|
||||
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 int moxart_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -66,8 +56,8 @@ static int moxart_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
bgc->gc.label = "moxart-gpio";
|
||||
bgc->gc.request = moxart_gpio_request;
|
||||
bgc->gc.free = moxart_gpio_free;
|
||||
bgc->gc.request = gpiochip_generic_request;
|
||||
bgc->gc.free = gpiochip_generic_free;
|
||||
bgc->data = bgc->read_reg(bgc->reg_set);
|
||||
bgc->gc.base = 0;
|
||||
bgc->gc.ngpio = 32;
|
||||
|
@ -1,453 +0,0 @@
|
||||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#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>
|
||||
|
||||
#define MAX_NR_GPIO 300
|
||||
|
||||
/* Bits of interest in the GPIO_IN_OUT register.
|
||||
*/
|
||||
enum {
|
||||
GPIO_IN = 0,
|
||||
GPIO_OUT = 1
|
||||
};
|
||||
|
||||
/* Bits of interest in the GPIO_INTR_STATUS register.
|
||||
*/
|
||||
enum {
|
||||
INTR_STATUS = 0,
|
||||
};
|
||||
|
||||
/* Bits of interest in the GPIO_CFG register.
|
||||
*/
|
||||
enum {
|
||||
GPIO_OE = 9,
|
||||
};
|
||||
|
||||
/* Bits of interest in the GPIO_INTR_CFG register.
|
||||
* When a GPIO triggers, two separate decisions are made, controlled
|
||||
* by two separate flags.
|
||||
*
|
||||
* - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
|
||||
* register for that GPIO will be updated to reflect the triggering of that
|
||||
* gpio. If this bit is 0, this register will not be updated.
|
||||
* - Second, INTR_ENABLE controls whether an interrupt is triggered.
|
||||
*
|
||||
* If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
|
||||
* can be triggered but the status register will not reflect it.
|
||||
*/
|
||||
enum {
|
||||
INTR_ENABLE = 0,
|
||||
INTR_POL_CTL = 1,
|
||||
INTR_DECT_CTL = 2,
|
||||
INTR_RAW_STATUS_EN = 3,
|
||||
};
|
||||
|
||||
/* Codes of interest in GPIO_INTR_CFG_SU.
|
||||
*/
|
||||
enum {
|
||||
TARGET_PROC_SCORPION = 4,
|
||||
TARGET_PROC_NONE = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
|
||||
*
|
||||
* @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
|
||||
* keeping track of which gpios are unmasked as irq sources, we avoid
|
||||
* having to do readl calls on hundreds of iomapped registers each time
|
||||
* the summary interrupt fires in order to locate the active interrupts.
|
||||
*
|
||||
* @wake_irqs: a bitmap for tracking which interrupt lines are enabled
|
||||
* as wakeup sources. When the device is suspended, interrupts which are
|
||||
* not wakeup sources are disabled.
|
||||
*
|
||||
* @dual_edge_irqs: a bitmap used to track which irqs are configured
|
||||
* as dual-edge, as this is not supported by the hardware and requires
|
||||
* some special handling in the driver.
|
||||
*/
|
||||
struct msm_gpio_dev {
|
||||
struct gpio_chip gpio_chip;
|
||||
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)
|
||||
{
|
||||
return container_of(chip, struct msm_gpio_dev, gpio_chip);
|
||||
}
|
||||
|
||||
static inline void set_gpio_bits(unsigned n, void __iomem *reg)
|
||||
{
|
||||
writel(readl(reg) | n, reg);
|
||||
}
|
||||
|
||||
static inline void clear_gpio_bits(unsigned n, void __iomem *reg)
|
||||
{
|
||||
writel(readl(reg) & ~n, reg);
|
||||
}
|
||||
|
||||
static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN);
|
||||
}
|
||||
|
||||
static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||
{
|
||||
writel(val ? BIT(GPIO_OUT) : 0, GPIO_IN_OUT(offset));
|
||||
}
|
||||
|
||||
static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&tlmm_lock, irq_flags);
|
||||
clear_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
|
||||
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned offset,
|
||||
int val)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&tlmm_lock, irq_flags);
|
||||
msm_gpio_set(chip, offset, val);
|
||||
set_gpio_bits(BIT(GPIO_OE), GPIO_CONFIG(offset));
|
||||
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned 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);
|
||||
}
|
||||
|
||||
/* For dual-edge interrupts in software, since the hardware has no
|
||||
* such support:
|
||||
*
|
||||
* At appropriate moments, this function may be called to flip the polarity
|
||||
* settings of both-edge irq lines to try and catch the next edge.
|
||||
*
|
||||
* The attempt is considered successful if:
|
||||
* - the status bit goes high, indicating that an edge was caught, or
|
||||
* - the input value of the gpio doesn't change during the attempt.
|
||||
* If the value changes twice during the process, that would cause the first
|
||||
* test to fail but would force the second, as two opposite
|
||||
* transitions would cause a detection no matter the polarity setting.
|
||||
*
|
||||
* The do-loop tries to sledge-hammer closed the timing hole between
|
||||
* the initial value-read and the polarity-write - if the line value changes
|
||||
* during that window, an interrupt is lost, the new polarity setting is
|
||||
* incorrect, and the first success test will fail, causing a retry.
|
||||
*
|
||||
* Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
|
||||
*/
|
||||
static void msm_gpio_update_dual_edge_pos(unsigned gpio)
|
||||
{
|
||||
int loop_limit = 100;
|
||||
unsigned val, val2, intstat;
|
||||
|
||||
do {
|
||||
val = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
|
||||
if (val)
|
||||
clear_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
|
||||
else
|
||||
set_gpio_bits(BIT(INTR_POL_CTL), GPIO_INTR_CFG(gpio));
|
||||
val2 = readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN);
|
||||
intstat = readl(GPIO_INTR_STATUS(gpio)) & BIT(INTR_STATUS);
|
||||
if (intstat || val == val2)
|
||||
return;
|
||||
} while (loop_limit-- > 0);
|
||||
pr_err("%s: dual-edge irq failed to stabilize, "
|
||||
"interrupts dropped. %#08x != %#08x\n",
|
||||
__func__, val, val2);
|
||||
}
|
||||
|
||||
static void msm_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
int gpio = d->hwirq;
|
||||
|
||||
writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio));
|
||||
if (test_bit(gpio, msm_gpio.dual_edge_irqs))
|
||||
msm_gpio_update_dual_edge_pos(gpio);
|
||||
}
|
||||
|
||||
static void msm_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
int gpio = d->hwirq;
|
||||
|
||||
spin_lock_irqsave(&tlmm_lock, irq_flags);
|
||||
writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(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);
|
||||
}
|
||||
|
||||
static void msm_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
int gpio = d->hwirq;
|
||||
|
||||
spin_lock_irqsave(&tlmm_lock, irq_flags);
|
||||
__set_bit(gpio, msm_gpio.enabled_irqs);
|
||||
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);
|
||||
}
|
||||
|
||||
static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
int gpio = d->hwirq;
|
||||
uint32_t bits;
|
||||
|
||||
spin_lock_irqsave(&tlmm_lock, irq_flags);
|
||||
|
||||
bits = readl(GPIO_INTR_CFG(gpio));
|
||||
|
||||
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
|
||||
bits |= BIT(INTR_DECT_CTL);
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
||||
__set_bit(gpio, msm_gpio.dual_edge_irqs);
|
||||
else
|
||||
__clear_bit(gpio, msm_gpio.dual_edge_irqs);
|
||||
} else {
|
||||
bits &= ~BIT(INTR_DECT_CTL);
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
__clear_bit(gpio, msm_gpio.dual_edge_irqs);
|
||||
}
|
||||
|
||||
if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
|
||||
bits |= BIT(INTR_POL_CTL);
|
||||
else
|
||||
bits &= ~BIT(INTR_POL_CTL);
|
||||
|
||||
writel(bits, GPIO_INTR_CFG(gpio));
|
||||
|
||||
if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
||||
msm_gpio_update_dual_edge_pos(gpio);
|
||||
|
||||
spin_unlock_irqrestore(&tlmm_lock, irq_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When the summary IRQ is raised, any number of GPIO lines may be high.
|
||||
* It is the job of the summary handler to find all those GPIO lines
|
||||
* which have been set as summary IRQ lines and which are triggered,
|
||||
* and to call their interrupt handlers.
|
||||
*/
|
||||
static void msm_summary_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
unsigned long i;
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) {
|
||||
if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
|
||||
generic_handle_irq(irq_find_mapping(msm_gpio.domain,
|
||||
i));
|
||||
}
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
{
|
||||
int gpio = d->hwirq;
|
||||
|
||||
if (on) {
|
||||
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, MAX_NR_GPIO))
|
||||
irq_set_irq_wake(msm_gpio.summary_irq, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip msm_gpio_irq_chip = {
|
||||
.name = "msmgpio",
|
||||
.irq_mask = msm_gpio_irq_mask,
|
||||
.irq_unmask = msm_gpio_irq_unmask,
|
||||
.irq_ack = msm_gpio_irq_ack,
|
||||
.irq_set_type = msm_gpio_irq_set_type,
|
||||
.irq_set_wake = msm_gpio_irq_set_wake,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
irq_set_lockdep_class(irq, &msm_gpio_lock_class);
|
||||
irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
|
||||
handle_level_irq);
|
||||
|
||||
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;
|
||||
|
||||
ret = gpiochip_add(&msm_gpio.gpio_chip);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
gpiochip_remove(&msm_gpio.gpio_chip);
|
||||
|
||||
irq_set_handler(msm_gpio.summary_irq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver msm_gpio_driver = {
|
||||
.probe = msm_gpio_probe,
|
||||
.remove = msm_gpio_remove,
|
||||
.driver = {
|
||||
.name = "msmgpio",
|
||||
.of_match_table = msm_gpio_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(msm_gpio_driver)
|
||||
|
||||
MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
|
||||
MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:msmgpio");
|
@ -185,16 +185,6 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
|
||||
* Functions implementing the gpio_chip methods
|
||||
*/
|
||||
|
||||
static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + pin);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + pin);
|
||||
}
|
||||
|
||||
static void mvebu_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||
{
|
||||
struct mvebu_gpio_chip *mvchip =
|
||||
@ -709,8 +699,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
||||
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.request = gpiochip_generic_request;
|
||||
mvchip->chip.free = gpiochip_generic_free;
|
||||
mvchip->chip.direction_input = mvebu_gpio_direction_input;
|
||||
mvchip->chip.get = mvebu_gpio_get;
|
||||
mvchip->chip.direction_output = mvebu_gpio_direction_output;
|
||||
|
@ -51,7 +51,7 @@ struct gpio_regs {
|
||||
struct gpio_bank {
|
||||
struct list_head node;
|
||||
void __iomem *base;
|
||||
u16 irq;
|
||||
int irq;
|
||||
u32 non_wakeup_gpios;
|
||||
u32 enabled_non_wakeup_gpios;
|
||||
struct gpio_regs context;
|
||||
@ -59,6 +59,7 @@ struct gpio_bank {
|
||||
u32 level_mask;
|
||||
u32 toggle_mask;
|
||||
raw_spinlock_t lock;
|
||||
raw_spinlock_t wa_lock;
|
||||
struct gpio_chip chip;
|
||||
struct clk *dbck;
|
||||
u32 mod_usage;
|
||||
@ -496,9 +497,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
retval = omap_set_gpio_triggering(bank, offset, type);
|
||||
if (retval) {
|
||||
@ -521,8 +519,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_put(bank->dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -654,8 +650,13 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(d);
|
||||
unsigned offset = d->hwirq;
|
||||
int ret;
|
||||
|
||||
return omap_set_gpio_wakeup(bank, offset, enable);
|
||||
ret = omap_set_gpio_wakeup(bank, offset, enable);
|
||||
if (!ret)
|
||||
ret = irq_set_irq_wake(bank->irq, enable);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
@ -709,26 +710,21 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
* line's interrupt handler has been run, we may miss some nested
|
||||
* interrupts.
|
||||
*/
|
||||
static void omap_gpio_irq_handler(struct irq_desc *desc)
|
||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
{
|
||||
void __iomem *isr_reg = NULL;
|
||||
u32 isr;
|
||||
unsigned int bit;
|
||||
struct gpio_bank *bank;
|
||||
int unmasked = 0;
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||
struct gpio_bank *bank = gpiobank;
|
||||
unsigned long wa_lock_flags;
|
||||
unsigned long lock_flags;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
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;
|
||||
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
while (1) {
|
||||
u32 isr_saved, level_mask = 0;
|
||||
u32 enabled;
|
||||
@ -750,13 +746,6 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
|
||||
|
||||
/* if there is only edge sensitive GPIO pin interrupts
|
||||
configured, we could unmask GPIO bank interrupt immediately */
|
||||
if (!level_mask && !unmasked) {
|
||||
unmasked = 1;
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
if (!isr)
|
||||
break;
|
||||
|
||||
@ -777,18 +766,18 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
|
||||
|
||||
raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
|
||||
|
||||
generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
|
||||
bit));
|
||||
|
||||
raw_spin_unlock_irqrestore(&bank->wa_lock,
|
||||
wa_lock_flags);
|
||||
}
|
||||
}
|
||||
/* if bank has any level sensitive GPIO pin interrupt
|
||||
configured, we must unmask the bank interrupt only after
|
||||
handler(s) are executed in order to avoid spurious bank
|
||||
interrupt */
|
||||
exit:
|
||||
if (!unmasked)
|
||||
chained_irq_exit(irqchip, desc);
|
||||
pm_runtime_put(bank->dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static unsigned int omap_gpio_irq_startup(struct irq_data *d)
|
||||
@ -797,9 +786,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
|
||||
unsigned long flags;
|
||||
unsigned offset = d->hwirq;
|
||||
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
|
||||
if (!LINE_USED(bank->mod_usage, offset))
|
||||
@ -815,8 +801,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
|
||||
return 0;
|
||||
err:
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_put(bank->dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -835,6 +819,19 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
|
||||
omap_clear_gpio_debounce(bank, offset);
|
||||
omap_disable_gpio_module(bank, offset);
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
}
|
||||
|
||||
static void omap_gpio_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(data);
|
||||
|
||||
if (!BANK_USED(bank))
|
||||
pm_runtime_get_sync(bank->dev);
|
||||
}
|
||||
|
||||
static void gpio_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_bank *bank = omap_irq_data_get_bank(data);
|
||||
|
||||
/*
|
||||
* If this is the last IRQ to be freed in the bank,
|
||||
@ -1132,7 +1129,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
||||
}
|
||||
|
||||
ret = gpiochip_irqchip_add(&bank->chip, irqc,
|
||||
irq_base, omap_gpio_irq_handler,
|
||||
irq_base, handle_bad_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
|
||||
if (ret) {
|
||||
@ -1141,10 +1138,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(&bank->chip, irqc,
|
||||
bank->irq, omap_gpio_irq_handler);
|
||||
gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
|
||||
|
||||
return 0;
|
||||
ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler,
|
||||
0, dev_name(bank->dev), bank);
|
||||
if (ret)
|
||||
gpiochip_remove(&bank->chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id omap_gpio_match[];
|
||||
@ -1183,6 +1184,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
irqc->irq_unmask = omap_gpio_unmask_irq,
|
||||
irqc->irq_set_type = omap_gpio_irq_type,
|
||||
irqc->irq_set_wake = omap_gpio_wake_enable,
|
||||
irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
|
||||
irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
|
||||
irqc->name = dev_name(&pdev->dev);
|
||||
|
||||
bank->irq = platform_get_irq(pdev, 0);
|
||||
@ -1224,6 +1227,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
bank->set_dataout = omap_set_gpio_dataout_mask;
|
||||
|
||||
raw_spin_lock_init(&bank->lock);
|
||||
raw_spin_lock_init(&bank->wa_lock);
|
||||
|
||||
/* Static mapping, never released */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define PCA953X_INPUT 0
|
||||
#define PCA953X_OUTPUT 1
|
||||
@ -42,6 +43,9 @@
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA953X_TYPE 0x1000
|
||||
#define PCA957X_TYPE 0x2000
|
||||
#define PCA_TYPE_MASK 0xF000
|
||||
|
||||
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
|
||||
|
||||
static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
|
||||
@ -67,11 +71,18 @@ 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, },
|
||||
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "xra1202", 8 | PCA953X_TYPE },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
||||
|
||||
static const struct acpi_device_id pca953x_acpi_ids[] = {
|
||||
{ "INT3491", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
|
||||
|
||||
#define MAX_BANK 5
|
||||
#define BANK_SZ 8
|
||||
|
||||
@ -95,6 +106,7 @@ struct pca953x_chip {
|
||||
struct gpio_chip gpio_chip;
|
||||
const char *const *names;
|
||||
int chip_type;
|
||||
unsigned long driver_data;
|
||||
};
|
||||
|
||||
static inline struct pca953x_chip *to_pca(struct gpio_chip *gc)
|
||||
@ -517,14 +529,13 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
|
||||
}
|
||||
|
||||
static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
const struct i2c_device_id *id,
|
||||
int irq_base)
|
||||
{
|
||||
struct i2c_client *client = chip->client;
|
||||
int ret, i, offset = 0;
|
||||
|
||||
if (client->irq && irq_base != -1
|
||||
&& (id->driver_data & PCA_INT)) {
|
||||
&& (chip->driver_data & PCA_INT)) {
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
@ -581,12 +592,11 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
|
||||
#else /* CONFIG_GPIO_PCA953X_IRQ */
|
||||
static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
const struct i2c_device_id *id,
|
||||
int irq_base)
|
||||
{
|
||||
struct i2c_client *client = chip->client;
|
||||
|
||||
if (irq_base != -1 && (id->driver_data & PCA_INT))
|
||||
if (irq_base != -1 && (chip->driver_data & PCA_INT))
|
||||
dev_warn(&client->dev, "interrupt support not compiled in\n");
|
||||
|
||||
return 0;
|
||||
@ -635,11 +645,15 @@ static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
|
||||
memset(val, 0xFF, NBANK(chip));
|
||||
else
|
||||
memset(val, 0, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_INVRT, val);
|
||||
ret = pca953x_write_regs(chip, PCA957X_INVRT, val);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* To enable register 6, 7 to control pull up and pull down */
|
||||
memset(val, 0x02, NBANK(chip));
|
||||
pca953x_write_regs(chip, PCA957X_BKEN, val);
|
||||
ret = pca953x_write_regs(chip, PCA957X_BKEN, val);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
@ -673,14 +687,26 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
|
||||
chip->client = client;
|
||||
|
||||
chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
|
||||
if (id) {
|
||||
chip->driver_data = id->driver_data;
|
||||
} else {
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
id = acpi_match_device(pca953x_acpi_ids, &client->dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
chip->driver_data = id->driver_data;
|
||||
}
|
||||
|
||||
chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
|
||||
|
||||
mutex_init(&chip->i2c_lock);
|
||||
|
||||
/* initialize cached registers from their original values.
|
||||
* we can't share this chip with another i2c master.
|
||||
*/
|
||||
pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
|
||||
pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
|
||||
|
||||
if (chip->chip_type == PCA953X_TYPE)
|
||||
ret = device_pca953x_init(chip, invert);
|
||||
@ -693,7 +719,7 @@ static int pca953x_probe(struct i2c_client *client,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pca953x_irq_setup(chip, id, irq_base);
|
||||
ret = pca953x_irq_setup(chip, irq_base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -765,6 +791,7 @@ static struct i2c_driver pca953x_driver = {
|
||||
.driver = {
|
||||
.name = "pca953x",
|
||||
.of_match_table = pca953x_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(pca953x_acpi_ids),
|
||||
},
|
||||
.probe = pca953x_probe,
|
||||
.remove = pca953x_remove,
|
||||
|
@ -52,36 +52,12 @@ struct pl061_gpio {
|
||||
|
||||
void __iomem *base;
|
||||
struct gpio_chip gc;
|
||||
bool uses_pinctrl;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct pl061_context_save_regs csave_regs;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int pl061_gpio_request(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
/*
|
||||
* Map back to global GPIO space and request muxing, the direction
|
||||
* parameter does not matter for this controller.
|
||||
*/
|
||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||
int gpio = gc->base + offset;
|
||||
|
||||
if (chip->uses_pinctrl)
|
||||
return pinctrl_request_gpio(gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pl061_gpio_free(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||
int gpio = gc->base + offset;
|
||||
|
||||
if (chip->uses_pinctrl)
|
||||
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);
|
||||
@ -152,6 +128,17 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||
if (offset < 0 || offset >= PL061_GPIO_NR)
|
||||
return -EINVAL;
|
||||
|
||||
if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
|
||||
(trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
|
||||
{
|
||||
dev_err(gc->dev,
|
||||
"trying to configure line %d for both level and edge "
|
||||
"detection, choose one!\n",
|
||||
offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
spin_lock_irqsave(&chip->lock, flags);
|
||||
|
||||
gpioiev = readb(chip->base + GPIOIEV);
|
||||
@ -159,23 +146,53 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||
gpioibe = readb(chip->base + GPIOIBE);
|
||||
|
||||
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
||||
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
|
||||
|
||||
/* Disable edge detection */
|
||||
gpioibe &= ~bit;
|
||||
/* Enable level detection */
|
||||
gpiois |= bit;
|
||||
if (trigger & IRQ_TYPE_LEVEL_HIGH)
|
||||
/* Select polarity */
|
||||
if (polarity)
|
||||
gpioiev |= bit;
|
||||
else
|
||||
gpioiev &= ~bit;
|
||||
} else
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
dev_dbg(gc->dev, "line %d: IRQ on %s level\n",
|
||||
offset,
|
||||
polarity ? "HIGH" : "LOW");
|
||||
} else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
|
||||
/* Disable level detection */
|
||||
gpiois &= ~bit;
|
||||
|
||||
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
||||
/* Setting this makes GPIOEV be ignored */
|
||||
/* Select both edges, setting this makes GPIOEV be ignored */
|
||||
gpioibe |= bit;
|
||||
else {
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
dev_dbg(gc->dev, "line %d: IRQ on both edges\n", offset);
|
||||
} else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
|
||||
(trigger & IRQ_TYPE_EDGE_FALLING)) {
|
||||
bool rising = trigger & IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
/* Disable level detection */
|
||||
gpiois &= ~bit;
|
||||
/* Clear detection on both edges */
|
||||
gpioibe &= ~bit;
|
||||
if (trigger & IRQ_TYPE_EDGE_RISING)
|
||||
/* Select edge */
|
||||
if (rising)
|
||||
gpioiev |= bit;
|
||||
else if (trigger & IRQ_TYPE_EDGE_FALLING)
|
||||
else
|
||||
gpioiev &= ~bit;
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
dev_dbg(gc->dev, "line %d: IRQ on %s edge\n",
|
||||
offset,
|
||||
rising ? "RISING" : "FALLING");
|
||||
} else {
|
||||
/* No trigger: disable everything */
|
||||
gpiois &= ~bit;
|
||||
gpioibe &= ~bit;
|
||||
gpioiev &= ~bit;
|
||||
irq_set_handler_locked(d, handle_bad_irq);
|
||||
dev_warn(gc->dev, "no trigger selected for line %d\n",
|
||||
offset);
|
||||
}
|
||||
|
||||
writeb(gpiois, chip->base + GPIOIS);
|
||||
@ -198,7 +215,6 @@ static void pl061_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
pending = readb(chip->base + GPIOMIS);
|
||||
writeb(pending, chip->base + GPIOIC);
|
||||
if (pending) {
|
||||
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
|
||||
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||
@ -234,8 +250,28 @@ static void pl061_irq_unmask(struct irq_data *d)
|
||||
spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* pl061_irq_ack() - ACK an edge IRQ
|
||||
* @d: IRQ data for this IRQ
|
||||
*
|
||||
* This gets called from the edge IRQ handler to ACK the edge IRQ
|
||||
* in the GPIOIC (interrupt-clear) register. For level IRQs this is
|
||||
* not needed: these go away when the level signal goes away.
|
||||
*/
|
||||
static void pl061_irq_ack(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);
|
||||
|
||||
spin_lock(&chip->lock);
|
||||
writeb(mask, chip->base + GPIOIC);
|
||||
spin_unlock(&chip->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip pl061_irqchip = {
|
||||
.name = "pl061",
|
||||
.irq_ack = pl061_irq_ack,
|
||||
.irq_mask = pl061_irq_mask,
|
||||
.irq_unmask = pl061_irq_unmask,
|
||||
.irq_set_type = pl061_irq_type,
|
||||
@ -269,11 +305,11 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
return PTR_ERR(chip->base);
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges"))
|
||||
chip->uses_pinctrl = true;
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
|
||||
chip->gc.request = gpiochip_generic_request;
|
||||
chip->gc.free = gpiochip_generic_free;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -298,7 +334,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
}
|
||||
|
||||
ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
|
||||
irq_base, handle_simple_irq,
|
||||
irq_base, handle_bad_irq,
|
||||
IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_info(&adev->dev, "could not add irqchip\n");
|
||||
|
@ -160,6 +160,11 @@ static const struct of_device_id sx150x_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sx150x_of_match);
|
||||
|
||||
struct sx150x_chip *to_sx150x(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct sx150x_chip, gpio_chip);
|
||||
}
|
||||
|
||||
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
|
||||
{
|
||||
s32 err = i2c_smbus_write_byte_data(client, reg, val);
|
||||
@ -296,11 +301,9 @@ static int sx150x_io_output(struct sx150x_chip *chip, unsigned offset, int val)
|
||||
|
||||
static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = to_sx150x(gc);
|
||||
int status = -EINVAL;
|
||||
|
||||
chip = container_of(gc, struct sx150x_chip, gpio_chip);
|
||||
|
||||
if (!offset_is_oscio(chip, offset)) {
|
||||
mutex_lock(&chip->lock);
|
||||
status = sx150x_get_io(chip, offset);
|
||||
@ -312,9 +315,7 @@ static int sx150x_gpio_get(struct gpio_chip *gc, unsigned offset)
|
||||
|
||||
static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
|
||||
{
|
||||
struct sx150x_chip *chip;
|
||||
|
||||
chip = container_of(gc, struct sx150x_chip, gpio_chip);
|
||||
struct sx150x_chip *chip = to_sx150x(gc);
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
if (offset_is_oscio(chip, offset))
|
||||
@ -326,11 +327,9 @@ static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
|
||||
|
||||
static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = to_sx150x(gc);
|
||||
int status = -EINVAL;
|
||||
|
||||
chip = container_of(gc, struct sx150x_chip, gpio_chip);
|
||||
|
||||
if (!offset_is_oscio(chip, offset)) {
|
||||
mutex_lock(&chip->lock);
|
||||
status = sx150x_io_input(chip, offset);
|
||||
@ -343,11 +342,9 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned offset,
|
||||
int val)
|
||||
{
|
||||
struct sx150x_chip *chip;
|
||||
struct sx150x_chip *chip = to_sx150x(gc);
|
||||
int status = 0;
|
||||
|
||||
chip = container_of(gc, struct sx150x_chip, gpio_chip);
|
||||
|
||||
if (!offset_is_oscio(chip, offset)) {
|
||||
mutex_lock(&chip->lock);
|
||||
status = sx150x_io_output(chip, offset, val);
|
||||
@ -358,7 +355,7 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc,
|
||||
|
||||
static void sx150x_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
|
||||
unsigned n = d->hwirq;
|
||||
|
||||
chip->irq_masked |= (1 << n);
|
||||
@ -367,7 +364,7 @@ static void sx150x_irq_mask(struct irq_data *d)
|
||||
|
||||
static void sx150x_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
|
||||
unsigned n = d->hwirq;
|
||||
|
||||
chip->irq_masked &= ~(1 << n);
|
||||
@ -376,7 +373,7 @@ static void sx150x_irq_unmask(struct irq_data *d)
|
||||
|
||||
static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
|
||||
unsigned n, val = 0;
|
||||
|
||||
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||
@ -431,14 +428,14 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
|
||||
|
||||
static void sx150x_irq_bus_lock(struct irq_data *d)
|
||||
{
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
}
|
||||
|
||||
static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
|
||||
{
|
||||
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
struct sx150x_chip *chip = to_sx150x(irq_data_get_irq_chip_data(d));
|
||||
unsigned n;
|
||||
|
||||
if (chip->irq_update == NO_UPDATE_PENDING)
|
||||
|
@ -138,16 +138,6 @@ static int tb10x_gpio_direction_out(struct gpio_chip *chip,
|
||||
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);
|
||||
@ -213,8 +203,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
||||
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.request = gpiochip_generic_request;
|
||||
tb10x_gpio->gc.free = gpiochip_generic_free;
|
||||
tb10x_gpio->gc.base = -1;
|
||||
tb10x_gpio->gc.ngpio = ngpio;
|
||||
tb10x_gpio->gc.can_sleep = false;
|
||||
|
@ -137,16 +137,6 @@ static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
__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);
|
||||
@ -203,8 +193,8 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
|
||||
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.free = gpiochip_generic_free;
|
||||
priv->chip.request = gpiochip_generic_request;
|
||||
priv->chip.to_irq = tz1090_pdc_gpio_to_irq;
|
||||
priv->chip.of_node = np;
|
||||
|
||||
|
@ -62,6 +62,11 @@ struct vf610_gpio_port {
|
||||
|
||||
static struct irq_chip vf610_gpio_irq_chip;
|
||||
|
||||
static struct vf610_gpio_port *to_vf610_gp(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct vf610_gpio_port, gc);
|
||||
}
|
||||
|
||||
static const struct of_device_id vf610_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,vf610-gpio" },
|
||||
{ /* sentinel */ }
|
||||
@ -77,28 +82,16 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
|
||||
return readl_relaxed(reg);
|
||||
}
|
||||
|
||||
static int vf610_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void vf610_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct vf610_gpio_port *port =
|
||||
container_of(gc, struct vf610_gpio_port, gc);
|
||||
struct vf610_gpio_port *port = to_vf610_gp(gc);
|
||||
|
||||
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
|
||||
}
|
||||
|
||||
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
struct vf610_gpio_port *port =
|
||||
container_of(gc, struct vf610_gpio_port, gc);
|
||||
struct vf610_gpio_port *port = to_vf610_gp(gc);
|
||||
unsigned long mask = BIT(gpio);
|
||||
|
||||
if (val)
|
||||
@ -122,7 +115,8 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
|
||||
|
||||
static void vf610_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_desc_get_handler_data(desc);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_desc_get_handler_data(desc));
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
int pin;
|
||||
unsigned long irq_isfr;
|
||||
@ -142,7 +136,8 @@ static void vf610_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
static void vf610_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_data_get_irq_chip_data(d));
|
||||
int gpio = d->hwirq;
|
||||
|
||||
vf610_gpio_writel(BIT(gpio), port->base + PORT_ISFR);
|
||||
@ -150,7 +145,8 @@ static void vf610_gpio_irq_ack(struct irq_data *d)
|
||||
|
||||
static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_data_get_irq_chip_data(d));
|
||||
u8 irqc;
|
||||
|
||||
switch (type) {
|
||||
@ -185,7 +181,8 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type)
|
||||
|
||||
static void vf610_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_data_get_irq_chip_data(d));
|
||||
void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
|
||||
|
||||
vf610_gpio_writel(0, pcr_base);
|
||||
@ -193,7 +190,8 @@ static void vf610_gpio_irq_mask(struct irq_data *d)
|
||||
|
||||
static void vf610_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_data_get_irq_chip_data(d));
|
||||
void __iomem *pcr_base = port->base + PORT_PCR(d->hwirq);
|
||||
|
||||
vf610_gpio_writel(port->irqc[d->hwirq] << PORT_PCR_IRQC_OFFSET,
|
||||
@ -202,7 +200,8 @@ static void vf610_gpio_irq_unmask(struct irq_data *d)
|
||||
|
||||
static int vf610_gpio_irq_set_wake(struct irq_data *d, u32 enable)
|
||||
{
|
||||
struct vf610_gpio_port *port = irq_data_get_irq_chip_data(d);
|
||||
struct vf610_gpio_port *port =
|
||||
to_vf610_gp(irq_data_get_irq_chip_data(d));
|
||||
|
||||
if (enable)
|
||||
enable_irq_wake(port->irq);
|
||||
@ -255,8 +254,8 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
||||
gc->ngpio = VF610_GPIO_PER_PORT;
|
||||
gc->base = of_alias_get_id(np, "gpio") * VF610_GPIO_PER_PORT;
|
||||
|
||||
gc->request = vf610_gpio_request;
|
||||
gc->free = vf610_gpio_free;
|
||||
gc->request = gpiochip_generic_request;
|
||||
gc->free = gpiochip_generic_free;
|
||||
gc->direction_input = vf610_gpio_direction_input;
|
||||
gc->get = vf610_gpio_get;
|
||||
gc->direction_output = vf610_gpio_direction_output;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
|
||||
/*
|
||||
* XLP GPIO has multiple 32 bit registers for each feature where each register
|
||||
@ -208,25 +209,28 @@ static struct irq_chip xlp_gpio_irq_chip = {
|
||||
.flags = IRQCHIP_ONESHOT_SAFE,
|
||||
};
|
||||
|
||||
static irqreturn_t xlp_gpio_generic_handler(int irq, void *data)
|
||||
static void xlp_gpio_generic_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct xlp_gpio_priv *priv = data;
|
||||
struct xlp_gpio_priv *priv = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
int gpio, regoff;
|
||||
u32 gpio_stat;
|
||||
|
||||
regoff = -1;
|
||||
gpio_stat = 0;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) {
|
||||
if (regoff != gpio / XLP_GPIO_REGSZ) {
|
||||
regoff = gpio / XLP_GPIO_REGSZ;
|
||||
gpio_stat = readl(priv->gpio_intr_stat + regoff * 4);
|
||||
}
|
||||
|
||||
if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
|
||||
generic_handle_irq(irq_find_mapping(
|
||||
priv->chip.irqdomain, gpio));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
|
||||
@ -378,12 +382,6 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
||||
gc->get = xlp_gpio_get;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
err = devm_request_irq(&pdev->dev, irq, xlp_gpio_generic_handler,
|
||||
IRQ_TYPE_NONE, pdev->name, priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
|
||||
if (irq_base < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
|
||||
@ -401,6 +399,9 @@ static int xlp_gpio_probe(struct platform_device *pdev)
|
||||
goto out_gpio_remove;
|
||||
}
|
||||
|
||||
gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq,
|
||||
xlp_gpio_generic_handler);
|
||||
|
||||
dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
|
||||
|
||||
return 0;
|
||||
|
@ -41,7 +41,6 @@ struct zx_gpio {
|
||||
|
||||
void __iomem *base;
|
||||
struct gpio_chip gc;
|
||||
bool uses_pinctrl;
|
||||
};
|
||||
|
||||
static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
|
||||
@ -49,25 +48,6 @@ static inline struct zx_gpio *to_zx(struct gpio_chip *gc)
|
||||
return container_of(gc, struct zx_gpio, gc);
|
||||
}
|
||||
|
||||
static int zx_gpio_request(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct zx_gpio *chip = to_zx(gc);
|
||||
int gpio = gc->base + offset;
|
||||
|
||||
if (chip->uses_pinctrl)
|
||||
return pinctrl_request_gpio(gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zx_gpio_free(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct zx_gpio *chip = to_zx(gc);
|
||||
int gpio = gc->base + offset;
|
||||
|
||||
if (chip->uses_pinctrl)
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static int zx_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
struct zx_gpio *chip = to_zx(gc);
|
||||
@ -252,12 +232,12 @@ static int zx_gpio_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(chip->base);
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges"))
|
||||
chip->uses_pinctrl = true;
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
|
||||
chip->gc.request = gpiochip_generic_request;
|
||||
chip->gc.free = gpiochip_generic_free;
|
||||
}
|
||||
|
||||
id = of_alias_get_id(dev->of_node, "gpio");
|
||||
chip->gc.request = zx_gpio_request;
|
||||
chip->gc.free = zx_gpio_free;
|
||||
chip->gc.direction_input = zx_direction_input;
|
||||
chip->gc.direction_output = zx_direction_output;
|
||||
chip->gc.get = zx_get_value;
|
||||
|
@ -130,6 +130,12 @@ struct zynq_platform_data {
|
||||
|
||||
static struct irq_chip zynq_gpio_level_irqchip;
|
||||
static struct irq_chip zynq_gpio_edge_irqchip;
|
||||
|
||||
static struct zynq_gpio *to_zynq_gpio(struct gpio_chip *gc)
|
||||
{
|
||||
return container_of(gc, struct zynq_gpio, chip);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
|
||||
* for a given pin in the GPIO device
|
||||
@ -177,7 +183,7 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u32 data;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
struct zynq_gpio *gpio = to_zynq_gpio(chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
@ -201,7 +207,7 @@ static void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin,
|
||||
int state)
|
||||
{
|
||||
unsigned int reg_offset, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
struct zynq_gpio *gpio = to_zynq_gpio(chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
@ -238,7 +244,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
struct zynq_gpio *gpio = to_zynq_gpio(chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
@ -271,7 +277,7 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip);
|
||||
struct zynq_gpio *gpio = to_zynq_gpio(chip);
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
@ -301,7 +307,8 @@ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin,
|
||||
static void zynq_gpio_irq_mask(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
@ -321,7 +328,8 @@ static void zynq_gpio_irq_mask(struct irq_data *irq_data)
|
||||
static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
@ -340,7 +348,8 @@ static void zynq_gpio_irq_unmask(struct irq_data *irq_data)
|
||||
static void zynq_gpio_irq_ack(struct irq_data *irq_data)
|
||||
{
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
@ -390,7 +399,8 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
{
|
||||
u32 int_type, int_pol, int_any;
|
||||
unsigned int device_pin_num, bank_num, bank_pin_num;
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(irq_data);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_data_get_irq_chip_data(irq_data));
|
||||
|
||||
device_pin_num = irq_data->hwirq;
|
||||
zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio);
|
||||
@ -453,7 +463,8 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
|
||||
static int zynq_gpio_set_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
struct zynq_gpio *gpio = irq_data_get_irq_chip_data(data);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_data_get_irq_chip_data(data));
|
||||
|
||||
irq_set_irq_wake(gpio->irq, on);
|
||||
|
||||
@ -518,7 +529,8 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc)
|
||||
{
|
||||
u32 int_sts, int_enb;
|
||||
unsigned int bank_num;
|
||||
struct zynq_gpio *gpio = irq_desc_get_handler_data(desc);
|
||||
struct zynq_gpio *gpio =
|
||||
to_zynq_gpio(irq_desc_get_handler_data(desc));
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
@ -304,7 +304,6 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
||||
if (ACPI_FAILURE(status))
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&acpi_gpio->events);
|
||||
acpi_walk_resources(handle, "_AEI",
|
||||
acpi_gpiochip_request_interrupt, acpi_gpio);
|
||||
}
|
||||
@ -603,6 +602,25 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The same GPIO can be shared between operation region and
|
||||
* event but only if the access here is ACPI_READ. In that
|
||||
* case we "borrow" the event GPIO instead.
|
||||
*/
|
||||
if (!found && agpio->sharable == ACPI_SHARED &&
|
||||
function == ACPI_READ) {
|
||||
struct acpi_gpio_event *event;
|
||||
|
||||
list_for_each_entry(event, &achip->events, node) {
|
||||
if (event->pin == pin) {
|
||||
desc = event->desc;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
desc = gpiochip_request_own_desc(chip, pin,
|
||||
"ACPI:OpRegion");
|
||||
@ -719,6 +737,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
|
||||
}
|
||||
|
||||
acpi_gpio->chip = chip;
|
||||
INIT_LIST_HEAD(&acpi_gpio->events);
|
||||
|
||||
status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -28,10 +28,6 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||
if (!desc && gpio_is_valid(gpio))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
|
||||
@ -41,6 +37,10 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||
if (flags & GPIOF_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
err = gpiod_request(desc, label);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (flags & GPIOF_DIR_IN)
|
||||
err = gpiod_direction_input(desc);
|
||||
else
|
||||
|
@ -119,20 +119,20 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
|
||||
EXPORT_SYMBOL(of_get_named_gpio_flags);
|
||||
|
||||
/**
|
||||
* of_get_gpio_hog() - Get a GPIO hog descriptor, names and flags for GPIO API
|
||||
* of_parse_own_gpio() - Get a GPIO hog descriptor, names and flags for GPIO API
|
||||
* @np: device node to get GPIO from
|
||||
* @name: GPIO line name
|
||||
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
|
||||
* of_get_gpio_hog()
|
||||
* of_parse_own_gpio()
|
||||
* @dflags: gpiod_flags - optional GPIO initialization flags
|
||||
*
|
||||
* Returns GPIO descriptor to use with Linux GPIO API, or one of the errno
|
||||
* value on the error condition.
|
||||
*/
|
||||
static struct gpio_desc *of_get_gpio_hog(struct device_node *np,
|
||||
const char **name,
|
||||
enum gpio_lookup_flags *lflags,
|
||||
enum gpiod_flags *dflags)
|
||||
static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
|
||||
const char **name,
|
||||
enum gpio_lookup_flags *lflags,
|
||||
enum gpiod_flags *dflags)
|
||||
{
|
||||
struct device_node *chip_np;
|
||||
enum of_gpio_flags xlate_flags;
|
||||
@ -196,13 +196,13 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np,
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpiochip_scan_hogs - Scan gpio-controller and apply GPIO hog as requested
|
||||
* of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
|
||||
* @chip: gpio chip to act on
|
||||
*
|
||||
* This is only used by of_gpiochip_add to request/set GPIO initial
|
||||
* configuration.
|
||||
*/
|
||||
static void of_gpiochip_scan_hogs(struct gpio_chip *chip)
|
||||
static void of_gpiochip_scan_gpios(struct gpio_chip *chip)
|
||||
{
|
||||
struct gpio_desc *desc = NULL;
|
||||
struct device_node *np;
|
||||
@ -214,7 +214,7 @@ static void of_gpiochip_scan_hogs(struct gpio_chip *chip)
|
||||
if (!of_property_read_bool(np, "gpio-hog"))
|
||||
continue;
|
||||
|
||||
desc = of_get_gpio_hog(np, &name, &lflags, &dflags);
|
||||
desc = of_parse_own_gpio(np, &name, &lflags, &dflags);
|
||||
if (IS_ERR(desc))
|
||||
continue;
|
||||
|
||||
@ -440,7 +440,7 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
||||
|
||||
of_node_get(chip->of_node);
|
||||
|
||||
of_gpiochip_scan_hogs(chip);
|
||||
of_gpiochip_scan_gpios(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
|
||||
@ -47,8 +48,6 @@
|
||||
*/
|
||||
DEFINE_SPINLOCK(gpio_lock);
|
||||
|
||||
#define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio)
|
||||
|
||||
static DEFINE_MUTEX(gpio_lookup_lock);
|
||||
static LIST_HEAD(gpio_lookup_list);
|
||||
LIST_HEAD(gpio_chips);
|
||||
@ -218,6 +217,68 @@ static int gpiochip_add_to_list(struct gpio_chip *chip)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a GPIO name to its descriptor
|
||||
*/
|
||||
static struct gpio_desc *gpio_name_to_desc(const char * const name)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
|
||||
list_for_each_entry(chip, &gpio_chips, list) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i != chip->ngpio; ++i) {
|
||||
struct gpio_desc *gpio = &chip->desc[i];
|
||||
|
||||
if (!gpio->name)
|
||||
continue;
|
||||
|
||||
if (!strcmp(gpio->name, name)) {
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return gpio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes the names from gc->names and checks if they are all unique. If they
|
||||
* are, they are assigned to their gpio descriptors.
|
||||
*
|
||||
* Returns -EEXIST if one of the names is already used for a different GPIO.
|
||||
*/
|
||||
static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gc->names)
|
||||
return 0;
|
||||
|
||||
/* First check all names if they are unique */
|
||||
for (i = 0; i != gc->ngpio; ++i) {
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
gpio = gpio_name_to_desc(gc->names[i]);
|
||||
if (gpio)
|
||||
dev_warn(gc->dev, "Detected name collision for "
|
||||
"GPIO name '%s'\n",
|
||||
gc->names[i]);
|
||||
}
|
||||
|
||||
/* Then add all names to the GPIO descriptors */
|
||||
for (i = 0; i != gc->ngpio; ++i)
|
||||
gc->desc[i].name = gc->names[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiochip_add() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
@ -290,6 +351,10 @@ int gpiochip_add(struct gpio_chip *chip)
|
||||
if (!chip->owner && chip->dev && chip->dev->driver)
|
||||
chip->owner = chip->dev->driver->owner;
|
||||
|
||||
status = gpiochip_set_desc_names(chip);
|
||||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = of_gpiochip_add(chip);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
@ -310,6 +375,7 @@ err_remove_chip:
|
||||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_free_hogs(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
err_remove_from_list:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
list_del(&chip->list);
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
@ -680,6 +746,28 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
/**
|
||||
* gpiochip_generic_request() - request the gpio function for a pin
|
||||
* @chip: the gpiochip owning the GPIO
|
||||
* @offset: the offset of the GPIO to request for GPIO function
|
||||
*/
|
||||
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_generic_request);
|
||||
|
||||
/**
|
||||
* gpiochip_generic_free() - free the gpio function from a pin
|
||||
* @chip: the gpiochip to request the gpio function for
|
||||
* @offset: the offset of the GPIO to free from GPIO function
|
||||
*/
|
||||
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_generic_free);
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
/**
|
||||
@ -839,6 +927,14 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
}
|
||||
done:
|
||||
if (status < 0) {
|
||||
/* Clear flags that might have been set by the caller before
|
||||
* requesting the GPIO.
|
||||
*/
|
||||
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||
return status;
|
||||
}
|
||||
@ -928,7 +1024,7 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
|
||||
if (!GPIO_OFFSET_VALID(chip, offset))
|
||||
if (offset >= chip->ngpio)
|
||||
return NULL;
|
||||
|
||||
desc = &chip->desc[offset];
|
||||
@ -1735,6 +1831,13 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
|
||||
if (of_flags & OF_GPIO_ACTIVE_LOW)
|
||||
*flags |= GPIO_ACTIVE_LOW;
|
||||
|
||||
if (of_flags & OF_GPIO_SINGLE_ENDED) {
|
||||
if (of_flags & OF_GPIO_ACTIVE_LOW)
|
||||
*flags |= GPIO_OPEN_DRAIN;
|
||||
else
|
||||
*flags |= GPIO_OPEN_SOURCE;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
@ -1953,13 +2056,28 @@ struct gpio_desc *__must_check gpiod_get_optional(struct device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_get_optional);
|
||||
|
||||
/**
|
||||
* gpiod_parse_flags - helper function to parse GPIO lookup flags
|
||||
* @desc: gpio to be setup
|
||||
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
|
||||
* of_get_gpio_hog()
|
||||
*
|
||||
* Set the GPIO descriptor flags based on the given GPIO lookup flags.
|
||||
*/
|
||||
static void gpiod_parse_flags(struct gpio_desc *desc, unsigned long lflags)
|
||||
{
|
||||
if (lflags & GPIO_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_configure_flags - helper function to configure a given GPIO
|
||||
* @desc: gpio whose value will be assigned
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @lflags: gpio_lookup_flags - returned from of_find_gpio() or
|
||||
* of_get_gpio_hog()
|
||||
* @dflags: gpiod_flags - optional GPIO initialization flags
|
||||
*
|
||||
* Return 0 on success, -ENOENT if no GPIO has been assigned to the
|
||||
@ -1967,17 +2085,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
|
||||
* occurred while trying to acquire the GPIO.
|
||||
*/
|
||||
static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||
unsigned long lflags, enum gpiod_flags dflags)
|
||||
enum gpiod_flags dflags)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (lflags & GPIO_ACTIVE_LOW)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_DRAIN)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
if (lflags & GPIO_OPEN_SOURCE)
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
|
||||
/* No particular flag request, return here... */
|
||||
if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
|
||||
pr_debug("no flags found for %s\n", con_id);
|
||||
@ -2044,11 +2155,13 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||
return desc;
|
||||
}
|
||||
|
||||
gpiod_parse_flags(desc, lookupflags);
|
||||
|
||||
status = gpiod_request(desc, con_id);
|
||||
if (status < 0)
|
||||
return ERR_PTR(status);
|
||||
|
||||
status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
|
||||
status = gpiod_configure_flags(desc, con_id, flags);
|
||||
if (status < 0) {
|
||||
dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
|
||||
gpiod_put(desc);
|
||||
@ -2078,6 +2191,7 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
{
|
||||
struct gpio_desc *desc = ERR_PTR(-ENODEV);
|
||||
bool active_low = false;
|
||||
bool single_ended = false;
|
||||
int ret;
|
||||
|
||||
if (!fwnode)
|
||||
@ -2088,8 +2202,10 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
|
||||
desc = of_get_named_gpiod_flags(to_of_node(fwnode), propname, 0,
|
||||
&flags);
|
||||
if (!IS_ERR(desc))
|
||||
if (!IS_ERR(desc)) {
|
||||
active_low = flags & OF_GPIO_ACTIVE_LOW;
|
||||
single_ended = flags & OF_GPIO_SINGLE_ENDED;
|
||||
}
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
struct acpi_gpio_info info;
|
||||
|
||||
@ -2102,14 +2218,20 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
if (IS_ERR(desc))
|
||||
return desc;
|
||||
|
||||
if (active_low)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
if (single_ended) {
|
||||
if (active_low)
|
||||
set_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||
else
|
||||
set_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||
}
|
||||
|
||||
ret = gpiod_request(desc, NULL);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
/* Only value flag can be set from both DT and ACPI is active_low */
|
||||
if (active_low)
|
||||
set_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||
|
||||
return desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
|
||||
@ -2162,6 +2284,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
chip = gpiod_to_chip(desc);
|
||||
hwnum = gpio_chip_hwgpio(desc);
|
||||
|
||||
gpiod_parse_flags(desc, lflags);
|
||||
|
||||
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
|
||||
if (IS_ERR(local_desc)) {
|
||||
pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
@ -2169,7 +2293,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
return PTR_ERR(local_desc);
|
||||
}
|
||||
|
||||
status = gpiod_configure_flags(desc, name, lflags, dflags);
|
||||
status = gpiod_configure_flags(desc, name, dflags);
|
||||
if (status < 0) {
|
||||
pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
|
||||
name, chip->label, hwnum);
|
||||
@ -2309,14 +2433,19 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
int is_irq;
|
||||
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
|
||||
if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
|
||||
if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
|
||||
if (gdesc->name) {
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s)\n",
|
||||
gpio, gdesc->name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
gpiod_get_direction(gdesc);
|
||||
is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
|
||||
is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s",
|
||||
gpio, gdesc->label,
|
||||
seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s",
|
||||
gpio, gdesc->name ? gdesc->name : "", gdesc->label,
|
||||
is_out ? "out" : "in ",
|
||||
chip->get
|
||||
? (chip->get(chip, i) ? "hi" : "lo")
|
||||
|
@ -89,7 +89,10 @@ struct gpio_desc {
|
||||
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
||||
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
|
||||
|
||||
/* Connection label */
|
||||
const char *label;
|
||||
/* Name of the GPIO */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||
|
@ -330,16 +330,6 @@ static inline void bcm2835_pinctrl_fsel_set(
|
||||
bcm2835_gpio_wr(pc, FSEL_REG(pin), val);
|
||||
}
|
||||
|
||||
static int bcm2835_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void bcm2835_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_gpio_direction_input(chip->base + offset);
|
||||
@ -375,8 +365,8 @@ static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
static struct gpio_chip bcm2835_gpio_chip = {
|
||||
.label = MODULE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.request = bcm2835_gpio_request,
|
||||
.free = bcm2835_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.direction_input = bcm2835_gpio_direction_input,
|
||||
.direction_output = bcm2835_gpio_direction_output,
|
||||
.get = bcm2835_gpio_get,
|
||||
|
@ -1149,16 +1149,6 @@ static struct pinctrl_desc chv_pinctrl_desc = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int chv_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void chv_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static unsigned chv_gpio_offset_to_pin(struct chv_pinctrl *pctrl,
|
||||
unsigned offset)
|
||||
{
|
||||
@ -1238,8 +1228,8 @@ static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
|
||||
static const struct gpio_chip chv_gpio_chip = {
|
||||
.owner = THIS_MODULE,
|
||||
.request = chv_gpio_request,
|
||||
.free = chv_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get_direction = chv_gpio_get_direction,
|
||||
.direction_input = chv_gpio_direction_input,
|
||||
.direction_output = chv_gpio_direction_output,
|
||||
|
@ -596,16 +596,6 @@ static const struct pinctrl_desc intel_pinctrl_desc = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int intel_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void intel_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int intel_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
|
||||
@ -653,8 +643,8 @@ static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
|
||||
static const struct gpio_chip intel_gpio_chip = {
|
||||
.owner = THIS_MODULE,
|
||||
.request = intel_gpio_request,
|
||||
.free = intel_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.direction_input = intel_gpio_direction_input,
|
||||
.direction_output = intel_gpio_direction_output,
|
||||
.get = intel_gpio_get,
|
||||
|
@ -723,16 +723,6 @@ static const struct pinmux_ops mtk_pmx_ops = {
|
||||
.gpio_set_direction = mtk_pmx_gpio_set_direction,
|
||||
};
|
||||
|
||||
static int mtk_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void mtk_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int mtk_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
@ -1005,8 +995,8 @@ static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
|
||||
|
||||
static struct gpio_chip mtk_gpio_chip = {
|
||||
.owner = THIS_MODULE,
|
||||
.request = mtk_gpio_request,
|
||||
.free = mtk_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.direction_input = mtk_gpio_direction_input,
|
||||
.direction_output = mtk_gpio_direction_output,
|
||||
.get = mtk_gpio_get,
|
||||
|
@ -654,25 +654,11 @@ static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
|
||||
#define abx500_gpio_dbg_show NULL
|
||||
#endif
|
||||
|
||||
static int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
return pinctrl_request_gpio(gpio);
|
||||
}
|
||||
|
||||
static void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static struct gpio_chip abx500gpio_chip = {
|
||||
.label = "abx500-gpio",
|
||||
.owner = THIS_MODULE,
|
||||
.request = abx500_gpio_request,
|
||||
.free = abx500_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.direction_input = abx500_gpio_direction_input,
|
||||
.get = abx500_gpio_get,
|
||||
.direction_output = abx500_gpio_direction_output,
|
||||
|
@ -884,24 +884,6 @@ static void nmk_gpio_latent_irq_handler(struct irq_desc *desc)
|
||||
|
||||
/* I/O Functions */
|
||||
|
||||
static int nmk_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 nmk_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct nmk_gpio_chip *nmk_chip =
|
||||
@ -1267,8 +1249,8 @@ static int nmk_gpio_probe(struct platform_device *dev)
|
||||
spin_lock_init(&nmk_chip->lock);
|
||||
|
||||
chip = &nmk_chip->chip;
|
||||
chip->request = nmk_gpio_request;
|
||||
chip->free = nmk_gpio_free;
|
||||
chip->request = gpiochip_generic_request;
|
||||
chip->free = gpiochip_generic_free;
|
||||
chip->direction_input = nmk_gpio_make_input;
|
||||
chip->get = nmk_gpio_get_input;
|
||||
chip->direction_output = nmk_gpio_make_output;
|
||||
|
@ -713,16 +713,6 @@ static struct pinctrl_desc adi_pinmux_desc = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct gpio_port *port;
|
||||
@ -994,8 +984,8 @@ static int adi_gpio_probe(struct platform_device *pdev)
|
||||
port->chip.get = adi_gpio_get_value;
|
||||
port->chip.direction_output = adi_gpio_direction_output;
|
||||
port->chip.set = adi_gpio_set_value;
|
||||
port->chip.request = adi_gpio_request;
|
||||
port->chip.free = adi_gpio_free;
|
||||
port->chip.request = gpiochip_generic_request,
|
||||
port->chip.free = gpiochip_generic_free,
|
||||
port->chip.to_irq = adi_gpio_to_irq;
|
||||
if (pdata->port_gpio_base > 0)
|
||||
port->chip.base = pdata->port_gpio_base;
|
||||
|
@ -536,21 +536,11 @@ static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
return as3722_irq_get_virq(as_pci->as3722, offset);
|
||||
}
|
||||
|
||||
static int as3722_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void as3722_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static const struct gpio_chip as3722_gpio_chip = {
|
||||
.label = "as3722-gpio",
|
||||
.owner = THIS_MODULE,
|
||||
.request = as3722_gpio_request,
|
||||
.free = as3722_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get = as3722_gpio_get,
|
||||
.set = as3722_gpio_set,
|
||||
.direction_input = as3722_gpio_direction_input,
|
||||
|
@ -1280,28 +1280,6 @@ static int at91_pinctrl_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_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;
|
||||
int bank = chip->base / chip->ngpio;
|
||||
|
||||
dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
|
||||
'A' + bank, offset, gpio);
|
||||
|
||||
return pinctrl_request_gpio(gpio);
|
||||
}
|
||||
|
||||
static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
|
||||
@ -1687,8 +1665,8 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
|
||||
|
||||
/* This structure is replicated for each GPIO block allocated at probe time */
|
||||
static struct gpio_chip at91_gpio_template = {
|
||||
.request = at91_gpio_request,
|
||||
.free = at91_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get_direction = at91_gpio_get_direction,
|
||||
.direction_input = at91_gpio_direction_input,
|
||||
.get = at91_gpio_get,
|
||||
|
@ -217,24 +217,6 @@ static inline struct u300_gpio *to_u300_gpio(struct gpio_chip *chip)
|
||||
return container_of(chip, struct u300_gpio, chip);
|
||||
}
|
||||
|
||||
static int u300_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 u300_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static int u300_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||
@ -417,8 +399,8 @@ int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
|
||||
static struct gpio_chip u300_gpio_chip = {
|
||||
.label = "u300-gpio-chip",
|
||||
.owner = THIS_MODULE,
|
||||
.request = u300_gpio_request,
|
||||
.free = u300_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get = u300_gpio_get,
|
||||
.set = u300_gpio_set,
|
||||
.direction_input = u300_gpio_direction_input,
|
||||
|
@ -169,16 +169,6 @@ static struct pinmux_ops dc_pmxops = {
|
||||
.gpio_request_enable = dc_pmx_request_gpio,
|
||||
};
|
||||
|
||||
static int dc_gpio_request(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + gpio);
|
||||
}
|
||||
|
||||
static void dc_gpio_free(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + gpio);
|
||||
}
|
||||
|
||||
static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip);
|
||||
@ -255,8 +245,8 @@ static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np)
|
||||
|
||||
chip->label = DRIVER_NAME;
|
||||
chip->dev = pmap->dev;
|
||||
chip->request = dc_gpio_request;
|
||||
chip->free = dc_gpio_free;
|
||||
chip->request = gpiochip_generic_request;
|
||||
chip->free = gpiochip_generic_free;
|
||||
chip->direction_input = dc_gpio_direction_input;
|
||||
chip->direction_output = dc_gpio_direction_output;
|
||||
chip->get = dc_gpio_get;
|
||||
|
@ -1171,16 +1171,6 @@ static struct pinctrl_desc pistachio_pinctrl_desc = {
|
||||
.confops = &pistachio_pinconf_ops,
|
||||
};
|
||||
|
||||
static int pistachio_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void pistachio_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int pistachio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct pistachio_gpio_bank *bank = gc_to_bank(chip);
|
||||
@ -1332,8 +1322,8 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc)
|
||||
.npins = _npins, \
|
||||
.gpio_chip = { \
|
||||
.label = "GPIO" #_bank, \
|
||||
.request = pistachio_gpio_request, \
|
||||
.free = pistachio_gpio_free, \
|
||||
.request = gpiochip_generic_request, \
|
||||
.free = gpiochip_generic_free, \
|
||||
.get_direction = pistachio_gpio_get_direction, \
|
||||
.direction_input = pistachio_gpio_direction_input, \
|
||||
.direction_output = pistachio_gpio_direction_output, \
|
||||
|
@ -1374,16 +1374,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
|
||||
* GPIO handling
|
||||
*/
|
||||
|
||||
static int rockchip_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void rockchip_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
|
||||
{
|
||||
struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
|
||||
@ -1461,8 +1451,8 @@ static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
}
|
||||
|
||||
static const struct gpio_chip rockchip_gpiolib_chip = {
|
||||
.request = rockchip_gpio_request,
|
||||
.free = rockchip_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.set = rockchip_gpio_set,
|
||||
.get = rockchip_gpio_get,
|
||||
.direction_input = rockchip_gpio_direction_input,
|
||||
|
@ -742,16 +742,6 @@ static void st_gpio_direction(struct st_gpio_bank *bank,
|
||||
}
|
||||
}
|
||||
|
||||
static int st_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void st_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct st_gpio_bank *bank = gpio_chip_to_bank(chip);
|
||||
@ -1490,8 +1480,8 @@ static void st_gpio_irqmux_handler(struct irq_desc *desc)
|
||||
}
|
||||
|
||||
static struct gpio_chip st_gpio_template = {
|
||||
.request = st_gpio_request,
|
||||
.free = st_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get = st_gpio_get,
|
||||
.set = st_gpio_set,
|
||||
.direction_input = st_gpio_direction_input,
|
||||
|
@ -682,28 +682,14 @@ static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xway_gpio_req(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
return pinctrl_request_gpio(gpio);
|
||||
}
|
||||
|
||||
static void xway_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
static struct gpio_chip xway_chip = {
|
||||
.label = "gpio-xway",
|
||||
.direction_input = xway_gpio_dir_in,
|
||||
.direction_output = xway_gpio_dir_out,
|
||||
.get = xway_gpio_get,
|
||||
.set = xway_gpio_set,
|
||||
.request = xway_gpio_req,
|
||||
.free = xway_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.base = -1,
|
||||
};
|
||||
|
||||
|
@ -458,18 +458,6 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
spin_unlock_irqrestore(&pctrl->lock, flags);
|
||||
}
|
||||
|
||||
static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
return pinctrl_request_gpio(gpio);
|
||||
}
|
||||
|
||||
static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
return pinctrl_free_gpio(gpio);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
@ -527,8 +515,8 @@ static struct gpio_chip msm_gpio_template = {
|
||||
.direction_output = msm_gpio_direction_output,
|
||||
.get = msm_gpio_get,
|
||||
.set = msm_gpio_set,
|
||||
.request = msm_gpio_request,
|
||||
.free = msm_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.dbg_show = msm_gpio_dbg_show,
|
||||
};
|
||||
|
||||
|
@ -546,16 +546,6 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||
pmic_gpio_config_set(state->ctrl, pin, &config, 1);
|
||||
}
|
||||
|
||||
static int pmic_gpio_request(struct gpio_chip *chip, unsigned base)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + base);
|
||||
}
|
||||
|
||||
static void pmic_gpio_free(struct gpio_chip *chip, unsigned base)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + base);
|
||||
}
|
||||
|
||||
static int pmic_gpio_of_xlate(struct gpio_chip *chip,
|
||||
const struct of_phandle_args *gpio_desc,
|
||||
u32 *flags)
|
||||
@ -595,8 +585,8 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
|
||||
.direction_output = pmic_gpio_direction_output,
|
||||
.get = pmic_gpio_get,
|
||||
.set = pmic_gpio_set,
|
||||
.request = pmic_gpio_request,
|
||||
.free = pmic_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.of_xlate = pmic_gpio_of_xlate,
|
||||
.to_irq = pmic_gpio_to_irq,
|
||||
.dbg_show = pmic_gpio_dbg_show,
|
||||
|
@ -604,16 +604,6 @@ static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||
pmic_mpp_config_set(state->ctrl, pin, &config, 1);
|
||||
}
|
||||
|
||||
static int pmic_mpp_request(struct gpio_chip *chip, unsigned base)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + base);
|
||||
}
|
||||
|
||||
static void pmic_mpp_free(struct gpio_chip *chip, unsigned base)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + base);
|
||||
}
|
||||
|
||||
static int pmic_mpp_of_xlate(struct gpio_chip *chip,
|
||||
const struct of_phandle_args *gpio_desc,
|
||||
u32 *flags)
|
||||
@ -653,8 +643,8 @@ static const struct gpio_chip pmic_mpp_gpio_template = {
|
||||
.direction_output = pmic_mpp_direction_output,
|
||||
.get = pmic_mpp_get,
|
||||
.set = pmic_mpp_set,
|
||||
.request = pmic_mpp_request,
|
||||
.free = pmic_mpp_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.of_xlate = pmic_mpp_of_xlate,
|
||||
.to_irq = pmic_mpp_to_irq,
|
||||
.dbg_show = pmic_mpp_dbg_show,
|
||||
|
@ -888,19 +888,9 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void samsung_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static const struct gpio_chip samsung_gpiolib_chip = {
|
||||
.request = samsung_gpio_request,
|
||||
.free = samsung_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.set = samsung_gpio_set,
|
||||
.get = samsung_gpio_get,
|
||||
.direction_input = samsung_gpio_direction_input,
|
||||
|
@ -446,16 +446,6 @@ static const struct pinmux_ops sunxi_pmx_ops = {
|
||||
.gpio_set_direction = sunxi_pmx_gpio_set_direction,
|
||||
};
|
||||
|
||||
static int sunxi_pinctrl_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void sunxi_pinctrl_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned offset)
|
||||
{
|
||||
@ -956,8 +946,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
|
||||
|
||||
last_pin = pctl->desc->pins[pctl->desc->npins - 1].pin.number;
|
||||
pctl->chip->owner = THIS_MODULE;
|
||||
pctl->chip->request = sunxi_pinctrl_gpio_request,
|
||||
pctl->chip->free = sunxi_pinctrl_gpio_free,
|
||||
pctl->chip->request = gpiochip_generic_request,
|
||||
pctl->chip->free = gpiochip_generic_free,
|
||||
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input,
|
||||
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output,
|
||||
pctl->chip->get = sunxi_pinctrl_gpio_get,
|
||||
|
@ -486,16 +486,6 @@ static struct pinctrl_desc wmt_desc = {
|
||||
.confops = &wmt_pinconf_ops,
|
||||
};
|
||||
|
||||
static int wmt_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return pinctrl_request_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static void wmt_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
pinctrl_free_gpio(chip->base + offset);
|
||||
}
|
||||
|
||||
static int wmt_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct wmt_pinctrl_data *data = dev_get_drvdata(chip->dev);
|
||||
@ -560,8 +550,8 @@ static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
static struct gpio_chip wmt_gpio_chip = {
|
||||
.label = "gpio-wmt",
|
||||
.owner = THIS_MODULE,
|
||||
.request = wmt_gpio_request,
|
||||
.free = wmt_gpio_free,
|
||||
.request = gpiochip_generic_request,
|
||||
.free = gpiochip_generic_free,
|
||||
.get_direction = wmt_gpio_get_direction,
|
||||
.direction_input = wmt_gpio_direction_input,
|
||||
.direction_output = wmt_gpio_direction_output,
|
||||
|
@ -9,7 +9,19 @@
|
||||
#ifndef _DT_BINDINGS_GPIO_GPIO_H
|
||||
#define _DT_BINDINGS_GPIO_GPIO_H
|
||||
|
||||
/* Bit 0 express polarity */
|
||||
#define GPIO_ACTIVE_HIGH 0
|
||||
#define GPIO_ACTIVE_LOW 1
|
||||
|
||||
/* Bit 1 express single-endedness */
|
||||
#define GPIO_PUSH_PULL 0
|
||||
#define GPIO_SINGLE_ENDED 2
|
||||
|
||||
/*
|
||||
* Open Drain/Collector is the combination of single-ended active low,
|
||||
* Open Source/Emitter is the combination of single-ended active high.
|
||||
*/
|
||||
#define GPIO_OPEN_DRAIN (GPIO_SINGLE_ENDED | GPIO_ACTIVE_LOW)
|
||||
#define GPIO_OPEN_SOURCE (GPIO_SINGLE_ENDED | GPIO_ACTIVE_HIGH)
|
||||
|
||||
#endif
|
||||
|
@ -400,6 +400,7 @@ static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline int desc_to_gpio(const struct gpio_desc *desc)
|
||||
{
|
||||
/* GPIO can never have been requested */
|
||||
|
@ -206,6 +206,9 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||
|
||||
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||
|
||||
int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
|
||||
void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
|
||||
/**
|
||||
|
@ -29,6 +29,7 @@ struct device_node;
|
||||
*/
|
||||
enum of_gpio_flags {
|
||||
OF_GPIO_ACTIVE_LOW = 0x1,
|
||||
OF_GPIO_SINGLE_ENDED = 0x2,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
|
Loading…
Reference in New Issue
Block a user