This is the bulk of GPIO changes for v3.15:
- Merged in a branch of irqchip changes from Thomas Gleixner: we need to have new callbacks from the irqchip to determine if the GPIO line will be eligible for IRQs, and this callback must be able to say "no". After some thinking I got the branch from tglx and have switched all current users over to use this. - Based on tglx patches, we have added some generic irqchip helpers in the gpiolib core. These will help centralize code when GPIO drivers have simple chained/cascaded IRQs. Drivers will still define their irqchip vtables, but the gpiolib core will take care of irqdomain set-up, mapping from local offsets to Linux irqs, and reserve resources by marking the GPIO lines for IRQs. - Initially the PL061 and Nomadik GPIO/pin control drivers have been switched over to use the new gpiochip-to-irqchip infrastructure with more drivers expected for the next kernel cycle. The factoring of just two drivers still makes it worth it so it is already a win. - A new driver for the Synopsys DesignWare APB GPIO block. - Modify the DaVinci GPIO driver to be reusable also for the new TI Keystone architecture. - A new driver for the LSI ZEVIO SoCs. - Delete the obsolte tnetv107x driver. - Some incremental work on GPIO descriptors: have gpiod_direction_output() use a logical level, respecting assertion polarity through ACTIVE_LOW flags, adding gpiod_direction_output_raw() for the case where you want to set that very value. Add gpiochip_get_desc() to fetch a GPIO descriptor from a specific offset on a certain chip inside driver code. - Switch ACPI GPIO code over to using gpiochip_get_desc() and get rid of gpio_to_desc(). - The ACPI GPIO event handling code has been reworked after encountering an actual real life implementation. - Support for ACPI GPIO operation regions. - Generic GPIO chips can now be assigned labels/names from platform data. - We now clamp values returned from GPIO drivers to the boolean [0,1] range. - Some improved documentation on how to use the polarity flag was added. - The a large slew of incremental driver updates and non-critical fixes. Some targeted for stable. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTPQnkAAoJEEEQszewGV1zyf4P/AmXV0O/FoyeQnXDxDsp7V/t JpfD0Gy8FlFmRxjG+UYutRCWUHxFQJU+j0ToVC4/N8clNS1LwA+ZwhNgB8dqRokz JVeeqUPn95z2kGe3j9DgVXWMRAytq7y8fXFuNUN36losceuxyOj4mYKLP9Yjnp9l 4pS1TtQHF95a7qmnyYjGZy8VNcUz1gJ7wJrGxKI+Kl/8pcdA6rPqom6ozCXpZjaD 5GGQoSvXKIn44+8qZeJsebd1YEso/8K66e9JomcGEsuZl78ArDOzoSllpYF2h/RM bo4BFUmoOL3/jVp7FFVbybfolwuRmQesY4NFqx03e+y++hxHFHl90FT+mnednS2Q k4lB0o1YRjf2tfMmm4cJ3tVBnFRhssTVb9ynDbzUw61mNVEuxP90f/njrHlObnPT 1uVVWUE+4ojral213S2IYGHkg1OlWSn0DP6tEaswjOsGJrMdXpdxS5RPwcRtcByT HufZRNbUbLzXBzf4WeV2foSS3XqbXYcuMfdRBSWrbuJqW56robbdKKyvrMRPvh7j FV7SEK0yFPRe3nuzKM+t9TDGdUt4qivv/YfVeGfCnTVgFOac6cKrHG9gzM58mVcb 4czG3B1TbqgfGVeZuew4qUdlHSmnSsS+pf/h9Yh9QCHqaKGh3R17cSDxIKAIVTIW pH6nuShTXsbrmRMeMhux =8Qqf -----END PGP SIGNATURE----- Merge tag 'gpio-v3.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull bulk of gpio updates from Linus Walleij: "A pretty big chunk of changes this time, but it has all been on rotation in linux-next and had some testing. Of course there will be some amount of fixes on top... - Merged in a branch of irqchip changes from Thomas Gleixner: we need to have new callbacks from the irqchip to determine if the GPIO line will be eligible for IRQs, and this callback must be able to say "no". After some thinking I got the branch from tglx and have switched all current users over to use this. - Based on tglx patches, we have added some generic irqchip helpers in the gpiolib core. These will help centralize code when GPIO drivers have simple chained/cascaded IRQs. Drivers will still define their irqchip vtables, but the gpiolib core will take care of irqdomain set-up, mapping from local offsets to Linux irqs, and reserve resources by marking the GPIO lines for IRQs. - Initially the PL061 and Nomadik GPIO/pin control drivers have been switched over to use the new gpiochip-to-irqchip infrastructure with more drivers expected for the next kernel cycle. The factoring of just two drivers still makes it worth it so it is already a win. - A new driver for the Synopsys DesignWare APB GPIO block. - Modify the DaVinci GPIO driver to be reusable also for the new TI Keystone architecture. - A new driver for the LSI ZEVIO SoCs. - Delete the obsolte tnetv107x driver. - Some incremental work on GPIO descriptors: have gpiod_direction_output() use a logical level, respecting assertion polarity through ACTIVE_LOW flags, adding gpiod_direction_output_raw() for the case where you want to set that very value. Add gpiochip_get_desc() to fetch a GPIO descriptor from a specific offset on a certain chip inside driver code. - Switch ACPI GPIO code over to using gpiochip_get_desc() and get rid of gpio_to_desc(). - The ACPI GPIO event handling code has been reworked after encountering an actual real life implementation. - Support for ACPI GPIO operation regions. - Generic GPIO chips can now be assigned labels/names from platform data. - We now clamp values returned from GPIO drivers to the boolean [0,1] range. - Some improved documentation on how to use the polarity flag was added. - a large slew of incremental driver updates and non-critical fixes. Some targeted for stable" * tag 'gpio-v3.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (80 commits) gpio: rcar: Add helper variable dev = &pdev->dev gpio-lynxpoint: force gpio_get() to return "1" and "0" only gpio: unmap gpio irqs properly pch_gpio: set value before enabling output direction gpio: moxart: Actually set output state in moxart_gpio_direction_output() gpio: moxart: Avoid forward declaration gpio: mxs: Allow for recursive enable_irq_wake() call gpio: samsung: Add missing "break" statement gpio: twl4030: Remove redundant assignment gpio: dwapb: correct gpio-cells in binding document gpio: iop: fix devm_ioremap_resource() return value checking pinctrl: coh901: convert driver to use gpiolib irqchip pinctrl: nomadik: convert driver to use gpiolib irqchip gpio: pl061: convert driver to use gpiolib irqchip gpio: add IRQ chip helpers in gpiolib pinctrl: nomadik: factor in platform data container pinctrl: nomadik: rename secondary to latent gpio: Driver for SYSCON-based GPIOs gpio: generic: Use platform_device_id->driver_data field for driver flags pinctrl: coh901: move irq line locking to resource callbacks ...
This commit is contained in:
commit
154d6f18a4
|
@ -0,0 +1,17 @@
|
||||||
|
* ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should contain "cirrus,clps711x-mctrl-gpio".
|
||||||
|
- gpio-controller: Marks the device node as a gpio controller.
|
||||||
|
- #gpio-cells: Should be two. The first cell is the pin number and
|
||||||
|
the second cell is used to specify the gpio polarity:
|
||||||
|
0 = Active high,
|
||||||
|
1 = Active low.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
sysgpio: sysgpio {
|
||||||
|
compatible = "cirrus,ep7312-mctrl-gpio",
|
||||||
|
"cirrus,clps711x-mctrl-gpio";
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
};
|
|
@ -1,13 +1,17 @@
|
||||||
Davinci GPIO controller bindings
|
Davinci/Keystone GPIO controller bindings
|
||||||
|
|
||||||
Required Properties:
|
Required Properties:
|
||||||
- compatible: should be "ti,dm6441-gpio"
|
- compatible: should be "ti,dm6441-gpio", "ti,keystone-gpio"
|
||||||
|
|
||||||
- reg: Physical base address of the controller and the size of memory mapped
|
- reg: Physical base address of the controller and the size of memory mapped
|
||||||
registers.
|
registers.
|
||||||
|
|
||||||
- gpio-controller : Marks the device node as a gpio controller.
|
- gpio-controller : Marks the device node as a gpio controller.
|
||||||
|
|
||||||
|
- #gpio-cells : Should be two.
|
||||||
|
- first cell is the pin number
|
||||||
|
- second cell is used to specify optional parameters (unused)
|
||||||
|
|
||||||
- interrupt-parent: phandle of the parent interrupt controller.
|
- interrupt-parent: phandle of the parent interrupt controller.
|
||||||
|
|
||||||
- interrupts: Array of GPIO interrupt number. Only banked or unbanked IRQs are
|
- interrupts: Array of GPIO interrupt number. Only banked or unbanked IRQs are
|
||||||
|
@ -27,6 +31,7 @@ Example:
|
||||||
gpio: gpio@1e26000 {
|
gpio: gpio@1e26000 {
|
||||||
compatible = "ti,dm6441-gpio";
|
compatible = "ti,dm6441-gpio";
|
||||||
gpio-controller;
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
reg = <0x226000 0x1000>;
|
reg = <0x226000 0x1000>;
|
||||||
interrupt-parent = <&intc>;
|
interrupt-parent = <&intc>;
|
||||||
interrupts = <42 IRQ_TYPE_EDGE_BOTH 43 IRQ_TYPE_EDGE_BOTH
|
interrupts = <42 IRQ_TYPE_EDGE_BOTH 43 IRQ_TYPE_EDGE_BOTH
|
||||||
|
@ -39,3 +44,19 @@ gpio: gpio@1e26000 {
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
#interrupt-cells = <2>;
|
#interrupt-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
leds {
|
||||||
|
compatible = "gpio-leds";
|
||||||
|
|
||||||
|
led1 {
|
||||||
|
label = "davinci:green:usr1";
|
||||||
|
gpios = <&gpio 10 GPIO_ACTIVE_HIGH>;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
led2 {
|
||||||
|
label = "davinci:red:debug1";
|
||||||
|
gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
|
||||||
|
...
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
Zevio GPIO controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Should be "lsi,zevio-gpio"
|
||||||
|
- reg: Address and length of the register set for the device
|
||||||
|
- #gpio-cells: Should be two. The first cell is the pin number and the
|
||||||
|
second cell is used to specify optional parameters (currently unused).
|
||||||
|
- gpio-controller: Marks the device node as a GPIO controller.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
gpio: gpio@90000000 {
|
||||||
|
compatible = "lsi,zevio-gpio";
|
||||||
|
reg = <0x90000000 0x1000>;
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
};
|
|
@ -13,11 +13,11 @@ properties, each containing a 'gpio-list':
|
||||||
gpio-specifier : Array of #gpio-cells specifying specific gpio
|
gpio-specifier : Array of #gpio-cells specifying specific gpio
|
||||||
(controller specific)
|
(controller specific)
|
||||||
|
|
||||||
GPIO properties should be named "[<name>-]gpios". Exact
|
GPIO properties should be named "[<name>-]gpios". The exact
|
||||||
meaning of each gpios property must be documented in the device tree
|
meaning of each gpios property must be documented in the device tree
|
||||||
binding for each device.
|
binding for each device.
|
||||||
|
|
||||||
For example, the following could be used to describe gpios pins to use
|
For example, the following could be used to describe GPIO pins used
|
||||||
as chip select lines; with chip selects 0, 1 and 3 populated, and chip
|
as chip select lines; with chip selects 0, 1 and 3 populated, and chip
|
||||||
select 2 left empty:
|
select 2 left empty:
|
||||||
|
|
||||||
|
@ -44,35 +44,79 @@ whether pin is open-drain and whether pin is logically inverted.
|
||||||
Exact meaning of each specifier cell is controller specific, and must
|
Exact meaning of each specifier cell is controller specific, and must
|
||||||
be documented in the device tree binding for the device.
|
be documented in the device tree binding for the device.
|
||||||
|
|
||||||
Example of the node using GPIOs:
|
Example of a node using GPIOs:
|
||||||
|
|
||||||
node {
|
node {
|
||||||
gpios = <&qe_pio_e 18 0>;
|
gpios = <&qe_pio_e 18 0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
In this example gpio-specifier is "18 0" and encodes GPIO pin number,
|
In this example gpio-specifier is "18 0" and encodes GPIO pin number,
|
||||||
and empty GPIO flags as accepted by the "qe_pio_e" gpio-controller.
|
and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
|
||||||
|
|
||||||
|
1.1) GPIO specifier best practices
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
A gpio-specifier should contain a flag indicating the GPIO polarity; active-
|
||||||
|
high or active-low. If it does, the follow best practices should be followed:
|
||||||
|
|
||||||
|
The gpio-specifier's polarity flag should represent the physical level at the
|
||||||
|
GPIO controller that achieves (or represents, for inputs) a logically asserted
|
||||||
|
value at the device. The exact definition of logically asserted should be
|
||||||
|
defined by the binding for the device. If the board inverts the signal between
|
||||||
|
the GPIO controller and the device, then the gpio-specifier will represent the
|
||||||
|
opposite physical level than the signal at the device's pin.
|
||||||
|
|
||||||
|
When the device's signal polarity is configurable, the binding for the
|
||||||
|
device must either:
|
||||||
|
|
||||||
|
a) Define a single static polarity for the signal, with the expectation that
|
||||||
|
any software using that binding would statically program the device to use
|
||||||
|
that signal polarity.
|
||||||
|
|
||||||
|
The static choice of polarity may be either:
|
||||||
|
|
||||||
|
a1) (Preferred) Dictated by a binding-specific DT property.
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
|
a2) Defined statically by the DT binding itself.
|
||||||
|
|
||||||
|
In particular, the polarity cannot be derived from the gpio-specifier, since
|
||||||
|
that would prevent the DT from separately representing the two orthogonal
|
||||||
|
concepts of configurable signal polarity in the device, and possible board-
|
||||||
|
level signal inversion.
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
|
b) Pick a single option for device signal polarity, and document this choice
|
||||||
|
in the binding. The gpio-specifier should represent the polarity of the signal
|
||||||
|
(at the GPIO controller) assuming that the device is configured for this
|
||||||
|
particular signal polarity choice. If software chooses to program the device
|
||||||
|
to generate or receive a signal of the opposite polarity, software will be
|
||||||
|
responsible for correctly interpreting (inverting) the GPIO signal at the GPIO
|
||||||
|
controller.
|
||||||
|
|
||||||
2) gpio-controller nodes
|
2) gpio-controller nodes
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Every GPIO controller node must both an empty "gpio-controller"
|
Every GPIO controller node must contain both an empty "gpio-controller"
|
||||||
property, and have #gpio-cells contain the size of the gpio-specifier.
|
property, and a #gpio-cells integer property, which indicates the number of
|
||||||
|
cells in a gpio-specifier.
|
||||||
|
|
||||||
Example of two SOC GPIO banks defined as gpio-controller nodes:
|
Example of two SOC GPIO banks defined as gpio-controller nodes:
|
||||||
|
|
||||||
qe_pio_a: gpio-controller@1400 {
|
qe_pio_a: gpio-controller@1400 {
|
||||||
#gpio-cells = <2>;
|
|
||||||
compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
|
compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
|
||||||
reg = <0x1400 0x18>;
|
reg = <0x1400 0x18>;
|
||||||
gpio-controller;
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
qe_pio_e: gpio-controller@1460 {
|
qe_pio_e: gpio-controller@1460 {
|
||||||
#gpio-cells = <2>;
|
|
||||||
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
|
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
|
||||||
reg = <0x1460 0x18>;
|
reg = <0x1460 0x18>;
|
||||||
gpio-controller;
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
2.1) gpio- and pin-controller interaction
|
2.1) gpio- and pin-controller interaction
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
* Synopsys DesignWare APB GPIO controller
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : Should contain "snps,dw-apb-gpio"
|
||||||
|
- reg : Address and length of the register set for the device.
|
||||||
|
- #address-cells : should be 1 (for addressing port subnodes).
|
||||||
|
- #size-cells : should be 0 (port subnodes).
|
||||||
|
|
||||||
|
The GPIO controller has a configurable number of ports, each of which are
|
||||||
|
represented as child nodes with the following properties:
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : "snps,dw-apb-gpio-port"
|
||||||
|
- gpio-controller : Marks the device node as a gpio controller.
|
||||||
|
- #gpio-cells : Should be two. The first cell is the pin number and
|
||||||
|
the second cell is used to specify the gpio polarity:
|
||||||
|
0 = active high
|
||||||
|
1 = active low
|
||||||
|
- reg : The integer port index of the port, a single cell.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- interrupt-controller : The first port may be configured to be an interrupt
|
||||||
|
controller.
|
||||||
|
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||||
|
interrupt. Shall be set to 2. The first cell defines the interrupt number,
|
||||||
|
the second encodes the triger flags encoded as described in
|
||||||
|
Documentation/devicetree/bindings/interrupts.txt
|
||||||
|
- interrupt-parent : The parent interrupt controller.
|
||||||
|
- interrupts : The interrupt to the parent controller raised when GPIOs
|
||||||
|
generate the interrupts.
|
||||||
|
- snps,nr-gpios : The number of pins in the port, a single cell.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
gpio: gpio@20000 {
|
||||||
|
compatible = "snps,dw-apb-gpio";
|
||||||
|
reg = <0x20000 0x1000>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
porta: gpio-controller@0 {
|
||||||
|
compatible = "snps,dw-apb-gpio-port";
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
snps,nr-gpios = <8>;
|
||||||
|
reg = <0>;
|
||||||
|
interrupt-controller;
|
||||||
|
#interrupt-cells = <2>;
|
||||||
|
interrupt-parent = <&vic1>;
|
||||||
|
interrupts = <0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
portb: gpio-controller@1 {
|
||||||
|
compatible = "snps,dw-apb-gpio-port";
|
||||||
|
gpio-controller;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
snps,nr-gpios = <8>;
|
||||||
|
reg = <1>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -154,6 +154,7 @@ raw line value:
|
||||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||||
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
|
int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
|
||||||
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
|
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
|
||||||
|
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||||
|
|
||||||
The active-low state of a GPIO can also be queried using the following call:
|
The active-low state of a GPIO can also be queried using the following call:
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,37 @@ Any debugfs dump method should normally ignore signals which haven't been
|
||||||
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
|
requested as GPIOs. They can use gpiochip_is_requested(), which returns either
|
||||||
NULL or the label associated with that GPIO when it was requested.
|
NULL or the label associated with that GPIO when it was requested.
|
||||||
|
|
||||||
|
|
||||||
|
GPIO drivers providing IRQs
|
||||||
|
---------------------------
|
||||||
|
It is custom that GPIO drivers (GPIO chips) are also providing interrupts,
|
||||||
|
most often cascaded off a parent interrupt controller, and in some special
|
||||||
|
cases the GPIO logic is melded with a SoC's primary interrupt controller.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
other.
|
||||||
|
|
||||||
|
gpiod_to_irq() is just a convenience function to figure out the IRQ for a
|
||||||
|
certain GPIO line and should not be relied upon to have been called before
|
||||||
|
the IRQ is used.
|
||||||
|
|
||||||
|
So always prepare the hardware and make it ready for action in respective
|
||||||
|
callbacks from the GPIO and irqchip APIs. Do not rely on gpiod_to_irq() having
|
||||||
|
been called first.
|
||||||
|
|
||||||
|
This orthogonality leads to ambiguities that we need to solve: if there is
|
||||||
|
competition inside the subsystem which side is using the resource (a certain
|
||||||
|
GPIO line and register for example) it needs to deny certain operations and
|
||||||
|
keep track of usage inside of the gpiolib subsystem. This is why the API
|
||||||
|
below exists.
|
||||||
|
|
||||||
|
|
||||||
Locking IRQ usage
|
Locking IRQ usage
|
||||||
-----------------
|
-----------------
|
||||||
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
||||||
|
@ -73,3 +104,7 @@ This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
|
||||||
is released:
|
is released:
|
||||||
|
|
||||||
void gpiod_unlock_as_irq(struct gpio_desc *desc)
|
void gpiod_unlock_as_irq(struct gpio_desc *desc)
|
||||||
|
|
||||||
|
When implementing an irqchip inside a GPIO driver, these two functions should
|
||||||
|
typically be called in the .startup() and .shutdown() callbacks from the
|
||||||
|
irqchip.
|
||||||
|
|
|
@ -1928,6 +1928,13 @@ L: linux-scsi@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/scsi/bnx2i/
|
F: drivers/scsi/bnx2i/
|
||||||
|
|
||||||
|
BROADCOM KONA GPIO DRIVER
|
||||||
|
M: Markus Mayer <markus.mayer@linaro.org>
|
||||||
|
L: bcm-kernel-feedback-list@broadcom.com
|
||||||
|
S: Supported
|
||||||
|
F: drivers/gpio/gpio-bcm-kona.c
|
||||||
|
F: Documentation/devicetree/bindings/gpio/gpio-bcm-kona.txt
|
||||||
|
|
||||||
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
|
BROADCOM SPECIFIC AMBA DRIVER (BCMA)
|
||||||
M: Rafał Miłecki <zajec5@gmail.com>
|
M: Rafał Miłecki <zajec5@gmail.com>
|
||||||
L: linux-wireless@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
|
|
|
@ -55,6 +55,9 @@ config GPIO_ACPI
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
|
|
||||||
|
config GPIOLIB_IRQCHIP
|
||||||
|
bool
|
||||||
|
|
||||||
config DEBUG_GPIO
|
config DEBUG_GPIO
|
||||||
bool "Debug GPIO calls"
|
bool "Debug GPIO calls"
|
||||||
depends on DEBUG_KERNEL
|
depends on DEBUG_KERNEL
|
||||||
|
@ -128,6 +131,15 @@ config GPIO_GENERIC_PLATFORM
|
||||||
help
|
help
|
||||||
Say yes here to support basic platform_device memory-mapped GPIO controllers.
|
Say yes here to support basic platform_device memory-mapped GPIO controllers.
|
||||||
|
|
||||||
|
config GPIO_DWAPB
|
||||||
|
tristate "Synopsys DesignWare APB GPIO driver"
|
||||||
|
select GPIO_GENERIC
|
||||||
|
select GENERIC_IRQ_CHIP
|
||||||
|
depends on OF_GPIO
|
||||||
|
help
|
||||||
|
Say Y or M here to build support for the Synopsys DesignWare APB
|
||||||
|
GPIO block.
|
||||||
|
|
||||||
config GPIO_IT8761E
|
config GPIO_IT8761E
|
||||||
tristate "IT8761E GPIO support"
|
tristate "IT8761E GPIO support"
|
||||||
depends on X86 # unconditional access to IO space.
|
depends on X86 # unconditional access to IO space.
|
||||||
|
@ -145,6 +157,12 @@ config GPIO_EP93XX
|
||||||
depends on ARCH_EP93XX
|
depends on ARCH_EP93XX
|
||||||
select GPIO_GENERIC
|
select GPIO_GENERIC
|
||||||
|
|
||||||
|
config GPIO_ZEVIO
|
||||||
|
bool "LSI ZEVIO SoC memory mapped GPIOs"
|
||||||
|
depends on ARM && OF_GPIO
|
||||||
|
help
|
||||||
|
Say yes here to support the GPIO controller in LSI ZEVIO SoCs.
|
||||||
|
|
||||||
config GPIO_MM_LANTIQ
|
config GPIO_MM_LANTIQ
|
||||||
bool "Lantiq Memory mapped GPIOs"
|
bool "Lantiq Memory mapped GPIOs"
|
||||||
depends on LANTIQ && SOC_XWAY
|
depends on LANTIQ && SOC_XWAY
|
||||||
|
@ -228,7 +246,8 @@ config GPIO_OCTEON
|
||||||
config GPIO_PL061
|
config GPIO_PL061
|
||||||
bool "PrimeCell PL061 GPIO support"
|
bool "PrimeCell PL061 GPIO support"
|
||||||
depends on ARM_AMBA
|
depends on ARM_AMBA
|
||||||
select GENERIC_IRQ_CHIP
|
select IRQ_DOMAIN
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Say yes here to support the PrimeCell PL061 GPIO device
|
Say yes here to support the PrimeCell PL061 GPIO device
|
||||||
|
|
||||||
|
@ -275,8 +294,15 @@ config GPIO_STA2X11
|
||||||
Say yes here to support the STA2x11/ConneXt GPIO device.
|
Say yes here to support the STA2x11/ConneXt GPIO device.
|
||||||
The GPIO module has 128 GPIO pins with alternate functions.
|
The GPIO module has 128 GPIO pins with alternate functions.
|
||||||
|
|
||||||
|
config GPIO_SYSCON
|
||||||
|
tristate "GPIO based on SYSCON"
|
||||||
|
depends on MFD_SYSCON && OF
|
||||||
|
help
|
||||||
|
Say yes here to support GPIO functionality though SYSCON driver.
|
||||||
|
|
||||||
config GPIO_TS5500
|
config GPIO_TS5500
|
||||||
tristate "TS-5500 DIO blocks and compatibles"
|
tristate "TS-5500 DIO blocks and compatibles"
|
||||||
|
depends on TS5500 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver supports Digital I/O exposed by pin blocks found on some
|
This driver supports Digital I/O exposed by pin blocks found on some
|
||||||
Technologic Systems platforms. It includes, but is not limited to, 3
|
Technologic Systems platforms. It includes, but is not limited to, 3
|
||||||
|
@ -462,7 +488,7 @@ config GPIO_MC9S08DZ60
|
||||||
Select this to enable the MC9S08DZ60 GPIO driver
|
Select this to enable the MC9S08DZ60 GPIO driver
|
||||||
|
|
||||||
config GPIO_PCA953X
|
config GPIO_PCA953X
|
||||||
tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports"
|
tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
help
|
help
|
||||||
Say yes here to provide access to several register-oriented
|
Say yes here to provide access to several register-oriented
|
||||||
|
@ -472,11 +498,15 @@ config GPIO_PCA953X
|
||||||
4 bits: pca9536, pca9537
|
4 bits: pca9536, pca9537
|
||||||
|
|
||||||
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
||||||
pca9556, pca9557, pca9574, tca6408
|
pca9556, pca9557, pca9574, tca6408, xra1202
|
||||||
|
|
||||||
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
||||||
tca6416
|
tca6416
|
||||||
|
|
||||||
|
24 bits: tca6424
|
||||||
|
|
||||||
|
40 bits: pca9505, pca9698
|
||||||
|
|
||||||
config GPIO_PCA953X_IRQ
|
config GPIO_PCA953X_IRQ
|
||||||
bool "Interrupt controller support for PCA953x"
|
bool "Interrupt controller support for PCA953x"
|
||||||
depends on GPIO_PCA953X=y
|
depends on GPIO_PCA953X=y
|
||||||
|
@ -630,7 +660,7 @@ comment "PCI GPIO expanders:"
|
||||||
|
|
||||||
config GPIO_CS5535
|
config GPIO_CS5535
|
||||||
tristate "AMD CS5535/CS5536 GPIO support"
|
tristate "AMD CS5535/CS5536 GPIO support"
|
||||||
depends on PCI && X86 && MFD_CS5535
|
depends on MFD_CS5535
|
||||||
help
|
help
|
||||||
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
|
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
|
||||||
can be used for quite a number of things. The CS5535/6 is found on
|
can be used for quite a number of things. The CS5535/6 is found on
|
||||||
|
@ -642,7 +672,7 @@ config GPIO_BT8XX
|
||||||
tristate "BT8XX GPIO abuser"
|
tristate "BT8XX GPIO abuser"
|
||||||
depends on PCI && VIDEO_BT848=n
|
depends on PCI && VIDEO_BT848=n
|
||||||
help
|
help
|
||||||
The BT8xx frame grabber chip has 24 GPIO pins than can be abused
|
The BT8xx frame grabber chip has 24 GPIO pins that can be abused
|
||||||
as a cheap PCI GPIO card.
|
as a cheap PCI GPIO card.
|
||||||
|
|
||||||
This chip can be found on Miro, Hauppauge and STB TV-cards.
|
This chip can be found on Miro, Hauppauge and STB TV-cards.
|
||||||
|
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
|
||||||
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
||||||
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
|
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
|
||||||
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
|
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
|
||||||
|
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||||
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||||
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o
|
||||||
|
@ -76,11 +77,11 @@ obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
|
||||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||||
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
||||||
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
|
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
|
||||||
|
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
|
||||||
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
|
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
|
||||||
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||||
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
|
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
|
||||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
||||||
obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
|
|
||||||
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
||||||
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
|
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
|
||||||
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
||||||
|
@ -99,3 +100,4 @@ obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
|
||||||
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
|
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
|
||||||
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
|
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
|
||||||
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
|
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
|
||||||
|
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
|
||||||
|
|
|
@ -408,24 +408,23 @@ static void adnp_irq_bus_unlock(struct irq_data *data)
|
||||||
mutex_unlock(&adnp->irq_lock);
|
mutex_unlock(&adnp->irq_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int adnp_irq_startup(struct irq_data *data)
|
static int adnp_irq_reqres(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&adnp->gpio, data->hwirq))
|
if (gpio_lock_as_irq(&adnp->gpio, data->hwirq)) {
|
||||||
dev_err(adnp->gpio.dev,
|
dev_err(adnp->gpio.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
data->hwirq);
|
data->hwirq);
|
||||||
/* Satisfy the .enable semantics by unmasking the line */
|
return -EINVAL;
|
||||||
adnp_irq_unmask(data);
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adnp_irq_shutdown(struct irq_data *data)
|
static void adnp_irq_relres(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
struct adnp *adnp = irq_data_get_irq_chip_data(data);
|
||||||
|
|
||||||
adnp_irq_mask(data);
|
|
||||||
gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
|
gpio_unlock_as_irq(&adnp->gpio, data->hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,8 +435,8 @@ static struct irq_chip adnp_irq_chip = {
|
||||||
.irq_set_type = adnp_irq_set_type,
|
.irq_set_type = adnp_irq_set_type,
|
||||||
.irq_bus_lock = adnp_irq_bus_lock,
|
.irq_bus_lock = adnp_irq_bus_lock,
|
||||||
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
|
.irq_bus_sync_unlock = adnp_irq_bus_unlock,
|
||||||
.irq_startup = adnp_irq_startup,
|
.irq_request_resources = adnp_irq_reqres,
|
||||||
.irq_shutdown = adnp_irq_shutdown,
|
.irq_release_resources = adnp_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
|
static int adnp_irq_map(struct irq_domain *domain, unsigned int irq,
|
||||||
|
|
|
@ -67,9 +67,20 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
|
||||||
{
|
{
|
||||||
struct adp5588_gpio *dev =
|
struct adp5588_gpio *dev =
|
||||||
container_of(chip, struct adp5588_gpio, gpio_chip);
|
container_of(chip, struct adp5588_gpio, gpio_chip);
|
||||||
|
unsigned bank = ADP5588_BANK(off);
|
||||||
|
unsigned bit = ADP5588_BIT(off);
|
||||||
|
int val;
|
||||||
|
|
||||||
return !!(adp5588_gpio_read(dev->client,
|
mutex_lock(&dev->lock);
|
||||||
GPIO_DAT_STAT1 + ADP5588_BANK(off)) & ADP5588_BIT(off));
|
|
||||||
|
if (dev->dir[bank] & bit)
|
||||||
|
val = dev->dat_out[bank];
|
||||||
|
else
|
||||||
|
val = adp5588_gpio_read(dev->client, GPIO_DAT_STAT1 + bank);
|
||||||
|
|
||||||
|
mutex_unlock(&dev->lock);
|
||||||
|
|
||||||
|
return !!(val & bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void adp5588_gpio_set_value(struct gpio_chip *chip,
|
static void adp5588_gpio_set_value(struct gpio_chip *chip,
|
||||||
|
@ -386,6 +397,7 @@ static int adp5588_gpio_probe(struct i2c_client *client,
|
||||||
gc->ngpio = ADP5588_MAXGPIO;
|
gc->ngpio = ADP5588_MAXGPIO;
|
||||||
gc->label = client->name;
|
gc->label = client->name;
|
||||||
gc->owner = THIS_MODULE;
|
gc->owner = THIS_MODULE;
|
||||||
|
gc->names = pdata->names;
|
||||||
|
|
||||||
mutex_init(&dev->lock);
|
mutex_init(&dev->lock);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
#define GPIO_BANK(gpio) ((gpio) >> 5)
|
#define GPIO_BANK(gpio) ((gpio) >> 5)
|
||||||
#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1))
|
#define GPIO_BIT(gpio) ((gpio) & (GPIO_PER_BANK - 1))
|
||||||
|
|
||||||
|
/* There is a GPIO control register for each GPIO */
|
||||||
|
#define GPIO_CONTROL(gpio) (0x00000100 + ((gpio) << 2))
|
||||||
|
|
||||||
|
/* The remaining registers are per GPIO bank */
|
||||||
#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
|
#define GPIO_OUT_STATUS(bank) (0x00000000 + ((bank) << 2))
|
||||||
#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
|
#define GPIO_IN_STATUS(bank) (0x00000020 + ((bank) << 2))
|
||||||
#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
|
#define GPIO_OUT_SET(bank) (0x00000040 + ((bank) << 2))
|
||||||
|
@ -35,7 +39,6 @@
|
||||||
#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
|
#define GPIO_INT_STATUS(bank) (0x00000080 + ((bank) << 2))
|
||||||
#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
|
#define GPIO_INT_MASK(bank) (0x000000a0 + ((bank) << 2))
|
||||||
#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
|
#define GPIO_INT_MSKCLR(bank) (0x000000c0 + ((bank) << 2))
|
||||||
#define GPIO_CONTROL(bank) (0x00000100 + ((bank) << 2))
|
|
||||||
#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
|
#define GPIO_PWD_STATUS(bank) (0x00000500 + ((bank) << 2))
|
||||||
|
|
||||||
#define GPIO_GPPWR_OFFSET 0x00000520
|
#define GPIO_GPPWR_OFFSET 0x00000520
|
||||||
|
@ -80,22 +83,43 @@ static inline struct bcm_kona_gpio *to_kona_gpio(struct gpio_chip *chip)
|
||||||
return container_of(chip, struct bcm_kona_gpio, gpio_chip);
|
return container_of(chip, struct bcm_kona_gpio, gpio_chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm_kona_gpio_set_lockcode_bank(void __iomem *reg_base,
|
static inline void bcm_kona_gpio_write_lock_regs(void __iomem *reg_base,
|
||||||
int bank_id, int lockcode)
|
int bank_id, u32 lockcode)
|
||||||
{
|
{
|
||||||
writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET);
|
writel(BCM_GPIO_PASSWD, reg_base + GPIO_GPPWR_OFFSET);
|
||||||
writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id));
|
writel(lockcode, reg_base + GPIO_PWD_STATUS(bank_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bcm_kona_gpio_lock_bank(void __iomem *reg_base, int bank_id)
|
static void bcm_kona_gpio_lock_gpio(struct bcm_kona_gpio *kona_gpio,
|
||||||
|
unsigned gpio)
|
||||||
{
|
{
|
||||||
bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, LOCK_CODE);
|
u32 val;
|
||||||
|
unsigned long flags;
|
||||||
|
int bank_id = GPIO_BANK(gpio);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
|
val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
|
||||||
|
val |= BIT(gpio);
|
||||||
|
bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void bcm_kona_gpio_unlock_bank(void __iomem *reg_base,
|
static void bcm_kona_gpio_unlock_gpio(struct bcm_kona_gpio *kona_gpio,
|
||||||
int bank_id)
|
unsigned gpio)
|
||||||
{
|
{
|
||||||
bcm_kona_gpio_set_lockcode_bank(reg_base, bank_id, UNLOCK_CODE);
|
u32 val;
|
||||||
|
unsigned long flags;
|
||||||
|
int bank_id = GPIO_BANK(gpio);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
|
val = readl(kona_gpio->reg_base + GPIO_PWD_STATUS(bank_id));
|
||||||
|
val &= ~BIT(gpio);
|
||||||
|
bcm_kona_gpio_write_lock_regs(kona_gpio->reg_base, bank_id, val);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
|
@ -110,7 +134,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
kona_gpio = to_kona_gpio(chip);
|
kona_gpio = to_kona_gpio(chip);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
/* determine the GPIO pin direction */
|
/* determine the GPIO pin direction */
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
|
@ -127,7 +150,6 @@ static void bcm_kona_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
writel(val, reg_base + reg_offset);
|
writel(val, reg_base + reg_offset);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +165,6 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||||
kona_gpio = to_kona_gpio(chip);
|
kona_gpio = to_kona_gpio(chip);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
/* determine the GPIO pin direction */
|
/* determine the GPIO pin direction */
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
|
@ -154,32 +175,43 @@ static int bcm_kona_gpio_get(struct gpio_chip *chip, unsigned gpio)
|
||||||
GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
|
GPIO_IN_STATUS(bank_id) : GPIO_OUT_STATUS(bank_id);
|
||||||
val = readl(reg_base + reg_offset);
|
val = readl(reg_base + reg_offset);
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
/* return the specified bit status */
|
/* return the specified bit status */
|
||||||
return !!(val & BIT(bit));
|
return !!(val & BIT(bit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bcm_kona_gpio_request(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
{
|
||||||
|
struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
|
||||||
|
|
||||||
|
bcm_kona_gpio_unlock_gpio(kona_gpio, gpio);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcm_kona_gpio_free(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
{
|
||||||
|
struct bcm_kona_gpio *kona_gpio = to_kona_gpio(chip);
|
||||||
|
|
||||||
|
bcm_kona_gpio_lock_gpio(kona_gpio, gpio);
|
||||||
|
}
|
||||||
|
|
||||||
static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
static int bcm_kona_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio;
|
struct bcm_kona_gpio *kona_gpio;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
|
||||||
|
|
||||||
kona_gpio = to_kona_gpio(chip);
|
kona_gpio = to_kona_gpio(chip);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
||||||
val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
|
val |= GPIO_GPCTR0_IOTR_CMD_INPUT;
|
||||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -198,7 +230,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
|
||||||
kona_gpio = to_kona_gpio(chip);
|
kona_gpio = to_kona_gpio(chip);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
val &= ~GPIO_GPCTR0_IOTR_MASK;
|
||||||
|
@ -210,7 +241,6 @@ static int bcm_kona_gpio_direction_output(struct gpio_chip *chip,
|
||||||
val |= BIT(bit);
|
val |= BIT(bit);
|
||||||
writel(val, reg_base + reg_offset);
|
writel(val, reg_base + reg_offset);
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -233,7 +263,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
u32 val, res;
|
u32 val, res;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
|
||||||
|
|
||||||
kona_gpio = to_kona_gpio(chip);
|
kona_gpio = to_kona_gpio(chip);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
|
@ -257,7 +286,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
||||||
|
|
||||||
/* spin lock for read-modify-write of the GPIO register */
|
/* spin lock for read-modify-write of the GPIO register */
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
val &= ~GPIO_GPCTR0_DBR_MASK;
|
val &= ~GPIO_GPCTR0_DBR_MASK;
|
||||||
|
@ -272,7 +300,6 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
||||||
|
|
||||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -281,6 +308,8 @@ static int bcm_kona_gpio_set_debounce(struct gpio_chip *chip, unsigned gpio,
|
||||||
static struct gpio_chip template_chip = {
|
static struct gpio_chip template_chip = {
|
||||||
.label = "bcm-kona-gpio",
|
.label = "bcm-kona-gpio",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.request = bcm_kona_gpio_request,
|
||||||
|
.free = bcm_kona_gpio_free,
|
||||||
.direction_input = bcm_kona_gpio_direction_input,
|
.direction_input = bcm_kona_gpio_direction_input,
|
||||||
.get = bcm_kona_gpio_get,
|
.get = bcm_kona_gpio_get,
|
||||||
.direction_output = bcm_kona_gpio_direction_output,
|
.direction_output = bcm_kona_gpio_direction_output,
|
||||||
|
@ -294,7 +323,7 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio;
|
struct bcm_kona_gpio *kona_gpio;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
int gpio = d->hwirq;
|
unsigned gpio = d->hwirq;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
int bank_id = GPIO_BANK(gpio);
|
||||||
int bit = GPIO_BIT(gpio);
|
int bit = GPIO_BIT(gpio);
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -303,13 +332,11 @@ static void bcm_kona_gpio_irq_ack(struct irq_data *d)
|
||||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_INT_STATUS(bank_id));
|
val = readl(reg_base + GPIO_INT_STATUS(bank_id));
|
||||||
val |= BIT(bit);
|
val |= BIT(bit);
|
||||||
writel(val, reg_base + GPIO_INT_STATUS(bank_id));
|
writel(val, reg_base + GPIO_INT_STATUS(bank_id));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +344,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio;
|
struct bcm_kona_gpio *kona_gpio;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
int gpio = d->hwirq;
|
unsigned gpio = d->hwirq;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
int bank_id = GPIO_BANK(gpio);
|
||||||
int bit = GPIO_BIT(gpio);
|
int bit = GPIO_BIT(gpio);
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -326,13 +353,11 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
|
||||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_INT_MASK(bank_id));
|
val = readl(reg_base + GPIO_INT_MASK(bank_id));
|
||||||
val |= BIT(bit);
|
val |= BIT(bit);
|
||||||
writel(val, reg_base + GPIO_INT_MASK(bank_id));
|
writel(val, reg_base + GPIO_INT_MASK(bank_id));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +365,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio;
|
struct bcm_kona_gpio *kona_gpio;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
int gpio = d->hwirq;
|
unsigned gpio = d->hwirq;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
int bank_id = GPIO_BANK(gpio);
|
||||||
int bit = GPIO_BIT(gpio);
|
int bit = GPIO_BIT(gpio);
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -349,13 +374,11 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
|
||||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
|
val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
|
||||||
val |= BIT(bit);
|
val |= BIT(bit);
|
||||||
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
|
writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,11 +386,10 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio;
|
struct bcm_kona_gpio *kona_gpio;
|
||||||
void __iomem *reg_base;
|
void __iomem *reg_base;
|
||||||
int gpio = d->hwirq;
|
unsigned gpio = d->hwirq;
|
||||||
u32 lvl_type;
|
u32 lvl_type;
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int bank_id = GPIO_BANK(gpio);
|
|
||||||
|
|
||||||
kona_gpio = irq_data_get_irq_chip_data(d);
|
kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
|
@ -394,14 +416,12 @@ static int bcm_kona_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&kona_gpio->lock, flags);
|
spin_lock_irqsave(&kona_gpio->lock, flags);
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
val = readl(reg_base + GPIO_CONTROL(gpio));
|
val = readl(reg_base + GPIO_CONTROL(gpio));
|
||||||
val &= ~GPIO_GPCTR0_ITR_MASK;
|
val &= ~GPIO_GPCTR0_ITR_MASK;
|
||||||
val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT;
|
val |= lvl_type << GPIO_GPCTR0_ITR_SHIFT;
|
||||||
writel(val, reg_base + GPIO_CONTROL(gpio));
|
writel(val, reg_base + GPIO_CONTROL(gpio));
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
spin_unlock_irqrestore(&kona_gpio->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -424,7 +444,6 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
*/
|
*/
|
||||||
reg_base = bank->kona_gpio->reg_base;
|
reg_base = bank->kona_gpio->reg_base;
|
||||||
bank_id = bank->id;
|
bank_id = bank->id;
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) &
|
while ((sta = readl(reg_base + GPIO_INT_STATUS(bank_id)) &
|
||||||
(~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) {
|
(~(readl(reg_base + GPIO_INT_MASK(bank_id)))))) {
|
||||||
|
@ -444,28 +463,26 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bcm_kona_gpio_lock_bank(reg_base, bank_id);
|
|
||||||
|
|
||||||
chained_irq_exit(chip, desc);
|
chained_irq_exit(chip, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int bcm_kona_gpio_irq_startup(struct irq_data *d)
|
static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
|
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq))
|
if (gpio_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq)) {
|
||||||
dev_err(kona_gpio->gpio_chip.dev,
|
dev_err(kona_gpio->gpio_chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
d->hwirq);
|
d->hwirq);
|
||||||
bcm_kona_gpio_irq_unmask(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bcm_kona_gpio_irq_shutdown(struct irq_data *d)
|
static void bcm_kona_gpio_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
|
struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
bcm_kona_gpio_irq_mask(d);
|
|
||||||
gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
|
gpio_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,8 +492,8 @@ static struct irq_chip bcm_gpio_irq_chip = {
|
||||||
.irq_mask = bcm_kona_gpio_irq_mask,
|
.irq_mask = bcm_kona_gpio_irq_mask,
|
||||||
.irq_unmask = bcm_kona_gpio_irq_unmask,
|
.irq_unmask = bcm_kona_gpio_irq_unmask,
|
||||||
.irq_set_type = bcm_kona_gpio_irq_set_type,
|
.irq_set_type = bcm_kona_gpio_irq_set_type,
|
||||||
.irq_startup = bcm_kona_gpio_irq_startup,
|
.irq_request_resources = bcm_kona_gpio_irq_reqres,
|
||||||
.irq_shutdown = bcm_kona_gpio_irq_shutdown,
|
.irq_release_resources = bcm_kona_gpio_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
|
static struct __initconst of_device_id bcm_kona_gpio_of_match[] = {
|
||||||
|
@ -531,10 +548,12 @@ static void bcm_kona_gpio_reset(struct bcm_kona_gpio *kona_gpio)
|
||||||
reg_base = kona_gpio->reg_base;
|
reg_base = kona_gpio->reg_base;
|
||||||
/* disable interrupts and clear status */
|
/* disable interrupts and clear status */
|
||||||
for (i = 0; i < kona_gpio->num_bank; i++) {
|
for (i = 0; i < kona_gpio->num_bank; i++) {
|
||||||
bcm_kona_gpio_unlock_bank(reg_base, i);
|
/* Unlock the entire bank first */
|
||||||
|
bcm_kona_gpio_write_lock_regs(kona_gpio, i, UNLOCK_CODE);
|
||||||
writel(0xffffffff, reg_base + GPIO_INT_MASK(i));
|
writel(0xffffffff, reg_base + GPIO_INT_MASK(i));
|
||||||
writel(0xffffffff, reg_base + GPIO_INT_STATUS(i));
|
writel(0xffffffff, reg_base + GPIO_INT_STATUS(i));
|
||||||
bcm_kona_gpio_lock_bank(reg_base, i);
|
/* Now re-lock the bank */
|
||||||
|
bcm_kona_gpio_write_lock_regs(kona_gpio, i, LOCK_CODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ static int clps711x_gpio_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
bgc->gc.base = id * 8;
|
bgc->gc.base = id * 8;
|
||||||
|
bgc->gc.owner = THIS_MODULE;
|
||||||
platform_set_drvdata(pdev, bgc);
|
platform_set_drvdata(pdev, bgc);
|
||||||
|
|
||||||
return gpiochip_add(&bgc->gc);
|
return gpiochip_add(&bgc->gc);
|
||||||
|
|
|
@ -37,6 +37,8 @@ struct davinci_gpio_regs {
|
||||||
u32 intstat;
|
u32 intstat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
|
||||||
|
|
||||||
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
|
#define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
|
||||||
|
|
||||||
#define chip2controller(chip) \
|
#define chip2controller(chip) \
|
||||||
|
@ -172,6 +174,27 @@ of_err:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF_GPIO
|
||||||
|
static int davinci_gpio_of_xlate(struct gpio_chip *gc,
|
||||||
|
const struct of_phandle_args *gpiospec,
|
||||||
|
u32 *flags)
|
||||||
|
{
|
||||||
|
struct davinci_gpio_controller *chips = dev_get_drvdata(gc->dev);
|
||||||
|
struct davinci_gpio_platform_data *pdata = dev_get_platdata(gc->dev);
|
||||||
|
|
||||||
|
if (gpiospec->args[0] > pdata->ngpio)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (gc != &chips[gpiospec->args[0] / 32].chip)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (flags)
|
||||||
|
*flags = gpiospec->args[1];
|
||||||
|
|
||||||
|
return gpiospec->args[0] % 32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int davinci_gpio_probe(struct platform_device *pdev)
|
static int davinci_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int i, base;
|
int i, base;
|
||||||
|
@ -236,6 +259,9 @@ static int davinci_gpio_probe(struct platform_device *pdev)
|
||||||
chips[i].chip.ngpio = 32;
|
chips[i].chip.ngpio = 32;
|
||||||
|
|
||||||
#ifdef CONFIG_OF_GPIO
|
#ifdef CONFIG_OF_GPIO
|
||||||
|
chips[i].chip.of_gpio_n_cells = 2;
|
||||||
|
chips[i].chip.of_xlate = davinci_gpio_of_xlate;
|
||||||
|
chips[i].chip.dev = dev;
|
||||||
chips[i].chip.of_node = dev->of_node;
|
chips[i].chip.of_node = dev->of_node;
|
||||||
#endif
|
#endif
|
||||||
spin_lock_init(&chips[i].lock);
|
spin_lock_init(&chips[i].lock);
|
||||||
|
@ -413,6 +439,26 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = {
|
||||||
.xlate = irq_domain_xlate_onetwocell,
|
.xlate = irq_domain_xlate_onetwocell,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct irq_chip *davinci_gpio_get_irq_chip(unsigned int irq)
|
||||||
|
{
|
||||||
|
static struct irq_chip_type gpio_unbanked;
|
||||||
|
|
||||||
|
gpio_unbanked = *container_of(irq_get_chip(irq),
|
||||||
|
struct irq_chip_type, chip);
|
||||||
|
|
||||||
|
return &gpio_unbanked.chip;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct irq_chip *keystone_gpio_get_irq_chip(unsigned int irq)
|
||||||
|
{
|
||||||
|
static struct irq_chip gpio_unbanked;
|
||||||
|
|
||||||
|
gpio_unbanked = *irq_get_chip(irq);
|
||||||
|
return &gpio_unbanked;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id davinci_gpio_ids[];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: for suspend/resume, probably best to make a platform_device with
|
* NOTE: for suspend/resume, probably best to make a platform_device with
|
||||||
* suspend_late/resume_resume calls hooking into results of the set_wake()
|
* suspend_late/resume_resume calls hooking into results of the set_wake()
|
||||||
|
@ -423,7 +469,8 @@ static const struct irq_domain_ops davinci_gpio_irq_ops = {
|
||||||
|
|
||||||
static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
unsigned gpio, irq, bank;
|
unsigned gpio, bank;
|
||||||
|
int irq;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
u32 binten = 0;
|
u32 binten = 0;
|
||||||
unsigned ngpio, bank_irq;
|
unsigned ngpio, bank_irq;
|
||||||
|
@ -433,6 +480,18 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
struct davinci_gpio_platform_data *pdata = dev->platform_data;
|
struct davinci_gpio_platform_data *pdata = dev->platform_data;
|
||||||
struct davinci_gpio_regs __iomem *g;
|
struct davinci_gpio_regs __iomem *g;
|
||||||
struct irq_domain *irq_domain = NULL;
|
struct irq_domain *irq_domain = NULL;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
struct irq_chip *irq_chip;
|
||||||
|
gpio_get_irq_chip_cb_t gpio_get_irq_chip;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use davinci_gpio_get_irq_chip by default to handle non DT cases
|
||||||
|
*/
|
||||||
|
gpio_get_irq_chip = davinci_gpio_get_irq_chip;
|
||||||
|
match = of_match_device(of_match_ptr(davinci_gpio_ids),
|
||||||
|
dev);
|
||||||
|
if (match)
|
||||||
|
gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data;
|
||||||
|
|
||||||
ngpio = pdata->ngpio;
|
ngpio = pdata->ngpio;
|
||||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
@ -489,8 +548,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
|
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
|
||||||
*/
|
*/
|
||||||
if (pdata->gpio_unbanked) {
|
if (pdata->gpio_unbanked) {
|
||||||
static struct irq_chip_type gpio_unbanked;
|
|
||||||
|
|
||||||
/* pass "bank 0" GPIO IRQs to AINTC */
|
/* pass "bank 0" GPIO IRQs to AINTC */
|
||||||
chips[0].chip.to_irq = gpio_to_irq_unbanked;
|
chips[0].chip.to_irq = gpio_to_irq_unbanked;
|
||||||
chips[0].gpio_irq = bank_irq;
|
chips[0].gpio_irq = bank_irq;
|
||||||
|
@ -499,10 +556,9 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
|
|
||||||
/* AINTC handles mask/unmask; GPIO handles triggering */
|
/* AINTC handles mask/unmask; GPIO handles triggering */
|
||||||
irq = bank_irq;
|
irq = bank_irq;
|
||||||
gpio_unbanked = *container_of(irq_get_chip(irq),
|
irq_chip = gpio_get_irq_chip(irq);
|
||||||
struct irq_chip_type, chip);
|
irq_chip->name = "GPIO-AINTC";
|
||||||
gpio_unbanked.chip.name = "GPIO-AINTC";
|
irq_chip->irq_set_type = gpio_irq_type_unbanked;
|
||||||
gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked;
|
|
||||||
|
|
||||||
/* default trigger: both edges */
|
/* default trigger: both edges */
|
||||||
g = gpio2regs(0);
|
g = gpio2regs(0);
|
||||||
|
@ -511,7 +567,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||||
|
|
||||||
/* set the direct IRQs up to use that irqchip */
|
/* set the direct IRQs up to use that irqchip */
|
||||||
for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
|
for (gpio = 0; gpio < pdata->gpio_unbanked; gpio++, irq++) {
|
||||||
irq_set_chip(irq, &gpio_unbanked.chip);
|
irq_set_chip(irq, irq_chip);
|
||||||
irq_set_handler_data(irq, &chips[gpio / 32]);
|
irq_set_handler_data(irq, &chips[gpio / 32]);
|
||||||
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
|
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
|
||||||
}
|
}
|
||||||
|
@ -554,7 +610,8 @@ done:
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_OF)
|
#if IS_ENABLED(CONFIG_OF)
|
||||||
static const struct of_device_id davinci_gpio_ids[] = {
|
static const struct of_device_id davinci_gpio_ids[] = {
|
||||||
{ .compatible = "ti,dm6441-gpio", },
|
{ .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip},
|
||||||
|
{ .compatible = "ti,dm6441-gpio", davinci_gpio_get_irq_chip},
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
|
MODULE_DEVICE_TABLE(of, davinci_gpio_ids);
|
||||||
|
|
|
@ -0,0 +1,438 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011 Jamie Iles
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* All enquiries to support@picochip.com
|
||||||
|
*/
|
||||||
|
#include <linux/basic_mmio_gpio.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#define GPIO_SWPORTA_DR 0x00
|
||||||
|
#define GPIO_SWPORTA_DDR 0x04
|
||||||
|
#define GPIO_SWPORTB_DR 0x0c
|
||||||
|
#define GPIO_SWPORTB_DDR 0x10
|
||||||
|
#define GPIO_SWPORTC_DR 0x18
|
||||||
|
#define GPIO_SWPORTC_DDR 0x1c
|
||||||
|
#define GPIO_SWPORTD_DR 0x24
|
||||||
|
#define GPIO_SWPORTD_DDR 0x28
|
||||||
|
#define GPIO_INTEN 0x30
|
||||||
|
#define GPIO_INTMASK 0x34
|
||||||
|
#define GPIO_INTTYPE_LEVEL 0x38
|
||||||
|
#define GPIO_INT_POLARITY 0x3c
|
||||||
|
#define GPIO_INTSTATUS 0x40
|
||||||
|
#define GPIO_PORTA_EOI 0x4c
|
||||||
|
#define GPIO_EXT_PORTA 0x50
|
||||||
|
#define GPIO_EXT_PORTB 0x54
|
||||||
|
#define GPIO_EXT_PORTC 0x58
|
||||||
|
#define GPIO_EXT_PORTD 0x5c
|
||||||
|
|
||||||
|
#define DWAPB_MAX_PORTS 4
|
||||||
|
#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA)
|
||||||
|
#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
|
||||||
|
#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
|
||||||
|
|
||||||
|
struct dwapb_gpio;
|
||||||
|
|
||||||
|
struct dwapb_gpio_port {
|
||||||
|
struct bgpio_chip bgc;
|
||||||
|
bool is_registered;
|
||||||
|
struct dwapb_gpio *gpio;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dwapb_gpio {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *regs;
|
||||||
|
struct dwapb_gpio_port *ports;
|
||||||
|
unsigned int nr_ports;
|
||||||
|
struct irq_domain *domain;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||||
|
{
|
||||||
|
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||||
|
struct dwapb_gpio_port *port = container_of(bgc, struct
|
||||||
|
dwapb_gpio_port, bgc);
|
||||||
|
struct dwapb_gpio *gpio = port->gpio;
|
||||||
|
|
||||||
|
return irq_find_mapping(gpio->domain, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
|
||||||
|
{
|
||||||
|
u32 v = readl(gpio->regs + GPIO_INT_POLARITY);
|
||||||
|
|
||||||
|
if (gpio_get_value(gpio->ports[0].bgc.gc.base + offs))
|
||||||
|
v &= ~BIT(offs);
|
||||||
|
else
|
||||||
|
v |= BIT(offs);
|
||||||
|
|
||||||
|
writel(v, gpio->regs + GPIO_INT_POLARITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_irq_handler(u32 irq, struct irq_desc *desc)
|
||||||
|
{
|
||||||
|
struct dwapb_gpio *gpio = irq_get_handler_data(irq);
|
||||||
|
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||||
|
u32 irq_status = readl_relaxed(gpio->regs + GPIO_INTSTATUS);
|
||||||
|
|
||||||
|
while (irq_status) {
|
||||||
|
int hwirq = fls(irq_status) - 1;
|
||||||
|
int gpio_irq = irq_find_mapping(gpio->domain, hwirq);
|
||||||
|
|
||||||
|
generic_handle_irq(gpio_irq);
|
||||||
|
irq_status &= ~BIT(hwirq);
|
||||||
|
|
||||||
|
if ((irq_get_trigger_type(gpio_irq) & IRQ_TYPE_SENSE_MASK)
|
||||||
|
== IRQ_TYPE_EDGE_BOTH)
|
||||||
|
dwapb_toggle_trigger(gpio, hwirq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chip->irq_eoi)
|
||||||
|
chip->irq_eoi(irq_desc_get_irq_data(desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_irq_enable(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct dwapb_gpio *gpio = igc->private;
|
||||||
|
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||||
|
unsigned long flags;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bgc->lock, flags);
|
||||||
|
val = readl(gpio->regs + GPIO_INTEN);
|
||||||
|
val |= BIT(d->hwirq);
|
||||||
|
writel(val, gpio->regs + GPIO_INTEN);
|
||||||
|
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_irq_disable(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct dwapb_gpio *gpio = igc->private;
|
||||||
|
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||||
|
unsigned long flags;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bgc->lock, flags);
|
||||||
|
val = readl(gpio->regs + GPIO_INTEN);
|
||||||
|
val &= ~BIT(d->hwirq);
|
||||||
|
writel(val, gpio->regs + GPIO_INTEN);
|
||||||
|
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwapb_irq_reqres(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct dwapb_gpio *gpio = igc->private;
|
||||||
|
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||||
|
|
||||||
|
if (gpio_lock_as_irq(&bgc->gc, irqd_to_hwirq(d))) {
|
||||||
|
dev_err(gpio->dev, "unable to lock HW IRQ %lu for IRQ\n",
|
||||||
|
irqd_to_hwirq(d));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_irq_relres(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct dwapb_gpio *gpio = igc->private;
|
||||||
|
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||||
|
|
||||||
|
gpio_unlock_as_irq(&bgc->gc, irqd_to_hwirq(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwapb_irq_set_type(struct irq_data *d, u32 type)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct dwapb_gpio *gpio = igc->private;
|
||||||
|
struct bgpio_chip *bgc = &gpio->ports[0].bgc;
|
||||||
|
int bit = d->hwirq;
|
||||||
|
unsigned long level, polarity, flags;
|
||||||
|
|
||||||
|
if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
|
||||||
|
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bgc->lock, flags);
|
||||||
|
level = readl(gpio->regs + GPIO_INTTYPE_LEVEL);
|
||||||
|
polarity = readl(gpio->regs + GPIO_INT_POLARITY);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
level |= BIT(bit);
|
||||||
|
dwapb_toggle_trigger(gpio, bit);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_RISING:
|
||||||
|
level |= BIT(bit);
|
||||||
|
polarity |= BIT(bit);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
level |= BIT(bit);
|
||||||
|
polarity &= ~BIT(bit);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
level &= ~BIT(bit);
|
||||||
|
polarity |= BIT(bit);
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
level &= ~BIT(bit);
|
||||||
|
polarity &= ~BIT(bit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(level, gpio->regs + GPIO_INTTYPE_LEVEL);
|
||||||
|
writel(polarity, gpio->regs + GPIO_INT_POLARITY);
|
||||||
|
spin_unlock_irqrestore(&bgc->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
|
||||||
|
struct dwapb_gpio_port *port)
|
||||||
|
{
|
||||||
|
struct gpio_chip *gc = &port->bgc.gc;
|
||||||
|
struct device_node *node = gc->of_node;
|
||||||
|
struct irq_chip_generic *irq_gc;
|
||||||
|
unsigned int hwirq, ngpio = gc->ngpio;
|
||||||
|
struct irq_chip_type *ct;
|
||||||
|
int err, irq;
|
||||||
|
|
||||||
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
|
if (!irq) {
|
||||||
|
dev_warn(gpio->dev, "no irq for bank %s\n",
|
||||||
|
port->bgc.gc.of_node->full_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio->domain = irq_domain_add_linear(node, ngpio,
|
||||||
|
&irq_generic_chip_ops, gpio);
|
||||||
|
if (!gpio->domain)
|
||||||
|
return;
|
||||||
|
|
||||||
|
err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 1,
|
||||||
|
"gpio-dwapb", handle_level_irq,
|
||||||
|
IRQ_NOREQUEST, 0,
|
||||||
|
IRQ_GC_INIT_NESTED_LOCK);
|
||||||
|
if (err) {
|
||||||
|
dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n");
|
||||||
|
irq_domain_remove(gpio->domain);
|
||||||
|
gpio->domain = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_gc = irq_get_domain_generic_chip(gpio->domain, 0);
|
||||||
|
if (!irq_gc) {
|
||||||
|
irq_domain_remove(gpio->domain);
|
||||||
|
gpio->domain = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_gc->reg_base = gpio->regs;
|
||||||
|
irq_gc->private = gpio;
|
||||||
|
|
||||||
|
ct = irq_gc->chip_types;
|
||||||
|
ct->chip.irq_ack = irq_gc_ack_set_bit;
|
||||||
|
ct->chip.irq_mask = irq_gc_mask_set_bit;
|
||||||
|
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
|
||||||
|
ct->chip.irq_set_type = dwapb_irq_set_type;
|
||||||
|
ct->chip.irq_enable = dwapb_irq_enable;
|
||||||
|
ct->chip.irq_disable = dwapb_irq_disable;
|
||||||
|
ct->chip.irq_request_resources = dwapb_irq_reqres;
|
||||||
|
ct->chip.irq_release_resources = dwapb_irq_relres;
|
||||||
|
ct->regs.ack = GPIO_PORTA_EOI;
|
||||||
|
ct->regs.mask = GPIO_INTMASK;
|
||||||
|
|
||||||
|
irq_setup_generic_chip(irq_gc, IRQ_MSK(port->bgc.gc.ngpio),
|
||||||
|
IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
|
||||||
|
|
||||||
|
irq_set_chained_handler(irq, dwapb_irq_handler);
|
||||||
|
irq_set_handler_data(irq, gpio);
|
||||||
|
|
||||||
|
for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
|
||||||
|
irq_create_mapping(gpio->domain, hwirq);
|
||||||
|
|
||||||
|
port->bgc.gc.to_irq = dwapb_gpio_to_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
|
||||||
|
{
|
||||||
|
struct dwapb_gpio_port *port = &gpio->ports[0];
|
||||||
|
struct gpio_chip *gc = &port->bgc.gc;
|
||||||
|
unsigned int ngpio = gc->ngpio;
|
||||||
|
irq_hw_number_t hwirq;
|
||||||
|
|
||||||
|
if (!gpio->domain)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (hwirq = 0 ; hwirq < ngpio ; hwirq++)
|
||||||
|
irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq));
|
||||||
|
|
||||||
|
irq_domain_remove(gpio->domain);
|
||||||
|
gpio->domain = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||||
|
struct device_node *port_np,
|
||||||
|
unsigned int offs)
|
||||||
|
{
|
||||||
|
struct dwapb_gpio_port *port;
|
||||||
|
u32 port_idx, ngpio;
|
||||||
|
void __iomem *dat, *set, *dirout;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (of_property_read_u32(port_np, "reg", &port_idx) ||
|
||||||
|
port_idx >= DWAPB_MAX_PORTS) {
|
||||||
|
dev_err(gpio->dev, "missing/invalid port index for %s\n",
|
||||||
|
port_np->full_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
port = &gpio->ports[offs];
|
||||||
|
port->gpio = gpio;
|
||||||
|
|
||||||
|
if (of_property_read_u32(port_np, "snps,nr-gpios", &ngpio)) {
|
||||||
|
dev_info(gpio->dev, "failed to get number of gpios for %s\n",
|
||||||
|
port_np->full_name);
|
||||||
|
ngpio = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
dat = gpio->regs + GPIO_EXT_PORTA + (port_idx * GPIO_EXT_PORT_SIZE);
|
||||||
|
set = gpio->regs + GPIO_SWPORTA_DR + (port_idx * GPIO_SWPORT_DR_SIZE);
|
||||||
|
dirout = gpio->regs + GPIO_SWPORTA_DDR +
|
||||||
|
(port_idx * GPIO_SWPORT_DDR_SIZE);
|
||||||
|
|
||||||
|
err = bgpio_init(&port->bgc, gpio->dev, 4, dat, set, NULL, dirout,
|
||||||
|
NULL, false);
|
||||||
|
if (err) {
|
||||||
|
dev_err(gpio->dev, "failed to init gpio chip for %s\n",
|
||||||
|
port_np->full_name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
port->bgc.gc.ngpio = ngpio;
|
||||||
|
port->bgc.gc.of_node = port_np;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only port A can provide interrupts in all configurations of the IP.
|
||||||
|
*/
|
||||||
|
if (port_idx == 0 &&
|
||||||
|
of_property_read_bool(port_np, "interrupt-controller"))
|
||||||
|
dwapb_configure_irqs(gpio, port);
|
||||||
|
|
||||||
|
err = gpiochip_add(&port->bgc.gc);
|
||||||
|
if (err)
|
||||||
|
dev_err(gpio->dev, "failed to register gpiochip for %s\n",
|
||||||
|
port_np->full_name);
|
||||||
|
else
|
||||||
|
port->is_registered = true;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
|
||||||
|
{
|
||||||
|
unsigned int m;
|
||||||
|
|
||||||
|
for (m = 0; m < gpio->nr_ports; ++m)
|
||||||
|
if (gpio->ports[m].is_registered)
|
||||||
|
WARN_ON(gpiochip_remove(&gpio->ports[m].bgc.gc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
struct dwapb_gpio *gpio;
|
||||||
|
struct device_node *np;
|
||||||
|
int err;
|
||||||
|
unsigned int offs = 0;
|
||||||
|
|
||||||
|
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||||
|
if (!gpio)
|
||||||
|
return -ENOMEM;
|
||||||
|
gpio->dev = &pdev->dev;
|
||||||
|
|
||||||
|
gpio->nr_ports = of_get_child_count(pdev->dev.of_node);
|
||||||
|
if (!gpio->nr_ports) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
gpio->ports = devm_kzalloc(&pdev->dev, gpio->nr_ports *
|
||||||
|
sizeof(*gpio->ports), GFP_KERNEL);
|
||||||
|
if (!gpio->ports) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
gpio->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(gpio->regs)) {
|
||||||
|
err = PTR_ERR(gpio->regs);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child_of_node(pdev->dev.of_node, np) {
|
||||||
|
err = dwapb_gpio_add_port(gpio, np, offs++);
|
||||||
|
if (err)
|
||||||
|
goto out_unregister;
|
||||||
|
}
|
||||||
|
platform_set_drvdata(pdev, gpio);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_unregister:
|
||||||
|
dwapb_gpio_unregister(gpio);
|
||||||
|
dwapb_irq_teardown(gpio);
|
||||||
|
|
||||||
|
out_err:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwapb_gpio_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
dwapb_gpio_unregister(gpio);
|
||||||
|
dwapb_irq_teardown(gpio);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id dwapb_of_match[] = {
|
||||||
|
{ .compatible = "snps,dw-apb-gpio" },
|
||||||
|
{ /* Sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, dwapb_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver dwapb_gpio_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "gpio-dwapb",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(dwapb_of_match),
|
||||||
|
},
|
||||||
|
.probe = dwapb_gpio_probe,
|
||||||
|
.remove = dwapb_gpio_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(dwapb_gpio_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jamie Iles");
|
||||||
|
MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
|
|
@ -99,23 +99,23 @@ static void em_gio_irq_enable(struct irq_data *d)
|
||||||
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
|
em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int em_gio_irq_startup(struct irq_data *d)
|
static int em_gio_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d)))
|
if (gpio_lock_as_irq(&p->gpio_chip, irqd_to_hwirq(d))) {
|
||||||
dev_err(p->gpio_chip.dev,
|
dev_err(p->gpio_chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
irqd_to_hwirq(d));
|
irqd_to_hwirq(d));
|
||||||
em_gio_irq_enable(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void em_gio_irq_shutdown(struct irq_data *d)
|
static void em_gio_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
struct em_gio_priv *p = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
em_gio_irq_disable(d);
|
|
||||||
gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
|
gpio_unlock_as_irq(&p->gpio_chip, irqd_to_hwirq(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,8 +359,8 @@ static int em_gio_probe(struct platform_device *pdev)
|
||||||
irq_chip->irq_mask = em_gio_irq_disable;
|
irq_chip->irq_mask = em_gio_irq_disable;
|
||||||
irq_chip->irq_unmask = em_gio_irq_enable;
|
irq_chip->irq_unmask = em_gio_irq_enable;
|
||||||
irq_chip->irq_set_type = em_gio_irq_set_type;
|
irq_chip->irq_set_type = em_gio_irq_set_type;
|
||||||
irq_chip->irq_startup = em_gio_irq_startup;
|
irq_chip->irq_request_resources = em_gio_irq_reqres;
|
||||||
irq_chip->irq_shutdown = em_gio_irq_shutdown;
|
irq_chip->irq_release_resources = em_gio_irq_relres;
|
||||||
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
|
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
|
p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
|
||||||
|
|
|
@ -139,7 +139,7 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||||
{
|
{
|
||||||
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
struct bgpio_chip *bgc = to_bgpio_chip(gc);
|
||||||
|
|
||||||
return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
|
return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
|
@ -488,7 +488,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||||
void __iomem *dirout;
|
void __iomem *dirout;
|
||||||
void __iomem *dirin;
|
void __iomem *dirin;
|
||||||
unsigned long sz;
|
unsigned long sz;
|
||||||
unsigned long flags = 0;
|
unsigned long flags = pdev->id_entry->driver_data;
|
||||||
int err;
|
int err;
|
||||||
struct bgpio_chip *bgc;
|
struct bgpio_chip *bgc;
|
||||||
struct bgpio_pdata *pdata = dev_get_platdata(dev);
|
struct bgpio_pdata *pdata = dev_get_platdata(dev);
|
||||||
|
@ -519,9 +519,6 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"))
|
|
||||||
flags |= BGPIOF_BIG_ENDIAN;
|
|
||||||
|
|
||||||
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
|
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
|
||||||
if (!bgc)
|
if (!bgc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -531,6 +528,8 @@ static int bgpio_pdev_probe(struct platform_device *pdev)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
|
if (pdata->label)
|
||||||
|
bgc->gc.label = pdata->label;
|
||||||
bgc->gc.base = pdata->base;
|
bgc->gc.base = pdata->base;
|
||||||
if (pdata->ngpio > 0)
|
if (pdata->ngpio > 0)
|
||||||
bgc->gc.ngpio = pdata->ngpio;
|
bgc->gc.ngpio = pdata->ngpio;
|
||||||
|
@ -549,9 +548,14 @@ static int bgpio_pdev_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct platform_device_id bgpio_id_table[] = {
|
static const struct platform_device_id bgpio_id_table[] = {
|
||||||
{ "basic-mmio-gpio", },
|
{
|
||||||
{ "basic-mmio-gpio-be", },
|
.name = "basic-mmio-gpio",
|
||||||
{},
|
.driver_data = 0,
|
||||||
|
}, {
|
||||||
|
.name = "basic-mmio-gpio-be",
|
||||||
|
.driver_data = BGPIOF_BIG_ENDIAN,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(platform, bgpio_id_table);
|
MODULE_DEVICE_TABLE(platform, bgpio_id_table);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,13 @@ struct ichx_desc {
|
||||||
/* Max GPIO pins the chipset can have */
|
/* Max GPIO pins the chipset can have */
|
||||||
uint ngpio;
|
uint ngpio;
|
||||||
|
|
||||||
|
/* chipset registers */
|
||||||
|
const u8 (*regs)[3];
|
||||||
|
const u8 *reglen;
|
||||||
|
|
||||||
|
/* GPO_BLINK is available on this chipset */
|
||||||
|
bool have_blink;
|
||||||
|
|
||||||
/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */
|
/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */
|
||||||
bool uses_gpe0;
|
bool uses_gpe0;
|
||||||
|
|
||||||
|
@ -71,6 +78,12 @@ struct ichx_desc {
|
||||||
/* Some chipsets have quirks, let these use their own request/get */
|
/* Some chipsets have quirks, let these use their own request/get */
|
||||||
int (*request)(struct gpio_chip *chip, unsigned offset);
|
int (*request)(struct gpio_chip *chip, unsigned offset);
|
||||||
int (*get)(struct gpio_chip *chip, unsigned offset);
|
int (*get)(struct gpio_chip *chip, unsigned offset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some chipsets don't let reading output values on GPIO_LVL register
|
||||||
|
* this option allows driver caching written output values
|
||||||
|
*/
|
||||||
|
bool use_outlvl_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -82,6 +95,7 @@ static struct {
|
||||||
struct ichx_desc *desc; /* Pointer to chipset-specific description */
|
struct ichx_desc *desc; /* Pointer to chipset-specific description */
|
||||||
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
|
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
|
||||||
u8 use_gpio; /* Which GPIO groups are usable */
|
u8 use_gpio; /* Which GPIO groups are usable */
|
||||||
|
int outlvl_cache[3]; /* cached output values */
|
||||||
} ichx_priv;
|
} ichx_priv;
|
||||||
|
|
||||||
static int modparam_gpiobase = -1; /* dynamic */
|
static int modparam_gpiobase = -1; /* dynamic */
|
||||||
|
@ -99,13 +113,23 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
|
||||||
|
|
||||||
spin_lock_irqsave(&ichx_priv.lock, flags);
|
spin_lock_irqsave(&ichx_priv.lock, flags);
|
||||||
|
|
||||||
data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
|
if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
|
||||||
|
data = ichx_priv.outlvl_cache[reg_nr];
|
||||||
|
else
|
||||||
|
data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
|
||||||
|
ichx_priv.gpio_base);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
data |= 1 << bit;
|
data |= 1 << bit;
|
||||||
else
|
else
|
||||||
data &= ~(1 << bit);
|
data &= ~(1 << bit);
|
||||||
ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
|
ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
|
||||||
tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
|
ichx_priv.gpio_base);
|
||||||
|
if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
|
||||||
|
ichx_priv.outlvl_cache[reg_nr] = data;
|
||||||
|
|
||||||
|
tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
|
||||||
|
ichx_priv.gpio_base);
|
||||||
if (verify && data != tmp)
|
if (verify && data != tmp)
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
|
|
||||||
|
@ -123,7 +147,11 @@ static int ichx_read_bit(int reg, unsigned nr)
|
||||||
|
|
||||||
spin_lock_irqsave(&ichx_priv.lock, flags);
|
spin_lock_irqsave(&ichx_priv.lock, flags);
|
||||||
|
|
||||||
data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
|
data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],
|
||||||
|
ichx_priv.gpio_base);
|
||||||
|
|
||||||
|
if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
|
||||||
|
data = ichx_priv.outlvl_cache[reg_nr] | data;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
||||||
|
|
||||||
|
@ -151,7 +179,7 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||||
int val)
|
int val)
|
||||||
{
|
{
|
||||||
/* Disable blink hardware which is available for GPIOs from 0 to 31. */
|
/* Disable blink hardware which is available for GPIOs from 0 to 31. */
|
||||||
if (nr < 32)
|
if (nr < 32 && ichx_priv.desc->have_blink)
|
||||||
ichx_write_bit(GPO_BLINK, nr, 0, 0);
|
ichx_write_bit(GPO_BLINK, nr, 0, 0);
|
||||||
|
|
||||||
/* Set GPIO output value. */
|
/* Set GPIO output value. */
|
||||||
|
@ -266,6 +294,7 @@ static struct ichx_desc ich6_desc = {
|
||||||
.uses_gpe0 = true,
|
.uses_gpe0 = true,
|
||||||
|
|
||||||
.ngpio = 50,
|
.ngpio = 50,
|
||||||
|
.have_blink = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Intel 3100 */
|
/* Intel 3100 */
|
||||||
|
@ -290,24 +319,38 @@ static struct ichx_desc i3100_desc = {
|
||||||
/* ICH7 and ICH8-based */
|
/* ICH7 and ICH8-based */
|
||||||
static struct ichx_desc ich7_desc = {
|
static struct ichx_desc ich7_desc = {
|
||||||
.ngpio = 50,
|
.ngpio = 50,
|
||||||
|
.have_blink = true,
|
||||||
|
.regs = ichx_regs,
|
||||||
|
.reglen = ichx_reglen,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ICH9-based */
|
/* ICH9-based */
|
||||||
static struct ichx_desc ich9_desc = {
|
static struct ichx_desc ich9_desc = {
|
||||||
.ngpio = 61,
|
.ngpio = 61,
|
||||||
|
.have_blink = true,
|
||||||
|
.regs = ichx_regs,
|
||||||
|
.reglen = ichx_reglen,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
|
/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
|
||||||
static struct ichx_desc ich10_cons_desc = {
|
static struct ichx_desc ich10_cons_desc = {
|
||||||
.ngpio = 61,
|
.ngpio = 61,
|
||||||
|
.have_blink = true,
|
||||||
|
.regs = ichx_regs,
|
||||||
|
.reglen = ichx_reglen,
|
||||||
};
|
};
|
||||||
static struct ichx_desc ich10_corp_desc = {
|
static struct ichx_desc ich10_corp_desc = {
|
||||||
.ngpio = 72,
|
.ngpio = 72,
|
||||||
|
.have_blink = true,
|
||||||
|
.regs = ichx_regs,
|
||||||
|
.reglen = ichx_reglen,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Intel 5 series, 6 series, 3400 series, and C200 series */
|
/* Intel 5 series, 6 series, 3400 series, and C200 series */
|
||||||
static struct ichx_desc intel5_desc = {
|
static struct ichx_desc intel5_desc = {
|
||||||
.ngpio = 76,
|
.ngpio = 76,
|
||||||
|
.regs = ichx_regs,
|
||||||
|
.reglen = ichx_reglen,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ichx_gpio_request_regions(struct resource *res_base,
|
static int ichx_gpio_request_regions(struct resource *res_base,
|
||||||
|
@ -318,11 +361,12 @@ static int ichx_gpio_request_regions(struct resource *res_base,
|
||||||
if (!res_base || !res_base->start || !res_base->end)
|
if (!res_base || !res_base->start || !res_base->end)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
|
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
|
||||||
if (!(use_gpio & (1 << i)))
|
if (!(use_gpio & (1 << i)))
|
||||||
continue;
|
continue;
|
||||||
if (!request_region(res_base->start + ichx_regs[0][i],
|
if (!request_region(
|
||||||
ichx_reglen[i], name))
|
res_base->start + ichx_priv.desc->regs[0][i],
|
||||||
|
ichx_priv.desc->reglen[i], name))
|
||||||
goto request_err;
|
goto request_err;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -332,8 +376,8 @@ request_err:
|
||||||
for (i--; i >= 0; i--) {
|
for (i--; i >= 0; i--) {
|
||||||
if (!(use_gpio & (1 << i)))
|
if (!(use_gpio & (1 << i)))
|
||||||
continue;
|
continue;
|
||||||
release_region(res_base->start + ichx_regs[0][i],
|
release_region(res_base->start + ichx_priv.desc->regs[0][i],
|
||||||
ichx_reglen[i]);
|
ichx_priv.desc->reglen[i]);
|
||||||
}
|
}
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -342,11 +386,11 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) {
|
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
|
||||||
if (!(use_gpio & (1 << i)))
|
if (!(use_gpio & (1 << i)))
|
||||||
continue;
|
continue;
|
||||||
release_region(res_base->start + ichx_regs[0][i],
|
release_region(res_base->start + ichx_priv.desc->regs[0][i],
|
||||||
ichx_reglen[i]);
|
ichx_priv.desc->reglen[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Moorestown platform Langwell chip GPIO driver
|
* Intel MID GPIO driver
|
||||||
*
|
*
|
||||||
* Copyright (c) 2008, 2009, 2013, Intel Corporation.
|
* Copyright (c) 2008-2014 Intel Corporation.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -11,10 +11,6 @@
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Supports:
|
/* Supports:
|
||||||
|
@ -235,23 +231,23 @@ static void intel_mid_irq_mask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int intel_mid_irq_startup(struct irq_data *d)
|
static int intel_mid_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d)))
|
if (gpio_lock_as_irq(&priv->chip, irqd_to_hwirq(d))) {
|
||||||
dev_err(priv->chip.dev,
|
dev_err(priv->chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
irqd_to_hwirq(d));
|
irqd_to_hwirq(d));
|
||||||
intel_mid_irq_unmask(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_mid_irq_shutdown(struct irq_data *d)
|
static void intel_mid_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
struct intel_mid_gpio *priv = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
intel_mid_irq_mask(d);
|
|
||||||
gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
|
gpio_unlock_as_irq(&priv->chip, irqd_to_hwirq(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,8 +256,8 @@ static struct irq_chip intel_mid_irqchip = {
|
||||||
.irq_mask = intel_mid_irq_mask,
|
.irq_mask = intel_mid_irq_mask,
|
||||||
.irq_unmask = intel_mid_irq_unmask,
|
.irq_unmask = intel_mid_irq_unmask,
|
||||||
.irq_set_type = intel_mid_irq_type,
|
.irq_set_type = intel_mid_irq_type,
|
||||||
.irq_startup = intel_mid_irq_startup,
|
.irq_request_resources = intel_mid_irq_reqres,
|
||||||
.irq_shutdown = intel_mid_irq_shutdown,
|
.irq_release_resources = intel_mid_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct intel_mid_gpio_ddata gpio_lincroft = {
|
static const struct intel_mid_gpio_ddata gpio_lincroft = {
|
||||||
|
|
|
@ -111,6 +111,8 @@ static int iop3xx_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
base = devm_ioremap_resource(&pdev->dev, res);
|
base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(base))
|
||||||
|
return PTR_ERR(base);
|
||||||
|
|
||||||
return gpiochip_add(&iop3xx_chip);
|
return gpiochip_add(&iop3xx_chip);
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,7 +188,7 @@ static int lp_irq_type(struct irq_data *d, unsigned type)
|
||||||
static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
|
static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
{
|
{
|
||||||
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
|
unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
|
||||||
return inl(reg) & IN_LVL_BIT;
|
return !!(inl(reg) & IN_LVL_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
@ -301,23 +301,23 @@ static void lp_irq_disable(struct irq_data *d)
|
||||||
spin_unlock_irqrestore(&lg->lock, flags);
|
spin_unlock_irqrestore(&lg->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int lp_irq_startup(struct irq_data *d)
|
static int lp_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d)))
|
if (gpio_lock_as_irq(&lg->chip, irqd_to_hwirq(d))) {
|
||||||
dev_err(lg->chip.dev,
|
dev_err(lg->chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
irqd_to_hwirq(d));
|
irqd_to_hwirq(d));
|
||||||
lp_irq_enable(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lp_irq_shutdown(struct irq_data *d)
|
static void lp_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
struct lp_gpio *lg = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
lp_irq_disable(d);
|
|
||||||
gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
|
gpio_unlock_as_irq(&lg->chip, irqd_to_hwirq(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,8 +328,8 @@ static struct irq_chip lp_irqchip = {
|
||||||
.irq_enable = lp_irq_enable,
|
.irq_enable = lp_irq_enable,
|
||||||
.irq_disable = lp_irq_disable,
|
.irq_disable = lp_irq_disable,
|
||||||
.irq_set_type = lp_irq_type,
|
.irq_set_type = lp_irq_type,
|
||||||
.irq_startup = lp_irq_startup,
|
.irq_request_resources = lp_irq_reqres,
|
||||||
.irq_shutdown = lp_irq_shutdown,
|
.irq_release_resources = lp_irq_relres,
|
||||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -622,6 +622,13 @@ static int max732x_probe(struct i2c_client *client,
|
||||||
goto out_failed;
|
goto out_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nr_port > 8 && !chip->client_dummy) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Failed to allocate second group I2C device\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto out_failed;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_init(&chip->lock);
|
mutex_init(&chip->lock);
|
||||||
|
|
||||||
max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
|
max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]);
|
||||||
|
@ -647,6 +654,8 @@ static int max732x_probe(struct i2c_client *client,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_failed:
|
out_failed:
|
||||||
|
if (chip->client_dummy)
|
||||||
|
i2c_unregister_device(chip->client_dummy);
|
||||||
max732x_irq_teardown(chip);
|
max732x_irq_teardown(chip);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
|
||||||
|
|
||||||
tx[0] = mcp->addr | 0x01;
|
tx[0] = mcp->addr | 0x01;
|
||||||
tx[1] = reg;
|
tx[1] = reg;
|
||||||
status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
|
status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
|
||||||
return (status < 0) ? status : rx[0];
|
return (status < 0) ? status : rx[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
|
||||||
tx[0] = mcp->addr;
|
tx[0] = mcp->addr;
|
||||||
tx[1] = reg;
|
tx[1] = reg;
|
||||||
tx[2] = val;
|
tx[2] = val;
|
||||||
return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
|
return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -193,13 +193,13 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
|
||||||
u8 tx[2], *tmp;
|
u8 tx[2], *tmp;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if ((n + reg) > sizeof mcp->cache)
|
if ((n + reg) > sizeof(mcp->cache))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tx[0] = mcp->addr | 0x01;
|
tx[0] = mcp->addr | 0x01;
|
||||||
tx[1] = reg;
|
tx[1] = reg;
|
||||||
|
|
||||||
tmp = (u8 *)vals;
|
tmp = (u8 *)vals;
|
||||||
status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n);
|
status = spi_write_then_read(mcp->data, tx, sizeof(tx), tmp, n);
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
while (n--)
|
while (n--)
|
||||||
vals[n] = tmp[n]; /* expand to 16bit */
|
vals[n] = tmp[n]; /* expand to 16bit */
|
||||||
|
@ -214,7 +214,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
|
||||||
|
|
||||||
tx[0] = mcp->addr | 0x01;
|
tx[0] = mcp->addr | 0x01;
|
||||||
tx[1] = reg << 1;
|
tx[1] = reg << 1;
|
||||||
status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
|
status = spi_write_then_read(mcp->data, tx, sizeof(tx), rx, sizeof(rx));
|
||||||
return (status < 0) ? status : (rx[0] | (rx[1] << 8));
|
return (status < 0) ? status : (rx[0] | (rx[1] << 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
|
||||||
tx[1] = reg << 1;
|
tx[1] = reg << 1;
|
||||||
tx[2] = val;
|
tx[2] = val;
|
||||||
tx[3] = val >> 8;
|
tx[3] = val >> 8;
|
||||||
return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
|
return spi_write_then_read(mcp->data, tx, sizeof(tx), NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -235,12 +235,12 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
|
||||||
u8 tx[2];
|
u8 tx[2];
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
if ((n + reg) > sizeof mcp->cache)
|
if ((n + reg) > sizeof(mcp->cache))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
tx[0] = mcp->addr | 0x01;
|
tx[0] = mcp->addr | 0x01;
|
||||||
tx[1] = reg << 1;
|
tx[1] = reg << 1;
|
||||||
|
|
||||||
status = spi_write_then_read(mcp->data, tx, sizeof tx,
|
status = spi_write_then_read(mcp->data, tx, sizeof(tx),
|
||||||
(u8 *)vals, n * 2);
|
(u8 *)vals, n * 2);
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
while (n--)
|
while (n--)
|
||||||
|
@ -440,24 +440,24 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data)
|
||||||
mutex_unlock(&mcp->irq_lock);
|
mutex_unlock(&mcp->irq_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int mcp23s08_irq_startup(struct irq_data *data)
|
static int mcp23s08_irq_reqres(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
|
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&mcp->chip, data->hwirq))
|
if (gpio_lock_as_irq(&mcp->chip, data->hwirq)) {
|
||||||
dev_err(mcp->chip.dev,
|
dev_err(mcp->chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ usage\n",
|
"unable to lock HW IRQ %lu for IRQ usage\n",
|
||||||
data->hwirq);
|
data->hwirq);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
mcp23s08_irq_unmask(data);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mcp23s08_irq_shutdown(struct irq_data *data)
|
static void mcp23s08_irq_relres(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
|
struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
|
||||||
|
|
||||||
mcp23s08_irq_mask(data);
|
|
||||||
gpio_unlock_as_irq(&mcp->chip, data->hwirq);
|
gpio_unlock_as_irq(&mcp->chip, data->hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,8 +468,8 @@ static struct irq_chip mcp23s08_irq_chip = {
|
||||||
.irq_set_type = mcp23s08_irq_set_type,
|
.irq_set_type = mcp23s08_irq_set_type,
|
||||||
.irq_bus_lock = mcp23s08_irq_bus_lock,
|
.irq_bus_lock = mcp23s08_irq_bus_lock,
|
||||||
.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
|
.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
|
||||||
.irq_startup = mcp23s08_irq_startup,
|
.irq_request_resources = mcp23s08_irq_reqres,
|
||||||
.irq_shutdown = mcp23s08_irq_shutdown,
|
.irq_release_resources = mcp23s08_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
|
static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
|
||||||
|
@ -567,7 +567,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
|
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
|
||||||
(mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
|
(mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
|
||||||
/* NOTE: ignoring the irq-related registers */
|
/* NOTE: ignoring the irq-related registers */
|
||||||
seq_printf(s, "\n");
|
seq_puts(s, "\n");
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
mutex_unlock(&mcp->lock);
|
mutex_unlock(&mcp->lock);
|
||||||
|
@ -789,7 +789,7 @@ static int mcp230xx_probe(struct i2c_client *client,
|
||||||
pullups = pdata->chip[0].pullups;
|
pullups = pdata->chip[0].pullups;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
|
mcp = kzalloc(sizeof(*mcp), GFP_KERNEL);
|
||||||
if (!mcp)
|
if (!mcp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -925,7 +925,7 @@ static int mcp23s08_probe(struct spi_device *spi)
|
||||||
base = pdata->base;
|
base = pdata->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08),
|
data = kzalloc(sizeof(*data) + chips * sizeof(struct mcp23s08),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -48,6 +48,31 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||||
pinctrl_free_gpio(offset);
|
pinctrl_free_gpio(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
||||||
|
void __iomem *ioaddr = gc->base + GPIO_DATA_OUT;
|
||||||
|
u32 reg = readl(ioaddr);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
reg = reg | BIT(offset);
|
||||||
|
else
|
||||||
|
reg = reg & ~BIT(offset);
|
||||||
|
|
||||||
|
writel(reg, ioaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
||||||
|
u32 ret = readl(gc->base + GPIO_PIN_DIRECTION);
|
||||||
|
|
||||||
|
if (ret & BIT(offset))
|
||||||
|
return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset));
|
||||||
|
else
|
||||||
|
return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset));
|
||||||
|
}
|
||||||
|
|
||||||
static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
{
|
{
|
||||||
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
||||||
|
@ -63,36 +88,11 @@ static int moxart_gpio_direction_output(struct gpio_chip *chip,
|
||||||
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
||||||
void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
|
void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
|
||||||
|
|
||||||
|
moxart_gpio_set(chip, offset, value);
|
||||||
writel(readl(ioaddr) | BIT(offset), ioaddr);
|
writel(readl(ioaddr) | BIT(offset), ioaddr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
|
||||||
{
|
|
||||||
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
|
||||||
void __iomem *ioaddr = gc->base + GPIO_DATA_OUT;
|
|
||||||
u32 reg = readl(ioaddr);
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
reg = reg | BIT(offset);
|
|
||||||
else
|
|
||||||
reg = reg & ~BIT(offset);
|
|
||||||
|
|
||||||
|
|
||||||
writel(reg, ioaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
|
|
||||||
u32 ret = readl(gc->base + GPIO_PIN_DIRECTION);
|
|
||||||
|
|
||||||
if (ret & BIT(offset))
|
|
||||||
return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset));
|
|
||||||
else
|
|
||||||
return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct gpio_chip moxart_template_chip = {
|
static struct gpio_chip moxart_template_chip = {
|
||||||
.label = "moxart-gpio",
|
.label = "moxart-gpio",
|
||||||
.request = moxart_gpio_request,
|
.request = moxart_gpio_request,
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
#include <linux/irqchip/chained_irq.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPIO unit register offsets.
|
* GPIO unit register offsets.
|
||||||
|
@ -438,12 +439,15 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq);
|
struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq);
|
||||||
|
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||||
u32 cause, type;
|
u32 cause, type;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mvchip == NULL)
|
if (mvchip == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
chained_irq_enter(chip, desc);
|
||||||
|
|
||||||
cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
|
cause = readl_relaxed(mvebu_gpioreg_data_in(mvchip)) &
|
||||||
readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
|
readl_relaxed(mvebu_gpioreg_level_mask(mvchip));
|
||||||
cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
|
cause |= readl_relaxed(mvebu_gpioreg_edge_cause(mvchip)) &
|
||||||
|
@ -466,8 +470,11 @@ static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
polarity ^= 1 << i;
|
polarity ^= 1 << i;
|
||||||
writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
|
writel_relaxed(polarity, mvebu_gpioreg_in_pol(mvchip));
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_handle_irq(irq);
|
generic_handle_irq(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chained_irq_exit(chip, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
|
|
@ -214,7 +214,8 @@ static void __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||||
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
|
ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
|
||||||
ct->regs.mask = PINCTRL_IRQEN(port);
|
ct->regs.mask = PINCTRL_IRQEN(port);
|
||||||
|
|
||||||
irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0);
|
irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
|
||||||
|
IRQ_NOREQUEST, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||||
|
|
|
@ -1214,24 +1214,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* Static mapping, never released */
|
/* Static mapping, never released */
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (unlikely(!res)) {
|
bank->base = devm_ioremap_resource(dev, res);
|
||||||
dev_err(dev, "Invalid mem resource\n");
|
if (IS_ERR(bank->base)) {
|
||||||
irq_domain_remove(bank->domain);
|
irq_domain_remove(bank->domain);
|
||||||
return -ENODEV;
|
return PTR_ERR(bank->base);
|
||||||
}
|
|
||||||
|
|
||||||
if (!devm_request_mem_region(dev, res->start, resource_size(res),
|
|
||||||
pdev->name)) {
|
|
||||||
dev_err(dev, "Region already claimed\n");
|
|
||||||
irq_domain_remove(bank->domain);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bank->base = devm_ioremap(dev, res->start, resource_size(res));
|
|
||||||
if (!bank->base) {
|
|
||||||
dev_err(dev, "Could not ioremap\n");
|
|
||||||
irq_domain_remove(bank->domain);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, bank);
|
platform_set_drvdata(pdev, bank);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* PCA953x 4/8/16 bit I/O ports
|
* PCA953x 4/8/16/24/40 bit I/O ports
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
|
* Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
|
||||||
* Copyright (C) 2007 Marvell International Ltd.
|
* Copyright (C) 2007 Marvell International Ltd.
|
||||||
|
@ -59,6 +59,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||||
{ "pca9557", 8 | PCA953X_TYPE, },
|
{ "pca9557", 8 | PCA953X_TYPE, },
|
||||||
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
|
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
|
||||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||||
|
{ "pca9698", 40 | PCA953X_TYPE, },
|
||||||
|
|
||||||
{ "max7310", 8 | PCA953X_TYPE, },
|
{ "max7310", 8 | PCA953X_TYPE, },
|
||||||
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
|
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
|
||||||
|
@ -68,6 +69,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||||
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
|
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
|
||||||
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
||||||
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
|
{ "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
|
||||||
|
{ "xra1202", 8 | PCA953X_TYPE },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
||||||
|
@ -625,11 +627,12 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
|
||||||
const __be32 *val;
|
const __be32 *val;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
*gpio_base = -1;
|
||||||
|
|
||||||
node = client->dev.of_node;
|
node = client->dev.of_node;
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
*gpio_base = -1;
|
|
||||||
val = of_get_property(node, "linux,gpio-base", &size);
|
val = of_get_property(node, "linux,gpio-base", &size);
|
||||||
WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
|
WARN(val, "%s: device-tree property 'linux,gpio-base' is deprecated!", __func__);
|
||||||
if (val) {
|
if (val) {
|
||||||
|
@ -812,6 +815,7 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||||
{ .compatible = "nxp,pca9557", },
|
{ .compatible = "nxp,pca9557", },
|
||||||
{ .compatible = "nxp,pca9574", },
|
{ .compatible = "nxp,pca9574", },
|
||||||
{ .compatible = "nxp,pca9575", },
|
{ .compatible = "nxp,pca9575", },
|
||||||
|
{ .compatible = "nxp,pca9698", },
|
||||||
|
|
||||||
{ .compatible = "maxim,max7310", },
|
{ .compatible = "maxim,max7310", },
|
||||||
{ .compatible = "maxim,max7312", },
|
{ .compatible = "maxim,max7312", },
|
||||||
|
@ -822,6 +826,8 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||||
{ .compatible = "ti,tca6408", },
|
{ .compatible = "ti,tca6408", },
|
||||||
{ .compatible = "ti,tca6416", },
|
{ .compatible = "ti,tca6416", },
|
||||||
{ .compatible = "ti,tca6424", },
|
{ .compatible = "ti,tca6424", },
|
||||||
|
|
||||||
|
{ .compatible = "exar,xra1202", },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -138,9 +138,6 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&chip->spinlock, flags);
|
spin_lock_irqsave(&chip->spinlock, flags);
|
||||||
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
|
||||||
pm |= (1 << nr);
|
|
||||||
iowrite32(pm, &chip->reg->pm);
|
|
||||||
|
|
||||||
reg_val = ioread32(&chip->reg->po);
|
reg_val = ioread32(&chip->reg->po);
|
||||||
if (val)
|
if (val)
|
||||||
|
@ -148,6 +145,11 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
||||||
else
|
else
|
||||||
reg_val &= ~(1 << nr);
|
reg_val &= ~(1 << nr);
|
||||||
iowrite32(reg_val, &chip->reg->po);
|
iowrite32(reg_val, &chip->reg->po);
|
||||||
|
|
||||||
|
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
||||||
|
pm |= (1 << nr);
|
||||||
|
iowrite32(pm, &chip->reg->pm);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
@ -53,7 +52,6 @@ struct pl061_gpio {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct irq_domain *domain;
|
|
||||||
struct gpio_chip gc;
|
struct gpio_chip gc;
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@ -137,19 +135,14 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
|
||||||
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
|
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
|
|
||||||
{
|
|
||||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
|
||||||
|
|
||||||
return irq_create_mapping(chip->domain, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||||
{
|
{
|
||||||
struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
|
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
int offset = irqd_to_hwirq(d);
|
int offset = irqd_to_hwirq(d);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 gpiois, gpioibe, gpioiev;
|
u8 gpiois, gpioibe, gpioiev;
|
||||||
|
u8 bit = BIT(offset);
|
||||||
|
|
||||||
if (offset < 0 || offset >= PL061_GPIO_NR)
|
if (offset < 0 || offset >= PL061_GPIO_NR)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -157,30 +150,31 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||||
spin_lock_irqsave(&chip->lock, flags);
|
spin_lock_irqsave(&chip->lock, flags);
|
||||||
|
|
||||||
gpioiev = readb(chip->base + GPIOIEV);
|
gpioiev = readb(chip->base + GPIOIEV);
|
||||||
|
|
||||||
gpiois = readb(chip->base + GPIOIS);
|
gpiois = readb(chip->base + GPIOIS);
|
||||||
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
|
||||||
gpiois |= 1 << offset;
|
|
||||||
if (trigger & IRQ_TYPE_LEVEL_HIGH)
|
|
||||||
gpioiev |= 1 << offset;
|
|
||||||
else
|
|
||||||
gpioiev &= ~(1 << offset);
|
|
||||||
} else
|
|
||||||
gpiois &= ~(1 << offset);
|
|
||||||
writeb(gpiois, chip->base + GPIOIS);
|
|
||||||
|
|
||||||
gpioibe = readb(chip->base + GPIOIBE);
|
gpioibe = readb(chip->base + GPIOIBE);
|
||||||
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
|
||||||
gpioibe |= 1 << offset;
|
|
||||||
else {
|
|
||||||
gpioibe &= ~(1 << offset);
|
|
||||||
if (trigger & IRQ_TYPE_EDGE_RISING)
|
|
||||||
gpioiev |= 1 << offset;
|
|
||||||
else if (trigger & IRQ_TYPE_EDGE_FALLING)
|
|
||||||
gpioiev &= ~(1 << offset);
|
|
||||||
}
|
|
||||||
writeb(gpioibe, chip->base + GPIOIBE);
|
|
||||||
|
|
||||||
|
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
||||||
|
gpiois |= bit;
|
||||||
|
if (trigger & IRQ_TYPE_LEVEL_HIGH)
|
||||||
|
gpioiev |= bit;
|
||||||
|
else
|
||||||
|
gpioiev &= ~bit;
|
||||||
|
} else
|
||||||
|
gpiois &= ~bit;
|
||||||
|
|
||||||
|
if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
||||||
|
/* Setting this makes GPIOEV be ignored */
|
||||||
|
gpioibe |= bit;
|
||||||
|
else {
|
||||||
|
gpioibe &= ~bit;
|
||||||
|
if (trigger & IRQ_TYPE_EDGE_RISING)
|
||||||
|
gpioiev |= bit;
|
||||||
|
else if (trigger & IRQ_TYPE_EDGE_FALLING)
|
||||||
|
gpioiev &= ~bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeb(gpiois, chip->base + GPIOIS);
|
||||||
|
writeb(gpioibe, chip->base + GPIOIBE);
|
||||||
writeb(gpioiev, chip->base + GPIOIEV);
|
writeb(gpioiev, chip->base + GPIOIEV);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&chip->lock, flags);
|
spin_unlock_irqrestore(&chip->lock, flags);
|
||||||
|
@ -192,7 +186,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
unsigned long pending;
|
unsigned long pending;
|
||||||
int offset;
|
int offset;
|
||||||
struct pl061_gpio *chip = irq_desc_get_handler_data(desc);
|
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||||
|
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||||
|
|
||||||
chained_irq_enter(irqchip, desc);
|
chained_irq_enter(irqchip, desc);
|
||||||
|
@ -201,7 +196,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
writeb(pending, chip->base + GPIOIC);
|
writeb(pending, chip->base + GPIOIC);
|
||||||
if (pending) {
|
if (pending) {
|
||||||
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
|
for_each_set_bit(offset, &pending, PL061_GPIO_NR)
|
||||||
generic_handle_irq(pl061_to_irq(&chip->gc, offset));
|
generic_handle_irq(irq_find_mapping(gc->irqdomain,
|
||||||
|
offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
chained_irq_exit(irqchip, desc);
|
chained_irq_exit(irqchip, desc);
|
||||||
|
@ -209,7 +205,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
|
|
||||||
static void pl061_irq_mask(struct irq_data *d)
|
static void pl061_irq_mask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct pl061_gpio *chip = irq_data_get_irq_chip_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 = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||||
u8 gpioie;
|
u8 gpioie;
|
||||||
|
|
||||||
|
@ -221,7 +218,8 @@ static void pl061_irq_mask(struct irq_data *d)
|
||||||
|
|
||||||
static void pl061_irq_unmask(struct irq_data *d)
|
static void pl061_irq_unmask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct pl061_gpio *chip = irq_data_get_irq_chip_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 = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
|
||||||
u8 gpioie;
|
u8 gpioie;
|
||||||
|
|
||||||
|
@ -232,30 +230,12 @@ static void pl061_irq_unmask(struct irq_data *d)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip pl061_irqchip = {
|
static struct irq_chip pl061_irqchip = {
|
||||||
.name = "pl061 gpio",
|
.name = "pl061",
|
||||||
.irq_mask = pl061_irq_mask,
|
.irq_mask = pl061_irq_mask,
|
||||||
.irq_unmask = pl061_irq_unmask,
|
.irq_unmask = pl061_irq_unmask,
|
||||||
.irq_set_type = pl061_irq_type,
|
.irq_set_type = pl061_irq_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pl061_irq_map(struct irq_domain *d, unsigned int irq,
|
|
||||||
irq_hw_number_t hwirq)
|
|
||||||
{
|
|
||||||
struct pl061_gpio *chip = d->host_data;
|
|
||||||
|
|
||||||
irq_set_chip_and_handler_name(irq, &pl061_irqchip, handle_simple_irq,
|
|
||||||
"pl061");
|
|
||||||
irq_set_chip_data(irq, chip);
|
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_NONE);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct irq_domain_ops pl061_domain_ops = {
|
|
||||||
.map = pl061_irq_map,
|
|
||||||
.xlate = irq_domain_xlate_twocell,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
{
|
{
|
||||||
struct device *dev = &adev->dev;
|
struct device *dev = &adev->dev;
|
||||||
|
@ -270,21 +250,18 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
chip->gc.base = pdata->gpio_base;
|
chip->gc.base = pdata->gpio_base;
|
||||||
irq_base = pdata->irq_base;
|
irq_base = pdata->irq_base;
|
||||||
if (irq_base <= 0)
|
if (irq_base <= 0) {
|
||||||
|
dev_err(&adev->dev, "invalid IRQ base in pdata\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
chip->gc.base = -1;
|
chip->gc.base = -1;
|
||||||
irq_base = 0;
|
irq_base = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!devm_request_mem_region(dev, adev->res.start,
|
chip->base = devm_ioremap_resource(dev, &adev->res);
|
||||||
resource_size(&adev->res), "pl061"))
|
if (IS_ERR(chip->base))
|
||||||
return -EBUSY;
|
return PTR_ERR(chip->base);
|
||||||
|
|
||||||
chip->base = devm_ioremap(dev, adev->res.start,
|
|
||||||
resource_size(&adev->res));
|
|
||||||
if (!chip->base)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
spin_lock_init(&chip->lock);
|
spin_lock_init(&chip->lock);
|
||||||
|
|
||||||
|
@ -294,7 +271,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
chip->gc.direction_output = pl061_direction_output;
|
chip->gc.direction_output = pl061_direction_output;
|
||||||
chip->gc.get = pl061_get_value;
|
chip->gc.get = pl061_get_value;
|
||||||
chip->gc.set = pl061_set_value;
|
chip->gc.set = pl061_set_value;
|
||||||
chip->gc.to_irq = pl061_to_irq;
|
|
||||||
chip->gc.ngpio = PL061_GPIO_NR;
|
chip->gc.ngpio = PL061_GPIO_NR;
|
||||||
chip->gc.label = dev_name(dev);
|
chip->gc.label = dev_name(dev);
|
||||||
chip->gc.dev = dev;
|
chip->gc.dev = dev;
|
||||||
|
@ -309,16 +285,20 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
*/
|
*/
|
||||||
writeb(0, chip->base + GPIOIE); /* disable irqs */
|
writeb(0, chip->base + GPIOIE); /* disable irqs */
|
||||||
irq = adev->irq[0];
|
irq = adev->irq[0];
|
||||||
if (irq < 0)
|
if (irq < 0) {
|
||||||
|
dev_err(&adev->dev, "invalid IRQ\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
irq_set_chained_handler(irq, pl061_irq_handler);
|
ret = gpiochip_irqchip_add(&chip->gc, &pl061_irqchip,
|
||||||
irq_set_handler_data(irq, chip);
|
irq_base, handle_simple_irq,
|
||||||
|
IRQ_TYPE_NONE);
|
||||||
chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
|
if (ret) {
|
||||||
irq_base, &pl061_domain_ops, chip);
|
dev_info(&adev->dev, "could not add irqchip\n");
|
||||||
if (!chip->domain)
|
return ret;
|
||||||
return -ENODEV;
|
}
|
||||||
|
gpiochip_set_chained_irqchip(&chip->gc, &pl061_irqchip,
|
||||||
|
irq, pl061_irq_handler);
|
||||||
|
|
||||||
for (i = 0; i < PL061_GPIO_NR; i++) {
|
for (i = 0; i < PL061_GPIO_NR; i++) {
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
|
@ -331,6 +311,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
}
|
}
|
||||||
|
|
||||||
amba_set_drvdata(adev, chip);
|
amba_set_drvdata(adev, chip);
|
||||||
|
dev_info(&adev->dev, "PL061 GPIO chip @%pa registered\n",
|
||||||
|
&adev->res.start);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||||
{
|
{
|
||||||
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
|
struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
|
||||||
|
|
||||||
if ((offset >= 0) && (offset < 8))
|
if (offset < RC5T583_MAX_GPIO)
|
||||||
return rc5t583_gpio->rc5t583->irq_base +
|
return rc5t583_gpio->rc5t583->irq_base +
|
||||||
RC5T583_IRQ_GPIO0 + offset;
|
RC5T583_IRQ_GPIO0 + offset;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -356,12 +356,13 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
struct resource *io, *irq;
|
struct resource *io, *irq;
|
||||||
struct gpio_chip *gpio_chip;
|
struct gpio_chip *gpio_chip;
|
||||||
struct irq_chip *irq_chip;
|
struct irq_chip *irq_chip;
|
||||||
const char *name = dev_name(&pdev->dev);
|
struct device *dev = &pdev->dev;
|
||||||
|
const char *name = dev_name(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
|
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
dev_err(dev, "failed to allocate driver data\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
@ -380,15 +381,14 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
|
||||||
if (!io || !irq) {
|
if (!io || !irq) {
|
||||||
dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
|
dev_err(dev, "missing IRQ or IOMEM\n");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->base = devm_ioremap_nocache(&pdev->dev, io->start,
|
p->base = devm_ioremap_nocache(dev, io->start, resource_size(io));
|
||||||
resource_size(io));
|
|
||||||
if (!p->base) {
|
if (!p->base) {
|
||||||
dev_err(&pdev->dev, "failed to remap I/O memory\n");
|
dev_err(dev, "failed to remap I/O memory\n");
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
@ -402,7 +402,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
gpio_chip->set = gpio_rcar_set;
|
gpio_chip->set = gpio_rcar_set;
|
||||||
gpio_chip->to_irq = gpio_rcar_to_irq;
|
gpio_chip->to_irq = gpio_rcar_to_irq;
|
||||||
gpio_chip->label = name;
|
gpio_chip->label = name;
|
||||||
gpio_chip->dev = &pdev->dev;
|
gpio_chip->dev = dev;
|
||||||
gpio_chip->owner = THIS_MODULE;
|
gpio_chip->owner = THIS_MODULE;
|
||||||
gpio_chip->base = p->config.gpio_base;
|
gpio_chip->base = p->config.gpio_base;
|
||||||
gpio_chip->ngpio = p->config.number_of_pins;
|
gpio_chip->ngpio = p->config.number_of_pins;
|
||||||
|
@ -421,30 +421,30 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
&gpio_rcar_irq_domain_ops, p);
|
&gpio_rcar_irq_domain_ops, p);
|
||||||
if (!p->irq_domain) {
|
if (!p->irq_domain) {
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
dev_err(&pdev->dev, "cannot initialize irq domain\n");
|
dev_err(dev, "cannot initialize irq domain\n");
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (devm_request_irq(&pdev->dev, irq->start,
|
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
|
||||||
gpio_rcar_irq_handler, IRQF_SHARED, name, p)) {
|
IRQF_SHARED, name, p)) {
|
||||||
dev_err(&pdev->dev, "failed to request IRQ\n");
|
dev_err(dev, "failed to request IRQ\n");
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gpiochip_add(gpio_chip);
|
ret = gpiochip_add(gpio_chip);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to add GPIO controller\n");
|
dev_err(dev, "failed to add GPIO controller\n");
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&pdev->dev, "driving %d GPIOs\n", p->config.number_of_pins);
|
dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
|
||||||
|
|
||||||
/* warn in case of mismatch if irq base is specified */
|
/* warn in case of mismatch if irq base is specified */
|
||||||
if (p->config.irq_base) {
|
if (p->config.irq_base) {
|
||||||
ret = irq_find_mapping(p->irq_domain, 0);
|
ret = irq_find_mapping(p->irq_domain, 0);
|
||||||
if (p->config.irq_base != ret)
|
if (p->config.irq_base != ret)
|
||||||
dev_warn(&pdev->dev, "irq base mismatch (%u/%u)\n",
|
dev_warn(dev, "irq base mismatch (%u/%u)\n",
|
||||||
p->config.irq_base, ret);
|
p->config.irq_base, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
|
||||||
ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
|
ret = gpiochip_add_pin_range(gpio_chip, p->config.pctl_name, 0,
|
||||||
gpio_chip->base, gpio_chip->ngpio);
|
gpio_chip->base, gpio_chip->ngpio);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
dev_warn(&pdev->dev, "failed to add pin range\n");
|
dev_warn(dev, "failed to add pin range\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -379,6 +379,7 @@ static int s5p64x0_gpio_setcfg_rbank(struct samsung_gpio_chip *chip,
|
||||||
case 6:
|
case 6:
|
||||||
shift = ((off + 1) & 7) * 4;
|
shift = ((off + 1) & 7) * 4;
|
||||||
reg -= 4;
|
reg -= 4;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
shift = ((off + 1) & 7) * 4;
|
shift = ((off + 1) & 7) * 4;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
/*
|
||||||
|
* SYSCON GPIO driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
|
||||||
|
#define GPIO_SYSCON_FEAT_IN BIT(0)
|
||||||
|
#define GPIO_SYSCON_FEAT_OUT BIT(1)
|
||||||
|
#define GPIO_SYSCON_FEAT_DIR BIT(2)
|
||||||
|
|
||||||
|
/* SYSCON driver is designed to use 32-bit wide registers */
|
||||||
|
#define SYSCON_REG_SIZE (4)
|
||||||
|
#define SYSCON_REG_BITS (SYSCON_REG_SIZE * 8)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct syscon_gpio_data - Configuration for the device.
|
||||||
|
* compatible: SYSCON driver compatible string.
|
||||||
|
* flags: Set of GPIO_SYSCON_FEAT_ flags:
|
||||||
|
* GPIO_SYSCON_FEAT_IN: GPIOs supports input,
|
||||||
|
* GPIO_SYSCON_FEAT_OUT: GPIOs supports output,
|
||||||
|
* GPIO_SYSCON_FEAT_DIR: GPIOs supports switch direction.
|
||||||
|
* bit_count: Number of bits used as GPIOs.
|
||||||
|
* dat_bit_offset: Offset (in bits) to the first GPIO bit.
|
||||||
|
* dir_bit_offset: Optional offset (in bits) to the first bit to switch
|
||||||
|
* GPIO direction (Used with GPIO_SYSCON_FEAT_DIR flag).
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct syscon_gpio_data {
|
||||||
|
const char *compatible;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int bit_count;
|
||||||
|
unsigned int dat_bit_offset;
|
||||||
|
unsigned int dir_bit_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct syscon_gpio_priv {
|
||||||
|
struct gpio_chip chip;
|
||||||
|
struct regmap *syscon;
|
||||||
|
const struct syscon_gpio_data *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct syscon_gpio_priv *to_syscon_gpio(struct gpio_chip *chip)
|
||||||
|
{
|
||||||
|
return container_of(chip, struct syscon_gpio_priv, chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int syscon_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||||
|
unsigned int val, offs = priv->data->dat_bit_offset + offset;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_read(priv->syscon,
|
||||||
|
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return !!(val & BIT(offs % SYSCON_REG_BITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void syscon_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
|
||||||
|
{
|
||||||
|
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||||
|
unsigned int offs = priv->data->dat_bit_offset + offset;
|
||||||
|
|
||||||
|
regmap_update_bits(priv->syscon,
|
||||||
|
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||||
|
BIT(offs % SYSCON_REG_BITS),
|
||||||
|
val ? BIT(offs % SYSCON_REG_BITS) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int syscon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||||
|
|
||||||
|
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
|
||||||
|
unsigned int offs = priv->data->dir_bit_offset + offset;
|
||||||
|
|
||||||
|
regmap_update_bits(priv->syscon,
|
||||||
|
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||||
|
BIT(offs % SYSCON_REG_BITS), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
|
||||||
|
{
|
||||||
|
struct syscon_gpio_priv *priv = to_syscon_gpio(chip);
|
||||||
|
|
||||||
|
if (priv->data->flags & GPIO_SYSCON_FEAT_DIR) {
|
||||||
|
unsigned int offs = priv->data->dir_bit_offset + offset;
|
||||||
|
|
||||||
|
regmap_update_bits(priv->syscon,
|
||||||
|
(offs / SYSCON_REG_BITS) * SYSCON_REG_SIZE,
|
||||||
|
BIT(offs % SYSCON_REG_BITS),
|
||||||
|
BIT(offs % SYSCON_REG_BITS));
|
||||||
|
}
|
||||||
|
|
||||||
|
syscon_gpio_set(chip, offset, val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct syscon_gpio_data clps711x_mctrl_gpio = {
|
||||||
|
/* ARM CLPS711X SYSFLG1 Bits 8-10 */
|
||||||
|
.compatible = "cirrus,clps711x-syscon1",
|
||||||
|
.flags = GPIO_SYSCON_FEAT_IN,
|
||||||
|
.bit_count = 3,
|
||||||
|
.dat_bit_offset = 0x40 * 8 + 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id syscon_gpio_ids[] = {
|
||||||
|
{
|
||||||
|
.compatible = "cirrus,clps711x-mctrl-gpio",
|
||||||
|
.data = &clps711x_mctrl_gpio,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
|
||||||
|
|
||||||
|
static int syscon_gpio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
|
||||||
|
struct syscon_gpio_priv *priv;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->data = of_id->data;
|
||||||
|
|
||||||
|
priv->syscon =
|
||||||
|
syscon_regmap_lookup_by_compatible(priv->data->compatible);
|
||||||
|
if (IS_ERR(priv->syscon))
|
||||||
|
return PTR_ERR(priv->syscon);
|
||||||
|
|
||||||
|
priv->chip.dev = dev;
|
||||||
|
priv->chip.owner = THIS_MODULE;
|
||||||
|
priv->chip.label = dev_name(dev);
|
||||||
|
priv->chip.base = -1;
|
||||||
|
priv->chip.ngpio = priv->data->bit_count;
|
||||||
|
priv->chip.get = syscon_gpio_get;
|
||||||
|
if (priv->data->flags & GPIO_SYSCON_FEAT_IN)
|
||||||
|
priv->chip.direction_input = syscon_gpio_dir_in;
|
||||||
|
if (priv->data->flags & GPIO_SYSCON_FEAT_OUT) {
|
||||||
|
priv->chip.set = syscon_gpio_set;
|
||||||
|
priv->chip.direction_output = syscon_gpio_dir_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
return gpiochip_add(&priv->chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int syscon_gpio_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct syscon_gpio_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
return gpiochip_remove(&priv->chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver syscon_gpio_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "gpio-syscon",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = syscon_gpio_ids,
|
||||||
|
},
|
||||||
|
.probe = syscon_gpio_probe,
|
||||||
|
.remove = syscon_gpio_remove,
|
||||||
|
};
|
||||||
|
module_platform_driver(syscon_gpio_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
|
||||||
|
MODULE_DESCRIPTION("SYSCON GPIO driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -1,206 +0,0 @@
|
||||||
/*
|
|
||||||
* Texas Instruments TNETV107X GPIO Controller
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010 Texas Instruments
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation version 2.
|
|
||||||
*
|
|
||||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
|
||||||
* kind, whether express or implied; without even the implied warranty
|
|
||||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/platform_data/gpio-davinci.h>
|
|
||||||
|
|
||||||
#include <mach/common.h>
|
|
||||||
#include <mach/tnetv107x.h>
|
|
||||||
|
|
||||||
struct tnetv107x_gpio_regs {
|
|
||||||
u32 idver;
|
|
||||||
u32 data_in[3];
|
|
||||||
u32 data_out[3];
|
|
||||||
u32 direction[3];
|
|
||||||
u32 enable[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define gpio_reg_index(gpio) ((gpio) >> 5)
|
|
||||||
#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
|
|
||||||
|
|
||||||
#define gpio_reg_rmw(reg, mask, val) \
|
|
||||||
__raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg))
|
|
||||||
|
|
||||||
#define gpio_reg_set_bit(reg, gpio) \
|
|
||||||
gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio))
|
|
||||||
|
|
||||||
#define gpio_reg_clear_bit(reg, gpio) \
|
|
||||||
gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0)
|
|
||||||
|
|
||||||
#define gpio_reg_get_bit(reg, gpio) \
|
|
||||||
(__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio))
|
|
||||||
|
|
||||||
#define chip2controller(chip) \
|
|
||||||
container_of(chip, struct davinci_gpio_controller, chip)
|
|
||||||
|
|
||||||
#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
|
|
||||||
|
|
||||||
static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS];
|
|
||||||
|
|
||||||
static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
gpio_reg_set_bit(regs->enable, gpio);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
gpio_reg_clear_bit(regs->enable, gpio);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
gpio_reg_set_bit(regs->direction, gpio);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
|
|
||||||
unsigned offset, int value)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
gpio_reg_set_bit(regs->data_out, gpio);
|
|
||||||
else
|
|
||||||
gpio_reg_clear_bit(regs->data_out, gpio);
|
|
||||||
|
|
||||||
gpio_reg_clear_bit(regs->direction, gpio);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = gpio_reg_get_bit(regs->data_in, gpio);
|
|
||||||
|
|
||||||
return ret ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tnetv107x_gpio_set(struct gpio_chip *chip,
|
|
||||||
unsigned offset, int value)
|
|
||||||
{
|
|
||||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
|
||||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
|
||||||
unsigned gpio = chip->base + offset;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ctlr->lock, flags);
|
|
||||||
|
|
||||||
if (value)
|
|
||||||
gpio_reg_set_bit(regs->data_out, gpio);
|
|
||||||
else
|
|
||||||
gpio_reg_clear_bit(regs->data_out, gpio);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __init tnetv107x_gpio_setup(void)
|
|
||||||
{
|
|
||||||
int i, base;
|
|
||||||
unsigned ngpio;
|
|
||||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
|
||||||
struct tnetv107x_gpio_regs *regs;
|
|
||||||
struct davinci_gpio_controller *ctlr;
|
|
||||||
|
|
||||||
if (soc_info->gpio_type != GPIO_TYPE_TNETV107X)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ngpio = soc_info->gpio_num;
|
|
||||||
if (ngpio == 0) {
|
|
||||||
pr_err("GPIO setup: how many GPIOs?\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WARN_ON(TNETV107X_N_GPIO < ngpio))
|
|
||||||
ngpio = TNETV107X_N_GPIO;
|
|
||||||
|
|
||||||
regs = ioremap(soc_info->gpio_base, SZ_4K);
|
|
||||||
if (WARN_ON(!regs))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
|
|
||||||
ctlr = &chips[i];
|
|
||||||
|
|
||||||
ctlr->chip.label = "tnetv107x";
|
|
||||||
ctlr->chip.can_sleep = false;
|
|
||||||
ctlr->chip.base = base;
|
|
||||||
ctlr->chip.ngpio = ngpio - base;
|
|
||||||
if (ctlr->chip.ngpio > 32)
|
|
||||||
ctlr->chip.ngpio = 32;
|
|
||||||
|
|
||||||
ctlr->chip.request = tnetv107x_gpio_request;
|
|
||||||
ctlr->chip.free = tnetv107x_gpio_free;
|
|
||||||
ctlr->chip.direction_input = tnetv107x_gpio_dir_in;
|
|
||||||
ctlr->chip.get = tnetv107x_gpio_get;
|
|
||||||
ctlr->chip.direction_output = tnetv107x_gpio_dir_out;
|
|
||||||
ctlr->chip.set = tnetv107x_gpio_set;
|
|
||||||
|
|
||||||
spin_lock_init(&ctlr->lock);
|
|
||||||
|
|
||||||
ctlr->regs = regs;
|
|
||||||
ctlr->set_data = ®s->data_out[i];
|
|
||||||
ctlr->clr_data = ®s->data_out[i];
|
|
||||||
ctlr->in_data = ®s->data_in[i];
|
|
||||||
|
|
||||||
gpiochip_add(&ctlr->chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
soc_info->gpio_ctlrs = chips;
|
|
||||||
soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pure_initcall(tnetv107x_gpio_setup);
|
|
|
@ -139,7 +139,6 @@ static u8 cached_leden;
|
||||||
static void twl4030_led_set_value(int led, int value)
|
static void twl4030_led_set_value(int led, int value)
|
||||||
{
|
{
|
||||||
u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
|
u8 mask = LEDEN_LEDAON | LEDEN_LEDAPWM;
|
||||||
int status;
|
|
||||||
|
|
||||||
if (led)
|
if (led)
|
||||||
mask <<= 1;
|
mask <<= 1;
|
||||||
|
@ -148,8 +147,9 @@ static void twl4030_led_set_value(int led, int value)
|
||||||
cached_leden &= ~mask;
|
cached_leden &= ~mask;
|
||||||
else
|
else
|
||||||
cached_leden |= mask;
|
cached_leden |= mask;
|
||||||
status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
|
|
||||||
TWL4030_LED_LEDEN_REG);
|
WARN_ON_ONCE(twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden,
|
||||||
|
TWL4030_LED_LEDEN_REG));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int twl4030_set_gpio_direction(int gpio, int is_input)
|
static int twl4030_set_gpio_direction(int gpio, int is_input)
|
||||||
|
|
|
@ -488,26 +488,26 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
|
||||||
gc->chip_types[0].handler = handle_level_irq;
|
gc->chip_types[0].handler = handle_level_irq;
|
||||||
gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS;
|
gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS;
|
||||||
gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN;
|
gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN;
|
||||||
gc->chip_types[0].chip.irq_startup = gpio_startup_irq,
|
gc->chip_types[0].chip.irq_startup = gpio_startup_irq;
|
||||||
gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit,
|
gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
|
||||||
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit,
|
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
|
||||||
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit,
|
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
|
||||||
gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type,
|
gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type;
|
||||||
gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake,
|
gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake;
|
||||||
gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND,
|
gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
/* edge chip type */
|
/* edge chip type */
|
||||||
gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
|
gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
|
||||||
gc->chip_types[1].handler = handle_edge_irq;
|
gc->chip_types[1].handler = handle_edge_irq;
|
||||||
gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS;
|
gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS;
|
||||||
gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN;
|
gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN;
|
||||||
gc->chip_types[1].chip.irq_startup = gpio_startup_irq,
|
gc->chip_types[1].chip.irq_startup = gpio_startup_irq;
|
||||||
gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit,
|
gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit;
|
||||||
gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit,
|
gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
|
||||||
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit,
|
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
|
||||||
gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type,
|
gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type;
|
||||||
gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake,
|
gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake;
|
||||||
gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND,
|
gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||||
|
|
||||||
/* Setup chained handler for this GPIO bank */
|
/* Setup chained handler for this GPIO bank */
|
||||||
irq_set_handler_data(bank->irq, bank);
|
irq_set_handler_data(bank->irq, bank);
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
/*
|
||||||
|
* GPIO controller in LSI ZEVIO SoCs.
|
||||||
|
*
|
||||||
|
* Author: Fabian Vogt <fabian@ritter-vogt.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Memory layout:
|
||||||
|
* This chip has four gpio sections, each controls 8 GPIOs.
|
||||||
|
* Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10.
|
||||||
|
* Disclaimer: Reverse engineered!
|
||||||
|
* For more information refer to:
|
||||||
|
* http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
|
||||||
|
*
|
||||||
|
* 0x00-0x3F: Section 0
|
||||||
|
* +0x00: Masked interrupt status (read-only)
|
||||||
|
* +0x04: R: Interrupt status W: Reset interrupt status
|
||||||
|
* +0x08: R: Interrupt mask W: Mask interrupt
|
||||||
|
* +0x0C: W: Unmask interrupt (write-only)
|
||||||
|
* +0x10: Direction: I/O=1/0
|
||||||
|
* +0x14: Output
|
||||||
|
* +0x18: Input (read-only)
|
||||||
|
* +0x20: R: Level interrupt W: Set as level interrupt
|
||||||
|
* 0x40-0x7F: Section 1
|
||||||
|
* 0x80-0xBF: Section 2
|
||||||
|
* 0xC0-0xFF: Section 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ZEVIO_GPIO_SECTION_SIZE 0x40
|
||||||
|
|
||||||
|
/* Offsets to various registers */
|
||||||
|
#define ZEVIO_GPIO_INT_MASKED_STATUS 0x00
|
||||||
|
#define ZEVIO_GPIO_INT_STATUS 0x04
|
||||||
|
#define ZEVIO_GPIO_INT_UNMASK 0x08
|
||||||
|
#define ZEVIO_GPIO_INT_MASK 0x0C
|
||||||
|
#define ZEVIO_GPIO_DIRECTION 0x10
|
||||||
|
#define ZEVIO_GPIO_OUTPUT 0x14
|
||||||
|
#define ZEVIO_GPIO_INPUT 0x18
|
||||||
|
#define ZEVIO_GPIO_INT_STICKY 0x20
|
||||||
|
|
||||||
|
#define to_zevio_gpio(chip) container_of(to_of_mm_gpio_chip(chip), \
|
||||||
|
struct zevio_gpio, chip)
|
||||||
|
|
||||||
|
/* Bit number of GPIO in its section */
|
||||||
|
#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
|
||||||
|
|
||||||
|
struct zevio_gpio {
|
||||||
|
spinlock_t lock;
|
||||||
|
struct of_mm_gpio_chip chip;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
|
||||||
|
unsigned port_offset)
|
||||||
|
{
|
||||||
|
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
|
||||||
|
return readl(IOMEM(c->chip.regs + section_offset + port_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
|
||||||
|
unsigned port_offset, u32 val)
|
||||||
|
{
|
||||||
|
unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
|
||||||
|
writel(val, IOMEM(c->chip.regs + section_offset + port_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Functions for struct gpio_chip */
|
||||||
|
static int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
|
||||||
|
{
|
||||||
|
struct zevio_gpio *controller = to_zevio_gpio(chip);
|
||||||
|
|
||||||
|
/* Only reading allowed, so no spinlock needed */
|
||||||
|
u32 val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
|
||||||
|
|
||||||
|
return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
|
||||||
|
{
|
||||||
|
struct zevio_gpio *controller = to_zevio_gpio(chip);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&controller->lock);
|
||||||
|
val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
|
||||||
|
if (value)
|
||||||
|
val |= BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
else
|
||||||
|
val &= ~BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
|
||||||
|
zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
|
||||||
|
spin_unlock(&controller->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
|
||||||
|
{
|
||||||
|
struct zevio_gpio *controller = to_zevio_gpio(chip);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&controller->lock);
|
||||||
|
|
||||||
|
val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
|
||||||
|
val |= BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
|
||||||
|
|
||||||
|
spin_unlock(&controller->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zevio_gpio_direction_output(struct gpio_chip *chip,
|
||||||
|
unsigned pin, int value)
|
||||||
|
{
|
||||||
|
struct zevio_gpio *controller = to_zevio_gpio(chip);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&controller->lock);
|
||||||
|
val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
|
||||||
|
if (value)
|
||||||
|
val |= BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
else
|
||||||
|
val &= ~BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
|
||||||
|
zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
|
||||||
|
val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
|
||||||
|
val &= ~BIT(ZEVIO_GPIO_BIT(pin));
|
||||||
|
zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
|
||||||
|
|
||||||
|
spin_unlock(&controller->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* TODO: Implement IRQs.
|
||||||
|
* Not implemented yet due to weird lockups
|
||||||
|
*/
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gpio_chip zevio_gpio_chip = {
|
||||||
|
.direction_input = zevio_gpio_direction_input,
|
||||||
|
.direction_output = zevio_gpio_direction_output,
|
||||||
|
.set = zevio_gpio_set,
|
||||||
|
.get = zevio_gpio_get,
|
||||||
|
.to_irq = zevio_gpio_to_irq,
|
||||||
|
.base = 0,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.ngpio = 32,
|
||||||
|
.of_gpio_n_cells = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Initialization */
|
||||||
|
static int zevio_gpio_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct zevio_gpio *controller;
|
||||||
|
int status, i;
|
||||||
|
|
||||||
|
controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
|
||||||
|
if (!controller) {
|
||||||
|
dev_err(&pdev->dev, "not enough free memory\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy our reference */
|
||||||
|
controller->chip.gc = zevio_gpio_chip;
|
||||||
|
controller->chip.gc.dev = &pdev->dev;
|
||||||
|
|
||||||
|
status = of_mm_gpiochip_add(pdev->dev.of_node, &(controller->chip));
|
||||||
|
if (status) {
|
||||||
|
dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&controller->lock);
|
||||||
|
|
||||||
|
/* Disable interrupts, they only cause errors */
|
||||||
|
for (i = 0; i < controller->chip.gc.ngpio; i += 8)
|
||||||
|
zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
|
||||||
|
|
||||||
|
dev_dbg(controller->chip.gc.dev, "ZEVIO GPIO controller set up!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct of_device_id zevio_gpio_of_match[] = {
|
||||||
|
{ .compatible = "lsi,zevio-gpio", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, zevio_gpio_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver zevio_gpio_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "gpio-zevio",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(zevio_gpio_of_match),
|
||||||
|
},
|
||||||
|
.probe = zevio_gpio_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(zevio_gpio_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>");
|
||||||
|
MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver");
|
|
@ -16,16 +16,35 @@
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
#include "gpiolib.h"
|
#include "gpiolib.h"
|
||||||
|
|
||||||
struct acpi_gpio_evt_pin {
|
struct acpi_gpio_event {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
acpi_handle *evt_handle;
|
acpi_handle handle;
|
||||||
unsigned int pin;
|
unsigned int pin;
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct acpi_gpio_connection {
|
||||||
|
struct list_head node;
|
||||||
|
struct gpio_desc *desc;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acpi_gpio_chip {
|
||||||
|
/*
|
||||||
|
* ACPICA requires that the first field of the context parameter
|
||||||
|
* passed to acpi_install_address_space_handler() is large enough
|
||||||
|
* to hold struct acpi_connection_info.
|
||||||
|
*/
|
||||||
|
struct acpi_connection_info conn_info;
|
||||||
|
struct list_head conns;
|
||||||
|
struct mutex conn_lock;
|
||||||
|
struct gpio_chip *chip;
|
||||||
|
struct list_head events;
|
||||||
|
};
|
||||||
|
|
||||||
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
||||||
{
|
{
|
||||||
if (!gc->dev)
|
if (!gc->dev)
|
||||||
|
@ -60,35 +79,149 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
||||||
if (pin < 0 || pin > chip->ngpio)
|
if (pin < 0 || pin > chip->ngpio)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
return gpio_to_desc(chip->base + pin);
|
return gpiochip_get_desc(chip, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
|
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
acpi_handle handle = data;
|
struct acpi_gpio_event *event = data;
|
||||||
|
|
||||||
acpi_evaluate_object(handle, NULL, NULL, NULL);
|
acpi_evaluate_object(event->handle, NULL, NULL, NULL);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
|
static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct acpi_gpio_evt_pin *evt_pin = data;
|
struct acpi_gpio_event *event = data;
|
||||||
|
|
||||||
acpi_execute_simple_method(evt_pin->evt_handle, NULL, evt_pin->pin);
|
acpi_execute_simple_method(event->handle, NULL, event->pin);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void acpi_gpio_evt_dh(acpi_handle handle, void *data)
|
static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
|
||||||
{
|
{
|
||||||
/* The address of this function is used as a key. */
|
/* The address of this function is used as a key. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
struct acpi_gpio_chip *acpi_gpio = context;
|
||||||
|
struct gpio_chip *chip = acpi_gpio->chip;
|
||||||
|
struct acpi_resource_gpio *agpio;
|
||||||
|
acpi_handle handle, evt_handle;
|
||||||
|
struct acpi_gpio_event *event;
|
||||||
|
irq_handler_t handler = NULL;
|
||||||
|
struct gpio_desc *desc;
|
||||||
|
unsigned long irqflags;
|
||||||
|
int ret, pin, irq;
|
||||||
|
|
||||||
|
if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
|
||||||
|
return AE_OK;
|
||||||
|
|
||||||
|
agpio = &ares->data.gpio;
|
||||||
|
if (agpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
|
||||||
|
return AE_OK;
|
||||||
|
|
||||||
|
handle = ACPI_HANDLE(chip->dev);
|
||||||
|
pin = agpio->pin_table[0];
|
||||||
|
|
||||||
|
if (pin <= 255) {
|
||||||
|
char ev_name[5];
|
||||||
|
sprintf(ev_name, "_%c%02X",
|
||||||
|
agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
|
||||||
|
pin);
|
||||||
|
if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
|
||||||
|
handler = acpi_gpio_irq_handler;
|
||||||
|
}
|
||||||
|
if (!handler) {
|
||||||
|
if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
|
||||||
|
handler = acpi_gpio_irq_handler_evt;
|
||||||
|
}
|
||||||
|
if (!handler)
|
||||||
|
return AE_BAD_PARAMETER;
|
||||||
|
|
||||||
|
desc = gpiochip_get_desc(chip, pin);
|
||||||
|
if (IS_ERR(desc)) {
|
||||||
|
dev_err(chip->dev, "Failed to get GPIO descriptor\n");
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gpiochip_request_own_desc(desc, "ACPI:Event");
|
||||||
|
if (ret) {
|
||||||
|
dev_err(chip->dev, "Failed to request GPIO\n");
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpiod_direction_input(desc);
|
||||||
|
|
||||||
|
ret = gpiod_lock_as_irq(desc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
|
||||||
|
goto fail_free_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = gpiod_to_irq(desc);
|
||||||
|
if (irq < 0) {
|
||||||
|
dev_err(chip->dev, "Failed to translate GPIO to IRQ\n");
|
||||||
|
goto fail_unlock_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqflags = IRQF_ONESHOT;
|
||||||
|
if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
|
||||||
|
if (agpio->polarity == ACPI_ACTIVE_HIGH)
|
||||||
|
irqflags |= IRQF_TRIGGER_HIGH;
|
||||||
|
else
|
||||||
|
irqflags |= IRQF_TRIGGER_LOW;
|
||||||
|
} else {
|
||||||
|
switch (agpio->polarity) {
|
||||||
|
case ACPI_ACTIVE_HIGH:
|
||||||
|
irqflags |= IRQF_TRIGGER_RISING;
|
||||||
|
break;
|
||||||
|
case ACPI_ACTIVE_LOW:
|
||||||
|
irqflags |= IRQF_TRIGGER_FALLING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
irqflags |= IRQF_TRIGGER_RISING |
|
||||||
|
IRQF_TRIGGER_FALLING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||||
|
if (!event)
|
||||||
|
goto fail_unlock_irq;
|
||||||
|
|
||||||
|
event->handle = evt_handle;
|
||||||
|
event->irq = irq;
|
||||||
|
event->pin = pin;
|
||||||
|
|
||||||
|
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
|
||||||
|
"ACPI:Event", event);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(chip->dev, "Failed to setup interrupt handler for %d\n",
|
||||||
|
event->irq);
|
||||||
|
goto fail_free_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&event->node, &acpi_gpio->events);
|
||||||
|
return AE_OK;
|
||||||
|
|
||||||
|
fail_free_event:
|
||||||
|
kfree(event);
|
||||||
|
fail_unlock_irq:
|
||||||
|
gpiod_unlock_as_irq(desc);
|
||||||
|
fail_free_desc:
|
||||||
|
gpiochip_free_own_desc(desc);
|
||||||
|
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
|
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
|
||||||
* @chip: gpio chip
|
* @acpi_gpio: ACPI GPIO chip
|
||||||
*
|
*
|
||||||
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
|
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
|
||||||
* handled by ACPI event methods which need to be called from the GPIO
|
* handled by ACPI event methods which need to be called from the GPIO
|
||||||
|
@ -96,140 +229,45 @@ static void acpi_gpio_evt_dh(acpi_handle handle, void *data)
|
||||||
* gpio pins have acpi event methods and assigns interrupt handlers that calls
|
* gpio pins have acpi event methods and assigns interrupt handlers that calls
|
||||||
* the acpi event methods for those pins.
|
* the acpi event methods for those pins.
|
||||||
*/
|
*/
|
||||||
static void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
|
static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
||||||
{
|
{
|
||||||
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
|
struct gpio_chip *chip = acpi_gpio->chip;
|
||||||
struct acpi_resource *res;
|
|
||||||
acpi_handle handle, evt_handle;
|
|
||||||
struct list_head *evt_pins = NULL;
|
|
||||||
acpi_status status;
|
|
||||||
unsigned int pin;
|
|
||||||
int irq, ret;
|
|
||||||
char ev_name[5];
|
|
||||||
|
|
||||||
if (!chip->dev || !chip->to_irq)
|
if (!chip->dev || !chip->to_irq)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle = ACPI_HANDLE(chip->dev);
|
INIT_LIST_HEAD(&acpi_gpio->events);
|
||||||
if (!handle)
|
acpi_walk_resources(ACPI_HANDLE(chip->dev), "_AEI",
|
||||||
return;
|
acpi_gpiochip_request_interrupt, acpi_gpio);
|
||||||
|
|
||||||
status = acpi_get_event_resources(handle, &buf);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
status = acpi_get_handle(handle, "_EVT", &evt_handle);
|
|
||||||
if (ACPI_SUCCESS(status)) {
|
|
||||||
evt_pins = kzalloc(sizeof(*evt_pins), GFP_KERNEL);
|
|
||||||
if (evt_pins) {
|
|
||||||
INIT_LIST_HEAD(evt_pins);
|
|
||||||
status = acpi_attach_data(handle, acpi_gpio_evt_dh,
|
|
||||||
evt_pins);
|
|
||||||
if (ACPI_FAILURE(status)) {
|
|
||||||
kfree(evt_pins);
|
|
||||||
evt_pins = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a GPIO interrupt has an ACPI event handler method, or _EVT is
|
|
||||||
* present, set up an interrupt handler that calls the ACPI event
|
|
||||||
* handler.
|
|
||||||
*/
|
|
||||||
for (res = buf.pointer;
|
|
||||||
res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
|
|
||||||
res = ACPI_NEXT_RESOURCE(res)) {
|
|
||||||
irq_handler_t handler = NULL;
|
|
||||||
void *data;
|
|
||||||
|
|
||||||
if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
|
|
||||||
res->data.gpio.connection_type !=
|
|
||||||
ACPI_RESOURCE_GPIO_TYPE_INT)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pin = res->data.gpio.pin_table[0];
|
|
||||||
if (pin > chip->ngpio)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
irq = chip->to_irq(chip, pin);
|
|
||||||
if (irq < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pin <= 255) {
|
|
||||||
acpi_handle ev_handle;
|
|
||||||
|
|
||||||
sprintf(ev_name, "_%c%02X",
|
|
||||||
res->data.gpio.triggering ? 'E' : 'L', pin);
|
|
||||||
status = acpi_get_handle(handle, ev_name, &ev_handle);
|
|
||||||
if (ACPI_SUCCESS(status)) {
|
|
||||||
handler = acpi_gpio_irq_handler;
|
|
||||||
data = ev_handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!handler && evt_pins) {
|
|
||||||
struct acpi_gpio_evt_pin *evt_pin;
|
|
||||||
|
|
||||||
evt_pin = kzalloc(sizeof(*evt_pin), GFP_KERNEL);
|
|
||||||
if (!evt_pin)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
list_add_tail(&evt_pin->node, evt_pins);
|
|
||||||
evt_pin->evt_handle = evt_handle;
|
|
||||||
evt_pin->pin = pin;
|
|
||||||
evt_pin->irq = irq;
|
|
||||||
handler = acpi_gpio_irq_handler_evt;
|
|
||||||
data = evt_pin;
|
|
||||||
}
|
|
||||||
if (!handler)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Assume BIOS sets the triggering, so no flags */
|
|
||||||
ret = devm_request_threaded_irq(chip->dev, irq, NULL, handler,
|
|
||||||
0, "GPIO-signaled-ACPI-event",
|
|
||||||
data);
|
|
||||||
if (ret)
|
|
||||||
dev_err(chip->dev,
|
|
||||||
"Failed to request IRQ %d ACPI event handler\n",
|
|
||||||
irq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts.
|
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
|
||||||
* @chip: gpio chip
|
* @acpi_gpio: ACPI GPIO chip
|
||||||
*
|
*
|
||||||
* Free interrupts associated with the _EVT method for the given GPIO chip.
|
* Free interrupts associated with GPIO ACPI event method for the given
|
||||||
*
|
* GPIO chip.
|
||||||
* The remaining ACPI event interrupts associated with the chip are freed
|
|
||||||
* automatically.
|
|
||||||
*/
|
*/
|
||||||
static void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
|
static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
|
||||||
{
|
{
|
||||||
acpi_handle handle;
|
struct acpi_gpio_event *event, *ep;
|
||||||
acpi_status status;
|
struct gpio_chip *chip = acpi_gpio->chip;
|
||||||
struct list_head *evt_pins;
|
|
||||||
struct acpi_gpio_evt_pin *evt_pin, *ep;
|
|
||||||
|
|
||||||
if (!chip->dev || !chip->to_irq)
|
if (!chip->dev || !chip->to_irq)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle = ACPI_HANDLE(chip->dev);
|
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
|
||||||
if (!handle)
|
struct gpio_desc *desc;
|
||||||
return;
|
|
||||||
|
|
||||||
status = acpi_get_data(handle, acpi_gpio_evt_dh, (void **)&evt_pins);
|
free_irq(event->irq, event);
|
||||||
if (ACPI_FAILURE(status))
|
desc = gpiochip_get_desc(chip, event->pin);
|
||||||
return;
|
if (WARN_ON(IS_ERR(desc)))
|
||||||
|
continue;
|
||||||
list_for_each_entry_safe_reverse(evt_pin, ep, evt_pins, node) {
|
gpiod_unlock_as_irq(desc);
|
||||||
devm_free_irq(chip->dev, evt_pin->irq, evt_pin);
|
gpiochip_free_own_desc(desc);
|
||||||
list_del(&evt_pin->node);
|
list_del(&event->node);
|
||||||
kfree(evt_pin);
|
kfree(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_detach_data(handle, acpi_gpio_evt_dh);
|
|
||||||
kfree(evt_pins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct acpi_gpio_lookup {
|
struct acpi_gpio_lookup {
|
||||||
|
@ -310,12 +348,202 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
|
||||||
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
|
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static acpi_status
|
||||||
|
acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
|
||||||
|
u32 bits, u64 *value, void *handler_context,
|
||||||
|
void *region_context)
|
||||||
|
{
|
||||||
|
struct acpi_gpio_chip *achip = region_context;
|
||||||
|
struct gpio_chip *chip = achip->chip;
|
||||||
|
struct acpi_resource_gpio *agpio;
|
||||||
|
struct acpi_resource *ares;
|
||||||
|
acpi_status status;
|
||||||
|
bool pull_up;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
status = acpi_buffer_to_resource(achip->conn_info.connection,
|
||||||
|
achip->conn_info.length, &ares);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
|
||||||
|
ACPI_FREE(ares);
|
||||||
|
return AE_BAD_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
agpio = &ares->data.gpio;
|
||||||
|
pull_up = agpio->pin_config == ACPI_PIN_CONFIG_PULLUP;
|
||||||
|
|
||||||
|
if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
|
||||||
|
function == ACPI_WRITE)) {
|
||||||
|
ACPI_FREE(ares);
|
||||||
|
return AE_BAD_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < agpio->pin_table_length; i++) {
|
||||||
|
unsigned pin = agpio->pin_table[i];
|
||||||
|
struct acpi_gpio_connection *conn;
|
||||||
|
struct gpio_desc *desc;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
desc = gpiochip_get_desc(chip, pin);
|
||||||
|
if (IS_ERR(desc)) {
|
||||||
|
status = AE_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&achip->conn_lock);
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
list_for_each_entry(conn, &achip->conns, node) {
|
||||||
|
if (conn->desc == desc) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
|
||||||
|
if (ret) {
|
||||||
|
status = AE_ERROR;
|
||||||
|
mutex_unlock(&achip->conn_lock);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (agpio->io_restriction) {
|
||||||
|
case ACPI_IO_RESTRICT_INPUT:
|
||||||
|
gpiod_direction_input(desc);
|
||||||
|
break;
|
||||||
|
case ACPI_IO_RESTRICT_OUTPUT:
|
||||||
|
/*
|
||||||
|
* ACPI GPIO resources don't contain an
|
||||||
|
* initial value for the GPIO. Therefore we
|
||||||
|
* deduce that value from the pull field
|
||||||
|
* instead. If the pin is pulled up we
|
||||||
|
* assume default to be high, otherwise
|
||||||
|
* low.
|
||||||
|
*/
|
||||||
|
gpiod_direction_output(desc, pull_up);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
* Assume that the BIOS has configured the
|
||||||
|
* direction and pull accordingly.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
|
||||||
|
if (!conn) {
|
||||||
|
status = AE_NO_MEMORY;
|
||||||
|
gpiochip_free_own_desc(desc);
|
||||||
|
mutex_unlock(&achip->conn_lock);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->desc = desc;
|
||||||
|
list_add_tail(&conn->node, &achip->conns);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&achip->conn_lock);
|
||||||
|
|
||||||
|
if (function == ACPI_WRITE)
|
||||||
|
gpiod_set_raw_value(desc, !!((1 << i) & *value));
|
||||||
|
else
|
||||||
|
*value |= gpiod_get_raw_value(desc) << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
ACPI_FREE(ares);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = achip->chip;
|
||||||
|
acpi_handle handle = ACPI_HANDLE(chip->dev);
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&achip->conns);
|
||||||
|
mutex_init(&achip->conn_lock);
|
||||||
|
status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
|
||||||
|
acpi_gpio_adr_space_handler,
|
||||||
|
NULL, achip);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
dev_err(chip->dev, "Failed to install GPIO OpRegion handler\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = achip->chip;
|
||||||
|
acpi_handle handle = ACPI_HANDLE(chip->dev);
|
||||||
|
struct acpi_gpio_connection *conn, *tmp;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
|
||||||
|
acpi_gpio_adr_space_handler);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_err(chip->dev, "Failed to remove GPIO OpRegion handler\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
|
||||||
|
gpiochip_free_own_desc(conn->desc);
|
||||||
|
list_del(&conn->node);
|
||||||
|
kfree(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void acpi_gpiochip_add(struct gpio_chip *chip)
|
void acpi_gpiochip_add(struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
acpi_gpiochip_request_interrupts(chip);
|
struct acpi_gpio_chip *acpi_gpio;
|
||||||
|
acpi_handle handle;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
handle = ACPI_HANDLE(chip->dev);
|
||||||
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
|
||||||
|
if (!acpi_gpio) {
|
||||||
|
dev_err(chip->dev,
|
||||||
|
"Failed to allocate memory for ACPI GPIO chip\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_gpio->chip = chip;
|
||||||
|
|
||||||
|
status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_err(chip->dev, "Failed to attach ACPI GPIO chip\n");
|
||||||
|
kfree(acpi_gpio);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_gpiochip_request_interrupts(acpi_gpio);
|
||||||
|
acpi_gpiochip_request_regions(acpi_gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void acpi_gpiochip_remove(struct gpio_chip *chip)
|
void acpi_gpiochip_remove(struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
acpi_gpiochip_free_interrupts(chip);
|
struct acpi_gpio_chip *acpi_gpio;
|
||||||
|
acpi_handle handle;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
handle = ACPI_HANDLE(chip->dev);
|
||||||
|
if (!handle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_warn(chip->dev, "Failed to retrieve ACPI GPIO chip\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
acpi_gpiochip_free_regions(acpi_gpio);
|
||||||
|
acpi_gpiochip_free_interrupts(acpi_gpio);
|
||||||
|
|
||||||
|
acpi_detach_data(handle, acpi_gpio_chip_dh);
|
||||||
|
kfree(acpi_gpio);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -90,7 +91,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||||
|
|
||||||
of_node_put(gg_data.gpiospec.np);
|
of_node_put(gg_data.gpiospec.np);
|
||||||
pr_debug("%s exited with status %d\n", __func__,
|
pr_debug("%s exited with status %d\n", __func__,
|
||||||
PTR_RET(gg_data.out_gpio));
|
PTR_ERR_OR_ZERO(gg_data.out_gpio));
|
||||||
return gg_data.out_gpio;
|
return gg_data.out_gpio;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_get_named_gpiod_flags);
|
EXPORT_SYMBOL(of_get_named_gpiod_flags);
|
||||||
|
|
|
@ -164,16 +164,17 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||||
EXPORT_SYMBOL_GPL(gpio_to_desc);
|
EXPORT_SYMBOL_GPL(gpio_to_desc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an offset on a certain chip to a corresponding descriptor
|
* Get the GPIO descriptor corresponding to the given hw number for this chip.
|
||||||
*/
|
*/
|
||||||
static struct gpio_desc *gpiochip_offset_to_desc(struct gpio_chip *chip,
|
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
|
||||||
unsigned int offset)
|
u16 hwnum)
|
||||||
{
|
{
|
||||||
if (offset >= chip->ngpio)
|
if (hwnum >= chip->ngpio)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
return &chip->desc[offset];
|
return &chip->desc[hwnum];
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpiochip_get_desc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a GPIO descriptor to the integer namespace.
|
* Convert a GPIO descriptor to the integer namespace.
|
||||||
|
@ -350,9 +351,9 @@ static ssize_t gpio_direction_store(struct device *dev,
|
||||||
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
if (!test_bit(FLAG_EXPORT, &desc->flags))
|
||||||
status = -EIO;
|
status = -EIO;
|
||||||
else if (sysfs_streq(buf, "high"))
|
else if (sysfs_streq(buf, "high"))
|
||||||
status = gpiod_direction_output(desc, 1);
|
status = gpiod_direction_output_raw(desc, 1);
|
||||||
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
|
else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
|
||||||
status = gpiod_direction_output(desc, 0);
|
status = gpiod_direction_output_raw(desc, 0);
|
||||||
else if (sysfs_streq(buf, "in"))
|
else if (sysfs_streq(buf, "in"))
|
||||||
status = gpiod_direction_input(desc);
|
status = gpiod_direction_input(desc);
|
||||||
else
|
else
|
||||||
|
@ -1253,6 +1254,9 @@ fail:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiochip_add);
|
EXPORT_SYMBOL_GPL(gpiochip_add);
|
||||||
|
|
||||||
|
/* Forward-declaration */
|
||||||
|
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gpiochip_remove() - unregister a gpio_chip
|
* gpiochip_remove() - unregister a gpio_chip
|
||||||
* @chip: the chip to unregister
|
* @chip: the chip to unregister
|
||||||
|
@ -1265,11 +1269,13 @@ int gpiochip_remove(struct gpio_chip *chip)
|
||||||
int status = 0;
|
int status = 0;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
|
||||||
|
acpi_gpiochip_remove(chip);
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
|
|
||||||
|
gpiochip_irqchip_remove(chip);
|
||||||
gpiochip_remove_pin_ranges(chip);
|
gpiochip_remove_pin_ranges(chip);
|
||||||
of_gpiochip_remove(chip);
|
of_gpiochip_remove(chip);
|
||||||
acpi_gpiochip_remove(chip);
|
|
||||||
|
|
||||||
for (id = 0; id < chip->ngpio; id++) {
|
for (id = 0; id < chip->ngpio; id++) {
|
||||||
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
|
if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags)) {
|
||||||
|
@ -1337,6 +1343,215 @@ static struct gpio_chip *find_chip_by_name(const char *name)
|
||||||
return gpiochip_find((void *)name, gpiochip_match_name);
|
return gpiochip_find((void *)name, gpiochip_match_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following is irqchip helper code for gpiochips.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_add_chained_irqchip() - adds a chained irqchip to a gpiochip
|
||||||
|
* @gpiochip: the gpiochip to add the irqchip to
|
||||||
|
* @irqchip: the irqchip to add to the gpiochip
|
||||||
|
* @parent_irq: the irq number corresponding to the parent IRQ for this
|
||||||
|
* chained irqchip
|
||||||
|
* @parent_handler: the parent interrupt handler for the accumulated IRQ
|
||||||
|
* coming out of the gpiochip
|
||||||
|
*/
|
||||||
|
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||||
|
struct irq_chip *irqchip,
|
||||||
|
int parent_irq,
|
||||||
|
irq_flow_handler_t parent_handler)
|
||||||
|
{
|
||||||
|
irq_set_chained_handler(parent_irq, parent_handler);
|
||||||
|
/*
|
||||||
|
* The parent irqchip is already using the chip_data for this
|
||||||
|
* irqchip, so our callbacks simply use the handler_data.
|
||||||
|
*/
|
||||||
|
irq_set_handler_data(parent_irq, gpiochip);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
|
||||||
|
* @d: the irqdomain used by this irqchip
|
||||||
|
* @irq: the global irq number used by this GPIO irqchip irq
|
||||||
|
* @hwirq: the local IRQ/GPIO line offset on this gpiochip
|
||||||
|
*
|
||||||
|
* This function will set up the mapping for a certain IRQ line on a
|
||||||
|
* gpiochip by assigning the gpiochip as chip data, and using the irqchip
|
||||||
|
* stored inside the gpiochip.
|
||||||
|
*/
|
||||||
|
static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||||
|
irq_hw_number_t hwirq)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = d->host_data;
|
||||||
|
|
||||||
|
irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
|
||||||
|
irq_set_chip_data(irq, chip);
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
set_irq_flags(irq, IRQF_VALID);
|
||||||
|
#else
|
||||||
|
irq_set_noprobe(irq);
|
||||||
|
#endif
|
||||||
|
irq_set_irq_type(irq, chip->irq_default_type);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
set_irq_flags(irq, 0);
|
||||||
|
#endif
|
||||||
|
irq_set_chip_and_handler(irq, NULL, NULL);
|
||||||
|
irq_set_chip_data(irq, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct irq_domain_ops gpiochip_domain_ops = {
|
||||||
|
.map = gpiochip_irq_map,
|
||||||
|
.unmap = gpiochip_irq_unmap,
|
||||||
|
/* Virtually all GPIO irqchips are twocell:ed */
|
||||||
|
.xlate = irq_domain_xlate_twocell,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int gpiochip_irq_reqres(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
|
if (gpio_lock_as_irq(chip, d->hwirq)) {
|
||||||
|
chip_err(chip,
|
||||||
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
|
d->hwirq);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpiochip_irq_relres(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
|
gpio_unlock_as_irq(chip, d->hwirq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
return irq_find_mapping(chip->irqdomain, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_irqchip_remove() - removes an irqchip added to a gpiochip
|
||||||
|
* @gpiochip: the gpiochip to remove the irqchip from
|
||||||
|
*
|
||||||
|
* This is called only from gpiochip_remove()
|
||||||
|
*/
|
||||||
|
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
|
||||||
|
{
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
/* Remove all IRQ mappings and delete the domain */
|
||||||
|
if (gpiochip->irqdomain) {
|
||||||
|
for (offset = 0; offset < gpiochip->ngpio; offset++)
|
||||||
|
irq_dispose_mapping(gpiochip->irq_base + offset);
|
||||||
|
irq_domain_remove(gpiochip->irqdomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpiochip->irqchip) {
|
||||||
|
gpiochip->irqchip->irq_request_resources = NULL;
|
||||||
|
gpiochip->irqchip->irq_release_resources = NULL;
|
||||||
|
gpiochip->irqchip = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_irqchip_add() - adds an irqchip to a gpiochip
|
||||||
|
* @gpiochip: the gpiochip to add the irqchip to
|
||||||
|
* @irqchip: the irqchip to add to the gpiochip
|
||||||
|
* @first_irq: if not dynamically assigned, the base (first) IRQ to
|
||||||
|
* allocate gpiochip irqs from
|
||||||
|
* @handler: the irq handler to use (often a predefined irq core function)
|
||||||
|
* @type: the default type for IRQs on this irqchip
|
||||||
|
*
|
||||||
|
* This function closely associates a certain irqchip with a certain
|
||||||
|
* gpiochip, providing an irq domain to translate the local IRQs to
|
||||||
|
* global irqs in the gpiolib core, and making sure that the gpiochip
|
||||||
|
* is passed as chip data to all related functions. Driver callbacks
|
||||||
|
* need to use container_of() to get their local state containers back
|
||||||
|
* from the gpiochip passed as chip data. An irqdomain will be stored
|
||||||
|
* in the gpiochip that shall be used by the driver to handle IRQ number
|
||||||
|
* translation. The gpiochip will need to be initialized and registered
|
||||||
|
* before calling this function.
|
||||||
|
*
|
||||||
|
* This function will handle two cell:ed simple IRQs and assumes all
|
||||||
|
* the pins on the gpiochip can generate a unique IRQ. Everything else
|
||||||
|
* need to be open coded.
|
||||||
|
*/
|
||||||
|
int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||||
|
struct irq_chip *irqchip,
|
||||||
|
unsigned int first_irq,
|
||||||
|
irq_flow_handler_t handler,
|
||||||
|
unsigned int type)
|
||||||
|
{
|
||||||
|
struct device_node *of_node;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned irq_base = 0;
|
||||||
|
|
||||||
|
if (!gpiochip || !irqchip)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!gpiochip->dev) {
|
||||||
|
pr_err("missing gpiochip .dev parent pointer\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
of_node = gpiochip->dev->of_node;
|
||||||
|
#ifdef CONFIG_OF_GPIO
|
||||||
|
/*
|
||||||
|
* If the gpiochip has an assigned OF node this takes precendence
|
||||||
|
* FIXME: get rid of this and use gpiochip->dev->of_node everywhere
|
||||||
|
*/
|
||||||
|
if (gpiochip->of_node)
|
||||||
|
of_node = gpiochip->of_node;
|
||||||
|
#endif
|
||||||
|
gpiochip->irqchip = irqchip;
|
||||||
|
gpiochip->irq_handler = handler;
|
||||||
|
gpiochip->irq_default_type = type;
|
||||||
|
gpiochip->to_irq = gpiochip_to_irq;
|
||||||
|
gpiochip->irqdomain = irq_domain_add_simple(of_node,
|
||||||
|
gpiochip->ngpio, first_irq,
|
||||||
|
&gpiochip_domain_ops, gpiochip);
|
||||||
|
if (!gpiochip->irqdomain) {
|
||||||
|
gpiochip->irqchip = NULL;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
irqchip->irq_request_resources = gpiochip_irq_reqres;
|
||||||
|
irqchip->irq_release_resources = gpiochip_irq_relres;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare the mapping since the irqchip shall be orthogonal to
|
||||||
|
* any gpiochip calls. If the first_irq was zero, this is
|
||||||
|
* necessary to allocate descriptors for all IRQs.
|
||||||
|
*/
|
||||||
|
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||||
|
irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
|
||||||
|
if (offset == 0)
|
||||||
|
/*
|
||||||
|
* Store the base into the gpiochip to be used when
|
||||||
|
* unmapping the irqs.
|
||||||
|
*/
|
||||||
|
gpiochip->irq_base = irq_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpiochip_irqchip_add);
|
||||||
|
|
||||||
|
#else /* CONFIG_GPIOLIB_IRQCHIP */
|
||||||
|
|
||||||
|
static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
|
||||||
|
|
||||||
|
#endif /* CONFIG_GPIOLIB_IRQCHIP */
|
||||||
|
|
||||||
#ifdef CONFIG_PINCTRL
|
#ifdef CONFIG_PINCTRL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1457,26 +1672,14 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
|
||||||
* on each other, and help provide better diagnostics in debugfs.
|
* on each other, and help provide better diagnostics in debugfs.
|
||||||
* They're called even less than the "set direction" calls.
|
* They're called even less than the "set direction" calls.
|
||||||
*/
|
*/
|
||||||
static int gpiod_request(struct gpio_desc *desc, const char *label)
|
static int __gpiod_request(struct gpio_desc *desc, const char *label)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip = desc->chip;
|
||||||
int status = -EPROBE_DEFER;
|
int status;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!desc) {
|
|
||||||
pr_warn("%s: invalid GPIO\n", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
|
|
||||||
chip = desc->chip;
|
|
||||||
if (chip == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
if (!try_module_get(chip->owner))
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
/* NOTE: gpio_request() can be called in early boot,
|
/* NOTE: gpio_request() can be called in early boot,
|
||||||
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
|
* before IRQs are enabled, for non-sleeping (SOC) GPIOs.
|
||||||
*/
|
*/
|
||||||
|
@ -1486,7 +1689,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||||
status = 0;
|
status = 0;
|
||||||
} else {
|
} else {
|
||||||
status = -EBUSY;
|
status = -EBUSY;
|
||||||
module_put(chip->owner);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1498,7 +1700,6 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||||
|
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
desc_set_label(desc, NULL);
|
desc_set_label(desc, NULL);
|
||||||
module_put(chip->owner);
|
|
||||||
clear_bit(FLAG_REQUESTED, &desc->flags);
|
clear_bit(FLAG_REQUESTED, &desc->flags);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1509,10 +1710,35 @@ static int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||||
gpiod_get_direction(desc);
|
gpiod_get_direction(desc);
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpiod_request(struct gpio_desc *desc, const char *label)
|
||||||
|
{
|
||||||
|
int status = -EPROBE_DEFER;
|
||||||
|
struct gpio_chip *chip;
|
||||||
|
|
||||||
|
if (!desc) {
|
||||||
|
pr_warn("%s: invalid GPIO\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip = desc->chip;
|
||||||
|
if (!chip)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (try_module_get(chip->owner)) {
|
||||||
|
status = __gpiod_request(desc, label);
|
||||||
|
if (status < 0)
|
||||||
|
module_put(chip->owner);
|
||||||
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (status)
|
if (status)
|
||||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1522,18 +1748,14 @@ int gpio_request(unsigned gpio, const char *label)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpio_request);
|
EXPORT_SYMBOL_GPL(gpio_request);
|
||||||
|
|
||||||
static void gpiod_free(struct gpio_desc *desc)
|
static bool __gpiod_free(struct gpio_desc *desc)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
||||||
if (!desc) {
|
|
||||||
WARN_ON(extra_checks);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiod_unexport(desc);
|
gpiod_unexport(desc);
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
|
@ -1547,15 +1769,23 @@ static void gpiod_free(struct gpio_desc *desc)
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
}
|
}
|
||||||
desc_set_label(desc, NULL);
|
desc_set_label(desc, NULL);
|
||||||
module_put(desc->chip->owner);
|
|
||||||
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
|
||||||
clear_bit(FLAG_REQUESTED, &desc->flags);
|
clear_bit(FLAG_REQUESTED, &desc->flags);
|
||||||
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
|
||||||
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
|
||||||
} else
|
ret = true;
|
||||||
WARN_ON(extra_checks);
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
spin_unlock_irqrestore(&gpio_lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpiod_free(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
if (desc && __gpiod_free(desc))
|
||||||
|
module_put(desc->chip->owner);
|
||||||
|
else
|
||||||
|
WARN_ON(extra_checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_free(unsigned gpio)
|
void gpio_free(unsigned gpio)
|
||||||
|
@ -1590,7 +1820,7 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
|
||||||
if (flags & GPIOF_DIR_IN)
|
if (flags & GPIOF_DIR_IN)
|
||||||
err = gpiod_direction_input(desc);
|
err = gpiod_direction_input(desc);
|
||||||
else
|
else
|
||||||
err = gpiod_direction_output(desc,
|
err = gpiod_direction_output_raw(desc,
|
||||||
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
|
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1677,6 +1907,37 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiochip_is_requested);
|
EXPORT_SYMBOL_GPL(gpiochip_is_requested);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor
|
||||||
|
* @desc: GPIO descriptor to request
|
||||||
|
* @label: label for the GPIO
|
||||||
|
*
|
||||||
|
* Function allows GPIO chip drivers to request and use their own GPIO
|
||||||
|
* descriptors via gpiolib API. Difference to gpiod_request() is that this
|
||||||
|
* function will not increase reference count of the GPIO chip module. This
|
||||||
|
* allows the GPIO chip module to be unloaded as needed (we assume that the
|
||||||
|
* GPIO chip driver handles freeing the GPIOs it has requested).
|
||||||
|
*/
|
||||||
|
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->chip)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __gpiod_request(desc, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiochip_free_own_desc - Free GPIO requested by the chip driver
|
||||||
|
* @desc: GPIO descriptor to free
|
||||||
|
*
|
||||||
|
* Function frees the given GPIO requested previously with
|
||||||
|
* gpiochip_request_own_desc().
|
||||||
|
*/
|
||||||
|
void gpiochip_free_own_desc(struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
if (desc)
|
||||||
|
__gpiod_free(desc);
|
||||||
|
}
|
||||||
|
|
||||||
/* Drivers MUST set GPIO direction before making get/set calls. In
|
/* Drivers MUST set GPIO direction before making get/set calls. In
|
||||||
* some cases this is done in early boot, before IRQs are enabled.
|
* some cases this is done in early boot, before IRQs are enabled.
|
||||||
|
@ -1756,28 +2017,13 @@ fail:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_direction_input);
|
EXPORT_SYMBOL_GPL(gpiod_direction_input);
|
||||||
|
|
||||||
/**
|
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||||
* gpiod_direction_output - set the GPIO direction to input
|
|
||||||
* @desc: GPIO to set to output
|
|
||||||
* @value: initial output value of the GPIO
|
|
||||||
*
|
|
||||||
* Set the direction of the passed GPIO to output, such as gpiod_set_value() can
|
|
||||||
* be called safely on it. The initial value of the output must be specified.
|
|
||||||
*
|
|
||||||
* Return 0 in case of success, else an error code.
|
|
||||||
*/
|
|
||||||
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
int status = -EINVAL;
|
int status = -EINVAL;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
if (!desc || !desc->chip) {
|
|
||||||
pr_warn("%s: invalid GPIO\n", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GPIOs used for IRQs shall not be set as output */
|
/* GPIOs used for IRQs shall not be set as output */
|
||||||
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
|
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
|
||||||
gpiod_err(desc,
|
gpiod_err(desc,
|
||||||
|
@ -1840,6 +2086,50 @@ fail:
|
||||||
gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
|
gpiod_dbg(desc, "%s: gpio status %d\n", __func__, status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiod_direction_output_raw - set the GPIO direction to output
|
||||||
|
* @desc: GPIO to set to output
|
||||||
|
* @value: initial output value of the GPIO
|
||||||
|
*
|
||||||
|
* Set the direction of the passed GPIO to output, such as gpiod_set_value() can
|
||||||
|
* be called safely on it. The initial value of the output must be specified
|
||||||
|
* as raw value on the physical line without regard for the ACTIVE_LOW status.
|
||||||
|
*
|
||||||
|
* Return 0 in case of success, else an error code.
|
||||||
|
*/
|
||||||
|
int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->chip) {
|
||||||
|
pr_warn("%s: invalid GPIO\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return _gpiod_direction_output_raw(desc, value);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpiod_direction_output_raw);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpiod_direction_output - set the GPIO direction to output
|
||||||
|
* @desc: GPIO to set to output
|
||||||
|
* @value: initial output value of the GPIO
|
||||||
|
*
|
||||||
|
* Set the direction of the passed GPIO to output, such as gpiod_set_value() can
|
||||||
|
* be called safely on it. The initial value of the output must be specified
|
||||||
|
* as the logical value of the GPIO, i.e. taking its ACTIVE_LOW status into
|
||||||
|
* account.
|
||||||
|
*
|
||||||
|
* Return 0 in case of success, else an error code.
|
||||||
|
*/
|
||||||
|
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||||
|
{
|
||||||
|
if (!desc || !desc->chip) {
|
||||||
|
pr_warn("%s: invalid GPIO\n", __func__);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
|
||||||
|
value = !value;
|
||||||
|
return _gpiod_direction_output_raw(desc, value);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiod_direction_output);
|
EXPORT_SYMBOL_GPL(gpiod_direction_output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1928,15 +2218,15 @@ EXPORT_SYMBOL_GPL(gpiod_is_active_low);
|
||||||
* that the GPIO was actually requested.
|
* that the GPIO was actually requested.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int _gpiod_get_raw_value(const struct gpio_desc *desc)
|
static bool _gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
int value;
|
bool value;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
chip = desc->chip;
|
chip = desc->chip;
|
||||||
offset = gpio_chip_hwgpio(desc);
|
offset = gpio_chip_hwgpio(desc);
|
||||||
value = chip->get ? chip->get(chip, offset) : 0;
|
value = chip->get ? chip->get(chip, offset) : false;
|
||||||
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
trace_gpio_value(desc_to_gpio(desc), 1, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -1992,7 +2282,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
|
||||||
* @desc: gpio descriptor whose state need to be set.
|
* @desc: gpio descriptor whose state need to be set.
|
||||||
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
||||||
*/
|
*/
|
||||||
static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
|
static void _gpio_set_open_drain_value(struct gpio_desc *desc, bool value)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct gpio_chip *chip = desc->chip;
|
struct gpio_chip *chip = desc->chip;
|
||||||
|
@ -2019,7 +2309,7 @@ static void _gpio_set_open_drain_value(struct gpio_desc *desc, int value)
|
||||||
* @desc: gpio descriptor whose state need to be set.
|
* @desc: gpio descriptor whose state need to be set.
|
||||||
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
* @value: Non-zero for setting it HIGH otherise it will set to LOW.
|
||||||
*/
|
*/
|
||||||
static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
|
static void _gpio_set_open_source_value(struct gpio_desc *desc, bool value)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct gpio_chip *chip = desc->chip;
|
struct gpio_chip *chip = desc->chip;
|
||||||
|
@ -2041,7 +2331,7 @@ static void _gpio_set_open_source_value(struct gpio_desc *desc, int value)
|
||||||
__func__, err);
|
__func__, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
static void _gpiod_set_raw_value(struct gpio_desc *desc, bool value)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
|
|
||||||
|
@ -2137,10 +2427,7 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
|
||||||
* @gpio: the GPIO line to lock as used for IRQ
|
* @gpio: the GPIO line to lock as used for IRQ
|
||||||
*
|
*
|
||||||
* This is used directly by GPIO drivers that want to lock down
|
* This is used directly by GPIO drivers that want to lock down
|
||||||
* a certain GPIO line to be used as IRQs, for example in the
|
* a certain GPIO line to be used for IRQs.
|
||||||
* .to_irq() callback of their gpio_chip, or in the .irq_enable()
|
|
||||||
* of its irq_chip implementation if the GPIO is known from that
|
|
||||||
* code.
|
|
||||||
*/
|
*/
|
||||||
int gpiod_lock_as_irq(struct gpio_desc *desc)
|
int gpiod_lock_as_irq(struct gpio_desc *desc)
|
||||||
{
|
{
|
||||||
|
@ -2161,7 +2448,7 @@ EXPORT_SYMBOL_GPL(gpiod_lock_as_irq);
|
||||||
|
|
||||||
int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
int gpio_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||||
{
|
{
|
||||||
return gpiod_lock_as_irq(gpiochip_offset_to_desc(chip, offset));
|
return gpiod_lock_as_irq(gpiochip_get_desc(chip, offset));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
|
EXPORT_SYMBOL_GPL(gpio_lock_as_irq);
|
||||||
|
|
||||||
|
@ -2183,7 +2470,7 @@ EXPORT_SYMBOL_GPL(gpiod_unlock_as_irq);
|
||||||
|
|
||||||
void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
void gpio_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||||
{
|
{
|
||||||
return gpiod_unlock_as_irq(gpiochip_offset_to_desc(chip, offset));
|
return gpiod_unlock_as_irq(gpiochip_get_desc(chip, offset));
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
|
EXPORT_SYMBOL_GPL(gpio_unlock_as_irq);
|
||||||
|
|
||||||
|
@ -2404,7 +2691,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
desc = gpiochip_offset_to_desc(chip, p->chip_hwnum);
|
desc = gpiochip_get_desc(chip, p->chip_hwnum);
|
||||||
*flags = p->flags;
|
*flags = p->flags;
|
||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
|
|
|
@ -43,4 +43,7 @@ acpi_get_gpiod_by_index(struct device *dev, int index,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int gpiochip_request_own_desc(struct gpio_desc *desc, const char *label);
|
||||||
|
void gpiochip_free_own_desc(struct gpio_desc *desc);
|
||||||
|
|
||||||
#endif /* GPIOLIB_H */
|
#endif /* GPIOLIB_H */
|
||||||
|
|
|
@ -235,6 +235,9 @@ config PINCTRL_NOMADIK
|
||||||
depends on ARCH_U8500 || ARCH_NOMADIK
|
depends on ARCH_U8500 || ARCH_NOMADIK
|
||||||
select PINMUX
|
select PINMUX
|
||||||
select PINCONF
|
select PINCONF
|
||||||
|
select GPIOLIB
|
||||||
|
select OF_GPIO
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
|
|
||||||
config PINCTRL_STN8815
|
config PINCTRL_STN8815
|
||||||
bool "STN8815 pin controller driver"
|
bool "STN8815 pin controller driver"
|
||||||
|
@ -321,6 +324,7 @@ config PINCTRL_U300
|
||||||
config PINCTRL_COH901
|
config PINCTRL_COH901
|
||||||
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
|
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
|
||||||
depends on GPIOLIB && ARCH_U300 && PINCTRL_U300
|
depends on GPIOLIB && ARCH_U300 && PINCTRL_U300
|
||||||
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Say yes here to support GPIO interface on ST-Ericsson U300.
|
Say yes here to support GPIO interface on ST-Ericsson U300.
|
||||||
The names of the two IP block variants supported are
|
The names of the two IP block variants supported are
|
||||||
|
|
|
@ -337,6 +337,7 @@ static unsigned int adi_gpio_irq_startup(struct irq_data *d)
|
||||||
|
|
||||||
if (!port) {
|
if (!port) {
|
||||||
pr_err("GPIO IRQ %d :Not exist\n", d->irq);
|
pr_err("GPIO IRQ %d :Not exist\n", d->irq);
|
||||||
|
/* FIXME: negative return code will be ignored */
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -407,23 +407,23 @@ static void byt_irq_mask(struct irq_data *d)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int byt_irq_startup(struct irq_data *d)
|
static int byt_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
|
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d)))
|
if (gpio_lock_as_irq(&vg->chip, irqd_to_hwirq(d))) {
|
||||||
dev_err(vg->chip.dev,
|
dev_err(vg->chip.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
irqd_to_hwirq(d));
|
irqd_to_hwirq(d));
|
||||||
byt_irq_unmask(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void byt_irq_shutdown(struct irq_data *d)
|
static void byt_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
|
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
byt_irq_mask(d);
|
|
||||||
gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d));
|
gpio_unlock_as_irq(&vg->chip, irqd_to_hwirq(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,8 +432,8 @@ static struct irq_chip byt_irqchip = {
|
||||||
.irq_mask = byt_irq_mask,
|
.irq_mask = byt_irq_mask,
|
||||||
.irq_unmask = byt_irq_unmask,
|
.irq_unmask = byt_irq_unmask,
|
||||||
.irq_set_type = byt_irq_type,
|
.irq_set_type = byt_irq_type,
|
||||||
.irq_startup = byt_irq_startup,
|
.irq_request_resources = byt_irq_reqres,
|
||||||
.irq_shutdown = byt_irq_shutdown,
|
.irq_release_resources = byt_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
|
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
|
||||||
|
|
|
@ -8,17 +8,14 @@
|
||||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||||
*/
|
*/
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/irq.h>
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/pinctrl/pinconf-generic.h>
|
#include <linux/pinctrl/pinconf-generic.h>
|
||||||
|
@ -61,9 +58,17 @@
|
||||||
#define U300_GPIO_PINS_PER_PORT 8
|
#define U300_GPIO_PINS_PER_PORT 8
|
||||||
#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS)
|
#define U300_GPIO_MAX (U300_GPIO_PINS_PER_PORT * U300_GPIO_NUM_PORTS)
|
||||||
|
|
||||||
|
struct u300_gpio_port {
|
||||||
|
struct u300_gpio *gpio;
|
||||||
|
char name[8];
|
||||||
|
int irq;
|
||||||
|
int number;
|
||||||
|
u8 toggle_edge_mode;
|
||||||
|
};
|
||||||
|
|
||||||
struct u300_gpio {
|
struct u300_gpio {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
struct list_head port_list;
|
struct u300_gpio_port ports[U300_GPIO_NUM_PORTS];
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -78,16 +83,6 @@ struct u300_gpio {
|
||||||
u32 iev;
|
u32 iev;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct u300_gpio_port {
|
|
||||||
struct list_head node;
|
|
||||||
struct u300_gpio *gpio;
|
|
||||||
char name[8];
|
|
||||||
struct irq_domain *domain;
|
|
||||||
int irq;
|
|
||||||
int number;
|
|
||||||
u8 toggle_edge_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macro to expand to read a specific register found in the "gpio"
|
* Macro to expand to read a specific register found in the "gpio"
|
||||||
* struct. It requires the struct u300_gpio *gpio variable to exist in
|
* struct. It requires the struct u300_gpio *gpio variable to exist in
|
||||||
|
@ -308,39 +303,6 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct u300_gpio *gpio = to_u300_gpio(chip);
|
|
||||||
int portno = offset >> 3;
|
|
||||||
struct u300_gpio_port *port = NULL;
|
|
||||||
struct list_head *p;
|
|
||||||
int retirq;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
list_for_each(p, &gpio->port_list) {
|
|
||||||
port = list_entry(p, struct u300_gpio_port, node);
|
|
||||||
if (port->number == portno) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
|
|
||||||
offset);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The local hwirqs on the port are the lower three bits, there
|
|
||||||
* are exactly 8 IRQs per port since they are 8-bit
|
|
||||||
*/
|
|
||||||
retirq = irq_find_mapping(port->domain, (offset & 0x7));
|
|
||||||
|
|
||||||
dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
|
|
||||||
offset, retirq, port->number);
|
|
||||||
return retirq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returning -EINVAL means "supported but not available" */
|
/* Returning -EINVAL means "supported but not available" */
|
||||||
int u300_gpio_config_get(struct gpio_chip *chip,
|
int u300_gpio_config_get(struct gpio_chip *chip,
|
||||||
unsigned offset,
|
unsigned offset,
|
||||||
|
@ -461,7 +423,6 @@ static struct gpio_chip u300_gpio_chip = {
|
||||||
.set = u300_gpio_set,
|
.set = u300_gpio_set,
|
||||||
.direction_input = u300_gpio_direction_input,
|
.direction_input = u300_gpio_direction_input,
|
||||||
.direction_output = u300_gpio_direction_output,
|
.direction_output = u300_gpio_direction_output,
|
||||||
.to_irq = u300_gpio_to_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
|
static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
|
||||||
|
@ -485,9 +446,10 @@ static void u300_toggle_trigger(struct u300_gpio *gpio, unsigned offset)
|
||||||
|
|
||||||
static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
|
static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
|
||||||
{
|
{
|
||||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
struct u300_gpio *gpio = port->gpio;
|
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||||
int offset = (port->number << 3) + d->hwirq;
|
struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
|
||||||
|
int offset = d->hwirq;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
if ((trigger & IRQF_TRIGGER_RISING) &&
|
if ((trigger & IRQF_TRIGGER_RISING) &&
|
||||||
|
@ -521,18 +483,15 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
|
||||||
|
|
||||||
static void u300_gpio_irq_enable(struct irq_data *d)
|
static void u300_gpio_irq_enable(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
struct u300_gpio *gpio = port->gpio;
|
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||||
int offset = (port->number << 3) + d->hwirq;
|
struct u300_gpio_port *port = &gpio->ports[d->hwirq >> 3];
|
||||||
|
int offset = d->hwirq;
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
|
dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
|
||||||
d->hwirq, port->name, offset);
|
d->hwirq, port->name, offset);
|
||||||
if (gpio_lock_as_irq(&gpio->chip, d->hwirq))
|
|
||||||
dev_err(gpio->dev,
|
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
|
||||||
d->hwirq);
|
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
val = readl(U300_PIN_REG(offset, ien));
|
val = readl(U300_PIN_REG(offset, ien));
|
||||||
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
|
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
|
||||||
|
@ -541,9 +500,9 @@ static void u300_gpio_irq_enable(struct irq_data *d)
|
||||||
|
|
||||||
static void u300_gpio_irq_disable(struct irq_data *d)
|
static void u300_gpio_irq_disable(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
struct u300_gpio *gpio = port->gpio;
|
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||||
int offset = (port->number << 3) + d->hwirq;
|
int offset = d->hwirq;
|
||||||
u32 val;
|
u32 val;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -551,7 +510,6 @@ static void u300_gpio_irq_disable(struct irq_data *d)
|
||||||
val = readl(U300_PIN_REG(offset, ien));
|
val = readl(U300_PIN_REG(offset, ien));
|
||||||
writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
|
writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
gpio_unlock_as_irq(&gpio->chip, d->hwirq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip u300_gpio_irqchip = {
|
static struct irq_chip u300_gpio_irqchip = {
|
||||||
|
@ -559,17 +517,19 @@ static struct irq_chip u300_gpio_irqchip = {
|
||||||
.irq_enable = u300_gpio_irq_enable,
|
.irq_enable = u300_gpio_irq_enable,
|
||||||
.irq_disable = u300_gpio_irq_disable,
|
.irq_disable = u300_gpio_irq_disable,
|
||||||
.irq_set_type = u300_gpio_irq_type,
|
.irq_set_type = u300_gpio_irq_type,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct u300_gpio_port *port = irq_get_handler_data(irq);
|
struct irq_chip *parent_chip = irq_get_chip(irq);
|
||||||
struct u300_gpio *gpio = port->gpio;
|
struct gpio_chip *chip = irq_get_handler_data(irq);
|
||||||
|
struct u300_gpio *gpio = to_u300_gpio(chip);
|
||||||
|
struct u300_gpio_port *port = &gpio->ports[irq - chip->base];
|
||||||
int pinoffset = port->number << 3; /* get the right stride */
|
int pinoffset = port->number << 3; /* get the right stride */
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
|
|
||||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
chained_irq_enter(parent_chip, desc);
|
||||||
|
|
||||||
/* Read event register */
|
/* Read event register */
|
||||||
val = readl(U300_PIN_REG(pinoffset, iev));
|
val = readl(U300_PIN_REG(pinoffset, iev));
|
||||||
/* Mask relevant bits */
|
/* Mask relevant bits */
|
||||||
|
@ -582,8 +542,8 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
int irqoffset;
|
int irqoffset;
|
||||||
|
|
||||||
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
|
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
|
||||||
int pin_irq = irq_find_mapping(port->domain, irqoffset);
|
|
||||||
int offset = pinoffset + irqoffset;
|
int offset = pinoffset + irqoffset;
|
||||||
|
int pin_irq = irq_find_mapping(chip->irqdomain, offset);
|
||||||
|
|
||||||
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
|
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
|
||||||
pin_irq, offset);
|
pin_irq, offset);
|
||||||
|
@ -597,7 +557,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
desc->irq_data.chip->irq_unmask(&desc->irq_data);
|
chained_irq_exit(parent_chip, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
|
static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
|
||||||
|
@ -648,20 +608,6 @@ static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
|
|
||||||
{
|
|
||||||
struct u300_gpio_port *port;
|
|
||||||
struct list_head *p, *n;
|
|
||||||
|
|
||||||
list_for_each_safe(p, n, &gpio->port_list) {
|
|
||||||
port = list_entry(p, struct u300_gpio_port, node);
|
|
||||||
list_del(&port->node);
|
|
||||||
if (port->domain)
|
|
||||||
irq_domain_remove(port->domain);
|
|
||||||
kfree(port);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we map a GPIO in the local gpio_chip pin space to a pin in
|
* Here we map a GPIO in the local gpio_chip pin space to a pin in
|
||||||
* the local pinctrl pin space. The pin controller used is
|
* the local pinctrl pin space. The pin controller used is
|
||||||
|
@ -752,59 +698,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
||||||
gpio->base + U300_GPIO_CR);
|
gpio->base + U300_GPIO_CR);
|
||||||
u300_gpio_init_coh901571(gpio);
|
u300_gpio_init_coh901571(gpio);
|
||||||
|
|
||||||
/* Add each port with its IRQ separately */
|
|
||||||
INIT_LIST_HEAD(&gpio->port_list);
|
|
||||||
for (portno = 0 ; portno < U300_GPIO_NUM_PORTS; portno++) {
|
|
||||||
struct u300_gpio_port *port =
|
|
||||||
kmalloc(sizeof(struct u300_gpio_port), GFP_KERNEL);
|
|
||||||
|
|
||||||
if (!port) {
|
|
||||||
dev_err(gpio->dev, "out of memory\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_no_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(port->name, 8, "gpio%d", portno);
|
|
||||||
port->number = portno;
|
|
||||||
port->gpio = gpio;
|
|
||||||
|
|
||||||
port->irq = platform_get_irq(pdev, portno);
|
|
||||||
|
|
||||||
dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
|
|
||||||
port->name);
|
|
||||||
|
|
||||||
port->domain = irq_domain_add_linear(pdev->dev.of_node,
|
|
||||||
U300_GPIO_PINS_PER_PORT,
|
|
||||||
&irq_domain_simple_ops,
|
|
||||||
port);
|
|
||||||
if (!port->domain) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_no_domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
|
|
||||||
irq_set_handler_data(port->irq, port);
|
|
||||||
|
|
||||||
/* For each GPIO pin set the unique IRQ handler */
|
|
||||||
for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
|
|
||||||
int irqno = irq_create_mapping(port->domain, i);
|
|
||||||
|
|
||||||
dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
|
|
||||||
gpio->chip.base + (port->number << 3) + i,
|
|
||||||
port->name, irqno);
|
|
||||||
irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
|
|
||||||
handle_simple_irq);
|
|
||||||
set_irq_flags(irqno, IRQF_VALID);
|
|
||||||
irq_set_chip_data(irqno, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turns off irq force (test register) for this port */
|
|
||||||
writel(0x0, gpio->base + portno * gpio->stride + ifr);
|
|
||||||
|
|
||||||
list_add_tail(&port->node, &gpio->port_list);
|
|
||||||
}
|
|
||||||
dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno);
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF_GPIO
|
#ifdef CONFIG_OF_GPIO
|
||||||
gpio->chip.of_node = pdev->dev.of_node;
|
gpio->chip.of_node = pdev->dev.of_node;
|
||||||
#endif
|
#endif
|
||||||
|
@ -814,6 +707,36 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
||||||
goto err_no_chip;
|
goto err_no_chip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = gpiochip_irqchip_add(&gpio->chip,
|
||||||
|
&u300_gpio_irqchip,
|
||||||
|
0,
|
||||||
|
handle_simple_irq,
|
||||||
|
IRQ_TYPE_EDGE_FALLING);
|
||||||
|
if (err) {
|
||||||
|
dev_err(gpio->dev, "no GPIO irqchip\n");
|
||||||
|
goto err_no_irqchip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add each port with its IRQ separately */
|
||||||
|
for (portno = 0 ; portno < U300_GPIO_NUM_PORTS; portno++) {
|
||||||
|
struct u300_gpio_port *port = &gpio->ports[portno];
|
||||||
|
|
||||||
|
snprintf(port->name, 8, "gpio%d", portno);
|
||||||
|
port->number = portno;
|
||||||
|
port->gpio = gpio;
|
||||||
|
|
||||||
|
port->irq = platform_get_irq(pdev, portno);
|
||||||
|
|
||||||
|
gpiochip_set_chained_irqchip(&gpio->chip,
|
||||||
|
&u300_gpio_irqchip,
|
||||||
|
port->irq,
|
||||||
|
u300_gpio_irq_handler);
|
||||||
|
|
||||||
|
/* Turns off irq force (test register) for this port */
|
||||||
|
writel(0x0, gpio->base + portno * gpio->stride + ifr);
|
||||||
|
}
|
||||||
|
dev_dbg(gpio->dev, "initialized %d GPIO ports\n", portno);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add pinctrl pin ranges, the pin controller must be registered
|
* Add pinctrl pin ranges, the pin controller must be registered
|
||||||
* at this point
|
* at this point
|
||||||
|
@ -832,12 +755,10 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_no_range:
|
err_no_range:
|
||||||
|
err_no_irqchip:
|
||||||
if (gpiochip_remove(&gpio->chip))
|
if (gpiochip_remove(&gpio->chip))
|
||||||
dev_err(&pdev->dev, "failed to remove gpio chip\n");
|
dev_err(&pdev->dev, "failed to remove gpio chip\n");
|
||||||
err_no_chip:
|
err_no_chip:
|
||||||
err_no_domain:
|
|
||||||
err_no_port:
|
|
||||||
u300_gpio_free_ports(gpio);
|
|
||||||
clk_disable_unprepare(gpio->clk);
|
clk_disable_unprepare(gpio->clk);
|
||||||
dev_err(&pdev->dev, "module ERROR:%d\n", err);
|
dev_err(&pdev->dev, "module ERROR:%d\n", err);
|
||||||
return err;
|
return err;
|
||||||
|
@ -856,7 +777,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
|
||||||
dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err);
|
dev_err(gpio->dev, "unable to remove gpiochip: %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
u300_gpio_free_ports(gpio);
|
|
||||||
clk_disable_unprepare(gpio->clk);
|
clk_disable_unprepare(gpio->clk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -785,23 +785,22 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int msm_gpio_irq_startup(struct irq_data *d)
|
static int msm_gpio_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
|
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) {
|
if (gpio_lock_as_irq(&pctrl->chip, d->hwirq)) {
|
||||||
dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n",
|
dev_err(pctrl->dev, "unable to lock HW IRQ %lu for IRQ\n",
|
||||||
d->hwirq);
|
d->hwirq);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
msm_gpio_irq_unmask(d);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msm_gpio_irq_shutdown(struct irq_data *d)
|
static void msm_gpio_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
|
struct msm_pinctrl *pctrl = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
msm_gpio_irq_mask(d);
|
|
||||||
gpio_unlock_as_irq(&pctrl->chip, d->hwirq);
|
gpio_unlock_as_irq(&pctrl->chip, d->hwirq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,8 +811,8 @@ static struct irq_chip msm_gpio_irq_chip = {
|
||||||
.irq_ack = msm_gpio_irq_ack,
|
.irq_ack = msm_gpio_irq_ack,
|
||||||
.irq_set_type = msm_gpio_irq_set_type,
|
.irq_set_type = msm_gpio_irq_set_type,
|
||||||
.irq_set_wake = msm_gpio_irq_set_wake,
|
.irq_set_wake = msm_gpio_irq_set_wake,
|
||||||
.irq_startup = msm_gpio_irq_startup,
|
.irq_request_resources = msm_gpio_irq_reqres,
|
||||||
.irq_shutdown = msm_gpio_irq_shutdown,
|
.irq_release_resources = msm_gpio_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
|
|
|
@ -21,9 +21,6 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/irq.h>
|
|
||||||
#include <linux/irqdomain.h>
|
|
||||||
#include <linux/irqchip/chained_irq.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
@ -246,28 +243,14 @@ enum nmk_gpio_slpm {
|
||||||
NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
|
NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Platform data to register a block: only the initial gpio/irq number.
|
|
||||||
*/
|
|
||||||
struct nmk_gpio_platform_data {
|
|
||||||
char *name;
|
|
||||||
int first_gpio;
|
|
||||||
int first_irq;
|
|
||||||
int num_gpio;
|
|
||||||
u32 (*get_secondary_status)(unsigned int bank);
|
|
||||||
void (*set_ioforce)(bool enable);
|
|
||||||
bool supports_sleepmode;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nmk_gpio_chip {
|
struct nmk_gpio_chip {
|
||||||
struct gpio_chip chip;
|
struct gpio_chip chip;
|
||||||
struct irq_domain *domain;
|
|
||||||
void __iomem *addr;
|
void __iomem *addr;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
unsigned int bank;
|
unsigned int bank;
|
||||||
unsigned int parent_irq;
|
unsigned int parent_irq;
|
||||||
int secondary_parent_irq;
|
int latent_parent_irq;
|
||||||
u32 (*get_secondary_status)(unsigned int bank);
|
u32 (*get_latent_status)(unsigned int bank);
|
||||||
void (*set_ioforce)(bool enable);
|
void (*set_ioforce)(bool enable);
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
bool sleepmode;
|
bool sleepmode;
|
||||||
|
@ -432,7 +415,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
|
||||||
u32 falling = nmk_chip->fimsc & BIT(offset);
|
u32 falling = nmk_chip->fimsc & BIT(offset);
|
||||||
u32 rising = nmk_chip->rimsc & BIT(offset);
|
u32 rising = nmk_chip->rimsc & BIT(offset);
|
||||||
int gpio = nmk_chip->chip.base + offset;
|
int gpio = nmk_chip->chip.base + offset;
|
||||||
int irq = irq_find_mapping(nmk_chip->domain, offset);
|
int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
|
||||||
struct irq_data *d = irq_get_irq_data(irq);
|
struct irq_data *d = irq_get_irq_data(irq);
|
||||||
|
|
||||||
if (!rising && !falling)
|
if (!rising && !falling)
|
||||||
|
@ -660,11 +643,8 @@ static inline int nmk_gpio_get_bitmask(int gpio)
|
||||||
|
|
||||||
static void nmk_gpio_irq_ack(struct irq_data *d)
|
static void nmk_gpio_irq_ack(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip;
|
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
|
||||||
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
nmk_chip = irq_data_get_irq_chip_data(d);
|
|
||||||
if (!nmk_chip)
|
|
||||||
return;
|
|
||||||
|
|
||||||
clk_enable(nmk_chip->clk);
|
clk_enable(nmk_chip->clk);
|
||||||
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
|
writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
|
||||||
|
@ -848,10 +828,6 @@ static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&nmk_chip->chip, d->hwirq))
|
|
||||||
dev_err(nmk_chip->chip.dev,
|
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
|
||||||
d->hwirq);
|
|
||||||
clk_enable(nmk_chip->clk);
|
clk_enable(nmk_chip->clk);
|
||||||
nmk_gpio_irq_unmask(d);
|
nmk_gpio_irq_unmask(d);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -863,7 +839,6 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d)
|
||||||
|
|
||||||
nmk_gpio_irq_mask(d);
|
nmk_gpio_irq_mask(d);
|
||||||
clk_disable(nmk_chip->clk);
|
clk_disable(nmk_chip->clk);
|
||||||
gpio_unlock_as_irq(&nmk_chip->chip, d->hwirq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip nmk_gpio_irq_chip = {
|
static struct irq_chip nmk_gpio_irq_chip = {
|
||||||
|
@ -881,16 +856,15 @@ static struct irq_chip nmk_gpio_irq_chip = {
|
||||||
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
||||||
u32 status)
|
u32 status)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip;
|
|
||||||
struct irq_chip *host_chip = irq_get_chip(irq);
|
struct irq_chip *host_chip = irq_get_chip(irq);
|
||||||
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
|
|
||||||
chained_irq_enter(host_chip, desc);
|
chained_irq_enter(host_chip, desc);
|
||||||
|
|
||||||
nmk_chip = irq_get_handler_data(irq);
|
|
||||||
while (status) {
|
while (status) {
|
||||||
int bit = __ffs(status);
|
int bit = __ffs(status);
|
||||||
|
|
||||||
generic_handle_irq(irq_find_mapping(nmk_chip->domain, bit));
|
generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
|
||||||
status &= ~BIT(bit);
|
status &= ~BIT(bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,9 +873,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
||||||
|
|
||||||
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
|
pr_err("PLONK IRQ %d\n", irq);
|
||||||
clk_enable(nmk_chip->clk);
|
clk_enable(nmk_chip->clk);
|
||||||
status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
||||||
clk_disable(nmk_chip->clk);
|
clk_disable(nmk_chip->clk);
|
||||||
|
@ -909,29 +885,16 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
__nmk_gpio_irq_handler(irq, desc, status);
|
__nmk_gpio_irq_handler(irq, desc, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nmk_gpio_secondary_irq_handler(unsigned int irq,
|
static void nmk_gpio_latent_irq_handler(unsigned int irq,
|
||||||
struct irq_desc *desc)
|
struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
|
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||||
u32 status = nmk_chip->get_secondary_status(nmk_chip->bank);
|
struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
|
||||||
|
u32 status = nmk_chip->get_latent_status(nmk_chip->bank);
|
||||||
|
|
||||||
__nmk_gpio_irq_handler(irq, desc, status);
|
__nmk_gpio_irq_handler(irq, desc, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
|
|
||||||
{
|
|
||||||
irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
|
|
||||||
irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
|
|
||||||
|
|
||||||
if (nmk_chip->secondary_parent_irq >= 0) {
|
|
||||||
irq_set_chained_handler(nmk_chip->secondary_parent_irq,
|
|
||||||
nmk_gpio_secondary_irq_handler);
|
|
||||||
irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I/O Functions */
|
/* I/O Functions */
|
||||||
|
|
||||||
static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
|
static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||||
|
@ -1010,14 +973,6 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip =
|
|
||||||
container_of(chip, struct nmk_gpio_chip, chip);
|
|
||||||
|
|
||||||
return irq_create_mapping(nmk_chip->domain, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
@ -1116,7 +1071,6 @@ static struct gpio_chip nmk_gpio_template = {
|
||||||
.get = nmk_gpio_get_input,
|
.get = nmk_gpio_get_input,
|
||||||
.direction_output = nmk_gpio_make_output,
|
.direction_output = nmk_gpio_make_output,
|
||||||
.set = nmk_gpio_set_output,
|
.set = nmk_gpio_set_output,
|
||||||
.to_irq = nmk_gpio_to_irq,
|
|
||||||
.dbg_show = nmk_gpio_dbg_show,
|
.dbg_show = nmk_gpio_dbg_show,
|
||||||
.can_sleep = false,
|
.can_sleep = false,
|
||||||
};
|
};
|
||||||
|
@ -1217,62 +1171,35 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
|
||||||
irq_hw_number_t hwirq)
|
|
||||||
{
|
|
||||||
struct nmk_gpio_chip *nmk_chip = d->host_data;
|
|
||||||
|
|
||||||
if (!nmk_chip)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
|
|
||||||
set_irq_flags(irq, IRQF_VALID);
|
|
||||||
irq_set_chip_data(irq, nmk_chip);
|
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
|
|
||||||
.map = nmk_gpio_irq_map,
|
|
||||||
.xlate = irq_domain_xlate_twocell,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int nmk_gpio_probe(struct platform_device *dev)
|
static int nmk_gpio_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct nmk_gpio_platform_data *pdata;
|
|
||||||
struct device_node *np = dev->dev.of_node;
|
struct device_node *np = dev->dev.of_node;
|
||||||
struct nmk_gpio_chip *nmk_chip;
|
struct nmk_gpio_chip *nmk_chip;
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int secondary_irq;
|
int latent_irq;
|
||||||
|
bool supports_sleepmode;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
|
|
||||||
if (!pdata)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (of_get_property(np, "st,supports-sleepmode", NULL))
|
if (of_get_property(np, "st,supports-sleepmode", NULL))
|
||||||
pdata->supports_sleepmode = true;
|
supports_sleepmode = true;
|
||||||
|
else
|
||||||
|
supports_sleepmode = false;
|
||||||
|
|
||||||
if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
|
if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
|
||||||
dev_err(&dev->dev, "gpio-bank property not found\n");
|
dev_err(&dev->dev, "gpio-bank property not found\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
|
|
||||||
pdata->num_gpio = NMK_GPIO_PER_CHIP;
|
|
||||||
|
|
||||||
irq = platform_get_irq(dev, 0);
|
irq = platform_get_irq(dev, 0);
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
return irq;
|
return irq;
|
||||||
|
|
||||||
secondary_irq = platform_get_irq(dev, 1);
|
/* It's OK for this IRQ not to be present */
|
||||||
if (secondary_irq >= 0 && !pdata->get_secondary_status)
|
latent_irq = platform_get_irq(dev, 1);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||||
base = devm_ioremap_resource(&dev->dev, res);
|
base = devm_ioremap_resource(&dev->dev, res);
|
||||||
|
@ -1297,16 +1224,14 @@ static int nmk_gpio_probe(struct platform_device *dev)
|
||||||
nmk_chip->addr = base;
|
nmk_chip->addr = base;
|
||||||
nmk_chip->chip = nmk_gpio_template;
|
nmk_chip->chip = nmk_gpio_template;
|
||||||
nmk_chip->parent_irq = irq;
|
nmk_chip->parent_irq = irq;
|
||||||
nmk_chip->secondary_parent_irq = secondary_irq;
|
nmk_chip->latent_parent_irq = latent_irq;
|
||||||
nmk_chip->get_secondary_status = pdata->get_secondary_status;
|
nmk_chip->sleepmode = supports_sleepmode;
|
||||||
nmk_chip->set_ioforce = pdata->set_ioforce;
|
|
||||||
nmk_chip->sleepmode = pdata->supports_sleepmode;
|
|
||||||
spin_lock_init(&nmk_chip->lock);
|
spin_lock_init(&nmk_chip->lock);
|
||||||
|
|
||||||
chip = &nmk_chip->chip;
|
chip = &nmk_chip->chip;
|
||||||
chip->base = pdata->first_gpio;
|
chip->base = dev->id * NMK_GPIO_PER_CHIP;
|
||||||
chip->ngpio = pdata->num_gpio;
|
chip->ngpio = NMK_GPIO_PER_CHIP;
|
||||||
chip->label = pdata->name ?: dev_name(&dev->dev);
|
chip->label = dev_name(&dev->dev);
|
||||||
chip->dev = &dev->dev;
|
chip->dev = &dev->dev;
|
||||||
chip->owner = THIS_MODULE;
|
chip->owner = THIS_MODULE;
|
||||||
|
|
||||||
|
@ -1325,17 +1250,31 @@ static int nmk_gpio_probe(struct platform_device *dev)
|
||||||
|
|
||||||
platform_set_drvdata(dev, nmk_chip);
|
platform_set_drvdata(dev, nmk_chip);
|
||||||
|
|
||||||
nmk_chip->domain = irq_domain_add_simple(np,
|
/*
|
||||||
NMK_GPIO_PER_CHIP, 0,
|
* Let the generic code handle this edge IRQ, the the chained
|
||||||
&nmk_gpio_irq_simple_ops, nmk_chip);
|
* handler will perform the actual work of handling the parent
|
||||||
if (!nmk_chip->domain) {
|
* interrupt.
|
||||||
dev_err(&dev->dev, "failed to create irqdomain\n");
|
*/
|
||||||
/* Just do this, no matter if it fails */
|
ret = gpiochip_irqchip_add(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
0,
|
||||||
|
handle_edge_irq,
|
||||||
|
IRQ_TYPE_EDGE_FALLING);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&dev->dev, "could not add irqchip\n");
|
||||||
ret = gpiochip_remove(&nmk_chip->chip);
|
ret = gpiochip_remove(&nmk_chip->chip);
|
||||||
return -ENOSYS;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
/* Then register the chain on the parent IRQ */
|
||||||
nmk_gpio_init_irq(nmk_chip);
|
gpiochip_set_chained_irqchip(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
nmk_chip->parent_irq,
|
||||||
|
nmk_gpio_irq_handler);
|
||||||
|
if (nmk_chip->latent_parent_irq > 0)
|
||||||
|
gpiochip_set_chained_irqchip(&nmk_chip->chip,
|
||||||
|
&nmk_gpio_irq_chip,
|
||||||
|
nmk_chip->latent_parent_irq,
|
||||||
|
nmk_gpio_latent_irq_handler);
|
||||||
|
|
||||||
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
|
dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
|
||||||
|
|
||||||
|
|
|
@ -595,23 +595,23 @@ static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
|
static int sirfsoc_gpio_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE))
|
if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE)) {
|
||||||
dev_err(bank->chip.gc.dev,
|
dev_err(bank->chip.gc.dev,
|
||||||
"unable to lock HW IRQ %lu for IRQ\n",
|
"unable to lock HW IRQ %lu for IRQ\n",
|
||||||
d->hwirq);
|
d->hwirq);
|
||||||
sirfsoc_gpio_irq_unmask(d);
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
|
static void sirfsoc_gpio_irq_relres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||||
|
|
||||||
sirfsoc_gpio_irq_mask(d);
|
|
||||||
gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
|
gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,8 +621,8 @@ static struct irq_chip sirfsoc_irq_chip = {
|
||||||
.irq_mask = sirfsoc_gpio_irq_mask,
|
.irq_mask = sirfsoc_gpio_irq_mask,
|
||||||
.irq_unmask = sirfsoc_gpio_irq_unmask,
|
.irq_unmask = sirfsoc_gpio_irq_unmask,
|
||||||
.irq_set_type = sirfsoc_gpio_irq_type,
|
.irq_set_type = sirfsoc_gpio_irq_type,
|
||||||
.irq_startup = sirfsoc_gpio_irq_startup,
|
.irq_request_resources = sirfsoc_gpio_irq_reqres,
|
||||||
.irq_shutdown = sirfsoc_gpio_irq_shutdown,
|
.irq_release_resources = sirfsoc_gpio_irq_relres,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
|
static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
|
||||||
|
|
|
@ -69,7 +69,7 @@ static inline int gpio_direction_input(unsigned gpio)
|
||||||
}
|
}
|
||||||
static inline int gpio_direction_output(unsigned gpio, int value)
|
static inline int gpio_direction_output(unsigned gpio, int value)
|
||||||
{
|
{
|
||||||
return gpiod_direction_output(gpio_to_desc(gpio), value);
|
return gpiod_direction_output_raw(gpio_to_desc(gpio), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
|
static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/spinlock_types.h>
|
#include <linux/spinlock_types.h>
|
||||||
|
|
||||||
struct bgpio_pdata {
|
struct bgpio_pdata {
|
||||||
|
const char *label;
|
||||||
int base;
|
int base;
|
||||||
int ngpio;
|
int ngpio;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
struct gpio_chip;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are
|
* Opaque descriptor for a GPIO. These are obtained using gpiod_get() and are
|
||||||
|
@ -36,6 +35,7 @@ void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);
|
||||||
int gpiod_get_direction(const struct gpio_desc *desc);
|
int gpiod_get_direction(const struct gpio_desc *desc);
|
||||||
int gpiod_direction_input(struct gpio_desc *desc);
|
int gpiod_direction_input(struct gpio_desc *desc);
|
||||||
int gpiod_direction_output(struct gpio_desc *desc, int value);
|
int gpiod_direction_output(struct gpio_desc *desc, int value);
|
||||||
|
int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
|
||||||
|
|
||||||
/* Value get/set from non-sleeping context */
|
/* Value get/set from non-sleeping context */
|
||||||
int gpiod_get_value(const struct gpio_desc *desc);
|
int gpiod_get_value(const struct gpio_desc *desc);
|
||||||
|
@ -59,7 +59,6 @@ int gpiod_to_irq(const struct gpio_desc *desc);
|
||||||
/* Convert between the old gpio_ and new gpiod_ interfaces */
|
/* Convert between the old gpio_ and new gpiod_ interfaces */
|
||||||
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
struct gpio_desc *gpio_to_desc(unsigned gpio);
|
||||||
int desc_to_gpio(const struct gpio_desc *desc);
|
int desc_to_gpio(const struct gpio_desc *desc);
|
||||||
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
|
||||||
|
|
||||||
#else /* CONFIG_GPIOLIB */
|
#else /* CONFIG_GPIOLIB */
|
||||||
|
|
||||||
|
@ -121,6 +120,12 @@ static inline int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
|
||||||
|
{
|
||||||
|
/* GPIO can never have been requested */
|
||||||
|
WARN_ON(1);
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int gpiod_get_value(const struct gpio_desc *desc)
|
static inline int gpiod_get_value(const struct gpio_desc *desc)
|
||||||
|
@ -207,12 +212,6 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
|
|
||||||
{
|
|
||||||
/* GPIO can never have been requested */
|
|
||||||
WARN_ON(1);
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* CONFIG_GPIOLIB */
|
#endif /* CONFIG_GPIOLIB */
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/irqchip/chained_irq.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
|
||||||
struct device;
|
struct device;
|
||||||
struct gpio_desc;
|
struct gpio_desc;
|
||||||
|
@ -10,6 +13,8 @@ struct of_phandle_args;
|
||||||
struct device_node;
|
struct device_node;
|
||||||
struct seq_file;
|
struct seq_file;
|
||||||
|
|
||||||
|
#ifdef CONFIG_GPIOLIB
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct gpio_chip - abstract a GPIO controller
|
* struct gpio_chip - abstract a GPIO controller
|
||||||
* @label: for diagnostics
|
* @label: for diagnostics
|
||||||
|
@ -95,6 +100,18 @@ struct gpio_chip {
|
||||||
bool can_sleep;
|
bool can_sleep;
|
||||||
bool exported;
|
bool exported;
|
||||||
|
|
||||||
|
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||||
|
/*
|
||||||
|
* With CONFIG_GPIO_IRQCHIP we get an irqchip inside the gpiolib
|
||||||
|
* to handle IRQs for most practical cases.
|
||||||
|
*/
|
||||||
|
struct irq_chip *irqchip;
|
||||||
|
struct irq_domain *irqdomain;
|
||||||
|
unsigned int irq_base;
|
||||||
|
irq_flow_handler_t irq_handler;
|
||||||
|
unsigned int irq_default_type;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_OF_GPIO)
|
#if defined(CONFIG_OF_GPIO)
|
||||||
/*
|
/*
|
||||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||||
|
@ -129,6 +146,11 @@ extern struct gpio_chip *gpiochip_find(void *data,
|
||||||
int gpiod_lock_as_irq(struct gpio_desc *desc);
|
int gpiod_lock_as_irq(struct gpio_desc *desc);
|
||||||
void gpiod_unlock_as_irq(struct gpio_desc *desc);
|
void gpiod_unlock_as_irq(struct gpio_desc *desc);
|
||||||
|
|
||||||
|
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
|
||||||
|
|
||||||
|
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
|
||||||
|
u16 hwnum);
|
||||||
|
|
||||||
enum gpio_lookup_flags {
|
enum gpio_lookup_flags {
|
||||||
GPIO_ACTIVE_HIGH = (0 << 0),
|
GPIO_ACTIVE_HIGH = (0 << 0),
|
||||||
GPIO_ACTIVE_LOW = (1 << 0),
|
GPIO_ACTIVE_LOW = (1 << 0),
|
||||||
|
@ -183,4 +205,30 @@ struct gpiod_lookup_table {
|
||||||
|
|
||||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
||||||
|
|
||||||
|
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||||
|
|
||||||
|
void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
|
||||||
|
struct irq_chip *irqchip,
|
||||||
|
int parent_irq,
|
||||||
|
irq_flow_handler_t parent_handler);
|
||||||
|
|
||||||
|
int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
|
||||||
|
struct irq_chip *irqchip,
|
||||||
|
unsigned int first_irq,
|
||||||
|
irq_flow_handler_t handler,
|
||||||
|
unsigned int type);
|
||||||
|
|
||||||
|
#endif /* CONFIG_GPIO_IRQCHIP */
|
||||||
|
|
||||||
|
#else /* CONFIG_GPIOLIB */
|
||||||
|
|
||||||
|
static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
|
||||||
|
{
|
||||||
|
/* GPIO can never have been requested */
|
||||||
|
WARN_ON(1);
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_GPIOLIB */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -161,10 +161,10 @@ struct adp5588_gpio_platform_data {
|
||||||
unsigned irq_base; /* interrupt base # */
|
unsigned irq_base; /* interrupt base # */
|
||||||
unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
|
unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
|
||||||
int (*setup)(struct i2c_client *client,
|
int (*setup)(struct i2c_client *client,
|
||||||
int gpio, unsigned ngpio,
|
unsigned gpio, unsigned ngpio,
|
||||||
void *context);
|
void *context);
|
||||||
int (*teardown)(struct i2c_client *client,
|
int (*teardown)(struct i2c_client *client,
|
||||||
int gpio, unsigned ngpio,
|
unsigned gpio, unsigned ngpio,
|
||||||
void *context);
|
void *context);
|
||||||
void *context;
|
void *context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,10 +21,6 @@
|
||||||
|
|
||||||
#include <asm-generic/gpio.h>
|
#include <asm-generic/gpio.h>
|
||||||
|
|
||||||
enum davinci_gpio_type {
|
|
||||||
GPIO_TYPE_TNETV107X = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct davinci_gpio_platform_data {
|
struct davinci_gpio_platform_data {
|
||||||
u32 ngpio;
|
u32 ngpio;
|
||||||
u32 gpio_unbanked;
|
u32 gpio_unbanked;
|
||||||
|
|
Loading…
Reference in New Issue