mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
This is the bulk of GPIO changes for the v4.17 kernel cycle:
New drivers: - Nintendo Wii GameCube GPIO, known as "Hollywood" - Raspberry Pi mailbox service GPIO expander - Spreadtrum main SC9860 SoC and IEC GPIO controllers. Improvements: - Implemented .get_multiple() callback for most of the high-performance industrial GPIO cards for the ISA bus. - ISA GPIO drivers now select the ISA_BUS_API instead of depending on it. This is merged with the same pattern for all the ISA drivers and some other Kconfig cleanups related to this. Cleanup: - Delete the TZ1090 GPIO drivers following the deletion of this SoC from the ARM tree. - Move the documentation over to driver-api to conform with the rest of the kernel documentation build. - Continue to make the GPIO drivers include only <linux/gpio/driver.h> and not the too broad <linux/gpio.h> that we want to get rid of. - Managed to remove VLA allocation from two drivers pending more fixes in this area for the next merge window. - Misc janitorial fixes. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJaxIehAAoJEEEQszewGV1zlEAP/3p3E6J8vPqJNV/C39c40krC ajo0ndiTC7cotmCXNQOl9xfMCTgkjBtx3WEKwTDfCsuWW+2YB0DRmMd0Bkf2RWjQ nM4rB64FzAu+rdD9jdGtfn24ofylSRFaHNQ/V8Prc2JVAXJt4DS97h+6kwzIAqCm A/xXQAx67k5qoTXLvR2n/8LX8TphSe2kwH/f/3/lJpNLfLCRRJ3GqJfpa72jw2eL 4VIPc6KmttkqzJ1GFtzLPfhkhRr0p4sSzUNydlj5BKhmOSVu6Afv5ylgpK/p38dQ mGvNqFnU0lpwelsoZK75YikDFbqQjn4XkXJGvmIRMw4qM7crcw5oSkeMwCrcGqJW 7Uo7NoQU94wcQSZTppFQdaJs7NHdcnpW7jcfRYYetZL/6eDGBtfxoym90Lyjvaqs y+ykofbadI0X/9omO5j+qozvIneLam/CF7iDRUb/5t1LJbNwtXUsVYhz3FuwPDt1 ZHb6w+np9ZHN6H9jz3b/F9B/uQt54pshm7NorSXrJvZfKrv8kV14MoHgYsuQDDjV khbveygB8DwaPeV4XjpLeYhJB1L/Wjf46CVD6tyaCRDByGQmdoJEQF9QB2CxrF2J ouaaaS8tSC0IK/mKMMgJxC1Vr2gh0NMlQ3AL9EJDJvX+9RoIA2gwtBAiGnlEcdq3 GyFAZ0szb5P4BaNnX9qc =C5t5 -----END PGP SIGNATURE----- Merge tag 'gpio-v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v4.17 kernel cycle: New drivers: - Nintendo Wii GameCube GPIO, known as "Hollywood" - Raspberry Pi mailbox service GPIO expander - Spreadtrum main SC9860 SoC and IEC GPIO controllers. Improvements: - Implemented .get_multiple() callback for most of the high-performance industrial GPIO cards for the ISA bus. - ISA GPIO drivers now select the ISA_BUS_API instead of depending on it. This is merged with the same pattern for all the ISA drivers and some other Kconfig cleanups related to this. Cleanup: - Delete the TZ1090 GPIO drivers following the deletion of this SoC from the ARM tree. - Move the documentation over to driver-api to conform with the rest of the kernel documentation build. - Continue to make the GPIO drivers include only <linux/gpio/driver.h> and not the too broad <linux/gpio.h> that we want to get rid of. - Managed to remove VLA allocation from two drivers pending more fixes in this area for the next merge window. - Misc janitorial fixes" * tag 'gpio-v4.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (77 commits) gpio: Add Spreadtrum PMIC EIC driver support gpio: Add Spreadtrum EIC driver support dt-bindings: gpio: Add Spreadtrum EIC controller documentation gpio: ath79: Fix potential NULL dereference in ath79_gpio_probe() pinctrl: qcom: Don't allow protected pins to be requested gpiolib: Support 'gpio-reserved-ranges' property gpiolib: Change bitmap allocation to kmalloc_array gpiolib: Extract mask allocation into subroutine dt-bindings: gpio: Add a gpio-reserved-ranges property gpio: mockup: fix a potential crash when creating debugfs entries gpio: pca953x: add compatibility for pcal6524 and pcal9555a gpio: dwapb: Add support for a bus clock gpio: Remove VLA from xra1403 driver gpio: Remove VLA from MAX3191X driver gpio: ws16c48: Implement get_multiple callback gpio: gpio-mm: Implement get_multiple callback gpio: 104-idi-48: Implement get_multiple callback gpio: 104-dio-48e: Implement get_multiple callback gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks gpio: pci-idio-16: Implement get_multiple callback ...
This commit is contained in:
commit
1b2951dd99
97
Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt
Normal file
97
Documentation/devicetree/bindings/gpio/gpio-eic-sprd.txt
Normal file
@ -0,0 +1,97 @@
|
||||
Spreadtrum EIC controller bindings
|
||||
|
||||
The EIC is the abbreviation of external interrupt controller, which can
|
||||
be used only in input mode. The Spreadtrum platform has 2 EIC controllers,
|
||||
one is in digital chip, and another one is in PMIC. The digital chip EIC
|
||||
controller contains 4 sub-modules: EIC-debounce, EIC-latch, EIC-async and
|
||||
EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub-
|
||||
module.
|
||||
|
||||
The EIC-debounce sub-module provides up to 8 source input signal
|
||||
connections. A debounce mechanism is used to capture the input signals'
|
||||
stable status (millisecond resolution) and a single-trigger mechanism
|
||||
is introduced into this sub-module to enhance the input event detection
|
||||
reliability. In addition, this sub-module's clock can be shut off
|
||||
automatically to reduce power dissipation. Moreover the debounce range
|
||||
is from 1ms to 4s with a step size of 1ms. The input signal will be
|
||||
ignored if it is asserted for less than 1 ms.
|
||||
|
||||
The EIC-latch sub-module is used to latch some special power down signals
|
||||
and generate interrupts, since the EIC-latch does not depend on the APB
|
||||
clock to capture signals.
|
||||
|
||||
The EIC-async sub-module uses a 32kHz clock to capture the short signals
|
||||
(microsecond resolution) to generate interrupts by level or edge trigger.
|
||||
|
||||
The EIC-sync is similar with GPIO's input function, which is a synchronized
|
||||
signal input register. It can generate interrupts by level or edge trigger
|
||||
when detecting input signals.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of the following:
|
||||
"sprd,sc9860-eic-debounce",
|
||||
"sprd,sc9860-eic-latch",
|
||||
"sprd,sc9860-eic-async",
|
||||
"sprd,sc9860-eic-sync",
|
||||
"sprd,sc27xx-eic".
|
||||
- reg: Define the base and range of the I/O address space containing
|
||||
the GPIO controller registers.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the gpio number and
|
||||
the second cell is used to specify optional parameters.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be <2>. Specifies the number of cells needed
|
||||
to encode interrupt source.
|
||||
- interrupts: Should be the port interrupt shared by all the gpios.
|
||||
|
||||
Example:
|
||||
eic_debounce: gpio@40210000 {
|
||||
compatible = "sprd,sc9860-eic-debounce";
|
||||
reg = <0 0x40210000 0 0x80>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_latch: gpio@40210080 {
|
||||
compatible = "sprd,sc9860-eic-latch";
|
||||
reg = <0 0x40210080 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_async: gpio@402100a0 {
|
||||
compatible = "sprd,sc9860-eic-async";
|
||||
reg = <0 0x402100a0 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
eic_sync: gpio@402100c0 {
|
||||
compatible = "sprd,sc9860-eic-sync";
|
||||
reg = <0 0x402100c0 0 0x20>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
|
||||
pmic_eic: gpio@300 {
|
||||
compatible = "sprd,sc27xx-eic";
|
||||
reg = <0x300>;
|
||||
interrupt-parent = <&sc2731_pmic>;
|
||||
interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
@ -16,6 +16,8 @@ Required properties:
|
||||
nxp,pca9574
|
||||
nxp,pca9575
|
||||
nxp,pca9698
|
||||
nxp,pcal6524
|
||||
nxp,pcal9555a
|
||||
maxim,max7310
|
||||
maxim,max7312
|
||||
maxim,max7313
|
||||
|
28
Documentation/devicetree/bindings/gpio/gpio-sprd.txt
Normal file
28
Documentation/devicetree/bindings/gpio/gpio-sprd.txt
Normal file
@ -0,0 +1,28 @@
|
||||
Spreadtrum GPIO controller bindings
|
||||
|
||||
The controller's registers are organized as sets of sixteen 16-bit
|
||||
registers with each set controlling a bank of up to 16 pins. A single
|
||||
interrupt is shared for all of the banks handled by the controller.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "sprd,sc9860-gpio".
|
||||
- reg: Define the base and range of the I/O address space containing
|
||||
the GPIO controller registers.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the gpio number and
|
||||
the second cell is used to specify optional parameters.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be <2>. Specifies the number of cells needed
|
||||
to encode interrupt source.
|
||||
- interrupts: Should be the port interrupt shared by all the gpios.
|
||||
|
||||
Example:
|
||||
ap_gpio: gpio@40280000 {
|
||||
compatible = "sprd,sc9860-gpio";
|
||||
reg = <0 0x40280000 0 0x1000>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
@ -1,45 +0,0 @@
|
||||
ImgTec TZ1090 PDC GPIO Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Compatible property value should be "img,tz1090-pdc-gpio".
|
||||
|
||||
- reg: Physical base address of the controller and length of memory mapped
|
||||
region. This starts at and cover the SOC_GPIO_CONTROL registers.
|
||||
|
||||
- gpio-controller: Specifies that the node is a gpio controller.
|
||||
|
||||
- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
|
||||
nodes should have the following values.
|
||||
<[phandle of the gpio controller node]
|
||||
[PDC gpio number]
|
||||
[gpio flags]>
|
||||
|
||||
Values for gpio specifier:
|
||||
- GPIO number: a value in the range 0 to 6.
|
||||
- GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>.
|
||||
Only the following flags are supported:
|
||||
GPIO_ACTIVE_HIGH
|
||||
GPIO_ACTIVE_LOW
|
||||
|
||||
Optional properties:
|
||||
- gpio-ranges: Mapping to pin controller pins (as described in
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt)
|
||||
|
||||
- interrupts: Individual syswake interrupts (other GPIOs cannot interrupt)
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
pdc_gpios: gpio-controller@2006500 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
compatible = "img,tz1090-pdc-gpio";
|
||||
reg = <0x02006500 0x100>;
|
||||
|
||||
interrupt-parent = <&pdc>;
|
||||
interrupts = <8 IRQ_TYPE_NONE>, /* Syswake 0 */
|
||||
<9 IRQ_TYPE_NONE>, /* Syswake 1 */
|
||||
<10 IRQ_TYPE_NONE>; /* Syswake 2 */
|
||||
gpio-ranges = <&pdc_pinctrl 0 0 7>;
|
||||
};
|
@ -1,88 +0,0 @@
|
||||
ImgTec TZ1090 GPIO Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Compatible property value should be "img,tz1090-gpio".
|
||||
|
||||
- reg: Physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- #address-cells: Should be 1 (for bank subnodes)
|
||||
|
||||
- #size-cells: Should be 0 (for bank subnodes)
|
||||
|
||||
- Each bank of GPIOs should have a subnode to represent it.
|
||||
|
||||
Bank subnode required properties:
|
||||
- reg: Index of bank in the range 0 to 2.
|
||||
|
||||
- gpio-controller: Specifies that the node is a gpio controller.
|
||||
|
||||
- #gpio-cells: Should be 2. The syntax of the gpio specifier used by client
|
||||
nodes should have the following values.
|
||||
<[phandle of the gpio controller node]
|
||||
[gpio number within the gpio bank]
|
||||
[gpio flags]>
|
||||
|
||||
Values for gpio specifier:
|
||||
- GPIO number: a value in the range 0 to 29.
|
||||
- GPIO flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>.
|
||||
Only the following flags are supported:
|
||||
GPIO_ACTIVE_HIGH
|
||||
GPIO_ACTIVE_LOW
|
||||
|
||||
Bank subnode optional properties:
|
||||
- gpio-ranges: Mapping to pin controller pins (as described in
|
||||
Documentation/devicetree/bindings/gpio/gpio.txt)
|
||||
|
||||
- interrupts: Interrupt for the entire bank
|
||||
|
||||
- interrupt-controller: Specifies that the node is an interrupt controller
|
||||
|
||||
- #interrupt-cells: Should be 2. The syntax of the interrupt specifier used by
|
||||
client nodes should have the following values.
|
||||
<[phandle of the interurupt controller]
|
||||
[gpio number within the gpio bank]
|
||||
[irq flags]>
|
||||
|
||||
Values for irq specifier:
|
||||
- GPIO number: a value in the range 0 to 29
|
||||
- IRQ flags: value to describe edge and level triggering, as defined in
|
||||
<dt-bindings/interrupt-controller/irq.h>. Only the following flags are
|
||||
supported:
|
||||
IRQ_TYPE_EDGE_RISING
|
||||
IRQ_TYPE_EDGE_FALLING
|
||||
IRQ_TYPE_EDGE_BOTH
|
||||
IRQ_TYPE_LEVEL_HIGH
|
||||
IRQ_TYPE_LEVEL_LOW
|
||||
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
gpios: gpio-controller@2005800 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "img,tz1090-gpio";
|
||||
reg = <0x02005800 0x90>;
|
||||
|
||||
/* bank 0 with an interrupt */
|
||||
gpios0: bank@0 {
|
||||
#gpio-cells = <2>;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0>;
|
||||
interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl 0 0 30>;
|
||||
interrupt-controller;
|
||||
};
|
||||
|
||||
/* bank 2 without interrupt */
|
||||
gpios2: bank@2 {
|
||||
#gpio-cells = <2>;
|
||||
reg = <2>;
|
||||
gpio-controller;
|
||||
gpio-ranges = <&pinctrl 0 60 30>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -151,9 +151,9 @@ in a lot of designs, some using all 32 bits, some using 18 and some using
|
||||
first 18 GPIOs, at local offset 0 .. 17, are in use.
|
||||
|
||||
If these GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an
|
||||
additional bitmask is needed to specify which GPIOs are actually in use,
|
||||
and which are dummies. The bindings for this case has not yet been
|
||||
specified, but should be specified if/when such hardware appears.
|
||||
additional set of tuples is needed to specify which GPIOs are unusable, with
|
||||
the gpio-reserved-ranges binding. This property indicates the start and size
|
||||
of the GPIOs that can't be used.
|
||||
|
||||
Optionally, a GPIO controller may have a "gpio-line-names" property. This is
|
||||
an array of strings defining the names of the GPIO lines going out of the
|
||||
@ -178,6 +178,7 @@ gpio-controller@00000000 {
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <18>;
|
||||
gpio-reserved-ranges = <0 4>, <12 2>;
|
||||
gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
|
||||
"LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
|
||||
"Row A", "Row B", "Row C", "Row D", "NMI button",
|
||||
|
@ -0,0 +1,27 @@
|
||||
Nintendo Wii (Hollywood) GPIO controller
|
||||
|
||||
Required properties:
|
||||
- compatible: "nintendo,hollywood-gpio
|
||||
- reg: Physical base address and length of the controller's registers.
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
- #gpio-cells: Should be <2>. The first cell is the pin number and the
|
||||
second cell is used to specify optional parameters:
|
||||
- bit 0 specifies polarity (0 for normal, 1 for inverted).
|
||||
|
||||
Optional properties:
|
||||
- ngpios: see Documentation/devicetree/bindings/gpio/gpio.txt
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Should be two.
|
||||
- interrupts: Interrupt specifier for the controller's Broadway (PowerPC)
|
||||
interrupt.
|
||||
- interrupt-parent: phandle of the parent interrupt controller.
|
||||
|
||||
Example:
|
||||
|
||||
GPIO: gpio@d8000c0 {
|
||||
#gpio-cells = <2>;
|
||||
compatible = "nintendo,hollywood-gpio";
|
||||
reg = <0x0d8000c0 0x40>;
|
||||
gpio-controller;
|
||||
ngpios = <24>;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
Raspberry Pi GPIO expander
|
||||
|
||||
The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware. The
|
||||
firmware exposes a mailbox interface that allows the ARM core to control the
|
||||
GPIO lines on the expander.
|
||||
|
||||
The Raspberry Pi GPIO expander node must be a child node of the Raspberry Pi
|
||||
firmware node.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be "raspberrypi,firmware-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:
|
||||
|
||||
firmware: firmware-rpi {
|
||||
compatible = "raspberrypi,bcm2835-firmware";
|
||||
mboxes = <&mailbox>;
|
||||
|
||||
expgpio: gpio {
|
||||
compatible = "raspberrypi,firmware-gpio";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
};
|
@ -152,14 +152,7 @@ Nintendo Wii device tree
|
||||
|
||||
1.l) The General Purpose I/O (GPIO) controller node
|
||||
|
||||
Represents the dual access 32 GPIO controller interface.
|
||||
|
||||
Required properties:
|
||||
|
||||
- #gpio-cells : <2>
|
||||
- compatible : should be "nintendo,hollywood-gpio"
|
||||
- reg : should contain the IPC registers location and length
|
||||
- gpio-controller
|
||||
see Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
|
||||
|
||||
1.m) The control node
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
=============
|
||||
GPIO Mappings
|
||||
=============
|
||||
|
||||
@ -23,7 +24,7 @@ device tree bindings for your controller.
|
||||
|
||||
GPIOs mappings are defined in the consumer device's node, in a property named
|
||||
<function>-gpios, where <function> is the function the driver will request
|
||||
through gpiod_get(). For example:
|
||||
through gpiod_get(). For example::
|
||||
|
||||
foo_device {
|
||||
compatible = "acme,foo";
|
||||
@ -40,7 +41,7 @@ it but are only supported for compatibility reasons and should not be used for
|
||||
newer bindings since it has been deprecated.
|
||||
|
||||
This property will make GPIOs 15, 16 and 17 available to the driver under the
|
||||
"led" function, and GPIO 1 as the "power" GPIO:
|
||||
"led" function, and GPIO 1 as the "power" GPIO::
|
||||
|
||||
struct gpio_desc *red, *green, *blue, *power;
|
||||
|
||||
@ -60,13 +61,13 @@ looked up by the gpiod functions internally) used in the device tree. With above
|
||||
|
||||
Internally, the GPIO subsystem prefixes the GPIO suffix ("gpios" or "gpio")
|
||||
with the string passed in con_id to get the resulting string
|
||||
(snprintf(... "%s-%s", con_id, gpio_suffixes[]).
|
||||
(``snprintf(... "%s-%s", con_id, gpio_suffixes[]``).
|
||||
|
||||
ACPI
|
||||
----
|
||||
ACPI also supports function names for GPIOs in a similar fashion to DT.
|
||||
The above DT example can be converted to an equivalent ACPI description
|
||||
with the help of _DSD (Device Specific Data), introduced in ACPI 5.1:
|
||||
with the help of _DSD (Device Specific Data), introduced in ACPI 5.1::
|
||||
|
||||
Device (FOO) {
|
||||
Name (_CRS, ResourceTemplate () {
|
||||
@ -105,12 +106,12 @@ Documentation/acpi/gpio-properties.txt.
|
||||
Platform Data
|
||||
-------------
|
||||
Finally, GPIOs can be bound to devices and functions using platform data. Board
|
||||
files that desire to do so need to include the following header:
|
||||
files that desire to do so need to include the following header::
|
||||
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
GPIOs are mapped by the means of tables of lookups, containing instances of the
|
||||
gpiod_lookup structure. Two macros are defined to help declaring such mappings:
|
||||
gpiod_lookup structure. Two macros are defined to help declaring such mappings::
|
||||
|
||||
GPIO_LOOKUP(chip_label, chip_hwnum, con_id, flags)
|
||||
GPIO_LOOKUP_IDX(chip_label, chip_hwnum, con_id, idx, flags)
|
||||
@ -141,22 +142,24 @@ end. The 'dev_id' field of the table is the identifier of the device that will
|
||||
make use of these GPIOs. It can be NULL, in which case it will be matched for
|
||||
calls to gpiod_get() with a NULL device.
|
||||
|
||||
struct gpiod_lookup_table gpios_table = {
|
||||
.dev_id = "foo.0",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
.. code-block:: c
|
||||
|
||||
And the table can be added by the board code as follows:
|
||||
struct gpiod_lookup_table gpios_table = {
|
||||
.dev_id = "foo.0",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
And the table can be added by the board code as follows::
|
||||
|
||||
gpiod_add_lookup_table(&gpios_table);
|
||||
|
||||
The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
|
||||
The driver controlling "foo.0" will then be able to obtain its GPIOs as follows::
|
||||
|
||||
struct gpio_desc *red, *green, *blue, *power;
|
||||
|
@ -1,3 +1,4 @@
|
||||
==================================
|
||||
GPIO Descriptor Consumer Interface
|
||||
==================================
|
||||
|
||||
@ -30,10 +31,10 @@ warnings. These stubs are used for two use cases:
|
||||
be met with console warnings that may be perceived as intimidating.
|
||||
|
||||
All the functions that work with the descriptor-based GPIO interface are
|
||||
prefixed with gpiod_. The gpio_ prefix is used for the legacy interface. No
|
||||
other function in the kernel should use these prefixes. The use of the legacy
|
||||
functions is strongly discouraged, new code should use <linux/gpio/consumer.h>
|
||||
and descriptors exclusively.
|
||||
prefixed with ``gpiod_``. The ``gpio_`` prefix is used for the legacy
|
||||
interface. No other function in the kernel should use these prefixes. The use
|
||||
of the legacy functions is strongly discouraged, new code should use
|
||||
<linux/gpio/consumer.h> and descriptors exclusively.
|
||||
|
||||
|
||||
Obtaining and Disposing GPIOs
|
||||
@ -43,13 +44,13 @@ With the descriptor-based interface, GPIOs are identified with an opaque,
|
||||
non-forgeable handler that must be obtained through a call to one of the
|
||||
gpiod_get() functions. Like many other kernel subsystems, gpiod_get() takes the
|
||||
device that will use the GPIO and the function the requested GPIO is supposed to
|
||||
fulfill:
|
||||
fulfill::
|
||||
|
||||
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
If a function is implemented by using several GPIOs together (e.g. a simple LED
|
||||
device that displays digits), an additional index argument can be specified:
|
||||
device that displays digits), an additional index argument can be specified::
|
||||
|
||||
struct gpio_desc *gpiod_get_index(struct device *dev,
|
||||
const char *con_id, unsigned int idx,
|
||||
@ -84,7 +85,7 @@ occurred while trying to acquire it. This is useful to discriminate between mere
|
||||
errors and an absence of GPIO for optional GPIO parameters. For the common
|
||||
pattern where a GPIO is optional, the gpiod_get_optional() and
|
||||
gpiod_get_index_optional() functions can be used. These functions return NULL
|
||||
instead of -ENOENT if no GPIO has been assigned to the requested function:
|
||||
instead of -ENOENT if no GPIO has been assigned to the requested function::
|
||||
|
||||
struct gpio_desc *gpiod_get_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
@ -101,14 +102,14 @@ This is helpful to driver authors, since they do not need to special case
|
||||
-ENOSYS return codes. System integrators should however be careful to enable
|
||||
gpiolib on systems that need it.
|
||||
|
||||
For a function using multiple GPIOs all of those can be obtained with one call:
|
||||
For a function using multiple GPIOs all of those can be obtained with one call::
|
||||
|
||||
struct gpio_descs *gpiod_get_array(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
This function returns a struct gpio_descs which contains an array of
|
||||
descriptors:
|
||||
descriptors::
|
||||
|
||||
struct gpio_descs {
|
||||
unsigned int ndescs;
|
||||
@ -116,13 +117,13 @@ descriptors:
|
||||
}
|
||||
|
||||
The following function returns NULL instead of -ENOENT if no GPIOs have been
|
||||
assigned to the requested function:
|
||||
assigned to the requested function::
|
||||
|
||||
struct gpio_descs *gpiod_get_array_optional(struct device *dev,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
Device-managed variants of these functions are also defined:
|
||||
Device-managed variants of these functions are also defined::
|
||||
|
||||
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
@ -149,11 +150,11 @@ Device-managed variants of these functions are also defined:
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags)
|
||||
|
||||
A GPIO descriptor can be disposed of using the gpiod_put() function:
|
||||
A GPIO descriptor can be disposed of using the gpiod_put() function::
|
||||
|
||||
void gpiod_put(struct gpio_desc *desc)
|
||||
|
||||
For an array of GPIOs this function can be used:
|
||||
For an array of GPIOs this function can be used::
|
||||
|
||||
void gpiod_put_array(struct gpio_descs *descs)
|
||||
|
||||
@ -161,7 +162,7 @@ It is strictly forbidden to use a descriptor after calling these functions.
|
||||
It is also not allowed to individually release descriptors (using gpiod_put())
|
||||
from an array acquired with gpiod_get_array().
|
||||
|
||||
The device-managed variants are, unsurprisingly:
|
||||
The device-managed variants are, unsurprisingly::
|
||||
|
||||
void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
|
||||
|
||||
@ -175,7 +176,7 @@ Setting Direction
|
||||
-----------------
|
||||
The first thing a driver must do with a GPIO is setting its direction. If no
|
||||
direction-setting flags have been given to gpiod_get*(), this is done by
|
||||
invoking one of the gpiod_direction_*() functions:
|
||||
invoking one of the gpiod_direction_*() functions::
|
||||
|
||||
int gpiod_direction_input(struct gpio_desc *desc)
|
||||
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||
@ -189,7 +190,7 @@ of early board setup.
|
||||
For output GPIOs, the value provided becomes the initial output value. This
|
||||
helps avoid signal glitching during system startup.
|
||||
|
||||
A driver can also query the current direction of a GPIO:
|
||||
A driver can also query the current direction of a GPIO::
|
||||
|
||||
int gpiod_get_direction(const struct gpio_desc *desc)
|
||||
|
||||
@ -206,7 +207,7 @@ Most GPIO controllers can be accessed with memory read/write instructions. Those
|
||||
don't need to sleep, and can safely be done from inside hard (non-threaded) IRQ
|
||||
handlers and similar contexts.
|
||||
|
||||
Use the following calls to access GPIOs from an atomic context:
|
||||
Use the following calls to access GPIOs from an atomic context::
|
||||
|
||||
int gpiod_get_value(const struct gpio_desc *desc);
|
||||
void gpiod_set_value(struct gpio_desc *desc, int value);
|
||||
@ -231,11 +232,11 @@ head of a queue to transmit a command and get its response. This requires
|
||||
sleeping, which can't be done from inside IRQ handlers.
|
||||
|
||||
Platforms that support this type of GPIO distinguish them from other GPIOs by
|
||||
returning nonzero from this call:
|
||||
returning nonzero from this call::
|
||||
|
||||
int gpiod_cansleep(const struct gpio_desc *desc)
|
||||
|
||||
To access such GPIOs, a different set of accessors is defined:
|
||||
To access such GPIOs, a different set of accessors is defined::
|
||||
|
||||
int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
||||
@ -271,23 +272,23 @@ As an example, if the active low property for a dedicated GPIO is set, and the
|
||||
gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level
|
||||
will be driven low.
|
||||
|
||||
To summarize:
|
||||
To summarize::
|
||||
|
||||
Function (example) line property physical line
|
||||
gpiod_set_raw_value(desc, 0); don't care low
|
||||
gpiod_set_raw_value(desc, 1); don't care high
|
||||
gpiod_set_value(desc, 0); default (active high) low
|
||||
gpiod_set_value(desc, 1); default (active high) high
|
||||
gpiod_set_value(desc, 0); active low high
|
||||
gpiod_set_value(desc, 1); active low low
|
||||
gpiod_set_value(desc, 0); default (active high) low
|
||||
gpiod_set_value(desc, 1); default (active high) high
|
||||
gpiod_set_value(desc, 0); open drain low
|
||||
gpiod_set_value(desc, 1); open drain high impedance
|
||||
gpiod_set_value(desc, 0); open source high impedance
|
||||
gpiod_set_value(desc, 1); open source high
|
||||
Function (example) line property physical line
|
||||
gpiod_set_raw_value(desc, 0); don't care low
|
||||
gpiod_set_raw_value(desc, 1); don't care high
|
||||
gpiod_set_value(desc, 0); default (active high) low
|
||||
gpiod_set_value(desc, 1); default (active high) high
|
||||
gpiod_set_value(desc, 0); active low high
|
||||
gpiod_set_value(desc, 1); active low low
|
||||
gpiod_set_value(desc, 0); default (active high) low
|
||||
gpiod_set_value(desc, 1); default (active high) high
|
||||
gpiod_set_value(desc, 0); open drain low
|
||||
gpiod_set_value(desc, 1); open drain high impedance
|
||||
gpiod_set_value(desc, 0); open source high impedance
|
||||
gpiod_set_value(desc, 1); open source high
|
||||
|
||||
It is possible to override these semantics using the *set_raw/'get_raw functions
|
||||
It is possible to override these semantics using the set_raw/get_raw functions
|
||||
but it should be avoided as much as possible, especially by system-agnostic drivers
|
||||
which should not need to care about the actual physical line level and worry about
|
||||
the logical value instead.
|
||||
@ -300,7 +301,7 @@ their device will actually receive, no matter what lies between it and the GPIO
|
||||
line.
|
||||
|
||||
The following set of calls ignore the active-low or open drain property of a GPIO and
|
||||
work on the raw line value:
|
||||
work on the raw line value::
|
||||
|
||||
int gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
||||
@ -308,7 +309,7 @@ work on the raw line 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::
|
||||
|
||||
int gpiod_is_active_low(const struct gpio_desc *desc)
|
||||
|
||||
@ -318,7 +319,7 @@ should not have to care about the physical line level or open drain semantics.
|
||||
|
||||
Access multiple GPIOs with a single function call
|
||||
-------------------------------------------------
|
||||
The following functions get or set the values of an array of GPIOs:
|
||||
The following functions get or set the values of an array of GPIOs::
|
||||
|
||||
int gpiod_get_array_value(unsigned int array_size,
|
||||
struct gpio_desc **desc_array,
|
||||
@ -361,7 +362,7 @@ The functions take three arguments:
|
||||
The descriptor array can be obtained using the gpiod_get_array() function
|
||||
or one of its variants. If the group of descriptors returned by that function
|
||||
matches the desired group of GPIOs, those GPIOs can be accessed by simply using
|
||||
the struct gpio_descs returned by gpiod_get_array():
|
||||
the struct gpio_descs returned by gpiod_get_array()::
|
||||
|
||||
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
|
||||
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
|
||||
@ -384,7 +385,7 @@ values are stored in value_array rather than passed back as return value.
|
||||
GPIOs mapped to IRQs
|
||||
--------------------
|
||||
GPIO lines can quite often be used as IRQs. You can get the IRQ number
|
||||
corresponding to a given GPIO using the following call:
|
||||
corresponding to a given GPIO using the following call::
|
||||
|
||||
int gpiod_to_irq(const struct gpio_desc *desc)
|
||||
|
||||
@ -424,7 +425,7 @@ Interacting With the Legacy GPIO Subsystem
|
||||
Many kernel subsystems still handle GPIOs using the legacy integer-based
|
||||
interface. Although it is strongly encouraged to upgrade them to the safer
|
||||
descriptor-based API, the following two functions allow you to convert a GPIO
|
||||
descriptor into the GPIO integer namespace and vice-versa:
|
||||
descriptor into the GPIO integer namespace and vice-versa::
|
||||
|
||||
int desc_to_gpio(const struct gpio_desc *desc)
|
||||
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
@ -1,3 +1,4 @@
|
||||
================================
|
||||
GPIO Descriptor Driver Interface
|
||||
================================
|
||||
|
||||
@ -53,9 +54,9 @@ common to each controller of that type:
|
||||
|
||||
The code implementing a gpio_chip should support multiple instances of the
|
||||
controller, possibly using the driver model. That code will configure each
|
||||
gpio_chip and issue gpiochip_add[_data]() or devm_gpiochip_add_data().
|
||||
Removing a GPIO controller should be rare; use [devm_]gpiochip_remove() when
|
||||
it is unavoidable.
|
||||
gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
|
||||
Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
|
||||
when it is unavoidable.
|
||||
|
||||
Often a gpio_chip is part of an instance-specific structure with states not
|
||||
exposed by the GPIO interfaces, such as addressing, power management, and more.
|
||||
@ -115,7 +116,7 @@ GPIOs with open drain/source support
|
||||
|
||||
Open drain (CMOS) or open collector (TTL) means the line is not actively driven
|
||||
high: instead you provide the drain/collector as output, so when the transistor
|
||||
is not open, it will present a high-impedance (tristate) to the external rail.
|
||||
is not open, it will present a high-impedance (tristate) to the external rail::
|
||||
|
||||
|
||||
CMOS CONFIGURATION TTL CONFIGURATION
|
||||
@ -148,19 +149,19 @@ level-shift to the higher VDD.
|
||||
Integrated electronics often have an output driver stage in the form of a CMOS
|
||||
"totem-pole" with one N-MOS and one P-MOS transistor where one of them drives
|
||||
the line high and one of them drives the line low. This is called a push-pull
|
||||
output. The "totem-pole" looks like so:
|
||||
output. The "totem-pole" looks like so::
|
||||
|
||||
VDD
|
||||
|
|
||||
OD ||--+
|
||||
+--/ ---o|| P-MOS-FET
|
||||
| ||--+
|
||||
IN --+ +----- out
|
||||
| ||--+
|
||||
+--/ ----|| N-MOS-FET
|
||||
OS ||--+
|
||||
|
|
||||
GND
|
||||
VDD
|
||||
|
|
||||
OD ||--+
|
||||
+--/ ---o|| P-MOS-FET
|
||||
| ||--+
|
||||
IN --+ +----- out
|
||||
| ||--+
|
||||
+--/ ----|| N-MOS-FET
|
||||
OS ||--+
|
||||
|
|
||||
GND
|
||||
|
||||
The desired output signal (e.g. coming directly from some GPIO output register)
|
||||
arrives at IN. The switches named "OD" and "OS" are normally closed, creating
|
||||
@ -219,8 +220,9 @@ systems simultaneously: gpio and irq.
|
||||
|
||||
RT_FULL: a realtime compliant GPIO driver should not use spinlock_t or any
|
||||
sleepable APIs (like PM runtime) as part of its irq_chip implementation.
|
||||
- spinlock_t should be replaced with raw_spinlock_t [1].
|
||||
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
|
||||
|
||||
* spinlock_t should be replaced with raw_spinlock_t [1].
|
||||
* If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
|
||||
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
|
||||
on an irqchip. Create the callbacks if needed [2].
|
||||
|
||||
@ -232,12 +234,12 @@ GPIO irqchips usually fall in one of two categories:
|
||||
system interrupt controller. This means that the GPIO irqchip handler will
|
||||
be called immediately from the parent irqchip, while holding the IRQs
|
||||
disabled. The GPIO irqchip will then end up calling something like this
|
||||
sequence in its interrupt handler:
|
||||
sequence in its interrupt handler::
|
||||
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
chained_irq_enter(...);
|
||||
generic_handle_irq(...);
|
||||
chained_irq_exit(...);
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
chained_irq_enter(...);
|
||||
generic_handle_irq(...);
|
||||
chained_irq_exit(...);
|
||||
|
||||
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
|
||||
struct gpio_chip, as everything happens directly in the callbacks: no
|
||||
@ -252,7 +254,7 @@ GPIO irqchips usually fall in one of two categories:
|
||||
(for example, see [3]).
|
||||
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
|
||||
so the IRQ core will complain if it is called from an IRQ handler which is
|
||||
forced to a thread. The "fake?" raw lock can be used to W/A this problem:
|
||||
forced to a thread. The "fake?" raw lock can be used to W/A this problem::
|
||||
|
||||
raw_spinlock_t wa_lock;
|
||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
||||
@ -265,11 +267,11 @@ GPIO irqchips usually fall in one of two categories:
|
||||
but chained IRQ handlers are not used. Instead GPIO IRQs dispatching is
|
||||
performed by generic IRQ handler which is configured using request_irq().
|
||||
The GPIO irqchip will then end up calling something like this sequence in
|
||||
its interrupt handler:
|
||||
its interrupt handler::
|
||||
|
||||
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
|
||||
for each detected GPIO IRQ
|
||||
generic_handle_irq(...);
|
||||
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
|
||||
for each detected GPIO IRQ
|
||||
generic_handle_irq(...);
|
||||
|
||||
RT_FULL: Such kind of handlers will be forced threaded on -RT, as result IRQ
|
||||
core will complain that generic_handle_irq() is called with IRQ enabled and
|
||||
@ -282,11 +284,11 @@ GPIO irqchips usually fall in one of two categories:
|
||||
in a quick IRQ handler with IRQs disabled. Instead they need to spawn a
|
||||
thread and then mask the parent IRQ line until the interrupt is handled
|
||||
by the driver. The hallmark of this driver is to call something like
|
||||
this in its interrupt handler:
|
||||
this in its interrupt handler::
|
||||
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
...
|
||||
handle_nested_irq(irq);
|
||||
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||
...
|
||||
handle_nested_irq(irq);
|
||||
|
||||
The hallmark of threaded GPIO irqchips is that they set the .can_sleep
|
||||
flag on struct gpio_chip to true, indicating that this chip may sleep
|
||||
@ -359,12 +361,12 @@ below exists.
|
||||
Locking IRQ usage
|
||||
-----------------
|
||||
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
||||
to mark the GPIO as being used as an IRQ:
|
||||
to mark the GPIO as being used as an IRQ::
|
||||
|
||||
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
|
||||
This will prevent the use of non-irq related GPIO APIs until the GPIO IRQ lock
|
||||
is released:
|
||||
is released::
|
||||
|
||||
void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
|
||||
@ -408,7 +410,7 @@ Sometimes it is useful to allow a GPIO chip driver to request its own GPIO
|
||||
descriptors through the gpiolib API. Using gpio_request() for this purpose
|
||||
does not help since it pins the module to the kernel forever (it calls
|
||||
try_module_get()). A GPIO driver can use the following functions instead
|
||||
to request and free descriptors without being pinned to the kernel forever.
|
||||
to request and free descriptors without being pinned to the kernel forever::
|
||||
|
||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
|
||||
const char *label)
|
||||
@ -422,6 +424,6 @@ These functions must be used with care since they do not affect module use
|
||||
count. Do not use the functions to request gpio descriptors not owned by the
|
||||
calling driver.
|
||||
|
||||
[1] http://www.spinics.net/lists/linux-omap/msg120425.html
|
||||
[2] https://lkml.org/lkml/2015/9/25/494
|
||||
[3] https://lkml.org/lkml/2015/9/25/495
|
||||
* [1] http://www.spinics.net/lists/linux-omap/msg120425.html
|
||||
* [2] https://lkml.org/lkml/2015/9/25/494
|
||||
* [3] https://lkml.org/lkml/2015/9/25/495
|
@ -1,3 +1,4 @@
|
||||
============================
|
||||
Subsystem drivers using GPIO
|
||||
============================
|
||||
|
@ -2,6 +2,18 @@
|
||||
General Purpose Input/Output (GPIO)
|
||||
===================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro
|
||||
driver
|
||||
consumer
|
||||
board
|
||||
drivers-on-gpio
|
||||
legacy
|
||||
|
||||
Core
|
||||
====
|
||||
|
||||
@ -11,15 +23,6 @@ Core
|
||||
.. kernel-doc:: drivers/gpio/gpiolib.c
|
||||
:export:
|
||||
|
||||
Legacy API
|
||||
==========
|
||||
|
||||
The functions listed in this section are deprecated. The GPIO descriptor based
|
||||
API described above should be used in new code.
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-legacy.c
|
||||
:export:
|
||||
|
||||
ACPI support
|
||||
============
|
||||
|
@ -1,3 +1,8 @@
|
||||
============
|
||||
Introduction
|
||||
============
|
||||
|
||||
|
||||
GPIO Interfaces
|
||||
===============
|
||||
|
||||
@ -9,9 +14,9 @@ Due to the history of GPIO interfaces in the kernel, there are two different
|
||||
ways to obtain and use GPIOs:
|
||||
|
||||
- The descriptor-based interface is the preferred way to manipulate GPIOs,
|
||||
and is described by all the files in this directory excepted gpio-legacy.txt.
|
||||
and is described by all the files in this directory excepted gpio-legacy.txt.
|
||||
- The legacy integer-based interface which is considered deprecated (but still
|
||||
usable for compatibility reasons) is documented in gpio-legacy.txt.
|
||||
usable for compatibility reasons) is documented in gpio-legacy.txt.
|
||||
|
||||
The remainder of this document applies to the new descriptor-based interface.
|
||||
gpio-legacy.txt contains the same information applied to the legacy
|
@ -1,4 +1,6 @@
|
||||
GPIO Interfaces
|
||||
======================
|
||||
Legacy GPIO Interfaces
|
||||
======================
|
||||
|
||||
This provides an overview of GPIO access conventions on Linux.
|
||||
|
||||
@ -129,7 +131,7 @@ The first thing a system should do with a GPIO is allocate it, using
|
||||
the gpio_request() call; see later.
|
||||
|
||||
One of the next things to do with a GPIO, often in board setup code when
|
||||
setting up a platform_device using the GPIO, is mark its direction:
|
||||
setting up a platform_device using the GPIO, is mark its direction::
|
||||
|
||||
/* set as input or output, returning 0 or negative errno */
|
||||
int gpio_direction_input(unsigned gpio);
|
||||
@ -164,7 +166,7 @@ Those don't need to sleep, and can safely be done from inside hard
|
||||
(nonthreaded) IRQ handlers and similar contexts.
|
||||
|
||||
Use the following calls to access such GPIOs,
|
||||
for which gpio_cansleep() will always return false (see below):
|
||||
for which gpio_cansleep() will always return false (see below)::
|
||||
|
||||
/* GPIO INPUT: return zero or nonzero */
|
||||
int gpio_get_value(unsigned gpio);
|
||||
@ -201,11 +203,11 @@ This requires sleeping, which can't be done from inside IRQ handlers.
|
||||
|
||||
Platforms that support this type of GPIO distinguish them from other GPIOs
|
||||
by returning nonzero from this call (which requires a valid GPIO number,
|
||||
which should have been previously allocated with gpio_request):
|
||||
which should have been previously allocated with gpio_request)::
|
||||
|
||||
int gpio_cansleep(unsigned gpio);
|
||||
|
||||
To access such GPIOs, a different set of accessors is defined:
|
||||
To access such GPIOs, a different set of accessors is defined::
|
||||
|
||||
/* GPIO INPUT: return zero or nonzero, might sleep */
|
||||
int gpio_get_value_cansleep(unsigned gpio);
|
||||
@ -222,27 +224,27 @@ Other than the fact that these accessors might sleep, and will work
|
||||
on GPIOs that can't be accessed from hardIRQ handlers, these calls act
|
||||
the same as the spinlock-safe calls.
|
||||
|
||||
** IN ADDITION ** calls to setup and configure such GPIOs must be made
|
||||
**IN ADDITION** calls to setup and configure such GPIOs must be made
|
||||
from contexts which may sleep, since they may need to access the GPIO
|
||||
controller chip too: (These setup calls are usually made from board
|
||||
setup or driver probe/teardown code, so this is an easy constraint.)
|
||||
controller chip too (These setup calls are usually made from board
|
||||
setup or driver probe/teardown code, so this is an easy constraint.)::
|
||||
|
||||
gpio_direction_input()
|
||||
gpio_direction_output()
|
||||
gpio_request()
|
||||
gpio_direction_input()
|
||||
gpio_direction_output()
|
||||
gpio_request()
|
||||
|
||||
## gpio_request_one()
|
||||
## gpio_request_array()
|
||||
## gpio_free_array()
|
||||
## gpio_request_one()
|
||||
## gpio_request_array()
|
||||
## gpio_free_array()
|
||||
|
||||
gpio_free()
|
||||
gpio_set_debounce()
|
||||
gpio_free()
|
||||
gpio_set_debounce()
|
||||
|
||||
|
||||
|
||||
Claiming and Releasing GPIOs
|
||||
----------------------------
|
||||
To help catch system configuration errors, two calls are defined.
|
||||
To help catch system configuration errors, two calls are defined::
|
||||
|
||||
/* request GPIO, returning 0 or negative errno.
|
||||
* non-null labels may be useful for diagnostics.
|
||||
@ -296,7 +298,7 @@ Also note that it's your responsibility to have stopped using a GPIO
|
||||
before you free it.
|
||||
|
||||
Considering in most cases GPIOs are actually configured right after they
|
||||
are claimed, three additional calls are defined:
|
||||
are claimed, three additional calls are defined::
|
||||
|
||||
/* request a single GPIO, with initial configuration specified by
|
||||
* 'flags', identical to gpio_request() wrt other arguments and
|
||||
@ -347,7 +349,7 @@ to make the pin LOW. The pin is make to HIGH by driving value 1 in output mode.
|
||||
In the future, these flags can be extended to support more properties.
|
||||
|
||||
Further more, to ease the claim/release of multiple GPIOs, 'struct gpio' is
|
||||
introduced to encapsulate all three fields as:
|
||||
introduced to encapsulate all three fields as::
|
||||
|
||||
struct gpio {
|
||||
unsigned gpio;
|
||||
@ -355,7 +357,7 @@ introduced to encapsulate all three fields as:
|
||||
const char *label;
|
||||
};
|
||||
|
||||
A typical example of usage:
|
||||
A typical example of usage::
|
||||
|
||||
static struct gpio leds_gpios[] = {
|
||||
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */
|
||||
@ -380,7 +382,7 @@ GPIOs mapped to IRQs
|
||||
--------------------
|
||||
GPIO numbers are unsigned integers; so are IRQ numbers. These make up
|
||||
two logically distinct namespaces (GPIO 0 need not use IRQ 0). You can
|
||||
map between them using calls like:
|
||||
map between them using calls like::
|
||||
|
||||
/* map GPIO numbers to IRQ numbers */
|
||||
int gpio_to_irq(unsigned gpio);
|
||||
@ -446,12 +448,12 @@ A GPIO controller on a SOC might be tightly coupled with the pinctrl
|
||||
subsystem, in the sense that the pins can be used by other functions
|
||||
together with an optional gpio feature. We have already covered the
|
||||
case where e.g. a GPIO controller need to reserve a pin or set the
|
||||
direction of a pin by calling any of:
|
||||
direction of a pin by calling any of::
|
||||
|
||||
pinctrl_gpio_request()
|
||||
pinctrl_gpio_free()
|
||||
pinctrl_gpio_direction_input()
|
||||
pinctrl_gpio_direction_output()
|
||||
pinctrl_gpio_request()
|
||||
pinctrl_gpio_free()
|
||||
pinctrl_gpio_direction_input()
|
||||
pinctrl_gpio_direction_output()
|
||||
|
||||
But how does the pin control subsystem cross-correlate the GPIO
|
||||
numbers (which are a global business) to a certain pin on a certain
|
||||
@ -565,7 +567,7 @@ If neither of these options are selected, the platform does not support
|
||||
GPIOs through GPIO-lib and the code cannot be enabled by the user.
|
||||
|
||||
Trivial implementations of those functions can directly use framework
|
||||
code, which always dispatches through the gpio_chip:
|
||||
code, which always dispatches through the gpio_chip::
|
||||
|
||||
#define gpio_get_value __gpio_get_value
|
||||
#define gpio_set_value __gpio_set_value
|
||||
@ -731,7 +733,7 @@ the correct GPIO number to use for a given signal.
|
||||
Exporting from Kernel code
|
||||
--------------------------
|
||||
Kernel code can explicitly manage exports of GPIOs which have already been
|
||||
requested using gpio_request():
|
||||
requested using gpio_request()::
|
||||
|
||||
/* export the GPIO to userspace */
|
||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||
@ -756,3 +758,13 @@ After the GPIO has been exported, gpio_export_link() allows creating
|
||||
symlinks from elsewhere in sysfs to the GPIO sysfs node. Drivers can
|
||||
use this to provide the interface under their own device in sysfs with
|
||||
a descriptive name.
|
||||
|
||||
|
||||
API Reference
|
||||
=============
|
||||
|
||||
The functions listed in this section are deprecated. The GPIO descriptor based
|
||||
API should be used in new code.
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-legacy.c
|
||||
:export:
|
@ -44,7 +44,7 @@ available subsections can be seen below.
|
||||
uio-howto
|
||||
firmware/index
|
||||
pinctl
|
||||
gpio
|
||||
gpio/index
|
||||
misc_devices
|
||||
dmaengine/index
|
||||
slimbus
|
||||
|
@ -1,17 +1,4 @@
|
||||
00-INDEX
|
||||
- This file
|
||||
gpio.txt
|
||||
- Introduction to GPIOs and their kernel interfaces
|
||||
consumer.txt
|
||||
- How to obtain and use GPIOs in a driver
|
||||
driver.txt
|
||||
- How to write a GPIO driver
|
||||
drivers-on-gpio.txt:
|
||||
- Drivers in other subsystems that can use GPIO to provide more
|
||||
complex functionality.
|
||||
board.txt
|
||||
- How to assign GPIOs to a consumer device and a function
|
||||
sysfs.txt
|
||||
- Information about the GPIO sysfs interface
|
||||
gpio-legacy.txt
|
||||
- Historical documentation of the deprecated GPIO integer interface
|
||||
|
@ -32,9 +32,8 @@ standard kernels won't know about. And for some tasks, simple userspace
|
||||
GPIO drivers could be all that the system really needs.
|
||||
|
||||
DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
|
||||
PLEASE READ THE DOCUMENT NAMED "drivers-on-gpio.txt" IN THIS DOCUMENTATION
|
||||
DIRECTORY TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT.
|
||||
REALLY.
|
||||
PLEASE READ THE DOCUMENT AT Documentation/driver-api/gpio/drivers-on-gpio.rst
|
||||
TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. REALLY.
|
||||
|
||||
Paths in Sysfs
|
||||
--------------
|
||||
|
@ -5984,7 +5984,7 @@ S: Maintained
|
||||
F: drivers/media/rc/gpio-ir-tx.c
|
||||
|
||||
GPIO MOCKUP DRIVER
|
||||
M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
|
||||
M: Bamvor Jian Zhang <bamv2005@gmail.com>
|
||||
R: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
@ -5997,6 +5997,7 @@ L: linux-gpio@vger.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/
|
||||
F: Documentation/driver-api/gpio/
|
||||
F: Documentation/gpio/
|
||||
F: Documentation/ABI/testing/gpio-cdev
|
||||
F: Documentation/ABI/obsolete/sysfs-gpio
|
||||
|
@ -2665,11 +2665,13 @@ config PCI_CNB20LE_QUIRK
|
||||
source "drivers/pci/Kconfig"
|
||||
|
||||
config ISA_BUS
|
||||
bool "ISA-style bus support on modern systems" if EXPERT
|
||||
select ISA_BUS_API
|
||||
bool "ISA bus support on modern systems" if EXPERT
|
||||
help
|
||||
Enables ISA-style drivers on modern systems. This is necessary to
|
||||
support PC/104 devices on X86_64 platforms.
|
||||
Expose ISA bus device drivers and options available for selection and
|
||||
configuration. Enable this option if your target machine has an ISA
|
||||
bus. ISA is an older system, displaced by PCI and newer bus
|
||||
architectures -- if your target machine is modern, it probably does
|
||||
not have an ISA bus.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -122,6 +122,17 @@ config GPIO_ATH79
|
||||
Select this option to enable GPIO driver for
|
||||
Atheros AR71XX/AR724X/AR913X SoC devices.
|
||||
|
||||
config GPIO_RASPBERRYPI_EXP
|
||||
tristate "Raspberry Pi 3 GPIO Expander"
|
||||
default RASPBERRYPI_FIRMWARE
|
||||
depends on OF_GPIO
|
||||
# Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only
|
||||
# happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE.
|
||||
depends on (ARCH_BCM2835 && RASPBERRYPI_FIRMWARE) || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
|
||||
help
|
||||
Turn on GPIO support for the expander on Raspberry Pi 3 boards, using
|
||||
the firmware mailbox to communicate with VideoCore on BCM283x chips.
|
||||
|
||||
config GPIO_BCM_KONA
|
||||
bool "Broadcom Kona GPIO"
|
||||
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
||||
@ -159,6 +170,14 @@ config GPIO_DWAPB
|
||||
Say Y or M here to build support for the Synopsys DesignWare APB
|
||||
GPIO block.
|
||||
|
||||
config GPIO_EIC_SPRD
|
||||
tristate "Spreadtrum EIC support"
|
||||
depends on ARCH_SPRD || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Spreadtrum EIC device.
|
||||
|
||||
config GPIO_EM
|
||||
tristate "Emma Mobile GPIO"
|
||||
depends on (ARCH_EMEV2 || COMPILE_TEST) && OF_GPIO
|
||||
@ -214,6 +233,15 @@ config GPIO_GRGPIO
|
||||
Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
|
||||
VHDL IP core library.
|
||||
|
||||
config GPIO_HLWD
|
||||
tristate "Nintendo Wii (Hollywood) GPIO"
|
||||
depends on OF_GPIO
|
||||
select GPIO_GENERIC
|
||||
help
|
||||
Select this to support the GPIO controller of the Nintendo Wii.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config GPIO_ICH
|
||||
tristate "Intel ICH GPIO"
|
||||
depends on PCI && X86
|
||||
@ -363,6 +391,14 @@ config GPIO_PL061
|
||||
help
|
||||
Say yes here to support the PrimeCell PL061 GPIO device
|
||||
|
||||
config GPIO_PMIC_EIC_SPRD
|
||||
tristate "Spreadtrum PMIC EIC support"
|
||||
depends on MFD_SC27XX_PMIC || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Spreadtrum PMIC EIC device.
|
||||
|
||||
config GPIO_PXA
|
||||
bool "PXA GPIO support"
|
||||
depends on ARCH_PXA || ARCH_MMP
|
||||
@ -389,6 +425,14 @@ config GPIO_SPEAR_SPICS
|
||||
help
|
||||
Say yes here to support ST SPEAr SPI Chip Select as GPIO device
|
||||
|
||||
config GPIO_SPRD
|
||||
tristate "Spreadtrum GPIO support"
|
||||
depends on ARCH_SPRD || COMPILE_TEST
|
||||
depends on OF_GPIO
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support Spreadtrum GPIO device.
|
||||
|
||||
config GPIO_STA2X11
|
||||
bool "STA2x11/ConneXt GPIO support"
|
||||
depends on MFD_STA2X11
|
||||
@ -453,21 +497,6 @@ config GPIO_THUNDERX
|
||||
Say yes here to support the on-chip GPIO lines on the ThunderX
|
||||
and OCTEON-TX families of SoCs.
|
||||
|
||||
config GPIO_TZ1090
|
||||
bool "Toumaz Xenif TZ1090 GPIO support"
|
||||
depends on SOC_TZ1090
|
||||
select GENERIC_IRQ_CHIP
|
||||
default y
|
||||
help
|
||||
Say yes here to support Toumaz Xenif TZ1090 GPIOs.
|
||||
|
||||
config GPIO_TZ1090_PDC
|
||||
bool "Toumaz Xenif TZ1090 PDC GPIO support"
|
||||
depends on SOC_TZ1090
|
||||
default y
|
||||
help
|
||||
Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs.
|
||||
|
||||
config GPIO_UNIPHIER
|
||||
tristate "UniPhier GPIO support"
|
||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||
@ -581,7 +610,8 @@ menu "Port-mapped I/O GPIO drivers"
|
||||
|
||||
config GPIO_104_DIO_48E
|
||||
tristate "ACCES 104-DIO-48E GPIO support"
|
||||
depends on PC104 && ISA_BUS_API
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
|
||||
@ -591,7 +621,8 @@ config GPIO_104_DIO_48E
|
||||
|
||||
config GPIO_104_IDIO_16
|
||||
tristate "ACCES 104-IDIO-16 GPIO support"
|
||||
depends on PC104 && ISA_BUS_API
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
|
||||
@ -602,7 +633,8 @@ config GPIO_104_IDIO_16
|
||||
|
||||
config GPIO_104_IDI_48
|
||||
tristate "ACCES 104-IDI-48 GPIO support"
|
||||
depends on PC104 && ISA_BUS_API
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
|
||||
@ -622,7 +654,8 @@ config GPIO_F7188X
|
||||
|
||||
config GPIO_GPIO_MM
|
||||
tristate "Diamond Systems GPIO-MM GPIO support"
|
||||
depends on PC104 && ISA_BUS_API
|
||||
depends on PC104
|
||||
select ISA_BUS_API
|
||||
help
|
||||
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
|
||||
|
||||
@ -691,7 +724,7 @@ config GPIO_TS5500
|
||||
|
||||
config GPIO_WINBOND
|
||||
tristate "Winbond Super I/O GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
select ISA_BUS_API
|
||||
help
|
||||
This option enables support for GPIOs found on Winbond Super I/O
|
||||
chips.
|
||||
@ -707,7 +740,7 @@ config GPIO_WINBOND
|
||||
|
||||
config GPIO_WS16C48
|
||||
tristate "WinSystems WS16C48 GPIO support"
|
||||
depends on ISA_BUS_API
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Enables GPIO support for the WinSystems WS16C48. The base port
|
||||
|
@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
|
||||
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
|
||||
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
|
||||
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
@ -44,6 +45,7 @@ obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
|
||||
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
|
||||
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
||||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||
obj-$(CONFIG_GPIO_EIC_SPRD) += gpio-eic-sprd.o
|
||||
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o
|
||||
@ -52,6 +54,7 @@ obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o
|
||||
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
|
||||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o
|
||||
obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
|
||||
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
|
||||
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
|
||||
obj-$(CONFIG_GPIO_INGENIC) += gpio-ingenic.o
|
||||
@ -97,6 +100,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16) += gpio-pci-idio-16.o
|
||||
obj-$(CONFIG_GPIO_PCIE_IDIO_24) += gpio-pcie-idio-24.o
|
||||
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
|
||||
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
|
||||
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
|
||||
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
|
||||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
|
||||
@ -107,6 +111,7 @@ obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
|
||||
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o
|
||||
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
|
||||
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
|
||||
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
|
||||
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
|
||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
||||
@ -130,8 +135,6 @@ obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
|
||||
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
|
||||
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
||||
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o
|
||||
obj-$(CONFIG_GPIO_TZ1090) += gpio-tz1090.o
|
||||
obj-$(CONFIG_GPIO_TZ1090_PDC) += gpio-tz1090-pdc.o
|
||||
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
|
||||
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
|
||||
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
|
||||
|
@ -14,6 +14,7 @@
|
||||
* This driver supports the following ACCES devices: 104-DIO-48E and
|
||||
* 104-DIO-24E.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -182,6 +183,51 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
return !!(port_state & mask);
|
||||
}
|
||||
|
||||
static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port */
|
||||
port_state = inb(dio48egpio->base + ports[i]);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
@ -384,6 +430,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
|
||||
dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
|
||||
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
|
||||
dio48egpio->chip.get = dio48e_gpio_get;
|
||||
dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
|
||||
dio48egpio->chip.set = dio48e_gpio_set;
|
||||
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
||||
dio48egpio->base = base[id];
|
||||
|
@ -14,6 +14,7 @@
|
||||
* This driver supports the following ACCES devices: 104-IDI-48A,
|
||||
* 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port */
|
||||
port_state = inb(idi48gpio->base + ports[i]);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idi_48_irq_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
@ -256,6 +302,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
|
||||
idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
|
||||
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
|
||||
idi48gpio->chip.get = idi_48_gpio_get;
|
||||
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
|
||||
idi48gpio->base = base[id];
|
||||
|
||||
raw_spin_lock_init(&idi48gpio->lock);
|
||||
|
@ -90,6 +90,20 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
return !!(inb(idio16gpio->base + 5) & (mask>>8));
|
||||
}
|
||||
|
||||
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
|
||||
|
||||
*bits = 0;
|
||||
if (*mask & GENMASK(23, 16))
|
||||
*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
|
||||
if (*mask & GENMASK(31, 24))
|
||||
*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
|
||||
@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
|
||||
idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
|
||||
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
||||
idio16gpio->chip.get = idio_16_gpio_get;
|
||||
idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
|
||||
idio16gpio->chip.set = idio_16_gpio_set;
|
||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||
idio16gpio->base = base[id];
|
||||
|
@ -258,6 +258,8 @@ static int ath79_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
ctrl->base = devm_ioremap_nocache(
|
||||
&pdev->dev, res->start, resource_size(res));
|
||||
if (!ctrl->base)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/gpio-davinci.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
@ -225,6 +226,11 @@ static int davinci_gpio_probe(struct platform_device *pdev)
|
||||
chips->chip.of_gpio_n_cells = 2;
|
||||
chips->chip.parent = dev;
|
||||
chips->chip.of_node = dev->of_node;
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
|
||||
chips->chip.request = gpiochip_generic_request;
|
||||
chips->chip.free = gpiochip_generic_free;
|
||||
}
|
||||
#endif
|
||||
spin_lock_init(&chips->lock);
|
||||
bank_base += ngpio;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
@ -204,9 +203,9 @@ static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
struct dln2_gpio *dln2 = gpiochip_get_data(chip);
|
||||
|
||||
if (test_bit(offset, dln2->output_enabled))
|
||||
return GPIOF_DIR_OUT;
|
||||
return 0;
|
||||
|
||||
return GPIOF_DIR_IN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
@ -218,7 +217,7 @@ static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
if (dir == GPIOF_DIR_IN)
|
||||
if (dir == 1)
|
||||
return dln2_gpio_pin_get_in_val(dln2, offset);
|
||||
|
||||
return dln2_gpio_pin_get_out_val(dln2, offset);
|
||||
|
@ -8,10 +8,9 @@
|
||||
* All enquiries to support@picochip.com
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
/* FIXME: for gpio_get_value(), replace this with direct register read */
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
@ -53,9 +52,9 @@
|
||||
#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)
|
||||
#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
|
||||
#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
|
||||
#define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */
|
||||
|
||||
#define GPIO_REG_OFFSET_V2 1
|
||||
|
||||
@ -100,6 +99,7 @@ struct dwapb_gpio {
|
||||
struct irq_domain *domain;
|
||||
unsigned int flags;
|
||||
struct reset_control *rst;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static inline u32 gpio_reg_v2_convert(unsigned int offset)
|
||||
@ -153,16 +153,40 @@ static int dwapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
return irq_find_mapping(gpio->domain, offset);
|
||||
}
|
||||
|
||||
static struct dwapb_gpio_port *dwapb_offs_to_port(struct dwapb_gpio *gpio, unsigned int offs)
|
||||
{
|
||||
struct dwapb_gpio_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
port = &gpio->ports[i];
|
||||
if (port->idx == offs / 32)
|
||||
return port;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
|
||||
{
|
||||
u32 v = dwapb_read(gpio, GPIO_INT_POLARITY);
|
||||
struct dwapb_gpio_port *port = dwapb_offs_to_port(gpio, offs);
|
||||
struct gpio_chip *gc;
|
||||
u32 pol;
|
||||
int val;
|
||||
|
||||
if (gpio_get_value(gpio->ports[0].gc.base + offs))
|
||||
v &= ~BIT(offs);
|
||||
if (!port)
|
||||
return;
|
||||
gc = &port->gc;
|
||||
|
||||
pol = dwapb_read(gpio, GPIO_INT_POLARITY);
|
||||
/* Just read the current value right out of the data register */
|
||||
val = gc->get(gc, offs % 32);
|
||||
if (val)
|
||||
pol &= ~BIT(offs);
|
||||
else
|
||||
v |= BIT(offs);
|
||||
pol |= BIT(offs);
|
||||
|
||||
dwapb_write(gpio, GPIO_INT_POLARITY, v);
|
||||
dwapb_write(gpio, GPIO_INT_POLARITY, pol);
|
||||
}
|
||||
|
||||
static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
|
||||
@ -476,11 +500,12 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE);
|
||||
set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE);
|
||||
dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_STRIDE);
|
||||
set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_STRIDE);
|
||||
dirout = gpio->regs + GPIO_SWPORTA_DDR +
|
||||
(pp->idx * GPIO_SWPORT_DDR_SIZE);
|
||||
(pp->idx * GPIO_SWPORT_DDR_STRIDE);
|
||||
|
||||
/* This registers 32 GPIO lines per port */
|
||||
err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
|
||||
NULL, 0);
|
||||
if (err) {
|
||||
@ -647,6 +672,16 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(gpio->regs))
|
||||
return PTR_ERR(gpio->regs);
|
||||
|
||||
/* Optional bus clock */
|
||||
gpio->clk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (!IS_ERR(gpio->clk)) {
|
||||
err = clk_prepare_enable(gpio->clk);
|
||||
if (err) {
|
||||
dev_info(&pdev->dev, "Cannot enable clock\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
gpio->flags = 0;
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *of_devid;
|
||||
@ -689,6 +724,7 @@ static int dwapb_gpio_remove(struct platform_device *pdev)
|
||||
dwapb_gpio_unregister(gpio);
|
||||
dwapb_irq_teardown(gpio);
|
||||
reset_control_assert(gpio->rst);
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -710,13 +746,13 @@ static int dwapb_gpio_suspend(struct device *dev)
|
||||
|
||||
BUG_ON(!ctx);
|
||||
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE;
|
||||
ctx->dir = dwapb_read(gpio, offset);
|
||||
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE;
|
||||
ctx->data = dwapb_read(gpio, offset);
|
||||
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE;
|
||||
ctx->ext = dwapb_read(gpio, offset);
|
||||
|
||||
/* Only port A can provide interrupts */
|
||||
@ -734,6 +770,8 @@ static int dwapb_gpio_suspend(struct device *dev)
|
||||
}
|
||||
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
clk_disable_unprepare(gpio->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -745,6 +783,9 @@ static int dwapb_gpio_resume(struct device *dev)
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
if (!IS_ERR(gpio->clk))
|
||||
clk_prepare_enable(gpio->clk);
|
||||
|
||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
for (i = 0; i < gpio->nr_ports; i++) {
|
||||
unsigned int offset;
|
||||
@ -753,13 +794,13 @@ static int dwapb_gpio_resume(struct device *dev)
|
||||
|
||||
BUG_ON(!ctx);
|
||||
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_SIZE;
|
||||
offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE;
|
||||
dwapb_write(gpio, offset, ctx->data);
|
||||
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_SIZE;
|
||||
offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE;
|
||||
dwapb_write(gpio, offset, ctx->dir);
|
||||
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_SIZE;
|
||||
offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE;
|
||||
dwapb_write(gpio, offset, ctx->ext);
|
||||
|
||||
/* Only port A can provide interrupts */
|
||||
|
606
drivers/gpio/gpio-eic-sprd.c
Normal file
606
drivers/gpio/gpio-eic-sprd.c
Normal file
@ -0,0 +1,606 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Spreadtrum Communications Inc.
|
||||
* Copyright (C) 2018 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* EIC registers definition */
|
||||
#define SPRD_EIC_DBNC_DATA 0x0
|
||||
#define SPRD_EIC_DBNC_DMSK 0x4
|
||||
#define SPRD_EIC_DBNC_IEV 0x14
|
||||
#define SPRD_EIC_DBNC_IE 0x18
|
||||
#define SPRD_EIC_DBNC_RIS 0x1c
|
||||
#define SPRD_EIC_DBNC_MIS 0x20
|
||||
#define SPRD_EIC_DBNC_IC 0x24
|
||||
#define SPRD_EIC_DBNC_TRIG 0x28
|
||||
#define SPRD_EIC_DBNC_CTRL0 0x40
|
||||
|
||||
#define SPRD_EIC_LATCH_INTEN 0x0
|
||||
#define SPRD_EIC_LATCH_INTRAW 0x4
|
||||
#define SPRD_EIC_LATCH_INTMSK 0x8
|
||||
#define SPRD_EIC_LATCH_INTCLR 0xc
|
||||
#define SPRD_EIC_LATCH_INTPOL 0x10
|
||||
#define SPRD_EIC_LATCH_INTMODE 0x14
|
||||
|
||||
#define SPRD_EIC_ASYNC_INTIE 0x0
|
||||
#define SPRD_EIC_ASYNC_INTRAW 0x4
|
||||
#define SPRD_EIC_ASYNC_INTMSK 0x8
|
||||
#define SPRD_EIC_ASYNC_INTCLR 0xc
|
||||
#define SPRD_EIC_ASYNC_INTMODE 0x10
|
||||
#define SPRD_EIC_ASYNC_INTBOTH 0x14
|
||||
#define SPRD_EIC_ASYNC_INTPOL 0x18
|
||||
#define SPRD_EIC_ASYNC_DATA 0x1c
|
||||
|
||||
#define SPRD_EIC_SYNC_INTIE 0x0
|
||||
#define SPRD_EIC_SYNC_INTRAW 0x4
|
||||
#define SPRD_EIC_SYNC_INTMSK 0x8
|
||||
#define SPRD_EIC_SYNC_INTCLR 0xc
|
||||
#define SPRD_EIC_SYNC_INTMODE 0x10
|
||||
#define SPRD_EIC_SYNC_INTBOTH 0x14
|
||||
#define SPRD_EIC_SYNC_INTPOL 0x18
|
||||
#define SPRD_EIC_SYNC_DATA 0x1c
|
||||
|
||||
/*
|
||||
* The digital-chip EIC controller can support maximum 3 banks, and each bank
|
||||
* contains 8 EICs.
|
||||
*/
|
||||
#define SPRD_EIC_MAX_BANK 3
|
||||
#define SPRD_EIC_PER_BANK_NR 8
|
||||
#define SPRD_EIC_DATA_MASK GENMASK(7, 0)
|
||||
#define SPRD_EIC_BIT(x) ((x) & (SPRD_EIC_PER_BANK_NR - 1))
|
||||
#define SPRD_EIC_DBNC_MASK GENMASK(11, 0)
|
||||
|
||||
/*
|
||||
* The Spreadtrum EIC (external interrupt controller) can be used only in
|
||||
* input mode to generate interrupts if detecting input signals.
|
||||
*
|
||||
* The Spreadtrum digital-chip EIC controller contains 4 sub-modules:
|
||||
* debounce EIC, latch EIC, async EIC and sync EIC,
|
||||
*
|
||||
* The debounce EIC is used to capture the input signals' stable status
|
||||
* (millisecond resolution) and a single-trigger mechanism is introduced
|
||||
* into this sub-module to enhance the input event detection reliability.
|
||||
* The debounce range is from 1ms to 4s with a step size of 1ms.
|
||||
*
|
||||
* The latch EIC is used to latch some special power down signals and
|
||||
* generate interrupts, since the latch EIC does not depend on the APB clock
|
||||
* to capture signals.
|
||||
*
|
||||
* The async EIC uses a 32k clock to capture the short signals (microsecond
|
||||
* resolution) to generate interrupts by level or edge trigger.
|
||||
*
|
||||
* The EIC-sync is similar with GPIO's input function, which is a synchronized
|
||||
* signal input register.
|
||||
*/
|
||||
enum sprd_eic_type {
|
||||
SPRD_EIC_DEBOUNCE,
|
||||
SPRD_EIC_LATCH,
|
||||
SPRD_EIC_ASYNC,
|
||||
SPRD_EIC_SYNC,
|
||||
SPRD_EIC_MAX,
|
||||
};
|
||||
|
||||
struct sprd_eic {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip intc;
|
||||
void __iomem *base[SPRD_EIC_MAX_BANK];
|
||||
enum sprd_eic_type type;
|
||||
spinlock_t lock;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct sprd_eic_variant_data {
|
||||
enum sprd_eic_type type;
|
||||
u32 num_eics;
|
||||
};
|
||||
|
||||
static const char *sprd_eic_label_name[SPRD_EIC_MAX] = {
|
||||
"eic-debounce", "eic-latch", "eic-async",
|
||||
"eic-sync",
|
||||
};
|
||||
|
||||
static const struct sprd_eic_variant_data sc9860_eic_dbnc_data = {
|
||||
.type = SPRD_EIC_DEBOUNCE,
|
||||
.num_eics = 8,
|
||||
};
|
||||
|
||||
static const struct sprd_eic_variant_data sc9860_eic_latch_data = {
|
||||
.type = SPRD_EIC_LATCH,
|
||||
.num_eics = 8,
|
||||
};
|
||||
|
||||
static const struct sprd_eic_variant_data sc9860_eic_async_data = {
|
||||
.type = SPRD_EIC_ASYNC,
|
||||
.num_eics = 8,
|
||||
};
|
||||
|
||||
static const struct sprd_eic_variant_data sc9860_eic_sync_data = {
|
||||
.type = SPRD_EIC_SYNC,
|
||||
.num_eics = 8,
|
||||
};
|
||||
|
||||
static inline void __iomem *sprd_eic_offset_base(struct sprd_eic *sprd_eic,
|
||||
unsigned int bank)
|
||||
{
|
||||
if (bank >= SPRD_EIC_MAX_BANK)
|
||||
return NULL;
|
||||
|
||||
return sprd_eic->base[bank];
|
||||
}
|
||||
|
||||
static void sprd_eic_update(struct gpio_chip *chip, unsigned int offset,
|
||||
u16 reg, unsigned int val)
|
||||
{
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
void __iomem *base =
|
||||
sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR);
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
spin_lock_irqsave(&sprd_eic->lock, flags);
|
||||
tmp = readl_relaxed(base + reg);
|
||||
|
||||
if (val)
|
||||
tmp |= BIT(SPRD_EIC_BIT(offset));
|
||||
else
|
||||
tmp &= ~BIT(SPRD_EIC_BIT(offset));
|
||||
|
||||
writel_relaxed(tmp, base + reg);
|
||||
spin_unlock_irqrestore(&sprd_eic->lock, flags);
|
||||
}
|
||||
|
||||
static int sprd_eic_read(struct gpio_chip *chip, unsigned int offset, u16 reg)
|
||||
{
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
void __iomem *base =
|
||||
sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR);
|
||||
|
||||
return !!(readl_relaxed(base + reg) & BIT(SPRD_EIC_BIT(offset)));
|
||||
}
|
||||
|
||||
static int sprd_eic_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_DMSK, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_eic_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_DMSK, 0);
|
||||
}
|
||||
|
||||
static int sprd_eic_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return sprd_eic_read(chip, offset, SPRD_EIC_DBNC_DATA);
|
||||
}
|
||||
|
||||
static int sprd_eic_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
/* EICs are always input, nothing need to do here. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_eic_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
/* EICs are always input, nothing need to do here. */
|
||||
}
|
||||
|
||||
static int sprd_eic_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned int debounce)
|
||||
{
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
void __iomem *base =
|
||||
sprd_eic_offset_base(sprd_eic, offset / SPRD_EIC_PER_BANK_NR);
|
||||
u32 reg = SPRD_EIC_DBNC_CTRL0 + SPRD_EIC_BIT(offset) * 0x4;
|
||||
u32 value = readl_relaxed(base + reg) & ~SPRD_EIC_DBNC_MASK;
|
||||
|
||||
value |= (debounce / 1000) & SPRD_EIC_DBNC_MASK;
|
||||
writel_relaxed(value, base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_eic_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
unsigned long param = pinconf_to_config_param(config);
|
||||
u32 arg = pinconf_to_config_argument(config);
|
||||
|
||||
if (param == PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return sprd_eic_set_debounce(chip, offset, arg);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static void sprd_eic_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IE, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_TRIG, 0);
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTEN, 0);
|
||||
break;
|
||||
case SPRD_EIC_ASYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTIE, 0);
|
||||
break;
|
||||
case SPRD_EIC_SYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTIE, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->parent, "Unsupported EIC type.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void sprd_eic_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IE, 1);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_TRIG, 1);
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTEN, 1);
|
||||
break;
|
||||
case SPRD_EIC_ASYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTIE, 1);
|
||||
break;
|
||||
case SPRD_EIC_SYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTIE, 1);
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->parent, "Unsupported EIC type.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void sprd_eic_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1);
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1);
|
||||
break;
|
||||
case SPRD_EIC_ASYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1);
|
||||
break;
|
||||
case SPRD_EIC_SYNC:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1);
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->parent, "Unsupported EIC type.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
case SPRD_EIC_ASYNC:
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
break;
|
||||
case SPRD_EIC_SYNC:
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1);
|
||||
sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
default:
|
||||
dev_err(chip->parent, "Unsupported EIC type.\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
|
||||
{
|
||||
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
|
||||
|
||||
return !strcmp(chip->label, sprd_eic_label_name[type]);
|
||||
}
|
||||
|
||||
static void sprd_eic_handle_one_type(struct gpio_chip *chip)
|
||||
{
|
||||
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
|
||||
u32 bank, n, girq;
|
||||
|
||||
for (bank = 0; bank * SPRD_EIC_PER_BANK_NR < chip->ngpio; bank++) {
|
||||
void __iomem *base = sprd_eic_offset_base(sprd_eic, bank);
|
||||
unsigned long reg;
|
||||
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
reg = readl_relaxed(base + SPRD_EIC_DBNC_MIS) &
|
||||
SPRD_EIC_DATA_MASK;
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
reg = readl_relaxed(base + SPRD_EIC_LATCH_INTMSK) &
|
||||
SPRD_EIC_DATA_MASK;
|
||||
break;
|
||||
case SPRD_EIC_ASYNC:
|
||||
reg = readl_relaxed(base + SPRD_EIC_ASYNC_INTMSK) &
|
||||
SPRD_EIC_DATA_MASK;
|
||||
break;
|
||||
case SPRD_EIC_SYNC:
|
||||
reg = readl_relaxed(base + SPRD_EIC_SYNC_INTMSK) &
|
||||
SPRD_EIC_DATA_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->parent, "Unsupported EIC type.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_set_bit(n, ®, SPRD_EIC_PER_BANK_NR) {
|
||||
girq = irq_find_mapping(chip->irq.domain,
|
||||
bank * SPRD_EIC_PER_BANK_NR + n);
|
||||
|
||||
generic_handle_irq(girq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sprd_eic_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct irq_chip *ic = irq_desc_get_chip(desc);
|
||||
struct gpio_chip *chip;
|
||||
enum sprd_eic_type type;
|
||||
|
||||
chained_irq_enter(ic, desc);
|
||||
|
||||
/*
|
||||
* Since the digital-chip EIC 4 sub-modules (debounce, latch, async
|
||||
* and sync) share one same interrupt line, we should iterate each
|
||||
* EIC module to check if there are EIC interrupts were triggered.
|
||||
*/
|
||||
for (type = SPRD_EIC_DEBOUNCE; type < SPRD_EIC_MAX; type++) {
|
||||
chip = gpiochip_find(&type, sprd_eic_match_chip_by_type);
|
||||
if (!chip)
|
||||
continue;
|
||||
|
||||
sprd_eic_handle_one_type(chip);
|
||||
}
|
||||
|
||||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static int sprd_eic_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct sprd_eic_variant_data *pdata;
|
||||
struct gpio_irq_chip *irq;
|
||||
struct sprd_eic *sprd_eic;
|
||||
struct resource *res;
|
||||
int ret, i;
|
||||
|
||||
pdata = of_device_get_match_data(&pdev->dev);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No matching driver data found.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sprd_eic = devm_kzalloc(&pdev->dev, sizeof(*sprd_eic), GFP_KERNEL);
|
||||
if (!sprd_eic)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&sprd_eic->lock);
|
||||
sprd_eic->type = pdata->type;
|
||||
|
||||
sprd_eic->irq = platform_get_irq(pdev, 0);
|
||||
if (sprd_eic->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get EIC interrupt.\n");
|
||||
return sprd_eic->irq;
|
||||
}
|
||||
|
||||
for (i = 0; i < SPRD_EIC_MAX_BANK; i++) {
|
||||
/*
|
||||
* We can have maximum 3 banks EICs, and each EIC has
|
||||
* its own base address. But some platform maybe only
|
||||
* have one bank EIC, thus base[1] and base[2] can be
|
||||
* optional.
|
||||
*/
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(sprd_eic->base[i]))
|
||||
return PTR_ERR(sprd_eic->base[i]);
|
||||
}
|
||||
|
||||
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
|
||||
sprd_eic->chip.ngpio = pdata->num_eics;
|
||||
sprd_eic->chip.base = -1;
|
||||
sprd_eic->chip.parent = &pdev->dev;
|
||||
sprd_eic->chip.of_node = pdev->dev.of_node;
|
||||
sprd_eic->chip.direction_input = sprd_eic_direction_input;
|
||||
switch (sprd_eic->type) {
|
||||
case SPRD_EIC_DEBOUNCE:
|
||||
sprd_eic->chip.request = sprd_eic_request;
|
||||
sprd_eic->chip.free = sprd_eic_free;
|
||||
sprd_eic->chip.set_config = sprd_eic_set_config;
|
||||
sprd_eic->chip.set = sprd_eic_set;
|
||||
/* fall-through */
|
||||
case SPRD_EIC_ASYNC:
|
||||
/* fall-through */
|
||||
case SPRD_EIC_SYNC:
|
||||
sprd_eic->chip.get = sprd_eic_get;
|
||||
break;
|
||||
case SPRD_EIC_LATCH:
|
||||
/* fall-through */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sprd_eic->intc.name = dev_name(&pdev->dev);
|
||||
sprd_eic->intc.irq_ack = sprd_eic_irq_ack;
|
||||
sprd_eic->intc.irq_mask = sprd_eic_irq_mask;
|
||||
sprd_eic->intc.irq_unmask = sprd_eic_irq_unmask;
|
||||
sprd_eic->intc.irq_set_type = sprd_eic_irq_set_type;
|
||||
sprd_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE;
|
||||
|
||||
irq = &sprd_eic->chip.irq;
|
||||
irq->chip = &sprd_eic->intc;
|
||||
irq->handler = handle_bad_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->parent_handler = sprd_eic_irq_handler;
|
||||
irq->parent_handler_data = sprd_eic;
|
||||
irq->num_parents = 1;
|
||||
irq->parents = &sprd_eic->irq;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &sprd_eic->chip, sprd_eic);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, sprd_eic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sprd_eic_of_match[] = {
|
||||
{
|
||||
.compatible = "sprd,sc9860-eic-debounce",
|
||||
.data = &sc9860_eic_dbnc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "sprd,sc9860-eic-latch",
|
||||
.data = &sc9860_eic_latch_data,
|
||||
},
|
||||
{
|
||||
.compatible = "sprd,sc9860-eic-async",
|
||||
.data = &sc9860_eic_async_data,
|
||||
},
|
||||
{
|
||||
.compatible = "sprd,sc9860-eic-sync",
|
||||
.data = &sc9860_eic_sync_data,
|
||||
},
|
||||
{
|
||||
/* end of list */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sprd_eic_of_match);
|
||||
|
||||
static struct platform_driver sprd_eic_driver = {
|
||||
.probe = sprd_eic_probe,
|
||||
.driver = {
|
||||
.name = "sprd-eic",
|
||||
.of_match_table = sprd_eic_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(sprd_eic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Spreadtrum EIC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -27,7 +27,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
@ -14,19 +14,20 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* GPIO registers definition */
|
||||
#define GPIO_DATA_OUT 0x00
|
||||
#define GPIO_DATA_IN 0x04
|
||||
#define GPIO_DIR 0x08
|
||||
#define GPIO_BYPASS_IN 0x0C
|
||||
#define GPIO_DATA_SET 0x10
|
||||
#define GPIO_DATA_CLR 0x14
|
||||
#define GPIO_PULL_EN 0x18
|
||||
#define GPIO_PULL_TYPE 0x1C
|
||||
#define GPIO_INT_EN 0x20
|
||||
#define GPIO_INT_STAT 0x24
|
||||
#define GPIO_INT_STAT_RAW 0x24
|
||||
#define GPIO_INT_STAT_MASKED 0x28
|
||||
#define GPIO_INT_MASK 0x2C
|
||||
#define GPIO_INT_CLR 0x30
|
||||
#define GPIO_INT_TYPE 0x34
|
||||
@ -147,7 +148,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
stat = readl(g->base + GPIO_INT_STAT);
|
||||
stat = readl(g->base + GPIO_INT_STAT_RAW);
|
||||
if (stat)
|
||||
for_each_set_bit(offset, &stat, gc->ngpio)
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
@ -14,6 +14,7 @@
|
||||
* This driver supports the following Diamond Systems devices: GPIO-MM and
|
||||
* GPIO-MM-12.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -171,6 +172,51 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
return !!(port_state & mask);
|
||||
}
|
||||
|
||||
static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port */
|
||||
port_state = inb(gpiommgpio->base + ports[i]);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
@ -268,6 +314,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
|
||||
gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
|
||||
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
|
||||
gpiommgpio->chip.get = gpiomm_gpio_get;
|
||||
gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
|
||||
gpiommgpio->chip.set = gpiomm_gpio_set;
|
||||
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
|
||||
gpiommgpio->base = base[id];
|
||||
|
@ -26,9 +26,8 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
115
drivers/gpio/gpio-hlwd.c
Normal file
115
drivers/gpio/gpio-hlwd.c
Normal file
@ -0,0 +1,115 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright (C) 2008-2009 The GameCube Linux Team
|
||||
// Copyright (C) 2008,2009 Albert Herranz
|
||||
// Copyright (C) 2017-2018 Jonathan Neuschäfer
|
||||
//
|
||||
// Nintendo Wii (Hollywood) GPIO driver
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/*
|
||||
* Register names and offsets courtesy of WiiBrew:
|
||||
* https://wiibrew.org/wiki/Hardware/Hollywood_GPIOs
|
||||
*
|
||||
* Note that for most registers, there are two versions:
|
||||
* - HW_GPIOB_* Is always accessible by the Broadway PowerPC core, but does
|
||||
* always give access to all GPIO lines
|
||||
* - HW_GPIO_* Is only accessible by the Broadway PowerPC code if the memory
|
||||
* firewall (AHBPROT) in the Hollywood chipset has been configured to allow
|
||||
* such access.
|
||||
*
|
||||
* The ownership of each GPIO line can be configured in the HW_GPIO_OWNER
|
||||
* register: A one bit configures the line for access via the HW_GPIOB_*
|
||||
* registers, a zero bit indicates access via HW_GPIO_*. This driver uses
|
||||
* HW_GPIOB_*.
|
||||
*/
|
||||
#define HW_GPIOB_OUT 0x00
|
||||
#define HW_GPIOB_DIR 0x04
|
||||
#define HW_GPIOB_IN 0x08
|
||||
#define HW_GPIOB_INTLVL 0x0c
|
||||
#define HW_GPIOB_INTFLAG 0x10
|
||||
#define HW_GPIOB_INTMASK 0x14
|
||||
#define HW_GPIOB_INMIR 0x18
|
||||
#define HW_GPIO_ENABLE 0x1c
|
||||
#define HW_GPIO_OUT 0x20
|
||||
#define HW_GPIO_DIR 0x24
|
||||
#define HW_GPIO_IN 0x28
|
||||
#define HW_GPIO_INTLVL 0x2c
|
||||
#define HW_GPIO_INTFLAG 0x30
|
||||
#define HW_GPIO_INTMASK 0x34
|
||||
#define HW_GPIO_INMIR 0x38
|
||||
#define HW_GPIO_OWNER 0x3c
|
||||
|
||||
struct hlwd_gpio {
|
||||
struct gpio_chip gpioc;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int hlwd_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct hlwd_gpio *hlwd;
|
||||
struct resource *regs_resource;
|
||||
u32 ngpios;
|
||||
int res;
|
||||
|
||||
hlwd = devm_kzalloc(&pdev->dev, sizeof(*hlwd), GFP_KERNEL);
|
||||
if (!hlwd)
|
||||
return -ENOMEM;
|
||||
|
||||
regs_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
hlwd->regs = devm_ioremap_resource(&pdev->dev, regs_resource);
|
||||
if (IS_ERR(hlwd->regs))
|
||||
return PTR_ERR(hlwd->regs);
|
||||
|
||||
/*
|
||||
* Claim all GPIOs using the OWNER register. This will not work on
|
||||
* systems where the AHBPROT memory firewall hasn't been configured to
|
||||
* permit PPC access to HW_GPIO_*.
|
||||
*
|
||||
* Note that this has to happen before bgpio_init reads the
|
||||
* HW_GPIOB_OUT and HW_GPIOB_DIR, because otherwise it reads the wrong
|
||||
* values.
|
||||
*/
|
||||
iowrite32be(0xffffffff, hlwd->regs + HW_GPIO_OWNER);
|
||||
|
||||
res = bgpio_init(&hlwd->gpioc, &pdev->dev, 4,
|
||||
hlwd->regs + HW_GPIOB_IN, hlwd->regs + HW_GPIOB_OUT,
|
||||
NULL, hlwd->regs + HW_GPIOB_DIR, NULL,
|
||||
BGPIOF_BIG_ENDIAN_BYTE_ORDER);
|
||||
if (res < 0) {
|
||||
dev_warn(&pdev->dev, "bgpio_init failed: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
res = of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios);
|
||||
if (res)
|
||||
ngpios = 32;
|
||||
hlwd->gpioc.ngpio = ngpios;
|
||||
|
||||
return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
|
||||
}
|
||||
|
||||
static const struct of_device_id hlwd_gpio_match[] = {
|
||||
{ .compatible = "nintendo,hollywood-gpio", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hlwd_gpio_match);
|
||||
|
||||
static struct platform_driver hlwd_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-hlwd",
|
||||
.of_match_table = hlwd_gpio_match,
|
||||
},
|
||||
.probe = hlwd_gpio_probe,
|
||||
};
|
||||
module_platform_driver(hlwd_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
|
||||
MODULE_DESCRIPTION("Nintendo Wii GPIO driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -18,6 +18,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
struct egpio_chip {
|
||||
int reg_start;
|
||||
|
@ -23,9 +23,10 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/lpc_ich.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define DRV_NAME "gpio_ich"
|
||||
|
||||
@ -131,9 +132,9 @@ static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
|
||||
ichx_priv.gpio_base);
|
||||
|
||||
if (val)
|
||||
data |= 1 << bit;
|
||||
data |= BIT(bit);
|
||||
else
|
||||
data &= ~(1 << bit);
|
||||
data &= ~BIT(bit);
|
||||
ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
|
||||
ichx_priv.gpio_base);
|
||||
if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
|
||||
@ -166,17 +167,17 @@ static int ichx_read_bit(int reg, unsigned nr)
|
||||
|
||||
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
||||
|
||||
return data & (1 << bit) ? 1 : 0;
|
||||
return !!(data & BIT(bit));
|
||||
}
|
||||
|
||||
static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr)
|
||||
{
|
||||
return !!(ichx_priv.use_gpio & (1 << (nr / 32)));
|
||||
return !!(ichx_priv.use_gpio & BIT(nr / 32));
|
||||
}
|
||||
|
||||
static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned nr)
|
||||
{
|
||||
return ichx_read_bit(GPIO_IO_SEL, nr) ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
|
||||
return ichx_read_bit(GPIO_IO_SEL, nr);
|
||||
}
|
||||
|
||||
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
||||
@ -232,12 +233,12 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
|
||||
spin_lock_irqsave(&ichx_priv.lock, flags);
|
||||
|
||||
/* GPI 0 - 15 are latched, write 1 to clear*/
|
||||
ICHX_WRITE(1 << (16 + nr), 0, ichx_priv.pm_base);
|
||||
ICHX_WRITE(BIT(16 + nr), 0, ichx_priv.pm_base);
|
||||
data = ICHX_READ(0, ichx_priv.pm_base);
|
||||
|
||||
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
||||
|
||||
return (data >> 16) & (1 << nr) ? 1 : 0;
|
||||
return !!((data >> 16) & BIT(nr));
|
||||
} else {
|
||||
return ichx_gpio_get(chip, nr);
|
||||
}
|
||||
@ -254,7 +255,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
|
||||
* the chipset's USE value can be trusted for this specific bit.
|
||||
* If it can't be trusted, assume that the pin can be used as a GPIO.
|
||||
*/
|
||||
if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
|
||||
if (ichx_priv.desc->use_sel_ignore[nr / 32] & BIT(nr & 0x1f))
|
||||
return 0;
|
||||
|
||||
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
|
||||
@ -394,7 +395,7 @@ static int ichx_gpio_request_regions(struct device *dev,
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
|
||||
if (!(use_gpio & (1 << i)))
|
||||
if (!(use_gpio & BIT(i)))
|
||||
continue;
|
||||
if (!devm_request_region(dev,
|
||||
res_base->start + ichx_priv.desc->regs[0][i],
|
||||
|
@ -361,10 +361,8 @@ static int intel_gpio_probe(struct pci_dev *pdev,
|
||||
pcim_iounmap_regions(pdev, 1 << 1);
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "can't allocate chip data\n");
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->reg_base = pcim_iomap_table(pdev)[0];
|
||||
priv->chip.label = dev_name(&pdev->dev);
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
|
||||
/* Chip Id numbers */
|
||||
#define NO_DEV_ID 0xffff
|
||||
|
@ -16,8 +16,9 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/mfd/janz.h>
|
||||
|
||||
@ -33,9 +34,9 @@
|
||||
#define MASTER_INT_CTL 0x00
|
||||
#define MASTER_CONF_CTL 0x01
|
||||
|
||||
#define CONF_PAE (1 << 2)
|
||||
#define CONF_PBE (1 << 7)
|
||||
#define CONF_PCE (1 << 4)
|
||||
#define CONF_PAE BIT(2)
|
||||
#define CONF_PBE BIT(7)
|
||||
#define CONF_PCE BIT(4)
|
||||
|
||||
struct ttl_control_regs {
|
||||
__be16 portc;
|
||||
@ -74,7 +75,7 @@ static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
|
||||
}
|
||||
|
||||
spin_lock(&mod->lock);
|
||||
ret = *shadow & (1 << offset);
|
||||
ret = *shadow & BIT(offset);
|
||||
spin_unlock(&mod->lock);
|
||||
return !!ret;
|
||||
}
|
||||
@ -100,9 +101,9 @@ static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
|
||||
|
||||
spin_lock(&mod->lock);
|
||||
if (value)
|
||||
*shadow |= (1 << offset);
|
||||
*shadow |= BIT(offset);
|
||||
else
|
||||
*shadow &= ~(1 << offset);
|
||||
*shadow &= ~BIT(offset);
|
||||
|
||||
iowrite16be(*shadow, port);
|
||||
spin_unlock(&mod->lock);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mfd/kempld.h>
|
||||
|
||||
#define KEMPLD_GPIO_MAX_NUM 16
|
||||
|
@ -18,7 +18,7 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -315,12 +315,17 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
|
||||
struct gpio_desc **desc,
|
||||
int value)
|
||||
{
|
||||
int i, values[ndescs];
|
||||
int i, *values;
|
||||
|
||||
values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL);
|
||||
if (!values)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ndescs; i++)
|
||||
values[i] = value;
|
||||
|
||||
gpiod_set_array_value_cansleep(ndescs, desc, values);
|
||||
kfree(values);
|
||||
}
|
||||
|
||||
static struct gpio_descs *devm_gpiod_get_array_optional_count(
|
||||
|
@ -416,10 +416,8 @@ static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id
|
||||
pcim_iounmap_regions(pdev, BIT(1));
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "can't allocate chip data\n");
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
priv->reg_base = pcim_iomap_table(pdev)[0];
|
||||
|
@ -445,7 +445,6 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
|
||||
chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL);
|
||||
if (chip_save == NULL) {
|
||||
dev_err(&pdev->dev, "%s : kzalloc failed", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto err_kzalloc;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
* GPIO Testing Device Driver
|
||||
*
|
||||
* Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com>
|
||||
* Copyright (C) 2015-2016 Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
|
||||
* Copyright (C) 2015-2016 Bamvor Jian Zhang <bamv2005@gmail.com>
|
||||
* Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -314,7 +314,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (gpio_mockup_dbg_dir)
|
||||
if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
|
||||
gpio_mockup_debugfs_setup(dev, chip);
|
||||
|
||||
return 0;
|
||||
@ -411,7 +411,7 @@ module_init(gpio_mockup_init);
|
||||
module_exit(gpio_mockup_exit);
|
||||
|
||||
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
|
||||
MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
|
||||
MODULE_AUTHOR("Bamvor Jian Zhang <bamv2005@gmail.com>");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
|
||||
MODULE_DESCRIPTION("GPIO Testing driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -1157,11 +1157,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
|
||||
if (!bank) {
|
||||
dev_err(dev, "Memory alloc failed\n");
|
||||
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
|
||||
if (!bank)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
|
||||
if (!irqc)
|
||||
|
@ -70,6 +70,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||
{ "pca9698", 40 | PCA953X_TYPE, },
|
||||
|
||||
{ "pcal6524", 24 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
|
||||
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
|
||||
|
||||
{ "max7310", 8 | PCA953X_TYPE, },
|
||||
@ -935,6 +936,9 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
||||
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
|
||||
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
||||
|
||||
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_INT), },
|
||||
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_INT), },
|
||||
|
||||
{ .compatible = "maxim,max7310", .data = OF_953X( 8, 0), },
|
||||
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
||||
{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
|
||||
|
@ -11,6 +11,7 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -103,6 +104,54 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
|
||||
}
|
||||
|
||||
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
u8 __iomem ports[] = {
|
||||
idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
|
||||
idio16gpio->reg->in0_7, idio16gpio->reg->in8_15,
|
||||
};
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port */
|
||||
port_state = ioread8(ports + i);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
@ -299,6 +348,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
|
||||
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
||||
idio16gpio->chip.get = idio_16_gpio_get;
|
||||
idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
|
||||
idio16gpio->chip.set = idio_16_gpio_set;
|
||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
* This driver supports the following ACCES devices: PCIe-IDIO-24,
|
||||
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -193,6 +194,61 @@ static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
|
||||
}
|
||||
|
||||
static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
u8 __iomem ports[] = {
|
||||
idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
|
||||
idio24gpio->reg->out16_23, idio24gpio->reg->in0_7,
|
||||
idio24gpio->reg->in8_15, idio24gpio->reg->in16_23,
|
||||
};
|
||||
const unsigned long out_mode_mask = BIT(1);
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port (port 6 is TTL GPIO) */
|
||||
if (i < 6)
|
||||
port_state = ioread8(ports + i);
|
||||
else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
|
||||
port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
|
||||
else
|
||||
port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
@ -234,6 +290,65 @@ static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
|
||||
size_t i;
|
||||
unsigned long bits_offset;
|
||||
unsigned long gpio_mask;
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
|
||||
unsigned long flags;
|
||||
unsigned int out_state;
|
||||
u8 __iomem ports[] = {
|
||||
idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
|
||||
idio24gpio->reg->out16_23
|
||||
};
|
||||
const unsigned long out_mode_mask = BIT(1);
|
||||
const unsigned int ttl_offset = 48;
|
||||
const size_t ttl_i = BIT_WORD(ttl_offset);
|
||||
const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
|
||||
const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
|
||||
const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
|
||||
|
||||
/* set bits are processed a gpio port register at a time */
|
||||
for (i = 0; i < ARRAY_SIZE(ports); i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* check if any set bits for current port */
|
||||
gpio_mask = (*mask >> bits_offset) & port_mask;
|
||||
if (!gpio_mask) {
|
||||
/* no set bits for this port so move on to next port */
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
|
||||
|
||||
/* process output lines */
|
||||
out_state = ioread8(ports + i) & ~gpio_mask;
|
||||
out_state |= (*bits >> bits_offset) & gpio_mask;
|
||||
iowrite8(out_state, ports + i);
|
||||
|
||||
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
|
||||
}
|
||||
|
||||
/* check if setting TTL lines and if they are in output mode */
|
||||
if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
|
||||
return;
|
||||
|
||||
/* handle TTL output */
|
||||
raw_spin_lock_irqsave(&idio24gpio->lock, flags);
|
||||
|
||||
/* process output lines */
|
||||
out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
|
||||
out_state |= ttl_bits;
|
||||
iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
|
||||
|
||||
raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
|
||||
}
|
||||
|
||||
static void idio_24_irq_ack(struct irq_data *data)
|
||||
{
|
||||
}
|
||||
@ -397,7 +512,9 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
|
||||
idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
|
||||
idio24gpio->chip.get = idio_24_gpio_get;
|
||||
idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
|
||||
idio24gpio->chip.set = idio_24_gpio_set;
|
||||
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
|
||||
|
||||
raw_spin_lock_init(&idio24gpio->lock);
|
||||
|
||||
|
330
drivers/gpio/gpio-pmic-eic-sprd.c
Normal file
330
drivers/gpio/gpio-pmic-eic-sprd.c
Normal file
@ -0,0 +1,330 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Spreadtrum Communications Inc.
|
||||
* Copyright (C) 2018 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* EIC registers definition */
|
||||
#define SPRD_PMIC_EIC_DATA 0x0
|
||||
#define SPRD_PMIC_EIC_DMSK 0x4
|
||||
#define SPRD_PMIC_EIC_IEV 0x14
|
||||
#define SPRD_PMIC_EIC_IE 0x18
|
||||
#define SPRD_PMIC_EIC_RIS 0x1c
|
||||
#define SPRD_PMIC_EIC_MIS 0x20
|
||||
#define SPRD_PMIC_EIC_IC 0x24
|
||||
#define SPRD_PMIC_EIC_TRIG 0x28
|
||||
#define SPRD_PMIC_EIC_CTRL0 0x40
|
||||
|
||||
/*
|
||||
* The PMIC EIC controller only has one bank, and each bank now can contain
|
||||
* 16 EICs.
|
||||
*/
|
||||
#define SPRD_PMIC_EIC_PER_BANK_NR 16
|
||||
#define SPRD_PMIC_EIC_NR SPRD_PMIC_EIC_PER_BANK_NR
|
||||
#define SPRD_PMIC_EIC_DATA_MASK GENMASK(15, 0)
|
||||
#define SPRD_PMIC_EIC_BIT(x) ((x) & (SPRD_PMIC_EIC_PER_BANK_NR - 1))
|
||||
#define SPRD_PMIC_EIC_DBNC_MASK GENMASK(11, 0)
|
||||
|
||||
/*
|
||||
* These registers are modified under the irq bus lock and cached to avoid
|
||||
* unnecessary writes in bus_sync_unlock.
|
||||
*/
|
||||
enum {
|
||||
REG_IEV,
|
||||
REG_IE,
|
||||
REG_TRIG,
|
||||
CACHE_NR_REGS
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sprd_pmic_eic - PMIC EIC controller
|
||||
* @chip: the gpio_chip structure.
|
||||
* @intc: the irq_chip structure.
|
||||
* @regmap: the regmap from the parent device.
|
||||
* @offset: the EIC controller's offset address of the PMIC.
|
||||
* @reg: the array to cache the EIC registers.
|
||||
* @buslock: for bus lock/sync and unlock.
|
||||
* @irq: the interrupt number of the PMIC EIC conteroller.
|
||||
*/
|
||||
struct sprd_pmic_eic {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip intc;
|
||||
struct regmap *map;
|
||||
u32 offset;
|
||||
u8 reg[CACHE_NR_REGS];
|
||||
struct mutex buslock;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static void sprd_pmic_eic_update(struct gpio_chip *chip, unsigned int offset,
|
||||
u16 reg, unsigned int val)
|
||||
{
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
u32 shift = SPRD_PMIC_EIC_BIT(offset);
|
||||
|
||||
regmap_update_bits(pmic_eic->map, pmic_eic->offset + reg,
|
||||
BIT(shift), val << shift);
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_read(struct gpio_chip *chip, unsigned int offset,
|
||||
u16 reg)
|
||||
{
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pmic_eic->map, pmic_eic->offset + reg, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(value & BIT(SPRD_PMIC_EIC_BIT(offset)));
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_DMSK, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_DMSK, 0);
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return sprd_pmic_eic_read(chip, offset, SPRD_PMIC_EIC_DATA);
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* EICs are always input, nothing need to do here. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
/* EICs are always input, nothing need to do here. */
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_set_debounce(struct gpio_chip *chip,
|
||||
unsigned int offset,
|
||||
unsigned int debounce)
|
||||
{
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
u32 reg, value;
|
||||
int ret;
|
||||
|
||||
reg = SPRD_PMIC_EIC_CTRL0 + SPRD_PMIC_EIC_BIT(offset) * 0x4;
|
||||
ret = regmap_read(pmic_eic->map, pmic_eic->offset + reg, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
value &= ~SPRD_PMIC_EIC_DBNC_MASK;
|
||||
value |= (debounce / 1000) & SPRD_PMIC_EIC_DBNC_MASK;
|
||||
return regmap_write(pmic_eic->map, pmic_eic->offset + reg, value);
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
unsigned long param = pinconf_to_config_param(config);
|
||||
u32 arg = pinconf_to_config_argument(config);
|
||||
|
||||
if (param == PIN_CONFIG_INPUT_DEBOUNCE)
|
||||
return sprd_pmic_eic_set_debounce(chip, offset, arg);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
|
||||
pmic_eic->reg[REG_IE] = 0;
|
||||
pmic_eic->reg[REG_TRIG] = 0;
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
|
||||
pmic_eic->reg[REG_IE] = 1;
|
||||
pmic_eic->reg[REG_TRIG] = 1;
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_irq_set_type(struct irq_data *data,
|
||||
unsigned int flow_type)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
pmic_eic->reg[REG_IEV] = 1;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
pmic_eic->reg[REG_IEV] = 0;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
|
||||
mutex_lock(&pmic_eic->buslock);
|
||||
}
|
||||
|
||||
static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
/* Set irq type */
|
||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV,
|
||||
pmic_eic->reg[REG_IEV]);
|
||||
/* Set irq unmask */
|
||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE,
|
||||
pmic_eic->reg[REG_IE]);
|
||||
/* Generate trigger start pulse for debounce EIC */
|
||||
sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_TRIG,
|
||||
pmic_eic->reg[REG_TRIG]);
|
||||
|
||||
mutex_unlock(&pmic_eic->buslock);
|
||||
}
|
||||
|
||||
static irqreturn_t sprd_pmic_eic_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct sprd_pmic_eic *pmic_eic = data;
|
||||
struct gpio_chip *chip = &pmic_eic->chip;
|
||||
unsigned long status;
|
||||
u32 n, girq, val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pmic_eic->map, pmic_eic->offset + SPRD_PMIC_EIC_MIS,
|
||||
&val);
|
||||
if (ret)
|
||||
return IRQ_RETVAL(ret);
|
||||
|
||||
status = val & SPRD_PMIC_EIC_DATA_MASK;
|
||||
|
||||
for_each_set_bit(n, &status, chip->ngpio) {
|
||||
/* Clear the interrupt */
|
||||
sprd_pmic_eic_update(chip, n, SPRD_PMIC_EIC_IC, 1);
|
||||
|
||||
girq = irq_find_mapping(chip->irq.domain, n);
|
||||
handle_nested_irq(girq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sprd_pmic_eic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_irq_chip *irq;
|
||||
struct sprd_pmic_eic *pmic_eic;
|
||||
int ret;
|
||||
|
||||
pmic_eic = devm_kzalloc(&pdev->dev, sizeof(*pmic_eic), GFP_KERNEL);
|
||||
if (!pmic_eic)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&pmic_eic->buslock);
|
||||
|
||||
pmic_eic->irq = platform_get_irq(pdev, 0);
|
||||
if (pmic_eic->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n");
|
||||
return pmic_eic->irq;
|
||||
}
|
||||
|
||||
pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!pmic_eic->map)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "reg", &pmic_eic->offset);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to get PMIC EIC base address.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, pmic_eic->irq, NULL,
|
||||
sprd_pmic_eic_irq_handler,
|
||||
IRQF_TRIGGER_LOW |
|
||||
IRQF_ONESHOT | IRQF_NO_SUSPEND,
|
||||
dev_name(&pdev->dev), pmic_eic);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to request PMIC EIC IRQ.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pmic_eic->chip.label = dev_name(&pdev->dev);
|
||||
pmic_eic->chip.ngpio = SPRD_PMIC_EIC_NR;
|
||||
pmic_eic->chip.base = -1;
|
||||
pmic_eic->chip.parent = &pdev->dev;
|
||||
pmic_eic->chip.of_node = pdev->dev.of_node;
|
||||
pmic_eic->chip.direction_input = sprd_pmic_eic_direction_input;
|
||||
pmic_eic->chip.request = sprd_pmic_eic_request;
|
||||
pmic_eic->chip.free = sprd_pmic_eic_free;
|
||||
pmic_eic->chip.set_config = sprd_pmic_eic_set_config;
|
||||
pmic_eic->chip.set = sprd_pmic_eic_set;
|
||||
pmic_eic->chip.get = sprd_pmic_eic_get;
|
||||
|
||||
pmic_eic->intc.name = dev_name(&pdev->dev);
|
||||
pmic_eic->intc.irq_mask = sprd_pmic_eic_irq_mask;
|
||||
pmic_eic->intc.irq_unmask = sprd_pmic_eic_irq_unmask;
|
||||
pmic_eic->intc.irq_set_type = sprd_pmic_eic_irq_set_type;
|
||||
pmic_eic->intc.irq_bus_lock = sprd_pmic_eic_bus_lock;
|
||||
pmic_eic->intc.irq_bus_sync_unlock = sprd_pmic_eic_bus_sync_unlock;
|
||||
pmic_eic->intc.flags = IRQCHIP_SKIP_SET_WAKE;
|
||||
|
||||
irq = &pmic_eic->chip.irq;
|
||||
irq->chip = &pmic_eic->intc;
|
||||
irq->threaded = true;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &pmic_eic->chip, pmic_eic);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pmic_eic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sprd_pmic_eic_of_match[] = {
|
||||
{ .compatible = "sprd,sc27xx-eic", },
|
||||
{ /* end of list */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sprd_pmic_eic_of_match);
|
||||
|
||||
static struct platform_driver sprd_pmic_eic_driver = {
|
||||
.probe = sprd_pmic_eic_probe,
|
||||
.driver = {
|
||||
.name = "sprd-pmic-eic",
|
||||
.of_match_table = sprd_pmic_eic_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(sprd_pmic_eic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Spreadtrum PMIC EIC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
252
drivers/gpio/gpio-raspberrypi-exp.c
Normal file
252
drivers/gpio/gpio-raspberrypi-exp.c
Normal file
@ -0,0 +1,252 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Raspberry Pi 3 expander GPIO driver
|
||||
*
|
||||
* Uses the firmware mailbox service to communicate with the
|
||||
* GPIO expander on the VPU.
|
||||
*
|
||||
* Copyright (C) 2017 Raspberry Pi Trading Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
|
||||
#define MODULE_NAME "raspberrypi-exp-gpio"
|
||||
#define NUM_GPIO 8
|
||||
|
||||
#define RPI_EXP_GPIO_BASE 128
|
||||
|
||||
#define RPI_EXP_GPIO_DIR_IN 0
|
||||
#define RPI_EXP_GPIO_DIR_OUT 1
|
||||
|
||||
struct rpi_exp_gpio {
|
||||
struct gpio_chip gc;
|
||||
struct rpi_firmware *fw;
|
||||
};
|
||||
|
||||
/* VC4 firmware mailbox interface data structures */
|
||||
|
||||
struct gpio_set_config {
|
||||
u32 gpio;
|
||||
u32 direction;
|
||||
u32 polarity;
|
||||
u32 term_en;
|
||||
u32 term_pull_up;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
struct gpio_get_config {
|
||||
u32 gpio;
|
||||
u32 direction;
|
||||
u32 polarity;
|
||||
u32 term_en;
|
||||
u32 term_pull_up;
|
||||
};
|
||||
|
||||
struct gpio_get_set_state {
|
||||
u32 gpio;
|
||||
u32 state;
|
||||
};
|
||||
|
||||
static int rpi_exp_gpio_get_polarity(struct gpio_chip *gc, unsigned int off)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_get_config get;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
|
||||
&get, sizeof(get));
|
||||
if (ret || get.gpio != 0) {
|
||||
dev_err(gc->parent, "Failed to get GPIO %u config (%d %x)\n",
|
||||
off, ret, get.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return get.polarity;
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_dir_in(struct gpio_chip *gc, unsigned int off)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_set_config set_in;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
set_in.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
set_in.direction = RPI_EXP_GPIO_DIR_IN;
|
||||
set_in.term_en = 0; /* termination disabled */
|
||||
set_in.term_pull_up = 0; /* n/a as termination disabled */
|
||||
set_in.state = 0; /* n/a as configured as an input */
|
||||
|
||||
ret = rpi_exp_gpio_get_polarity(gc, off);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
set_in.polarity = ret; /* Retain existing setting */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
|
||||
&set_in, sizeof(set_in));
|
||||
if (ret || set_in.gpio != 0) {
|
||||
dev_err(gc->parent, "Failed to set GPIO %u to input (%d %x)\n",
|
||||
off, ret, set_in.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_dir_out(struct gpio_chip *gc, unsigned int off, int val)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_set_config set_out;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
set_out.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
set_out.direction = RPI_EXP_GPIO_DIR_OUT;
|
||||
set_out.term_en = 0; /* n/a as an output */
|
||||
set_out.term_pull_up = 0; /* n/a as termination disabled */
|
||||
set_out.state = val; /* Output state */
|
||||
|
||||
ret = rpi_exp_gpio_get_polarity(gc, off);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
set_out.polarity = ret; /* Retain existing setting */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_CONFIG,
|
||||
&set_out, sizeof(set_out));
|
||||
if (ret || set_out.gpio != 0) {
|
||||
dev_err(gc->parent, "Failed to set GPIO %u to output (%d %x)\n",
|
||||
off, ret, set_out.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_get_config get;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_CONFIG,
|
||||
&get, sizeof(get));
|
||||
if (ret || get.gpio != 0) {
|
||||
dev_err(gc->parent,
|
||||
"Failed to get GPIO %u config (%d %x)\n", off, ret,
|
||||
get.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return !get.direction;
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_get(struct gpio_chip *gc, unsigned int off)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_get_set_state get;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
get.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
get.state = 0; /* storage for returned value */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_GET_GPIO_STATE,
|
||||
&get, sizeof(get));
|
||||
if (ret || get.gpio != 0) {
|
||||
dev_err(gc->parent,
|
||||
"Failed to get GPIO %u state (%d %x)\n", off, ret,
|
||||
get.gpio);
|
||||
return ret ? ret : -EIO;
|
||||
}
|
||||
return !!get.state;
|
||||
}
|
||||
|
||||
static void rpi_exp_gpio_set(struct gpio_chip *gc, unsigned int off, int val)
|
||||
{
|
||||
struct rpi_exp_gpio *gpio;
|
||||
struct gpio_get_set_state set;
|
||||
int ret;
|
||||
|
||||
gpio = gpiochip_get_data(gc);
|
||||
|
||||
set.gpio = off + RPI_EXP_GPIO_BASE; /* GPIO to update */
|
||||
set.state = val; /* Output state */
|
||||
|
||||
ret = rpi_firmware_property(gpio->fw, RPI_FIRMWARE_SET_GPIO_STATE,
|
||||
&set, sizeof(set));
|
||||
if (ret || set.gpio != 0)
|
||||
dev_err(gc->parent,
|
||||
"Failed to set GPIO %u state (%d %x)\n", off, ret,
|
||||
set.gpio);
|
||||
}
|
||||
|
||||
static int rpi_exp_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *fw_node;
|
||||
struct rpi_firmware *fw;
|
||||
struct rpi_exp_gpio *rpi_gpio;
|
||||
|
||||
fw_node = of_get_parent(np);
|
||||
if (!fw_node) {
|
||||
dev_err(dev, "Missing firmware node\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
fw = rpi_firmware_get(fw_node);
|
||||
if (!fw)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
rpi_gpio = devm_kzalloc(dev, sizeof(*rpi_gpio), GFP_KERNEL);
|
||||
if (!rpi_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
rpi_gpio->fw = fw;
|
||||
rpi_gpio->gc.parent = dev;
|
||||
rpi_gpio->gc.label = MODULE_NAME;
|
||||
rpi_gpio->gc.owner = THIS_MODULE;
|
||||
rpi_gpio->gc.of_node = np;
|
||||
rpi_gpio->gc.base = -1;
|
||||
rpi_gpio->gc.ngpio = NUM_GPIO;
|
||||
|
||||
rpi_gpio->gc.direction_input = rpi_exp_gpio_dir_in;
|
||||
rpi_gpio->gc.direction_output = rpi_exp_gpio_dir_out;
|
||||
rpi_gpio->gc.get_direction = rpi_exp_gpio_get_direction;
|
||||
rpi_gpio->gc.get = rpi_exp_gpio_get;
|
||||
rpi_gpio->gc.set = rpi_exp_gpio_set;
|
||||
rpi_gpio->gc.can_sleep = true;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &rpi_gpio->gc, rpi_gpio);
|
||||
}
|
||||
|
||||
static const struct of_device_id rpi_exp_gpio_ids[] = {
|
||||
{ .compatible = "raspberrypi,firmware-gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rpi_exp_gpio_ids);
|
||||
|
||||
static struct platform_driver rpi_exp_gpio_driver = {
|
||||
.driver = {
|
||||
.name = MODULE_NAME,
|
||||
.of_match_table = of_match_ptr(rpi_exp_gpio_ids),
|
||||
},
|
||||
.probe = rpi_exp_gpio_probe,
|
||||
};
|
||||
module_platform_driver(rpi_exp_gpio_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.org>");
|
||||
MODULE_DESCRIPTION("Raspberry Pi 3 expander GPIO driver");
|
||||
MODULE_ALIAS("platform:rpi-exp-gpio");
|
@ -30,6 +30,16 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct gpio_rcar_bank_info {
|
||||
u32 iointsel;
|
||||
u32 inoutsel;
|
||||
u32 outdt;
|
||||
u32 posneg;
|
||||
u32 edglevel;
|
||||
u32 bothedge;
|
||||
u32 intmsk;
|
||||
};
|
||||
|
||||
struct gpio_rcar_priv {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
@ -39,6 +49,7 @@ struct gpio_rcar_priv {
|
||||
unsigned int irq_parent;
|
||||
atomic_t wakeup_path;
|
||||
bool has_both_edge_trigger;
|
||||
struct gpio_rcar_bank_info bank_info;
|
||||
};
|
||||
|
||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||
@ -512,17 +523,62 @@ static int gpio_rcar_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused gpio_rcar_suspend(struct device *dev)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int gpio_rcar_suspend(struct device *dev)
|
||||
{
|
||||
struct gpio_rcar_priv *p = dev_get_drvdata(dev);
|
||||
|
||||
p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL);
|
||||
p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL);
|
||||
p->bank_info.outdt = gpio_rcar_read(p, OUTDT);
|
||||
p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
|
||||
p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
|
||||
p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
|
||||
if (p->has_both_edge_trigger)
|
||||
p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
|
||||
|
||||
if (atomic_read(&p->wakeup_path))
|
||||
device_set_wakeup_path(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL);
|
||||
static int gpio_rcar_resume(struct device *dev)
|
||||
{
|
||||
struct gpio_rcar_priv *p = dev_get_drvdata(dev);
|
||||
unsigned int offset;
|
||||
u32 mask;
|
||||
|
||||
for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
|
||||
mask = BIT(offset);
|
||||
/* I/O pin */
|
||||
if (!(p->bank_info.iointsel & mask)) {
|
||||
if (p->bank_info.inoutsel & mask)
|
||||
gpio_rcar_direction_output(
|
||||
&p->gpio_chip, offset,
|
||||
!!(p->bank_info.outdt & mask));
|
||||
else
|
||||
gpio_rcar_direction_input(&p->gpio_chip,
|
||||
offset);
|
||||
} else {
|
||||
/* Interrupt pin */
|
||||
gpio_rcar_config_interrupt_input_mode(
|
||||
p,
|
||||
offset,
|
||||
!(p->bank_info.posneg & mask),
|
||||
!(p->bank_info.edglevel & mask),
|
||||
!!(p->bank_info.bothedge & mask));
|
||||
|
||||
if (p->bank_info.intmsk & mask)
|
||||
gpio_rcar_write(p, MSKCLR, mask);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP*/
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume);
|
||||
|
||||
static struct platform_driver gpio_rcar_device_driver = {
|
||||
.probe = gpio_rcar_probe,
|
||||
|
290
drivers/gpio/gpio-sprd.c
Normal file
290
drivers/gpio/gpio-sprd.c
Normal file
@ -0,0 +1,290 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Spreadtrum Communications Inc.
|
||||
* Copyright (C) 2018 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* GPIO registers definition */
|
||||
#define SPRD_GPIO_DATA 0x0
|
||||
#define SPRD_GPIO_DMSK 0x4
|
||||
#define SPRD_GPIO_DIR 0x8
|
||||
#define SPRD_GPIO_IS 0xc
|
||||
#define SPRD_GPIO_IBE 0x10
|
||||
#define SPRD_GPIO_IEV 0x14
|
||||
#define SPRD_GPIO_IE 0x18
|
||||
#define SPRD_GPIO_RIS 0x1c
|
||||
#define SPRD_GPIO_MIS 0x20
|
||||
#define SPRD_GPIO_IC 0x24
|
||||
#define SPRD_GPIO_INEN 0x28
|
||||
|
||||
/* We have 16 banks GPIOs and each bank contain 16 GPIOs */
|
||||
#define SPRD_GPIO_BANK_NR 16
|
||||
#define SPRD_GPIO_NR 256
|
||||
#define SPRD_GPIO_BANK_SIZE 0x80
|
||||
#define SPRD_GPIO_BANK_MASK GENMASK(15, 0)
|
||||
#define SPRD_GPIO_BIT(x) ((x) & (SPRD_GPIO_BANK_NR - 1))
|
||||
|
||||
struct sprd_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static inline void __iomem *sprd_gpio_bank_base(struct sprd_gpio *sprd_gpio,
|
||||
unsigned int bank)
|
||||
{
|
||||
return sprd_gpio->base + SPRD_GPIO_BANK_SIZE * bank;
|
||||
}
|
||||
|
||||
static void sprd_gpio_update(struct gpio_chip *chip, unsigned int offset,
|
||||
u16 reg, int val)
|
||||
{
|
||||
struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base = sprd_gpio_bank_base(sprd_gpio,
|
||||
offset / SPRD_GPIO_BANK_NR);
|
||||
unsigned long flags;
|
||||
u32 tmp;
|
||||
|
||||
spin_lock_irqsave(&sprd_gpio->lock, flags);
|
||||
tmp = readl_relaxed(base + reg);
|
||||
|
||||
if (val)
|
||||
tmp |= BIT(SPRD_GPIO_BIT(offset));
|
||||
else
|
||||
tmp &= ~BIT(SPRD_GPIO_BIT(offset));
|
||||
|
||||
writel_relaxed(tmp, base + reg);
|
||||
spin_unlock_irqrestore(&sprd_gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int sprd_gpio_read(struct gpio_chip *chip, unsigned int offset, u16 reg)
|
||||
{
|
||||
struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
|
||||
void __iomem *base = sprd_gpio_bank_base(sprd_gpio,
|
||||
offset / SPRD_GPIO_BANK_NR);
|
||||
|
||||
return !!(readl_relaxed(base + reg) & BIT(SPRD_GPIO_BIT(offset)));
|
||||
}
|
||||
|
||||
static int sprd_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 0);
|
||||
}
|
||||
|
||||
static int sprd_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 1);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return sprd_gpio_read(chip, offset, SPRD_GPIO_DATA);
|
||||
}
|
||||
|
||||
static void sprd_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value);
|
||||
}
|
||||
|
||||
static void sprd_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 0);
|
||||
}
|
||||
|
||||
static void sprd_gpio_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
|
||||
}
|
||||
|
||||
static void sprd_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 1);
|
||||
}
|
||||
|
||||
static int sprd_gpio_irq_set_type(struct irq_data *data,
|
||||
unsigned int flow_type)
|
||||
{
|
||||
struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
|
||||
u32 offset = irqd_to_hwirq(data);
|
||||
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1);
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
|
||||
sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *chip = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *ic = irq_desc_get_chip(desc);
|
||||
struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
|
||||
u32 bank, n, girq;
|
||||
|
||||
chained_irq_enter(ic, desc);
|
||||
|
||||
for (bank = 0; bank * SPRD_GPIO_BANK_NR < chip->ngpio; bank++) {
|
||||
void __iomem *base = sprd_gpio_bank_base(sprd_gpio, bank);
|
||||
unsigned long reg = readl_relaxed(base + SPRD_GPIO_MIS) &
|
||||
SPRD_GPIO_BANK_MASK;
|
||||
|
||||
for_each_set_bit(n, ®, SPRD_GPIO_BANK_NR) {
|
||||
girq = irq_find_mapping(chip->irq.domain,
|
||||
bank * SPRD_GPIO_BANK_NR + n);
|
||||
|
||||
generic_handle_irq(girq);
|
||||
}
|
||||
|
||||
}
|
||||
chained_irq_exit(ic, desc);
|
||||
}
|
||||
|
||||
static struct irq_chip sprd_gpio_irqchip = {
|
||||
.name = "sprd-gpio",
|
||||
.irq_ack = sprd_gpio_irq_ack,
|
||||
.irq_mask = sprd_gpio_irq_mask,
|
||||
.irq_unmask = sprd_gpio_irq_unmask,
|
||||
.irq_set_type = sprd_gpio_irq_set_type,
|
||||
.flags = IRQCHIP_SKIP_SET_WAKE,
|
||||
};
|
||||
|
||||
static int sprd_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_irq_chip *irq;
|
||||
struct sprd_gpio *sprd_gpio;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL);
|
||||
if (!sprd_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
sprd_gpio->irq = platform_get_irq(pdev, 0);
|
||||
if (sprd_gpio->irq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n");
|
||||
return sprd_gpio->irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sprd_gpio->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(sprd_gpio->base))
|
||||
return PTR_ERR(sprd_gpio->base);
|
||||
|
||||
spin_lock_init(&sprd_gpio->lock);
|
||||
|
||||
sprd_gpio->chip.label = dev_name(&pdev->dev);
|
||||
sprd_gpio->chip.ngpio = SPRD_GPIO_NR;
|
||||
sprd_gpio->chip.base = -1;
|
||||
sprd_gpio->chip.parent = &pdev->dev;
|
||||
sprd_gpio->chip.of_node = pdev->dev.of_node;
|
||||
sprd_gpio->chip.request = sprd_gpio_request;
|
||||
sprd_gpio->chip.free = sprd_gpio_free;
|
||||
sprd_gpio->chip.get = sprd_gpio_get;
|
||||
sprd_gpio->chip.set = sprd_gpio_set;
|
||||
sprd_gpio->chip.direction_input = sprd_gpio_direction_input;
|
||||
sprd_gpio->chip.direction_output = sprd_gpio_direction_output;
|
||||
|
||||
irq = &sprd_gpio->chip.irq;
|
||||
irq->chip = &sprd_gpio_irqchip;
|
||||
irq->handler = handle_bad_irq;
|
||||
irq->default_type = IRQ_TYPE_NONE;
|
||||
irq->parent_handler = sprd_gpio_irq_handler;
|
||||
irq->parent_handler_data = sprd_gpio;
|
||||
irq->num_parents = 1;
|
||||
irq->parents = &sprd_gpio->irq;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &sprd_gpio->chip, sprd_gpio);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Could not register gpiochip %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, sprd_gpio);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sprd_gpio_of_match[] = {
|
||||
{ .compatible = "sprd,sc9860-gpio", },
|
||||
{ /* end of list */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sprd_gpio_of_match);
|
||||
|
||||
static struct platform_driver sprd_gpio_driver = {
|
||||
.probe = sprd_gpio_probe,
|
||||
.driver = {
|
||||
.name = "sprd-gpio",
|
||||
.of_match_table = sprd_gpio_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(sprd_gpio_driver, sprd_gpio_probe);
|
||||
|
||||
MODULE_DESCRIPTION("Spreadtrum GPIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -506,7 +506,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
static int dbg_gpio_show(struct seq_file *s, void *unused)
|
||||
static int tegra_dbg_gpio_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = s->private;
|
||||
unsigned int i, j;
|
||||
@ -530,22 +530,12 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dbg_gpio_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dbg_gpio_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations debug_fops = {
|
||||
.open = dbg_gpio_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio);
|
||||
|
||||
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
|
||||
{
|
||||
(void) debugfs_create_file("tegra_gpio", 0444,
|
||||
NULL, tgi, &debug_fops);
|
||||
NULL, tgi, &tegra_dbg_gpio_fops);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -238,11 +238,10 @@ static int timbgpio_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL);
|
||||
if (!tgpio) {
|
||||
dev_err(dev, "Memory alloc failed\n");
|
||||
tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL);
|
||||
if (!tgpio)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tgpio->irq_base = pdata->irq_base;
|
||||
|
||||
spin_lock_init(&tgpio->lock);
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* GPIO driver for TPS68470 PMIC
|
||||
*
|
||||
@ -8,15 +9,6 @@
|
||||
* Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
* Jian Xu Zheng <jian.xu.zheng@intel.com>
|
||||
* Yuning Pu <yuning.pu@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* 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/gpio/driver.h>
|
||||
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Toumaz Xenif TZ1090 PDC GPIO handling.
|
||||
*
|
||||
* Copyright (C) 2012-2013 Imagination Technologies Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <asm/global_lock.h>
|
||||
|
||||
/* Register offsets from SOC_GPIO_CONTROL0 */
|
||||
#define REG_SOC_GPIO_CONTROL0 0x00
|
||||
#define REG_SOC_GPIO_CONTROL1 0x04
|
||||
#define REG_SOC_GPIO_CONTROL2 0x08
|
||||
#define REG_SOC_GPIO_CONTROL3 0x0c
|
||||
#define REG_SOC_GPIO_STATUS 0x80
|
||||
|
||||
/* PDC GPIOs go after normal GPIOs */
|
||||
#define GPIO_PDC_BASE 90
|
||||
#define GPIO_PDC_NGPIO 7
|
||||
|
||||
/* Out of PDC gpios, only syswakes have irqs */
|
||||
#define GPIO_PDC_IRQ_FIRST 2
|
||||
#define GPIO_PDC_NIRQ 3
|
||||
|
||||
/**
|
||||
* struct tz1090_pdc_gpio - GPIO bank private data
|
||||
* @chip: Generic GPIO chip for GPIO bank
|
||||
* @reg: Base of registers, offset for this GPIO bank
|
||||
* @irq: IRQ numbers for Syswake GPIOs
|
||||
*
|
||||
* This is the main private data for the PDC GPIO driver. It encapsulates a
|
||||
* gpio_chip, and the callbacks for the gpio_chip can access the private data
|
||||
* with the to_pdc() macro below.
|
||||
*/
|
||||
struct tz1090_pdc_gpio {
|
||||
struct gpio_chip chip;
|
||||
void __iomem *reg;
|
||||
int irq[GPIO_PDC_NIRQ];
|
||||
};
|
||||
|
||||
/* Register accesses into the PDC MMIO area */
|
||||
|
||||
static inline void pdc_write(struct tz1090_pdc_gpio *priv, unsigned int reg_offs,
|
||||
unsigned int data)
|
||||
{
|
||||
writel(data, priv->reg + reg_offs);
|
||||
}
|
||||
|
||||
static inline unsigned int pdc_read(struct tz1090_pdc_gpio *priv,
|
||||
unsigned int reg_offs)
|
||||
{
|
||||
return readl(priv->reg + reg_offs);
|
||||
}
|
||||
|
||||
/* Generic GPIO interface */
|
||||
|
||||
static int tz1090_pdc_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
|
||||
u32 value;
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
|
||||
value |= BIT(offset);
|
||||
pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
|
||||
__global_unlock2(lstat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tz1090_pdc_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset,
|
||||
int output_value)
|
||||
{
|
||||
struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
|
||||
u32 value;
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
/* EXT_POWER doesn't seem to have an output value bit */
|
||||
if (offset < 6) {
|
||||
value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
|
||||
if (output_value)
|
||||
value |= BIT(offset);
|
||||
else
|
||||
value &= ~BIT(offset);
|
||||
pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
|
||||
}
|
||||
|
||||
value = pdc_read(priv, REG_SOC_GPIO_CONTROL1);
|
||||
value &= ~BIT(offset);
|
||||
pdc_write(priv, REG_SOC_GPIO_CONTROL1, value);
|
||||
__global_unlock2(lstat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tz1090_pdc_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
|
||||
return !!(pdc_read(priv, REG_SOC_GPIO_STATUS) & BIT(offset));
|
||||
}
|
||||
|
||||
static void tz1090_pdc_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int output_value)
|
||||
{
|
||||
struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
|
||||
u32 value;
|
||||
int lstat;
|
||||
|
||||
/* EXT_POWER doesn't seem to have an output value bit */
|
||||
if (offset >= 6)
|
||||
return;
|
||||
|
||||
__global_lock2(lstat);
|
||||
value = pdc_read(priv, REG_SOC_GPIO_CONTROL0);
|
||||
if (output_value)
|
||||
value |= BIT(offset);
|
||||
else
|
||||
value &= ~BIT(offset);
|
||||
pdc_write(priv, REG_SOC_GPIO_CONTROL0, value);
|
||||
__global_unlock2(lstat);
|
||||
}
|
||||
|
||||
static int tz1090_pdc_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_pdc_gpio *priv = gpiochip_get_data(chip);
|
||||
unsigned int syswake = offset - GPIO_PDC_IRQ_FIRST;
|
||||
int irq;
|
||||
|
||||
/* only syswakes have irqs */
|
||||
if (syswake >= GPIO_PDC_NIRQ)
|
||||
return -EINVAL;
|
||||
|
||||
irq = priv->irq[syswake];
|
||||
if (!irq)
|
||||
return -EINVAL;
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *res_regs;
|
||||
struct tz1090_pdc_gpio *priv;
|
||||
unsigned int i;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "must be instantiated via devicetree\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res_regs) {
|
||||
dev_err(&pdev->dev, "cannot find registers resource\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&pdev->dev, "unable to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Ioremap the registers */
|
||||
priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
|
||||
resource_size(res_regs));
|
||||
if (!priv->reg) {
|
||||
dev_err(&pdev->dev, "unable to ioremap registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Set up GPIO chip */
|
||||
priv->chip.label = "tz1090-pdc-gpio";
|
||||
priv->chip.parent = &pdev->dev;
|
||||
priv->chip.direction_input = tz1090_pdc_gpio_direction_input;
|
||||
priv->chip.direction_output = tz1090_pdc_gpio_direction_output;
|
||||
priv->chip.get = tz1090_pdc_gpio_get;
|
||||
priv->chip.set = tz1090_pdc_gpio_set;
|
||||
priv->chip.free = gpiochip_generic_free;
|
||||
priv->chip.request = gpiochip_generic_request;
|
||||
priv->chip.to_irq = tz1090_pdc_gpio_to_irq;
|
||||
priv->chip.of_node = np;
|
||||
|
||||
/* GPIO numbering */
|
||||
priv->chip.base = GPIO_PDC_BASE;
|
||||
priv->chip.ngpio = GPIO_PDC_NGPIO;
|
||||
|
||||
/* Map the syswake irqs */
|
||||
for (i = 0; i < GPIO_PDC_NIRQ; ++i)
|
||||
priv->irq[i] = irq_of_parse_and_map(np, i);
|
||||
|
||||
/* Add the GPIO bank */
|
||||
gpiochip_add_data(&priv->chip, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id tz1090_pdc_gpio_of_match[] = {
|
||||
{ .compatible = "img,tz1090-pdc-gpio" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver tz1090_pdc_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "tz1090-pdc-gpio",
|
||||
.of_match_table = tz1090_pdc_gpio_of_match,
|
||||
},
|
||||
.probe = tz1090_pdc_gpio_probe,
|
||||
};
|
||||
|
||||
static int __init tz1090_pdc_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&tz1090_pdc_gpio_driver);
|
||||
}
|
||||
subsys_initcall(tz1090_pdc_gpio_init);
|
@ -1,602 +0,0 @@
|
||||
/*
|
||||
* Toumaz Xenif TZ1090 GPIO handling.
|
||||
*
|
||||
* Copyright (C) 2008-2013 Imagination Technologies Ltd.
|
||||
*
|
||||
* Based on ARM PXA code and others.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <asm/global_lock.h>
|
||||
|
||||
/* Register offsets from bank base address */
|
||||
#define REG_GPIO_DIR 0x00
|
||||
#define REG_GPIO_IRQ_PLRT 0x20
|
||||
#define REG_GPIO_IRQ_TYPE 0x30
|
||||
#define REG_GPIO_IRQ_EN 0x40
|
||||
#define REG_GPIO_IRQ_STS 0x50
|
||||
#define REG_GPIO_BIT_EN 0x60
|
||||
#define REG_GPIO_DIN 0x70
|
||||
#define REG_GPIO_DOUT 0x80
|
||||
|
||||
/* REG_GPIO_IRQ_PLRT */
|
||||
#define REG_GPIO_IRQ_PLRT_LOW 0
|
||||
#define REG_GPIO_IRQ_PLRT_HIGH 1
|
||||
|
||||
/* REG_GPIO_IRQ_TYPE */
|
||||
#define REG_GPIO_IRQ_TYPE_LEVEL 0
|
||||
#define REG_GPIO_IRQ_TYPE_EDGE 1
|
||||
|
||||
/**
|
||||
* struct tz1090_gpio_bank - GPIO bank private data
|
||||
* @chip: Generic GPIO chip for GPIO bank
|
||||
* @domain: IRQ domain for GPIO bank (may be NULL)
|
||||
* @reg: Base of registers, offset for this GPIO bank
|
||||
* @irq: IRQ number for GPIO bank
|
||||
* @label: Debug GPIO bank label, used for storage of chip->label
|
||||
*
|
||||
* This is the main private data for a GPIO bank. It encapsulates a gpio_chip,
|
||||
* and the callbacks for the gpio_chip can access the private data with the
|
||||
* to_bank() macro below.
|
||||
*/
|
||||
struct tz1090_gpio_bank {
|
||||
struct gpio_chip chip;
|
||||
struct irq_domain *domain;
|
||||
void __iomem *reg;
|
||||
int irq;
|
||||
char label[16];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tz1090_gpio - Overall GPIO device private data
|
||||
* @dev: Device (from platform device)
|
||||
* @reg: Base of GPIO registers
|
||||
*
|
||||
* Represents the overall GPIO device. This structure is actually only
|
||||
* temporary, and used during init.
|
||||
*/
|
||||
struct tz1090_gpio {
|
||||
struct device *dev;
|
||||
void __iomem *reg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank
|
||||
* @priv: Overall GPIO device private data
|
||||
* @node: Device tree node specific to this GPIO bank
|
||||
* @index: Index of bank in range 0-2
|
||||
*/
|
||||
struct tz1090_gpio_bank_info {
|
||||
struct tz1090_gpio *priv;
|
||||
struct device_node *node;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
/* Convenience register accessors */
|
||||
static inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs, u32 data)
|
||||
{
|
||||
iowrite32(data, bank->reg + reg_offs);
|
||||
}
|
||||
|
||||
static inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs)
|
||||
{
|
||||
return ioread32(bank->reg + reg_offs);
|
||||
}
|
||||
|
||||
/* caller must hold LOCK2 */
|
||||
static inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = tz1090_gpio_read(bank, reg_offs);
|
||||
value &= ~BIT(offset);
|
||||
tz1090_gpio_write(bank, reg_offs, value);
|
||||
}
|
||||
|
||||
static void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset)
|
||||
{
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
_tz1090_gpio_clear_bit(bank, reg_offs, offset);
|
||||
__global_unlock2(lstat);
|
||||
}
|
||||
|
||||
/* caller must hold LOCK2 */
|
||||
static inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = tz1090_gpio_read(bank, reg_offs);
|
||||
value |= BIT(offset);
|
||||
tz1090_gpio_write(bank, reg_offs, value);
|
||||
}
|
||||
|
||||
static void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset)
|
||||
{
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
_tz1090_gpio_set_bit(bank, reg_offs, offset);
|
||||
__global_unlock2(lstat);
|
||||
}
|
||||
|
||||
/* caller must hold LOCK2 */
|
||||
static inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset,
|
||||
bool val)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = tz1090_gpio_read(bank, reg_offs);
|
||||
value &= ~BIT(offset);
|
||||
if (val)
|
||||
value |= BIT(offset);
|
||||
tz1090_gpio_write(bank, reg_offs, value);
|
||||
}
|
||||
|
||||
static void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset,
|
||||
bool val)
|
||||
{
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
_tz1090_gpio_mod_bit(bank, reg_offs, offset, val);
|
||||
__global_unlock2(lstat);
|
||||
}
|
||||
|
||||
static inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank,
|
||||
unsigned int reg_offs,
|
||||
unsigned int offset)
|
||||
{
|
||||
return tz1090_gpio_read(bank, reg_offs) & BIT(offset);
|
||||
}
|
||||
|
||||
/* GPIO chip callbacks */
|
||||
|
||||
static int tz1090_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tz1090_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int output_value)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
int lstat;
|
||||
|
||||
__global_lock2(lstat);
|
||||
_tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
|
||||
_tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset);
|
||||
__global_unlock2(lstat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return GPIO level
|
||||
*/
|
||||
static int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
|
||||
return !!tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set output GPIO level
|
||||
*/
|
||||
static void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int output_value)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
|
||||
tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
|
||||
}
|
||||
|
||||
static int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_gpio_request(chip->base + offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
|
||||
tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
|
||||
pinctrl_gpio_free(chip->base + offset);
|
||||
|
||||
tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset);
|
||||
}
|
||||
|
||||
static int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = gpiochip_get_data(chip);
|
||||
|
||||
if (!bank->domain)
|
||||
return -EINVAL;
|
||||
|
||||
return irq_create_mapping(bank->domain, offset);
|
||||
}
|
||||
|
||||
/* IRQ chip handlers */
|
||||
|
||||
/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */
|
||||
static inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data)
|
||||
{
|
||||
return (struct tz1090_gpio_bank *)data->domain->host_data;
|
||||
}
|
||||
|
||||
static void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank,
|
||||
unsigned int offset, unsigned int polarity)
|
||||
{
|
||||
tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity);
|
||||
}
|
||||
|
||||
static void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank,
|
||||
unsigned int offset, unsigned int type)
|
||||
{
|
||||
tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type);
|
||||
}
|
||||
|
||||
/* set polarity to trigger on next edge, whether rising or falling */
|
||||
static void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank,
|
||||
unsigned int offset)
|
||||
{
|
||||
unsigned int value_p, value_i;
|
||||
int lstat;
|
||||
|
||||
/*
|
||||
* Set the GPIO's interrupt polarity to the opposite of the current
|
||||
* input value so that the next edge triggers an interrupt.
|
||||
*/
|
||||
__global_lock2(lstat);
|
||||
value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN);
|
||||
value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT);
|
||||
value_p &= ~BIT(offset);
|
||||
value_p |= value_i & BIT(offset);
|
||||
tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p);
|
||||
__global_unlock2(lstat);
|
||||
}
|
||||
|
||||
static unsigned int gpio_startup_irq(struct irq_data *data)
|
||||
{
|
||||
/*
|
||||
* This warning indicates that the type of the irq hasn't been set
|
||||
* before enabling the irq. This would normally be done by passing some
|
||||
* trigger flags to request_irq().
|
||||
*/
|
||||
WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE,
|
||||
"irq type not set before enabling gpio irq %d", data->irq);
|
||||
|
||||
irq_gc_ack_clr_bit(data);
|
||||
irq_gc_mask_set_bit(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
|
||||
unsigned int type;
|
||||
unsigned int polarity;
|
||||
|
||||
switch (flow_type) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
type = REG_GPIO_IRQ_TYPE_EDGE;
|
||||
polarity = REG_GPIO_IRQ_PLRT_LOW;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
type = REG_GPIO_IRQ_TYPE_EDGE;
|
||||
polarity = REG_GPIO_IRQ_PLRT_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
type = REG_GPIO_IRQ_TYPE_EDGE;
|
||||
polarity = REG_GPIO_IRQ_PLRT_LOW;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
type = REG_GPIO_IRQ_TYPE_LEVEL;
|
||||
polarity = REG_GPIO_IRQ_PLRT_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
type = REG_GPIO_IRQ_TYPE_LEVEL;
|
||||
polarity = REG_GPIO_IRQ_PLRT_LOW;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tz1090_gpio_irq_type(bank, data->hwirq, type);
|
||||
irq_setup_alt_chip(data, flow_type);
|
||||
|
||||
if (flow_type == IRQ_TYPE_EDGE_BOTH)
|
||||
tz1090_gpio_irq_next_edge(bank, data->hwirq);
|
||||
else
|
||||
tz1090_gpio_irq_polarity(bank, data->hwirq, polarity);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
static int gpio_set_irq_wake(struct irq_data *data, unsigned int on)
|
||||
{
|
||||
struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
|
||||
|
||||
#ifdef CONFIG_PM_DEBUG
|
||||
pr_info("irq_wake irq%d state:%d\n", data->irq, on);
|
||||
#endif
|
||||
|
||||
/* wake on gpio block interrupt */
|
||||
return irq_set_irq_wake(bank->irq, on);
|
||||
}
|
||||
#else
|
||||
#define gpio_set_irq_wake NULL
|
||||
#endif
|
||||
|
||||
static void tz1090_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
irq_hw_number_t hw;
|
||||
unsigned int irq_stat, irq_no;
|
||||
struct tz1090_gpio_bank *bank;
|
||||
struct irq_desc *child_desc;
|
||||
|
||||
bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc);
|
||||
irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) &
|
||||
tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) &
|
||||
tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) &
|
||||
0x3FFFFFFF; /* 30 bits only */
|
||||
|
||||
for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) {
|
||||
if (!(irq_stat & 1))
|
||||
continue;
|
||||
|
||||
irq_no = irq_linear_revmap(bank->domain, hw);
|
||||
child_desc = irq_to_desc(irq_no);
|
||||
|
||||
/* Toggle edge for pin with both edges triggering enabled */
|
||||
if (irqd_get_trigger_type(&child_desc->irq_data)
|
||||
== IRQ_TYPE_EDGE_BOTH)
|
||||
tz1090_gpio_irq_next_edge(bank, hw);
|
||||
|
||||
generic_handle_irq_desc(child_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
|
||||
{
|
||||
struct device_node *np = info->node;
|
||||
struct device *dev = info->priv->dev;
|
||||
struct tz1090_gpio_bank *bank;
|
||||
struct irq_chip_generic *gc;
|
||||
int err;
|
||||
|
||||
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
|
||||
if (!bank) {
|
||||
dev_err(dev, "unable to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Offset the main registers to the first register in this bank */
|
||||
bank->reg = info->priv->reg + info->index * 4;
|
||||
|
||||
/* Set up GPIO chip */
|
||||
snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
|
||||
info->index);
|
||||
bank->chip.label = bank->label;
|
||||
bank->chip.parent = dev;
|
||||
bank->chip.direction_input = tz1090_gpio_direction_input;
|
||||
bank->chip.direction_output = tz1090_gpio_direction_output;
|
||||
bank->chip.get = tz1090_gpio_get;
|
||||
bank->chip.set = tz1090_gpio_set;
|
||||
bank->chip.free = tz1090_gpio_free;
|
||||
bank->chip.request = tz1090_gpio_request;
|
||||
bank->chip.to_irq = tz1090_gpio_to_irq;
|
||||
bank->chip.of_node = np;
|
||||
|
||||
/* GPIO numbering from 0 */
|
||||
bank->chip.base = info->index * 30;
|
||||
bank->chip.ngpio = 30;
|
||||
|
||||
/* Add the GPIO bank */
|
||||
gpiochip_add_data(&bank->chip, bank);
|
||||
|
||||
/* Get the GPIO bank IRQ if provided */
|
||||
bank->irq = irq_of_parse_and_map(np, 0);
|
||||
|
||||
/* The interrupt is optional (it may be used by another core on chip) */
|
||||
if (!bank->irq) {
|
||||
dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n",
|
||||
info->index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_info(dev, "Setting up IRQs for GPIO bank %u\n",
|
||||
info->index);
|
||||
|
||||
/*
|
||||
* Initialise all interrupts to disabled so we don't get
|
||||
* spurious ones on a dirty boot and hit the BUG_ON in the
|
||||
* handler.
|
||||
*/
|
||||
tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0);
|
||||
|
||||
/* Add a virtual IRQ for each GPIO */
|
||||
bank->domain = irq_domain_add_linear(np,
|
||||
bank->chip.ngpio,
|
||||
&irq_generic_chip_ops,
|
||||
bank);
|
||||
|
||||
/* Set up a generic irq chip with 2 chip types (level and edge) */
|
||||
err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2,
|
||||
bank->label, handle_bad_irq, 0, 0,
|
||||
IRQ_GC_INIT_NESTED_LOCK);
|
||||
if (err) {
|
||||
dev_info(dev,
|
||||
"irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n",
|
||||
info->index);
|
||||
irq_domain_remove(bank->domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gc = irq_get_domain_generic_chip(bank->domain, 0);
|
||||
gc->reg_base = bank->reg;
|
||||
|
||||
/* level chip type */
|
||||
gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
|
||||
gc->chip_types[0].handler = handle_level_irq;
|
||||
gc->chip_types[0].regs.ack = REG_GPIO_IRQ_STS;
|
||||
gc->chip_types[0].regs.mask = REG_GPIO_IRQ_EN;
|
||||
gc->chip_types[0].chip.irq_startup = gpio_startup_irq;
|
||||
gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
|
||||
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
|
||||
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
|
||||
gc->chip_types[0].chip.irq_set_type = gpio_set_irq_type;
|
||||
gc->chip_types[0].chip.irq_set_wake = gpio_set_irq_wake;
|
||||
gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
/* edge chip type */
|
||||
gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
|
||||
gc->chip_types[1].handler = handle_edge_irq;
|
||||
gc->chip_types[1].regs.ack = REG_GPIO_IRQ_STS;
|
||||
gc->chip_types[1].regs.mask = REG_GPIO_IRQ_EN;
|
||||
gc->chip_types[1].chip.irq_startup = gpio_startup_irq;
|
||||
gc->chip_types[1].chip.irq_ack = irq_gc_ack_clr_bit;
|
||||
gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
|
||||
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
|
||||
gc->chip_types[1].chip.irq_set_type = gpio_set_irq_type;
|
||||
gc->chip_types[1].chip.irq_set_wake = gpio_set_irq_wake;
|
||||
gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND;
|
||||
|
||||
/* Setup chained handler for this GPIO bank */
|
||||
irq_set_chained_handler_and_data(bank->irq, tz1090_gpio_irq_handler,
|
||||
bank);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
|
||||
{
|
||||
struct device_node *np = priv->dev->of_node;
|
||||
struct device_node *node;
|
||||
|
||||
for_each_available_child_of_node(np, node) {
|
||||
struct tz1090_gpio_bank_info info;
|
||||
u32 addr;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(node, "reg", &addr);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "invalid reg on %pOF\n", node);
|
||||
continue;
|
||||
}
|
||||
if (addr >= 3) {
|
||||
dev_err(priv->dev, "index %u in %pOF out of range\n",
|
||||
addr, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
info.index = addr;
|
||||
info.node = of_node_get(node);
|
||||
info.priv = priv;
|
||||
|
||||
ret = tz1090_gpio_bank_probe(&info);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failure registering %pOF\n", node);
|
||||
of_node_put(node);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tz1090_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *res_regs;
|
||||
struct tz1090_gpio priv;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "must be instantiated via devicetree\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res_regs) {
|
||||
dev_err(&pdev->dev, "cannot find registers resource\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
priv.dev = &pdev->dev;
|
||||
|
||||
/* Ioremap the registers */
|
||||
priv.reg = devm_ioremap(&pdev->dev, res_regs->start,
|
||||
resource_size(res_regs));
|
||||
if (!priv.reg) {
|
||||
dev_err(&pdev->dev, "unable to ioremap registers\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Look for banks */
|
||||
tz1090_gpio_register_banks(&priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id tz1090_gpio_of_match[] = {
|
||||
{ .compatible = "img,tz1090-gpio" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver tz1090_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "tz1090-gpio",
|
||||
.of_match_table = tz1090_gpio_of_match,
|
||||
},
|
||||
.probe = tz1090_gpio_probe,
|
||||
};
|
||||
|
||||
static int __init tz1090_gpio_init(void)
|
||||
{
|
||||
return platform_driver_register(&tz1090_gpio_driver);
|
||||
}
|
||||
subsys_initcall(tz1090_gpio_init);
|
@ -182,7 +182,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
dev_err(wm831x->dev,
|
||||
"GPIO control %d read failed: %d\n",
|
||||
gpio, reg);
|
||||
seq_printf(s, "\n");
|
||||
seq_putc(s, '\n');
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
@ -129,6 +130,51 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
return !!(port_state & mask);
|
||||
}
|
||||
|
||||
static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
|
||||
const unsigned int gpio_reg_size = 8;
|
||||
size_t i;
|
||||
const size_t num_ports = chip->ngpio / gpio_reg_size;
|
||||
unsigned int bits_offset;
|
||||
size_t word_index;
|
||||
unsigned int word_offset;
|
||||
unsigned long word_mask;
|
||||
const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
|
||||
unsigned long port_state;
|
||||
|
||||
/* clear bits array to a clean slate */
|
||||
bitmap_zero(bits, chip->ngpio);
|
||||
|
||||
/* get bits are evaluated a gpio port register at a time */
|
||||
for (i = 0; i < num_ports; i++) {
|
||||
/* gpio offset in bits array */
|
||||
bits_offset = i * gpio_reg_size;
|
||||
|
||||
/* word index for bits array */
|
||||
word_index = BIT_WORD(bits_offset);
|
||||
|
||||
/* gpio offset within current word of bits array */
|
||||
word_offset = bits_offset % BITS_PER_LONG;
|
||||
|
||||
/* mask of get bits for current gpio within current word */
|
||||
word_mask = mask[word_index] & (port_mask << word_offset);
|
||||
if (!word_mask) {
|
||||
/* no get bits in this port so skip to next one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read bits from current gpio port */
|
||||
port_state = inb(ws16c48gpio->base + i);
|
||||
|
||||
/* store acquired bits at respective bits array offset */
|
||||
bits[word_index] |= port_state << word_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
|
||||
@ -383,6 +429,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
|
||||
ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
|
||||
ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
|
||||
ws16c48gpio->chip.get = ws16c48_gpio_get;
|
||||
ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
|
||||
ws16c48gpio->chip.set = ws16c48_gpio_set;
|
||||
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
||||
ws16c48gpio->base = base[id];
|
||||
|
@ -126,11 +126,16 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
{
|
||||
int reg;
|
||||
struct xra1403 *xra = gpiochip_get_data(chip);
|
||||
int value[xra1403_regmap_cfg.max_register];
|
||||
int *value;
|
||||
int i;
|
||||
unsigned int gcr;
|
||||
unsigned int gsr;
|
||||
|
||||
value = kmalloc_array(xra1403_regmap_cfg.max_register, sizeof(*value),
|
||||
GFP_KERNEL);
|
||||
if (!value)
|
||||
return;
|
||||
|
||||
seq_puts(s, "xra reg:");
|
||||
for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++)
|
||||
seq_printf(s, " %2.2x", reg);
|
||||
@ -154,6 +159,7 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
(gcr & BIT(i)) ? "in" : "out",
|
||||
(gsr & BIT(i)) ? "hi" : "lo");
|
||||
}
|
||||
kfree(value);
|
||||
}
|
||||
#else
|
||||
#define xra1403_dbg_show NULL
|
||||
|
@ -511,6 +511,28 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
|
||||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_remove);
|
||||
|
||||
static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
|
||||
{
|
||||
int len, i;
|
||||
u32 start, count;
|
||||
struct device_node *np = chip->of_node;
|
||||
|
||||
len = of_property_count_u32_elems(np, "gpio-reserved-ranges");
|
||||
if (len < 0 || len % 2 != 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; i += 2) {
|
||||
of_property_read_u32_index(np, "gpio-reserved-ranges",
|
||||
i, &start);
|
||||
of_property_read_u32_index(np, "gpio-reserved-ranges",
|
||||
i + 1, &count);
|
||||
if (start >= chip->ngpio || start + count >= chip->ngpio)
|
||||
continue;
|
||||
|
||||
bitmap_clear(chip->valid_mask, start, count);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PINCTRL
|
||||
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
{
|
||||
@ -615,6 +637,8 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
||||
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
|
||||
return -EINVAL;
|
||||
|
||||
of_gpiochip_init_valid_mask(chip);
|
||||
|
||||
status = of_gpiochip_add_pin_range(chip);
|
||||
if (status)
|
||||
return status;
|
||||
|
@ -337,6 +337,57 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
|
||||
{
|
||||
unsigned long *p;
|
||||
|
||||
p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
bitmap_fill(p, chip->ngpio);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
int size;
|
||||
struct device_node *np = gpiochip->of_node;
|
||||
|
||||
size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
|
||||
if (size > 0 && size % 2 == 0)
|
||||
gpiochip->need_valid_mask = true;
|
||||
#endif
|
||||
|
||||
if (!gpiochip->need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip);
|
||||
if (!gpiochip->valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
{
|
||||
kfree(gpiochip->valid_mask);
|
||||
gpiochip->valid_mask = NULL;
|
||||
}
|
||||
|
||||
bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->valid_mask))
|
||||
return true;
|
||||
return test_bit(offset, gpiochip->valid_mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
|
||||
|
||||
/*
|
||||
* GPIO line handle management
|
||||
*/
|
||||
@ -1261,6 +1312,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||
if (status)
|
||||
goto err_remove_from_list;
|
||||
|
||||
status = gpiochip_init_valid_mask(chip);
|
||||
if (status)
|
||||
goto err_remove_irqchip_mask;
|
||||
|
||||
status = gpiochip_add_irqchip(chip, lock_key, request_key);
|
||||
if (status)
|
||||
goto err_remove_chip;
|
||||
@ -1290,6 +1345,8 @@ err_remove_chip:
|
||||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_free_hogs(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
err_remove_irqchip_mask:
|
||||
gpiochip_irqchip_free_valid_mask(chip);
|
||||
err_remove_from_list:
|
||||
spin_lock_irqsave(&gpio_lock, flags);
|
||||
@ -1346,6 +1403,7 @@ void gpiochip_remove(struct gpio_chip *chip)
|
||||
acpi_gpiochip_remove(chip);
|
||||
gpiochip_remove_pin_ranges(chip);
|
||||
of_gpiochip_remove(chip);
|
||||
gpiochip_free_valid_mask(chip);
|
||||
/*
|
||||
* We accept no more calls into the driver from this point, so
|
||||
* NULL the driver data pointer
|
||||
@ -1506,14 +1564,10 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
|
||||
if (!gpiochip->irq.need_valid_mask)
|
||||
return 0;
|
||||
|
||||
gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
||||
sizeof(long), GFP_KERNEL);
|
||||
gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip);
|
||||
if (!gpiochip->irq.valid_mask)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Assume by default all GPIOs are valid */
|
||||
bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1526,6 +1580,8 @@ static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
|
||||
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (!gpiochip_line_is_valid(gpiochip, offset))
|
||||
return false;
|
||||
/* No mask means all valid */
|
||||
if (likely(!gpiochip->irq.valid_mask))
|
||||
return true;
|
||||
@ -3689,7 +3745,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||
}
|
||||
|
||||
if (IS_ERR(desc)) {
|
||||
dev_dbg(dev, "lookup for GPIO %s failed\n", con_id);
|
||||
dev_dbg(dev, "No GPIO consumer %s found\n", con_id);
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,13 @@
|
||||
#define GPIOLIB_H
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cdev.h>
|
||||
|
||||
enum of_gpio_flags;
|
||||
enum gpiod_flags;
|
||||
enum gpio_lookup_flags;
|
||||
struct acpi_device;
|
||||
|
||||
|
@ -697,7 +697,8 @@ config STM32_DFSDM_ADC
|
||||
|
||||
config STX104
|
||||
tristate "Apex Embedded Systems STX104 driver"
|
||||
depends on PC104 && X86 && ISA_BUS_API
|
||||
depends on PC104 && X86
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB
|
||||
help
|
||||
Say yes here to build support for the Apex Embedded Systems STX104
|
||||
|
@ -7,7 +7,8 @@ menu "Counters"
|
||||
|
||||
config 104_QUAD_8
|
||||
tristate "ACCES 104-QUAD-8 driver"
|
||||
depends on PC104 && X86 && ISA_BUS_API
|
||||
depends on PC104 && X86
|
||||
select ISA_BUS_API
|
||||
help
|
||||
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
|
||||
encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
|
||||
|
@ -195,7 +195,8 @@ config AD7303
|
||||
|
||||
config CIO_DAC
|
||||
tristate "Measurement Computing CIO-DAC IIO driver"
|
||||
depends on X86 && ISA_BUS_API
|
||||
depends on X86 && (ISA_BUS || PC104)
|
||||
select ISA_BUS_API
|
||||
help
|
||||
Say yes here to build support for the Measurement Computing CIO-DAC
|
||||
analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
|
||||
|
@ -105,6 +105,14 @@ static const struct pinctrl_ops msm_pinctrl_ops = {
|
||||
.dt_free_map = pinctrl_utils_free_map,
|
||||
};
|
||||
|
||||
static int msm_pinmux_request(struct pinctrl_dev *pctldev, unsigned offset)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct gpio_chip *chip = &pctrl->chip;
|
||||
|
||||
return gpiochip_line_is_valid(chip, offset) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static int msm_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
@ -166,6 +174,7 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
||||
}
|
||||
|
||||
static const struct pinmux_ops msm_pinmux_ops = {
|
||||
.request = msm_pinmux_request,
|
||||
.get_functions_count = msm_get_functions_count,
|
||||
.get_function_name = msm_get_function_name,
|
||||
.get_function_groups = msm_get_function_groups,
|
||||
@ -506,6 +515,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
||||
"pull up"
|
||||
};
|
||||
|
||||
if (!gpiochip_line_is_valid(chip, offset))
|
||||
return;
|
||||
|
||||
g = &pctrl->soc->groups[offset];
|
||||
ctl_reg = readl(pctrl->regs + g->ctl_reg);
|
||||
|
||||
@ -517,6 +529,7 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
||||
seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
|
||||
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
|
||||
seq_printf(s, " %s", pulls[pull]);
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
|
||||
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
@ -524,10 +537,8 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||
unsigned gpio = chip->base;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++) {
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++)
|
||||
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
|
||||
seq_puts(s, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
@ -808,6 +819,46 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
|
||||
struct msm_pinctrl *pctrl)
|
||||
{
|
||||
int ret;
|
||||
unsigned int len, i;
|
||||
unsigned int max_gpios = pctrl->soc->ngpios;
|
||||
u16 *tmp;
|
||||
|
||||
/* The number of GPIOs in the ACPI tables */
|
||||
len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (ret > max_gpios)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
|
||||
if (ret < 0) {
|
||||
dev_err(pctrl->dev, "could not read list of GPIOs\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
bitmap_zero(chip->valid_mask, max_gpios);
|
||||
for (i = 0; i < len; i++)
|
||||
set_bit(tmp[i], chip->valid_mask);
|
||||
|
||||
out:
|
||||
kfree(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
|
||||
{
|
||||
return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
|
||||
}
|
||||
|
||||
static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
@ -824,6 +875,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||
chip->parent = pctrl->dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->of_node = pctrl->dev->of_node;
|
||||
chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
|
||||
|
||||
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
||||
if (ret) {
|
||||
@ -831,6 +883,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = msm_gpio_init_valid_mask(chip, pctrl);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
|
||||
gpiochip_remove(&pctrl->chip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
|
||||
if (ret) {
|
||||
dev_err(pctrl->dev, "Failed to add pin range\n");
|
||||
|
@ -866,7 +866,8 @@ config ALIM7101_WDT
|
||||
|
||||
config EBC_C384_WDT
|
||||
tristate "WinSystems EBC-C384 Watchdog Timer"
|
||||
depends on X86 && ISA_BUS_API
|
||||
depends on X86
|
||||
select ISA_BUS_API
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Enables watchdog timer support for the watchdog timer on the
|
||||
|
@ -288,6 +288,21 @@ struct gpio_chip {
|
||||
struct gpio_irq_chip irq;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @need_valid_mask:
|
||||
*
|
||||
* If set core allocates @valid_mask with all bits set to one.
|
||||
*/
|
||||
bool need_valid_mask;
|
||||
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
* If not %NULL holds bitmask of GPIOs which are valid to be used
|
||||
* from the chip.
|
||||
*/
|
||||
unsigned long *valid_mask;
|
||||
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
/*
|
||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||
@ -384,6 +399,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
/* Sleep persistence inquiry for drivers */
|
||||
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
|
||||
bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);
|
||||
|
||||
/* get driver data */
|
||||
void *gpiochip_get_data(struct gpio_chip *chip);
|
||||
|
@ -6,8 +6,6 @@
|
||||
#ifndef __HTC_EGPIO_H__
|
||||
#define __HTC_EGPIO_H__
|
||||
|
||||
#include <linux/gpio.h>
|
||||
|
||||
/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */
|
||||
#define HTC_EGPIO_OUTPUT (~0)
|
||||
#define HTC_EGPIO_INPUT 0
|
||||
|
@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
|
||||
RPI_FIRMWARE_GET_TURBO = 0x00030009,
|
||||
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
|
||||
RPI_FIRMWARE_GET_STC = 0x0003000b,
|
||||
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
|
||||
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
|
||||
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
|
||||
@ -72,12 +73,22 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
|
||||
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
|
||||
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
|
||||
RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
|
||||
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
|
||||
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
|
||||
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
|
||||
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
|
||||
RPI_FIRMWARE_SET_TURBO = 0x00038009,
|
||||
RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
|
||||
RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
|
||||
RPI_FIRMWARE_GET_GPIO_STATE = 0x00030041,
|
||||
RPI_FIRMWARE_SET_GPIO_STATE = 0x00038041,
|
||||
RPI_FIRMWARE_SET_SDHOST_CLOCK = 0x00038042,
|
||||
RPI_FIRMWARE_GET_GPIO_CONFIG = 0x00030043,
|
||||
RPI_FIRMWARE_SET_GPIO_CONFIG = 0x00038043,
|
||||
RPI_FIRMWARE_GET_PERIPH_REG = 0x00030045,
|
||||
RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
|
||||
|
||||
|
||||
/* Dispmanx TAGS */
|
||||
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
|
||||
@ -91,6 +102,8 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_GPIOVIRTBUF = 0x00040010,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
|
||||
@ -100,6 +113,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
|
||||
@ -108,6 +122,10 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF = 0x0004801f,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_GPIOVIRTBUF = 0x00048020,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
|
||||
|
||||
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
|
||||
|
||||
|
@ -1437,7 +1437,7 @@ config PERF_USE_VMALLOC
|
||||
See tools/perf/design.txt for details
|
||||
|
||||
config PC104
|
||||
bool "PC/104 support"
|
||||
bool "PC/104 support" if EXPERT
|
||||
help
|
||||
Expose PC/104 form factor device drivers and options available for
|
||||
selection and configuration. Enable this option if your target
|
||||
|
@ -99,7 +99,7 @@ int monitor_device(const char *device_name,
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
|
||||
fprintf(stdout, "GPIO EVENT %llu: ", event.timestamp);
|
||||
switch (event.id) {
|
||||
case GPIOEVENT_EVENT_RISING_EDGE:
|
||||
fprintf(stdout, "rising edge");
|
||||
|
Loading…
Reference in New Issue
Block a user