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,pca9574
|
||||||
nxp,pca9575
|
nxp,pca9575
|
||||||
nxp,pca9698
|
nxp,pca9698
|
||||||
|
nxp,pcal6524
|
||||||
|
nxp,pcal9555a
|
||||||
maxim,max7310
|
maxim,max7310
|
||||||
maxim,max7312
|
maxim,max7312
|
||||||
maxim,max7313
|
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.
|
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
|
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,
|
additional set of tuples is needed to specify which GPIOs are unusable, with
|
||||||
and which are dummies. The bindings for this case has not yet been
|
the gpio-reserved-ranges binding. This property indicates the start and size
|
||||||
specified, but should be specified if/when such hardware appears.
|
of the GPIOs that can't be used.
|
||||||
|
|
||||||
Optionally, a GPIO controller may have a "gpio-line-names" property. This is
|
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
|
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-controller;
|
||||||
#gpio-cells = <2>;
|
#gpio-cells = <2>;
|
||||||
ngpios = <18>;
|
ngpios = <18>;
|
||||||
|
gpio-reserved-ranges = <0 4>, <12 2>;
|
||||||
gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
|
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",
|
"LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
|
||||||
"Row A", "Row B", "Row C", "Row D", "NMI button",
|
"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
|
1.l) The General Purpose I/O (GPIO) controller node
|
||||||
|
|
||||||
Represents the dual access 32 GPIO controller interface.
|
see Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- #gpio-cells : <2>
|
|
||||||
- compatible : should be "nintendo,hollywood-gpio"
|
|
||||||
- reg : should contain the IPC registers location and length
|
|
||||||
- gpio-controller
|
|
||||||
|
|
||||||
1.m) The control node
|
1.m) The control node
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
=============
|
||||||
GPIO Mappings
|
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
|
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
|
<function>-gpios, where <function> is the function the driver will request
|
||||||
through gpiod_get(). For example:
|
through gpiod_get(). For example::
|
||||||
|
|
||||||
foo_device {
|
foo_device {
|
||||||
compatible = "acme,foo";
|
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.
|
newer bindings since it has been deprecated.
|
||||||
|
|
||||||
This property will make GPIOs 15, 16 and 17 available to the driver under the
|
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;
|
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")
|
Internally, the GPIO subsystem prefixes the GPIO suffix ("gpios" or "gpio")
|
||||||
with the string passed in con_id to get the resulting string
|
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
|
||||||
----
|
----
|
||||||
ACPI also supports function names for GPIOs in a similar fashion to DT.
|
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
|
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) {
|
Device (FOO) {
|
||||||
Name (_CRS, ResourceTemplate () {
|
Name (_CRS, ResourceTemplate () {
|
||||||
|
@ -105,12 +106,12 @@ Documentation/acpi/gpio-properties.txt.
|
||||||
Platform Data
|
Platform Data
|
||||||
-------------
|
-------------
|
||||||
Finally, GPIOs can be bound to devices and functions using platform data. Board
|
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>
|
#include <linux/gpio/machine.h>
|
||||||
|
|
||||||
GPIOs are mapped by the means of tables of lookups, containing instances of the
|
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(chip_label, chip_hwnum, con_id, flags)
|
||||||
GPIO_LOOKUP_IDX(chip_label, chip_hwnum, con_id, idx, 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
|
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.
|
calls to gpiod_get() with a NULL device.
|
||||||
|
|
||||||
struct gpiod_lookup_table gpios_table = {
|
.. code-block:: c
|
||||||
.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:
|
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);
|
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;
|
struct gpio_desc *red, *green, *blue, *power;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
==================================
|
||||||
GPIO Descriptor Consumer Interface
|
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.
|
be met with console warnings that may be perceived as intimidating.
|
||||||
|
|
||||||
All the functions that work with the descriptor-based GPIO interface are
|
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
|
prefixed with ``gpiod_``. The ``gpio_`` prefix is used for the legacy
|
||||||
other function in the kernel should use these prefixes. The use of the legacy
|
interface. No other function in the kernel should use these prefixes. The use
|
||||||
functions is strongly discouraged, new code should use <linux/gpio/consumer.h>
|
of the legacy functions is strongly discouraged, new code should use
|
||||||
and descriptors exclusively.
|
<linux/gpio/consumer.h> and descriptors exclusively.
|
||||||
|
|
||||||
|
|
||||||
Obtaining and Disposing GPIOs
|
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
|
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
|
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
|
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,
|
struct gpio_desc *gpiod_get(struct device *dev, const char *con_id,
|
||||||
enum gpiod_flags flags)
|
enum gpiod_flags flags)
|
||||||
|
|
||||||
If a function is implemented by using several GPIOs together (e.g. a simple LED
|
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,
|
struct gpio_desc *gpiod_get_index(struct device *dev,
|
||||||
const char *con_id, unsigned int idx,
|
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
|
errors and an absence of GPIO for optional GPIO parameters. For the common
|
||||||
pattern where a GPIO is optional, the gpiod_get_optional() and
|
pattern where a GPIO is optional, the gpiod_get_optional() and
|
||||||
gpiod_get_index_optional() functions can be used. These functions return NULL
|
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,
|
struct gpio_desc *gpiod_get_optional(struct device *dev,
|
||||||
const char *con_id,
|
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
|
-ENOSYS return codes. System integrators should however be careful to enable
|
||||||
gpiolib on systems that need it.
|
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,
|
struct gpio_descs *gpiod_get_array(struct device *dev,
|
||||||
const char *con_id,
|
const char *con_id,
|
||||||
enum gpiod_flags flags)
|
enum gpiod_flags flags)
|
||||||
|
|
||||||
This function returns a struct gpio_descs which contains an array of
|
This function returns a struct gpio_descs which contains an array of
|
||||||
descriptors:
|
descriptors::
|
||||||
|
|
||||||
struct gpio_descs {
|
struct gpio_descs {
|
||||||
unsigned int ndescs;
|
unsigned int ndescs;
|
||||||
|
@ -116,13 +117,13 @@ descriptors:
|
||||||
}
|
}
|
||||||
|
|
||||||
The following function returns NULL instead of -ENOENT if no GPIOs have been
|
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,
|
struct gpio_descs *gpiod_get_array_optional(struct device *dev,
|
||||||
const char *con_id,
|
const char *con_id,
|
||||||
enum gpiod_flags flags)
|
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,
|
struct gpio_desc *devm_gpiod_get(struct device *dev, const char *con_id,
|
||||||
enum gpiod_flags flags)
|
enum gpiod_flags flags)
|
||||||
|
@ -149,11 +150,11 @@ Device-managed variants of these functions are also defined:
|
||||||
const char *con_id,
|
const char *con_id,
|
||||||
enum gpiod_flags flags)
|
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)
|
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)
|
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())
|
It is also not allowed to individually release descriptors (using gpiod_put())
|
||||||
from an array acquired with gpiod_get_array().
|
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)
|
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
|
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
|
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_input(struct gpio_desc *desc)
|
||||||
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||||
|
@ -189,7 +190,7 @@ of early board setup.
|
||||||
For output GPIOs, the value provided becomes the initial output value. This
|
For output GPIOs, the value provided becomes the initial output value. This
|
||||||
helps avoid signal glitching during system startup.
|
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)
|
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
|
don't need to sleep, and can safely be done from inside hard (non-threaded) IRQ
|
||||||
handlers and similar contexts.
|
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);
|
int gpiod_get_value(const struct gpio_desc *desc);
|
||||||
void gpiod_set_value(struct gpio_desc *desc, int value);
|
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.
|
sleeping, which can't be done from inside IRQ handlers.
|
||||||
|
|
||||||
Platforms that support this type of GPIO distinguish them from other GPIOs by
|
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)
|
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)
|
int gpiod_get_value_cansleep(const struct gpio_desc *desc)
|
||||||
void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
|
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
|
gpiod_set_(array)_value_xxx() passes "asserted" ("1"), the physical line level
|
||||||
will be driven low.
|
will be driven low.
|
||||||
|
|
||||||
To summarize:
|
To summarize::
|
||||||
|
|
||||||
Function (example) line property physical line
|
Function (example) line property physical line
|
||||||
gpiod_set_raw_value(desc, 0); don't care low
|
gpiod_set_raw_value(desc, 0); don't care low
|
||||||
gpiod_set_raw_value(desc, 1); don't care high
|
gpiod_set_raw_value(desc, 1); don't care high
|
||||||
gpiod_set_value(desc, 0); default (active high) low
|
gpiod_set_value(desc, 0); default (active high) low
|
||||||
gpiod_set_value(desc, 1); default (active high) high
|
gpiod_set_value(desc, 1); default (active high) high
|
||||||
gpiod_set_value(desc, 0); active low high
|
gpiod_set_value(desc, 0); active low high
|
||||||
gpiod_set_value(desc, 1); active low low
|
gpiod_set_value(desc, 1); active low low
|
||||||
gpiod_set_value(desc, 0); default (active high) low
|
gpiod_set_value(desc, 0); default (active high) low
|
||||||
gpiod_set_value(desc, 1); default (active high) high
|
gpiod_set_value(desc, 1); default (active high) high
|
||||||
gpiod_set_value(desc, 0); open drain low
|
gpiod_set_value(desc, 0); open drain low
|
||||||
gpiod_set_value(desc, 1); open drain high impedance
|
gpiod_set_value(desc, 1); open drain high impedance
|
||||||
gpiod_set_value(desc, 0); open source high impedance
|
gpiod_set_value(desc, 0); open source high impedance
|
||||||
gpiod_set_value(desc, 1); open source high
|
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
|
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
|
which should not need to care about the actual physical line level and worry about
|
||||||
the logical value instead.
|
the logical value instead.
|
||||||
|
@ -300,7 +301,7 @@ their device will actually receive, no matter what lies between it and the GPIO
|
||||||
line.
|
line.
|
||||||
|
|
||||||
The following set of calls ignore the active-low or open drain property of a GPIO and
|
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)
|
int gpiod_get_raw_value(const struct gpio_desc *desc)
|
||||||
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
|
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)
|
void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value)
|
||||||
int gpiod_direction_output_raw(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)
|
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
|
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,
|
int gpiod_get_array_value(unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
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
|
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
|
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
|
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(...);
|
struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
|
||||||
gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
|
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
|
GPIOs mapped to IRQs
|
||||||
--------------------
|
--------------------
|
||||||
GPIO lines can quite often be used as IRQs. You can get the IRQ number
|
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)
|
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
|
Many kernel subsystems still handle GPIOs using the legacy integer-based
|
||||||
interface. Although it is strongly encouraged to upgrade them to the safer
|
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-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)
|
int desc_to_gpio(const struct gpio_desc *desc)
|
||||||
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
|
@ -1,3 +1,4 @@
|
||||||
|
================================
|
||||||
GPIO Descriptor Driver Interface
|
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
|
The code implementing a gpio_chip should support multiple instances of the
|
||||||
controller, possibly using the driver model. That code will configure each
|
controller, possibly using the driver model. That code will configure each
|
||||||
gpio_chip and issue gpiochip_add[_data]() or devm_gpiochip_add_data().
|
gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
|
||||||
Removing a GPIO controller should be rare; use [devm_]gpiochip_remove() when
|
Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
|
||||||
it is unavoidable.
|
when it is unavoidable.
|
||||||
|
|
||||||
Often a gpio_chip is part of an instance-specific structure with states not
|
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.
|
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
|
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
|
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
|
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
|
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
|
"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
|
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
|
VDD
|
||||||
|
|
|
|
||||||
OD ||--+
|
OD ||--+
|
||||||
+--/ ---o|| P-MOS-FET
|
+--/ ---o|| P-MOS-FET
|
||||||
| ||--+
|
| ||--+
|
||||||
IN --+ +----- out
|
IN --+ +----- out
|
||||||
| ||--+
|
| ||--+
|
||||||
+--/ ----|| N-MOS-FET
|
+--/ ----|| N-MOS-FET
|
||||||
OS ||--+
|
OS ||--+
|
||||||
|
|
|
|
||||||
GND
|
GND
|
||||||
|
|
||||||
The desired output signal (e.g. coming directly from some GPIO output register)
|
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
|
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
|
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.
|
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
|
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
|
||||||
on an irqchip. Create the callbacks if needed [2].
|
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
|
system interrupt controller. This means that the GPIO irqchip handler will
|
||||||
be called immediately from the parent irqchip, while holding the IRQs
|
be called immediately from the parent irqchip, while holding the IRQs
|
||||||
disabled. The GPIO irqchip will then end up calling something like this
|
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)
|
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||||
chained_irq_enter(...);
|
chained_irq_enter(...);
|
||||||
generic_handle_irq(...);
|
generic_handle_irq(...);
|
||||||
chained_irq_exit(...);
|
chained_irq_exit(...);
|
||||||
|
|
||||||
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
|
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
|
||||||
struct gpio_chip, as everything happens directly in the callbacks: no
|
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]).
|
(for example, see [3]).
|
||||||
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
|
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
|
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;
|
raw_spinlock_t wa_lock;
|
||||||
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
|
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
|
but chained IRQ handlers are not used. Instead GPIO IRQs dispatching is
|
||||||
performed by generic IRQ handler which is configured using request_irq().
|
performed by generic IRQ handler which is configured using request_irq().
|
||||||
The GPIO irqchip will then end up calling something like this sequence in
|
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)
|
static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
|
||||||
for each detected GPIO IRQ
|
for each detected GPIO IRQ
|
||||||
generic_handle_irq(...);
|
generic_handle_irq(...);
|
||||||
|
|
||||||
RT_FULL: Such kind of handlers will be forced threaded on -RT, as result 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
|
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
|
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
|
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
|
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)
|
static irqreturn_t foo_gpio_irq(int irq, void *data)
|
||||||
...
|
...
|
||||||
handle_nested_irq(irq);
|
handle_nested_irq(irq);
|
||||||
|
|
||||||
The hallmark of threaded GPIO irqchips is that they set the .can_sleep
|
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
|
flag on struct gpio_chip to true, indicating that this chip may sleep
|
||||||
|
@ -359,12 +361,12 @@ below exists.
|
||||||
Locking IRQ usage
|
Locking IRQ usage
|
||||||
-----------------
|
-----------------
|
||||||
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
Input GPIOs can be used as IRQ signals. When this happens, a driver is requested
|
||||||
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)
|
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
|
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)
|
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
|
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
|
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
|
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,
|
struct gpio_desc *gpiochip_request_own_desc(struct gpio_desc *desc,
|
||||||
const char *label)
|
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
|
count. Do not use the functions to request gpio descriptors not owned by the
|
||||||
calling driver.
|
calling driver.
|
||||||
|
|
||||||
[1] http://www.spinics.net/lists/linux-omap/msg120425.html
|
* [1] http://www.spinics.net/lists/linux-omap/msg120425.html
|
||||||
[2] https://lkml.org/lkml/2015/9/25/494
|
* [2] https://lkml.org/lkml/2015/9/25/494
|
||||||
[3] https://lkml.org/lkml/2015/9/25/495
|
* [3] https://lkml.org/lkml/2015/9/25/495
|
|
@ -1,3 +1,4 @@
|
||||||
|
============================
|
||||||
Subsystem drivers using GPIO
|
Subsystem drivers using GPIO
|
||||||
============================
|
============================
|
||||||
|
|
|
@ -2,6 +2,18 @@
|
||||||
General Purpose Input/Output (GPIO)
|
General Purpose Input/Output (GPIO)
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
intro
|
||||||
|
driver
|
||||||
|
consumer
|
||||||
|
board
|
||||||
|
drivers-on-gpio
|
||||||
|
legacy
|
||||||
|
|
||||||
Core
|
Core
|
||||||
====
|
====
|
||||||
|
|
||||||
|
@ -11,15 +23,6 @@ Core
|
||||||
.. kernel-doc:: drivers/gpio/gpiolib.c
|
.. kernel-doc:: drivers/gpio/gpiolib.c
|
||||||
:export:
|
: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
|
ACPI support
|
||||||
============
|
============
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
============
|
||||||
|
Introduction
|
||||||
|
============
|
||||||
|
|
||||||
|
|
||||||
GPIO Interfaces
|
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:
|
ways to obtain and use GPIOs:
|
||||||
|
|
||||||
- The descriptor-based interface is the preferred way to manipulate 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
|
- 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.
|
The remainder of this document applies to the new descriptor-based interface.
|
||||||
gpio-legacy.txt contains the same information applied to the legacy
|
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.
|
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.
|
the gpio_request() call; see later.
|
||||||
|
|
||||||
One of the next things to do with a GPIO, often in board setup code when
|
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 */
|
/* set as input or output, returning 0 or negative errno */
|
||||||
int gpio_direction_input(unsigned gpio);
|
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.
|
(nonthreaded) IRQ handlers and similar contexts.
|
||||||
|
|
||||||
Use the following calls to access such GPIOs,
|
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 */
|
/* GPIO INPUT: return zero or nonzero */
|
||||||
int gpio_get_value(unsigned gpio);
|
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
|
Platforms that support this type of GPIO distinguish them from other GPIOs
|
||||||
by returning nonzero from this call (which requires a valid GPIO number,
|
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);
|
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 */
|
/* GPIO INPUT: return zero or nonzero, might sleep */
|
||||||
int gpio_get_value_cansleep(unsigned gpio);
|
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
|
on GPIOs that can't be accessed from hardIRQ handlers, these calls act
|
||||||
the same as the spinlock-safe calls.
|
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
|
from contexts which may sleep, since they may need to access the GPIO
|
||||||
controller chip too: (These setup calls are usually made from board
|
controller chip too (These setup calls are usually made from board
|
||||||
setup or driver probe/teardown code, so this is an easy constraint.)
|
setup or driver probe/teardown code, so this is an easy constraint.)::
|
||||||
|
|
||||||
gpio_direction_input()
|
gpio_direction_input()
|
||||||
gpio_direction_output()
|
gpio_direction_output()
|
||||||
gpio_request()
|
gpio_request()
|
||||||
|
|
||||||
## gpio_request_one()
|
## gpio_request_one()
|
||||||
## gpio_request_array()
|
## gpio_request_array()
|
||||||
## gpio_free_array()
|
## gpio_free_array()
|
||||||
|
|
||||||
gpio_free()
|
gpio_free()
|
||||||
gpio_set_debounce()
|
gpio_set_debounce()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Claiming and Releasing GPIOs
|
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.
|
/* request GPIO, returning 0 or negative errno.
|
||||||
* non-null labels may be useful for diagnostics.
|
* 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.
|
before you free it.
|
||||||
|
|
||||||
Considering in most cases GPIOs are actually configured right after they
|
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
|
/* request a single GPIO, with initial configuration specified by
|
||||||
* 'flags', identical to gpio_request() wrt other arguments and
|
* '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.
|
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
|
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 {
|
struct gpio {
|
||||||
unsigned gpio;
|
unsigned gpio;
|
||||||
|
@ -355,7 +357,7 @@ introduced to encapsulate all three fields as:
|
||||||
const char *label;
|
const char *label;
|
||||||
};
|
};
|
||||||
|
|
||||||
A typical example of usage:
|
A typical example of usage::
|
||||||
|
|
||||||
static struct gpio leds_gpios[] = {
|
static struct gpio leds_gpios[] = {
|
||||||
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */
|
{ 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
|
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
|
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 */
|
/* map GPIO numbers to IRQ numbers */
|
||||||
int gpio_to_irq(unsigned gpio);
|
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
|
subsystem, in the sense that the pins can be used by other functions
|
||||||
together with an optional gpio feature. We have already covered the
|
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
|
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_request()
|
||||||
pinctrl_gpio_free()
|
pinctrl_gpio_free()
|
||||||
pinctrl_gpio_direction_input()
|
pinctrl_gpio_direction_input()
|
||||||
pinctrl_gpio_direction_output()
|
pinctrl_gpio_direction_output()
|
||||||
|
|
||||||
But how does the pin control subsystem cross-correlate the GPIO
|
But how does the pin control subsystem cross-correlate the GPIO
|
||||||
numbers (which are a global business) to a certain pin on a certain
|
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.
|
GPIOs through GPIO-lib and the code cannot be enabled by the user.
|
||||||
|
|
||||||
Trivial implementations of those functions can directly use framework
|
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_get_value __gpio_get_value
|
||||||
#define gpio_set_value __gpio_set_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
|
Exporting from Kernel code
|
||||||
--------------------------
|
--------------------------
|
||||||
Kernel code can explicitly manage exports of GPIOs which have already been
|
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 */
|
/* export the GPIO to userspace */
|
||||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
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
|
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
|
use this to provide the interface under their own device in sysfs with
|
||||||
a descriptive name.
|
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
|
uio-howto
|
||||||
firmware/index
|
firmware/index
|
||||||
pinctl
|
pinctl
|
||||||
gpio
|
gpio/index
|
||||||
misc_devices
|
misc_devices
|
||||||
dmaengine/index
|
dmaengine/index
|
||||||
slimbus
|
slimbus
|
||||||
|
|
|
@ -1,17 +1,4 @@
|
||||||
00-INDEX
|
00-INDEX
|
||||||
- This file
|
- 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
|
sysfs.txt
|
||||||
- Information about the GPIO sysfs interface
|
- 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.
|
GPIO drivers could be all that the system really needs.
|
||||||
|
|
||||||
DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
|
DO NOT ABUSE SYSFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS.
|
||||||
PLEASE READ THE DOCUMENT NAMED "drivers-on-gpio.txt" IN THIS DOCUMENTATION
|
PLEASE READ THE DOCUMENT AT Documentation/driver-api/gpio/drivers-on-gpio.rst
|
||||||
DIRECTORY TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT.
|
TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. REALLY.
|
||||||
REALLY.
|
|
||||||
|
|
||||||
Paths in Sysfs
|
Paths in Sysfs
|
||||||
--------------
|
--------------
|
||||||
|
|
|
@ -5984,7 +5984,7 @@ S: Maintained
|
||||||
F: drivers/media/rc/gpio-ir-tx.c
|
F: drivers/media/rc/gpio-ir-tx.c
|
||||||
|
|
||||||
GPIO MOCKUP DRIVER
|
GPIO MOCKUP DRIVER
|
||||||
M: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
|
M: Bamvor Jian Zhang <bamv2005@gmail.com>
|
||||||
R: Bartosz Golaszewski <brgl@bgdev.pl>
|
R: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||||
L: linux-gpio@vger.kernel.org
|
L: linux-gpio@vger.kernel.org
|
||||||
S: Maintained
|
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
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/devicetree/bindings/gpio/
|
F: Documentation/devicetree/bindings/gpio/
|
||||||
|
F: Documentation/driver-api/gpio/
|
||||||
F: Documentation/gpio/
|
F: Documentation/gpio/
|
||||||
F: Documentation/ABI/testing/gpio-cdev
|
F: Documentation/ABI/testing/gpio-cdev
|
||||||
F: Documentation/ABI/obsolete/sysfs-gpio
|
F: Documentation/ABI/obsolete/sysfs-gpio
|
||||||
|
|
|
@ -2665,11 +2665,13 @@ config PCI_CNB20LE_QUIRK
|
||||||
source "drivers/pci/Kconfig"
|
source "drivers/pci/Kconfig"
|
||||||
|
|
||||||
config ISA_BUS
|
config ISA_BUS
|
||||||
bool "ISA-style bus support on modern systems" if EXPERT
|
bool "ISA bus support on modern systems" if EXPERT
|
||||||
select ISA_BUS_API
|
|
||||||
help
|
help
|
||||||
Enables ISA-style drivers on modern systems. This is necessary to
|
Expose ISA bus device drivers and options available for selection and
|
||||||
support PC/104 devices on X86_64 platforms.
|
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.
|
If unsure, say N.
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,17 @@ config GPIO_ATH79
|
||||||
Select this option to enable GPIO driver for
|
Select this option to enable GPIO driver for
|
||||||
Atheros AR71XX/AR724X/AR913X SoC devices.
|
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
|
config GPIO_BCM_KONA
|
||||||
bool "Broadcom Kona GPIO"
|
bool "Broadcom Kona GPIO"
|
||||||
depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST)
|
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
|
Say Y or M here to build support for the Synopsys DesignWare APB
|
||||||
GPIO block.
|
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
|
config GPIO_EM
|
||||||
tristate "Emma Mobile GPIO"
|
tristate "Emma Mobile GPIO"
|
||||||
depends on (ARCH_EMEV2 || COMPILE_TEST) && OF_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
|
Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
|
||||||
VHDL IP core library.
|
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
|
config GPIO_ICH
|
||||||
tristate "Intel ICH GPIO"
|
tristate "Intel ICH GPIO"
|
||||||
depends on PCI && X86
|
depends on PCI && X86
|
||||||
|
@ -363,6 +391,14 @@ config GPIO_PL061
|
||||||
help
|
help
|
||||||
Say yes here to support the PrimeCell PL061 GPIO device
|
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
|
config GPIO_PXA
|
||||||
bool "PXA GPIO support"
|
bool "PXA GPIO support"
|
||||||
depends on ARCH_PXA || ARCH_MMP
|
depends on ARCH_PXA || ARCH_MMP
|
||||||
|
@ -389,6 +425,14 @@ config GPIO_SPEAR_SPICS
|
||||||
help
|
help
|
||||||
Say yes here to support ST SPEAr SPI Chip Select as GPIO device
|
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
|
config GPIO_STA2X11
|
||||||
bool "STA2x11/ConneXt GPIO support"
|
bool "STA2x11/ConneXt GPIO support"
|
||||||
depends on MFD_STA2X11
|
depends on MFD_STA2X11
|
||||||
|
@ -453,21 +497,6 @@ config GPIO_THUNDERX
|
||||||
Say yes here to support the on-chip GPIO lines on the ThunderX
|
Say yes here to support the on-chip GPIO lines on the ThunderX
|
||||||
and OCTEON-TX families of SoCs.
|
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
|
config GPIO_UNIPHIER
|
||||||
tristate "UniPhier GPIO support"
|
tristate "UniPhier GPIO support"
|
||||||
depends on ARCH_UNIPHIER || COMPILE_TEST
|
depends on ARCH_UNIPHIER || COMPILE_TEST
|
||||||
|
@ -581,7 +610,8 @@ menu "Port-mapped I/O GPIO drivers"
|
||||||
|
|
||||||
config GPIO_104_DIO_48E
|
config GPIO_104_DIO_48E
|
||||||
tristate "ACCES 104-DIO-48E GPIO support"
|
tristate "ACCES 104-DIO-48E GPIO support"
|
||||||
depends on PC104 && ISA_BUS_API
|
depends on PC104
|
||||||
|
select ISA_BUS_API
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E,
|
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
|
config GPIO_104_IDIO_16
|
||||||
tristate "ACCES 104-IDIO-16 GPIO support"
|
tristate "ACCES 104-IDIO-16 GPIO support"
|
||||||
depends on PC104 && ISA_BUS_API
|
depends on PC104
|
||||||
|
select ISA_BUS_API
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
|
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
|
config GPIO_104_IDI_48
|
||||||
tristate "ACCES 104-IDI-48 GPIO support"
|
tristate "ACCES 104-IDI-48 GPIO support"
|
||||||
depends on PC104 && ISA_BUS_API
|
depends on PC104
|
||||||
|
select ISA_BUS_API
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
|
Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A,
|
||||||
|
@ -622,7 +654,8 @@ config GPIO_F7188X
|
||||||
|
|
||||||
config GPIO_GPIO_MM
|
config GPIO_GPIO_MM
|
||||||
tristate "Diamond Systems GPIO-MM GPIO support"
|
tristate "Diamond Systems GPIO-MM GPIO support"
|
||||||
depends on PC104 && ISA_BUS_API
|
depends on PC104
|
||||||
|
select ISA_BUS_API
|
||||||
help
|
help
|
||||||
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
|
Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12.
|
||||||
|
|
||||||
|
@ -691,7 +724,7 @@ config GPIO_TS5500
|
||||||
|
|
||||||
config GPIO_WINBOND
|
config GPIO_WINBOND
|
||||||
tristate "Winbond Super I/O GPIO support"
|
tristate "Winbond Super I/O GPIO support"
|
||||||
depends on ISA_BUS_API
|
select ISA_BUS_API
|
||||||
help
|
help
|
||||||
This option enables support for GPIOs found on Winbond Super I/O
|
This option enables support for GPIOs found on Winbond Super I/O
|
||||||
chips.
|
chips.
|
||||||
|
@ -707,7 +740,7 @@ config GPIO_WINBOND
|
||||||
|
|
||||||
config GPIO_WS16C48
|
config GPIO_WS16C48
|
||||||
tristate "WinSystems WS16C48 GPIO support"
|
tristate "WinSystems WS16C48 GPIO support"
|
||||||
depends on ISA_BUS_API
|
select ISA_BUS_API
|
||||||
select GPIOLIB_IRQCHIP
|
select GPIOLIB_IRQCHIP
|
||||||
help
|
help
|
||||||
Enables GPIO support for the WinSystems WS16C48. The base port
|
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_ARIZONA) += gpio-arizona.o
|
||||||
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||||
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.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_BCM_KONA) += gpio-bcm-kona.o
|
||||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.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_DAVINCI) += gpio-davinci.o
|
||||||
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
||||||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.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_EM) += gpio-em.o
|
||||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||||
obj-$(CONFIG_GPIO_EXAR) += gpio-exar.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_GE_FPGA) += gpio-ge.o
|
||||||
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o
|
||||||
obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.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_HTC_EGPIO) += gpio-htc-egpio.o
|
||||||
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
|
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
|
||||||
obj-$(CONFIG_GPIO_INGENIC) += gpio-ingenic.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_PCIE_IDIO_24) += gpio-pcie-idio-24.o
|
||||||
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
|
obj-$(CONFIG_GPIO_PISOSR) += gpio-pisosr.o
|
||||||
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.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_PXA) += gpio-pxa.o
|
||||||
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.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_SCH311X) += gpio-sch311x.o
|
||||||
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
|
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
|
||||||
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.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_STA2X11) += gpio-sta2x11.o
|
||||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||||
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
|
||||||
|
@ -130,8 +135,6 @@ obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
|
||||||
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
|
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
|
||||||
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
||||||
obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.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_UCB1400) += gpio-ucb1400.o
|
||||||
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
|
obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
|
||||||
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
|
obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* This driver supports the following ACCES devices: 104-DIO-48E and
|
* This driver supports the following ACCES devices: 104-DIO-48E and
|
||||||
* 104-DIO-24E.
|
* 104-DIO-24E.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
@ -182,6 +183,51 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
return !!(port_state & mask);
|
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)
|
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
{
|
{
|
||||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
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_input = dio48e_gpio_direction_input;
|
||||||
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
|
dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
|
||||||
dio48egpio->chip.get = dio48e_gpio_get;
|
dio48egpio->chip.get = dio48e_gpio_get;
|
||||||
|
dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
|
||||||
dio48egpio->chip.set = dio48e_gpio_set;
|
dio48egpio->chip.set = dio48e_gpio_set;
|
||||||
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
|
||||||
dio48egpio->base = base[id];
|
dio48egpio->base = base[id];
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* This driver supports the following ACCES devices: 104-IDI-48A,
|
* This driver supports the following ACCES devices: 104-IDI-48A,
|
||||||
* 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
|
* 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
return 0;
|
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)
|
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.get_direction = idi_48_gpio_get_direction;
|
||||||
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
|
idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
|
||||||
idi48gpio->chip.get = idi_48_gpio_get;
|
idi48gpio->chip.get = idi_48_gpio_get;
|
||||||
|
idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
|
||||||
idi48gpio->base = base[id];
|
idi48gpio->base = base[id];
|
||||||
|
|
||||||
raw_spin_lock_init(&idi48gpio->lock);
|
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));
|
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)
|
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
{
|
{
|
||||||
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
|
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_input = idio_16_gpio_direction_input;
|
||||||
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
||||||
idio16gpio->chip.get = idio_16_gpio_get;
|
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 = idio_16_gpio_set;
|
||||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||||
idio16gpio->base = base[id];
|
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);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res)
|
||||||
|
return -EINVAL;
|
||||||
ctrl->base = devm_ioremap_nocache(
|
ctrl->base = devm_ioremap_nocache(
|
||||||
&pdev->dev, res->start, resource_size(res));
|
&pdev->dev, res->start, resource_size(res));
|
||||||
if (!ctrl->base)
|
if (!ctrl->base)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/platform_data/gpio-davinci.h>
|
#include <linux/platform_data/gpio-davinci.h>
|
||||||
#include <linux/irqchip/chained_irq.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.of_gpio_n_cells = 2;
|
||||||
chips->chip.parent = dev;
|
chips->chip.parent = dev;
|
||||||
chips->chip.of_node = dev->of_node;
|
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
|
#endif
|
||||||
spin_lock_init(&chips->lock);
|
spin_lock_init(&chips->lock);
|
||||||
bank_base += ngpio;
|
bank_base += ngpio;
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/irqchip/chained_irq.h>
|
#include <linux/irqchip/chained_irq.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mfd/dln2.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);
|
struct dln2_gpio *dln2 = gpiochip_get_data(chip);
|
||||||
|
|
||||||
if (test_bit(offset, dln2->output_enabled))
|
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)
|
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)
|
if (dir < 0)
|
||||||
return dir;
|
return dir;
|
||||||
|
|
||||||
if (dir == GPIOF_DIR_IN)
|
if (dir == 1)
|
||||||
return dln2_gpio_pin_get_in_val(dln2, offset);
|
return dln2_gpio_pin_get_in_val(dln2, offset);
|
||||||
|
|
||||||
return dln2_gpio_pin_get_out_val(dln2, offset);
|
return dln2_gpio_pin_get_out_val(dln2, offset);
|
||||||
|
|
|
@ -8,10 +8,9 @@
|
||||||
* All enquiries to support@picochip.com
|
* All enquiries to support@picochip.com
|
||||||
*/
|
*/
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/clk.h>
|
||||||
/* FIXME: for gpio_get_value(), replace this with direct register read */
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -53,9 +52,9 @@
|
||||||
#define GPIO_EXT_PORTD 0x5c
|
#define GPIO_EXT_PORTD 0x5c
|
||||||
|
|
||||||
#define DWAPB_MAX_PORTS 4
|
#define DWAPB_MAX_PORTS 4
|
||||||
#define GPIO_EXT_PORT_SIZE (GPIO_EXT_PORTB - GPIO_EXT_PORTA)
|
#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
|
||||||
#define GPIO_SWPORT_DR_SIZE (GPIO_SWPORTB_DR - GPIO_SWPORTA_DR)
|
#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
|
||||||
#define GPIO_SWPORT_DDR_SIZE (GPIO_SWPORTB_DDR - GPIO_SWPORTA_DDR)
|
#define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */
|
||||||
|
|
||||||
#define GPIO_REG_OFFSET_V2 1
|
#define GPIO_REG_OFFSET_V2 1
|
||||||
|
|
||||||
|
@ -100,6 +99,7 @@ struct dwapb_gpio {
|
||||||
struct irq_domain *domain;
|
struct irq_domain *domain;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
struct reset_control *rst;
|
struct reset_control *rst;
|
||||||
|
struct clk *clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u32 gpio_reg_v2_convert(unsigned int offset)
|
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);
|
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)
|
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))
|
if (!port)
|
||||||
v &= ~BIT(offs);
|
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
|
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)
|
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;
|
return -ENOMEM;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_SIZE);
|
dat = gpio->regs + GPIO_EXT_PORTA + (pp->idx * GPIO_EXT_PORT_STRIDE);
|
||||||
set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_SIZE);
|
set = gpio->regs + GPIO_SWPORTA_DR + (pp->idx * GPIO_SWPORT_DR_STRIDE);
|
||||||
dirout = gpio->regs + GPIO_SWPORTA_DDR +
|
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,
|
err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -647,6 +672,16 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(gpio->regs))
|
if (IS_ERR(gpio->regs))
|
||||||
return PTR_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;
|
gpio->flags = 0;
|
||||||
if (dev->of_node) {
|
if (dev->of_node) {
|
||||||
const struct of_device_id *of_devid;
|
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_gpio_unregister(gpio);
|
||||||
dwapb_irq_teardown(gpio);
|
dwapb_irq_teardown(gpio);
|
||||||
reset_control_assert(gpio->rst);
|
reset_control_assert(gpio->rst);
|
||||||
|
clk_disable_unprepare(gpio->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -710,13 +746,13 @@ static int dwapb_gpio_suspend(struct device *dev)
|
||||||
|
|
||||||
BUG_ON(!ctx);
|
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);
|
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);
|
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);
|
ctx->ext = dwapb_read(gpio, offset);
|
||||||
|
|
||||||
/* Only port A can provide interrupts */
|
/* 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);
|
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||||
|
|
||||||
|
clk_disable_unprepare(gpio->clk);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -745,6 +783,9 @@ static int dwapb_gpio_resume(struct device *dev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!IS_ERR(gpio->clk))
|
||||||
|
clk_prepare_enable(gpio->clk);
|
||||||
|
|
||||||
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||||
for (i = 0; i < gpio->nr_ports; i++) {
|
for (i = 0; i < gpio->nr_ports; i++) {
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
@ -753,13 +794,13 @@ static int dwapb_gpio_resume(struct device *dev)
|
||||||
|
|
||||||
BUG_ON(!ctx);
|
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);
|
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);
|
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);
|
dwapb_write(gpio, offset, ctx->ext);
|
||||||
|
|
||||||
/* Only port A can provide interrupts */
|
/* 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/irqdomain.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
|
|
@ -14,19 +14,20 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
/* GPIO registers definition */
|
/* GPIO registers definition */
|
||||||
#define GPIO_DATA_OUT 0x00
|
#define GPIO_DATA_OUT 0x00
|
||||||
#define GPIO_DATA_IN 0x04
|
#define GPIO_DATA_IN 0x04
|
||||||
#define GPIO_DIR 0x08
|
#define GPIO_DIR 0x08
|
||||||
|
#define GPIO_BYPASS_IN 0x0C
|
||||||
#define GPIO_DATA_SET 0x10
|
#define GPIO_DATA_SET 0x10
|
||||||
#define GPIO_DATA_CLR 0x14
|
#define GPIO_DATA_CLR 0x14
|
||||||
#define GPIO_PULL_EN 0x18
|
#define GPIO_PULL_EN 0x18
|
||||||
#define GPIO_PULL_TYPE 0x1C
|
#define GPIO_PULL_TYPE 0x1C
|
||||||
#define GPIO_INT_EN 0x20
|
#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_MASK 0x2C
|
||||||
#define GPIO_INT_CLR 0x30
|
#define GPIO_INT_CLR 0x30
|
||||||
#define GPIO_INT_TYPE 0x34
|
#define GPIO_INT_TYPE 0x34
|
||||||
|
@ -147,7 +148,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
|
||||||
|
|
||||||
chained_irq_enter(irqchip, desc);
|
chained_irq_enter(irqchip, desc);
|
||||||
|
|
||||||
stat = readl(g->base + GPIO_INT_STAT);
|
stat = readl(g->base + GPIO_INT_STAT_RAW);
|
||||||
if (stat)
|
if (stat)
|
||||||
for_each_set_bit(offset, &stat, gc->ngpio)
|
for_each_set_bit(offset, &stat, gc->ngpio)
|
||||||
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
generic_handle_irq(irq_find_mapping(gc->irq.domain,
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
* This driver supports the following Diamond Systems devices: GPIO-MM and
|
* This driver supports the following Diamond Systems devices: GPIO-MM and
|
||||||
* GPIO-MM-12.
|
* GPIO-MM-12.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.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);
|
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,
|
static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||||
int value)
|
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_input = gpiomm_gpio_direction_input;
|
||||||
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
|
gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
|
||||||
gpiommgpio->chip.get = gpiomm_gpio_get;
|
gpiommgpio->chip.get = gpiomm_gpio_get;
|
||||||
|
gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
|
||||||
gpiommgpio->chip.set = gpiomm_gpio_set;
|
gpiommgpio->chip.set = gpiomm_gpio_set;
|
||||||
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
|
gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
|
||||||
gpiommgpio->base = base[id];
|
gpiommgpio->base = base[id];
|
||||||
|
|
|
@ -26,9 +26,8 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_gpio.h>
|
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/gpio/driver.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/platform_device.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
|
||||||
struct egpio_chip {
|
struct egpio_chip {
|
||||||
int reg_start;
|
int reg_start;
|
||||||
|
|
|
@ -23,9 +23,10 @@
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mfd/lpc_ich.h>
|
#include <linux/mfd/lpc_ich.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
#define DRV_NAME "gpio_ich"
|
#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);
|
ichx_priv.gpio_base);
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
data |= 1 << bit;
|
data |= BIT(bit);
|
||||||
else
|
else
|
||||||
data &= ~(1 << bit);
|
data &= ~BIT(bit);
|
||||||
ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
|
ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],
|
||||||
ichx_priv.gpio_base);
|
ichx_priv.gpio_base);
|
||||||
if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)
|
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);
|
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)
|
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)
|
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)
|
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);
|
spin_lock_irqsave(&ichx_priv.lock, flags);
|
||||||
|
|
||||||
/* GPI 0 - 15 are latched, write 1 to clear*/
|
/* 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);
|
data = ICHX_READ(0, ichx_priv.pm_base);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
spin_unlock_irqrestore(&ichx_priv.lock, flags);
|
||||||
|
|
||||||
return (data >> 16) & (1 << nr) ? 1 : 0;
|
return !!((data >> 16) & BIT(nr));
|
||||||
} else {
|
} else {
|
||||||
return ichx_gpio_get(chip, nr);
|
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.
|
* 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 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 0;
|
||||||
|
|
||||||
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
|
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;
|
return -ENODEV;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
|
for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {
|
||||||
if (!(use_gpio & (1 << i)))
|
if (!(use_gpio & BIT(i)))
|
||||||
continue;
|
continue;
|
||||||
if (!devm_request_region(dev,
|
if (!devm_request_region(dev,
|
||||||
res_base->start + ichx_priv.desc->regs[0][i],
|
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);
|
pcim_iounmap_regions(pdev, 1 << 1);
|
||||||
|
|
||||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv) {
|
if (!priv)
|
||||||
dev_err(&pdev->dev, "can't allocate chip data\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
priv->reg_base = pcim_iomap_table(pdev)[0];
|
priv->reg_base = pcim_iomap_table(pdev)[0];
|
||||||
priv->chip.label = dev_name(&pdev->dev);
|
priv->chip.label = dev_name(&pdev->dev);
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
|
|
||||||
/* Chip Id numbers */
|
/* Chip Id numbers */
|
||||||
#define NO_DEV_ID 0xffff
|
#define NO_DEV_ID 0xffff
|
||||||
|
|
|
@ -16,8 +16,9 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
|
||||||
#include <linux/mfd/janz.h>
|
#include <linux/mfd/janz.h>
|
||||||
|
|
||||||
|
@ -33,9 +34,9 @@
|
||||||
#define MASTER_INT_CTL 0x00
|
#define MASTER_INT_CTL 0x00
|
||||||
#define MASTER_CONF_CTL 0x01
|
#define MASTER_CONF_CTL 0x01
|
||||||
|
|
||||||
#define CONF_PAE (1 << 2)
|
#define CONF_PAE BIT(2)
|
||||||
#define CONF_PBE (1 << 7)
|
#define CONF_PBE BIT(7)
|
||||||
#define CONF_PCE (1 << 4)
|
#define CONF_PCE BIT(4)
|
||||||
|
|
||||||
struct ttl_control_regs {
|
struct ttl_control_regs {
|
||||||
__be16 portc;
|
__be16 portc;
|
||||||
|
@ -74,7 +75,7 @@ static int ttl_get_value(struct gpio_chip *gpio, unsigned offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&mod->lock);
|
spin_lock(&mod->lock);
|
||||||
ret = *shadow & (1 << offset);
|
ret = *shadow & BIT(offset);
|
||||||
spin_unlock(&mod->lock);
|
spin_unlock(&mod->lock);
|
||||||
return !!ret;
|
return !!ret;
|
||||||
}
|
}
|
||||||
|
@ -100,9 +101,9 @@ static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value)
|
||||||
|
|
||||||
spin_lock(&mod->lock);
|
spin_lock(&mod->lock);
|
||||||
if (value)
|
if (value)
|
||||||
*shadow |= (1 << offset);
|
*shadow |= BIT(offset);
|
||||||
else
|
else
|
||||||
*shadow &= ~(1 << offset);
|
*shadow &= ~BIT(offset);
|
||||||
|
|
||||||
iowrite16be(*shadow, port);
|
iowrite16be(*shadow, port);
|
||||||
spin_unlock(&mod->lock);
|
spin_unlock(&mod->lock);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/mfd/kempld.h>
|
#include <linux/mfd/kempld.h>
|
||||||
|
|
||||||
#define KEMPLD_GPIO_MAX_NUM 16
|
#define KEMPLD_GPIO_MAX_NUM 16
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* 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/kernel.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
|
@ -315,12 +315,17 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
|
||||||
struct gpio_desc **desc,
|
struct gpio_desc **desc,
|
||||||
int value)
|
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++)
|
for (i = 0; i < ndescs; i++)
|
||||||
values[i] = value;
|
values[i] = value;
|
||||||
|
|
||||||
gpiod_set_array_value_cansleep(ndescs, desc, values);
|
gpiod_set_array_value_cansleep(ndescs, desc, values);
|
||||||
|
kfree(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct gpio_descs *devm_gpiod_get_array_optional_count(
|
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));
|
pcim_iounmap_regions(pdev, BIT(1));
|
||||||
|
|
||||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||||
if (!priv) {
|
if (!priv)
|
||||||
dev_err(&pdev->dev, "can't allocate chip data\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
priv->dev = &pdev->dev;
|
priv->dev = &pdev->dev;
|
||||||
priv->reg_base = pcim_iomap_table(pdev)[0];
|
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);
|
chip_save = kzalloc(sizeof(*chip) * 8, GFP_KERNEL);
|
||||||
if (chip_save == NULL) {
|
if (chip_save == NULL) {
|
||||||
dev_err(&pdev->dev, "%s : kzalloc failed", __func__);
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_kzalloc;
|
goto err_kzalloc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* GPIO Testing Device Driver
|
* GPIO Testing Device Driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com>
|
* 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>
|
* Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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)
|
if (rv)
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
if (gpio_mockup_dbg_dir)
|
if (!IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
|
||||||
gpio_mockup_debugfs_setup(dev, chip);
|
gpio_mockup_debugfs_setup(dev, chip);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -411,7 +411,7 @@ module_init(gpio_mockup_init);
|
||||||
module_exit(gpio_mockup_exit);
|
module_exit(gpio_mockup_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
|
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_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
|
||||||
MODULE_DESCRIPTION("GPIO Testing driver");
|
MODULE_DESCRIPTION("GPIO Testing driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
|
@ -1157,11 +1157,9 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL);
|
bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
|
||||||
if (!bank) {
|
if (!bank)
|
||||||
dev_err(dev, "Memory alloc failed\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
|
irqc = devm_kzalloc(dev, sizeof(*irqc), GFP_KERNEL);
|
||||||
if (!irqc)
|
if (!irqc)
|
||||||
|
|
|
@ -70,6 +70,7 @@ static const struct i2c_device_id pca953x_id[] = {
|
||||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||||
{ "pca9698", 40 | PCA953X_TYPE, },
|
{ "pca9698", 40 | PCA953X_TYPE, },
|
||||||
|
|
||||||
|
{ "pcal6524", 24 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
|
||||||
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
|
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
|
||||||
|
|
||||||
{ "max7310", 8 | PCA953X_TYPE, },
|
{ "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,pca9575", .data = OF_957X(16, PCA_INT), },
|
||||||
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
|
{ .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,max7310", .data = OF_953X( 8, 0), },
|
||||||
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
|
||||||
{ .compatible = "maxim,max7313", .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
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.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));
|
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,
|
static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||||
int value)
|
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_input = idio_16_gpio_direction_input;
|
||||||
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
|
||||||
idio16gpio->chip.get = idio_16_gpio_get;
|
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 = idio_16_gpio_set;
|
||||||
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
* This driver supports the following ACCES devices: PCIe-IDIO-24,
|
* This driver supports the following ACCES devices: PCIe-IDIO-24,
|
||||||
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
|
* PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.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);
|
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,
|
static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||||
int value)
|
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);
|
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)
|
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_input = idio_24_gpio_direction_input;
|
||||||
idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
|
idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
|
||||||
idio24gpio->chip.get = idio_24_gpio_get;
|
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 = idio_24_gpio_set;
|
||||||
|
idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
|
||||||
|
|
||||||
raw_spin_lock_init(&idio24gpio->lock);
|
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/spinlock.h>
|
||||||
#include <linux/slab.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 {
|
struct gpio_rcar_priv {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
@ -39,6 +49,7 @@ struct gpio_rcar_priv {
|
||||||
unsigned int irq_parent;
|
unsigned int irq_parent;
|
||||||
atomic_t wakeup_path;
|
atomic_t wakeup_path;
|
||||||
bool has_both_edge_trigger;
|
bool has_both_edge_trigger;
|
||||||
|
struct gpio_rcar_bank_info bank_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
#define IOINTSEL 0x00 /* General IO/Interrupt Switching Register */
|
||||||
|
@ -512,17 +523,62 @@ static int gpio_rcar_remove(struct platform_device *pdev)
|
||||||
return 0;
|
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);
|
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))
|
if (atomic_read(&p->wakeup_path))
|
||||||
device_set_wakeup_path(dev);
|
device_set_wakeup_path(dev);
|
||||||
|
|
||||||
return 0;
|
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 = {
|
static struct platform_driver gpio_rcar_device_driver = {
|
||||||
.probe = gpio_rcar_probe,
|
.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/debugfs.h>
|
||||||
#include <linux/seq_file.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;
|
struct tegra_gpio_info *tgi = s->private;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
@ -530,22 +530,12 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dbg_gpio_open(struct inode *inode, struct file *file)
|
DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio);
|
||||||
{
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
|
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
|
||||||
{
|
{
|
||||||
(void) debugfs_create_file("tegra_gpio", 0444,
|
(void) debugfs_create_file("tegra_gpio", 0444,
|
||||||
NULL, tgi, &debug_fops);
|
NULL, tgi, &tegra_dbg_gpio_fops);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -238,11 +238,10 @@ static int timbgpio_probe(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tgpio = devm_kzalloc(dev, sizeof(struct timbgpio), GFP_KERNEL);
|
tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL);
|
||||||
if (!tgpio) {
|
if (!tgpio)
|
||||||
dev_err(dev, "Memory alloc failed\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
tgpio->irq_base = pdata->irq_base;
|
tgpio->irq_base = pdata->irq_base;
|
||||||
|
|
||||||
spin_lock_init(&tgpio->lock);
|
spin_lock_init(&tgpio->lock);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* GPIO driver for TPS68470 PMIC
|
* GPIO driver for TPS68470 PMIC
|
||||||
*
|
*
|
||||||
|
@ -8,15 +9,6 @@
|
||||||
* Tianshu Qiu <tian.shu.qiu@intel.com>
|
* Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||||
* Jian Xu Zheng <jian.xu.zheng@intel.com>
|
* Jian Xu Zheng <jian.xu.zheng@intel.com>
|
||||||
* Yuning Pu <yuning.pu@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>
|
#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,
|
dev_err(wm831x->dev,
|
||||||
"GPIO control %d read failed: %d\n",
|
"GPIO control %d read failed: %d\n",
|
||||||
gpio, reg);
|
gpio, reg);
|
||||||
seq_printf(s, "\n");
|
seq_putc(s, '\n');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* General Public License for more details.
|
* General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
@ -129,6 +130,51 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
return !!(port_state & mask);
|
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)
|
static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
{
|
{
|
||||||
struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
|
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_input = ws16c48_gpio_direction_input;
|
||||||
ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
|
ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
|
||||||
ws16c48gpio->chip.get = ws16c48_gpio_get;
|
ws16c48gpio->chip.get = ws16c48_gpio_get;
|
||||||
|
ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
|
||||||
ws16c48gpio->chip.set = ws16c48_gpio_set;
|
ws16c48gpio->chip.set = ws16c48_gpio_set;
|
||||||
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
|
||||||
ws16c48gpio->base = base[id];
|
ws16c48gpio->base = base[id];
|
||||||
|
|
|
@ -126,11 +126,16 @@ static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
||||||
{
|
{
|
||||||
int reg;
|
int reg;
|
||||||
struct xra1403 *xra = gpiochip_get_data(chip);
|
struct xra1403 *xra = gpiochip_get_data(chip);
|
||||||
int value[xra1403_regmap_cfg.max_register];
|
int *value;
|
||||||
int i;
|
int i;
|
||||||
unsigned int gcr;
|
unsigned int gcr;
|
||||||
unsigned int gsr;
|
unsigned int gsr;
|
||||||
|
|
||||||
|
value = kmalloc_array(xra1403_regmap_cfg.max_register, sizeof(*value),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
|
||||||
seq_puts(s, "xra reg:");
|
seq_puts(s, "xra reg:");
|
||||||
for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++)
|
for (reg = 0; reg <= xra1403_regmap_cfg.max_register; reg++)
|
||||||
seq_printf(s, " %2.2x", 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",
|
(gcr & BIT(i)) ? "in" : "out",
|
||||||
(gsr & BIT(i)) ? "hi" : "lo");
|
(gsr & BIT(i)) ? "hi" : "lo");
|
||||||
}
|
}
|
||||||
|
kfree(value);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define xra1403_dbg_show NULL
|
#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);
|
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
|
#ifdef CONFIG_PINCTRL
|
||||||
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
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)
|
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
of_gpiochip_init_valid_mask(chip);
|
||||||
|
|
||||||
status = of_gpiochip_add_pin_range(chip);
|
status = of_gpiochip_add_pin_range(chip);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -337,6 +337,57 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
|
||||||
return 0;
|
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
|
* GPIO line handle management
|
||||||
*/
|
*/
|
||||||
|
@ -1261,6 +1312,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
|
||||||
if (status)
|
if (status)
|
||||||
goto err_remove_from_list;
|
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);
|
status = gpiochip_add_irqchip(chip, lock_key, request_key);
|
||||||
if (status)
|
if (status)
|
||||||
goto err_remove_chip;
|
goto err_remove_chip;
|
||||||
|
@ -1290,6 +1345,8 @@ err_remove_chip:
|
||||||
acpi_gpiochip_remove(chip);
|
acpi_gpiochip_remove(chip);
|
||||||
gpiochip_free_hogs(chip);
|
gpiochip_free_hogs(chip);
|
||||||
of_gpiochip_remove(chip);
|
of_gpiochip_remove(chip);
|
||||||
|
gpiochip_free_valid_mask(chip);
|
||||||
|
err_remove_irqchip_mask:
|
||||||
gpiochip_irqchip_free_valid_mask(chip);
|
gpiochip_irqchip_free_valid_mask(chip);
|
||||||
err_remove_from_list:
|
err_remove_from_list:
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
spin_lock_irqsave(&gpio_lock, flags);
|
||||||
|
@ -1346,6 +1403,7 @@ void gpiochip_remove(struct gpio_chip *chip)
|
||||||
acpi_gpiochip_remove(chip);
|
acpi_gpiochip_remove(chip);
|
||||||
gpiochip_remove_pin_ranges(chip);
|
gpiochip_remove_pin_ranges(chip);
|
||||||
of_gpiochip_remove(chip);
|
of_gpiochip_remove(chip);
|
||||||
|
gpiochip_free_valid_mask(chip);
|
||||||
/*
|
/*
|
||||||
* We accept no more calls into the driver from this point, so
|
* We accept no more calls into the driver from this point, so
|
||||||
* NULL the driver data pointer
|
* 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)
|
if (!gpiochip->irq.need_valid_mask)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
|
gpiochip->irq.valid_mask = gpiochip_allocate_mask(gpiochip);
|
||||||
sizeof(long), GFP_KERNEL);
|
|
||||||
if (!gpiochip->irq.valid_mask)
|
if (!gpiochip->irq.valid_mask)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Assume by default all GPIOs are valid */
|
|
||||||
bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
|
|
||||||
|
|
||||||
return 0;
|
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,
|
bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
|
||||||
unsigned int offset)
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
|
if (!gpiochip_line_is_valid(gpiochip, offset))
|
||||||
|
return false;
|
||||||
/* No mask means all valid */
|
/* No mask means all valid */
|
||||||
if (likely(!gpiochip->irq.valid_mask))
|
if (likely(!gpiochip->irq.valid_mask))
|
||||||
return true;
|
return true;
|
||||||
|
@ -3689,7 +3745,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR(desc)) {
|
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;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
#define GPIOLIB_H
|
#define GPIOLIB_H
|
||||||
|
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
enum of_gpio_flags;
|
enum of_gpio_flags;
|
||||||
enum gpiod_flags;
|
|
||||||
enum gpio_lookup_flags;
|
enum gpio_lookup_flags;
|
||||||
struct acpi_device;
|
struct acpi_device;
|
||||||
|
|
||||||
|
|
|
@ -697,7 +697,8 @@ config STM32_DFSDM_ADC
|
||||||
|
|
||||||
config STX104
|
config STX104
|
||||||
tristate "Apex Embedded Systems STX104 driver"
|
tristate "Apex Embedded Systems STX104 driver"
|
||||||
depends on PC104 && X86 && ISA_BUS_API
|
depends on PC104 && X86
|
||||||
|
select ISA_BUS_API
|
||||||
select GPIOLIB
|
select GPIOLIB
|
||||||
help
|
help
|
||||||
Say yes here to build support for the Apex Embedded Systems STX104
|
Say yes here to build support for the Apex Embedded Systems STX104
|
||||||
|
|
|
@ -7,7 +7,8 @@ menu "Counters"
|
||||||
|
|
||||||
config 104_QUAD_8
|
config 104_QUAD_8
|
||||||
tristate "ACCES 104-QUAD-8 driver"
|
tristate "ACCES 104-QUAD-8 driver"
|
||||||
depends on PC104 && X86 && ISA_BUS_API
|
depends on PC104 && X86
|
||||||
|
select ISA_BUS_API
|
||||||
help
|
help
|
||||||
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
|
Say yes here to build support for the ACCES 104-QUAD-8 quadrature
|
||||||
encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
|
encoder counter/interface device family (104-QUAD-8, 104-QUAD-4).
|
||||||
|
|
|
@ -195,7 +195,8 @@ config AD7303
|
||||||
|
|
||||||
config CIO_DAC
|
config CIO_DAC
|
||||||
tristate "Measurement Computing CIO-DAC IIO driver"
|
tristate "Measurement Computing CIO-DAC IIO driver"
|
||||||
depends on X86 && ISA_BUS_API
|
depends on X86 && (ISA_BUS || PC104)
|
||||||
|
select ISA_BUS_API
|
||||||
help
|
help
|
||||||
Say yes here to build support for the Measurement Computing CIO-DAC
|
Say yes here to build support for the Measurement Computing CIO-DAC
|
||||||
analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
|
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,
|
.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)
|
static int msm_get_functions_count(struct pinctrl_dev *pctldev)
|
||||||
{
|
{
|
||||||
struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(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 = {
|
static const struct pinmux_ops msm_pinmux_ops = {
|
||||||
|
.request = msm_pinmux_request,
|
||||||
.get_functions_count = msm_get_functions_count,
|
.get_functions_count = msm_get_functions_count,
|
||||||
.get_function_name = msm_get_function_name,
|
.get_function_name = msm_get_function_name,
|
||||||
.get_function_groups = msm_get_function_groups,
|
.get_function_groups = msm_get_function_groups,
|
||||||
|
@ -506,6 +515,9 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
|
||||||
"pull up"
|
"pull up"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!gpiochip_line_is_valid(chip, offset))
|
||||||
|
return;
|
||||||
|
|
||||||
g = &pctrl->soc->groups[offset];
|
g = &pctrl->soc->groups[offset];
|
||||||
ctl_reg = readl(pctrl->regs + g->ctl_reg);
|
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, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
|
||||||
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
|
seq_printf(s, " %dmA", msm_regval_to_drive(drive));
|
||||||
seq_printf(s, " %s", pulls[pull]);
|
seq_printf(s, " %s", pulls[pull]);
|
||||||
|
seq_puts(s, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
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 gpio = chip->base;
|
||||||
unsigned i;
|
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);
|
msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
|
||||||
seq_puts(s, "\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -808,6 +819,46 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
|
||||||
chained_irq_exit(chip, 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)
|
static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||||
{
|
{
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
|
@ -824,6 +875,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||||
chip->parent = pctrl->dev;
|
chip->parent = pctrl->dev;
|
||||||
chip->owner = THIS_MODULE;
|
chip->owner = THIS_MODULE;
|
||||||
chip->of_node = pctrl->dev->of_node;
|
chip->of_node = pctrl->dev->of_node;
|
||||||
|
chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
|
||||||
|
|
||||||
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
ret = gpiochip_add_data(&pctrl->chip, pctrl);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -831,6 +883,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
|
||||||
return ret;
|
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);
|
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(pctrl->dev, "Failed to add pin range\n");
|
dev_err(pctrl->dev, "Failed to add pin range\n");
|
||||||
|
|
|
@ -866,7 +866,8 @@ config ALIM7101_WDT
|
||||||
|
|
||||||
config EBC_C384_WDT
|
config EBC_C384_WDT
|
||||||
tristate "WinSystems EBC-C384 Watchdog Timer"
|
tristate "WinSystems EBC-C384 Watchdog Timer"
|
||||||
depends on X86 && ISA_BUS_API
|
depends on X86
|
||||||
|
select ISA_BUS_API
|
||||||
select WATCHDOG_CORE
|
select WATCHDOG_CORE
|
||||||
help
|
help
|
||||||
Enables watchdog timer support for the watchdog timer on the
|
Enables watchdog timer support for the watchdog timer on the
|
||||||
|
|
|
@ -288,6 +288,21 @@ struct gpio_chip {
|
||||||
struct gpio_irq_chip irq;
|
struct gpio_irq_chip irq;
|
||||||
#endif
|
#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 defined(CONFIG_OF_GPIO)
|
||||||
/*
|
/*
|
||||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||||
|
@ -384,6 +399,7 @@ bool gpiochip_line_is_open_source(struct gpio_chip *chip, unsigned int offset);
|
||||||
|
|
||||||
/* Sleep persistence inquiry for drivers */
|
/* Sleep persistence inquiry for drivers */
|
||||||
bool gpiochip_line_is_persistent(struct gpio_chip *chip, unsigned int offset);
|
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 */
|
/* get driver data */
|
||||||
void *gpiochip_get_data(struct gpio_chip *chip);
|
void *gpiochip_get_data(struct gpio_chip *chip);
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
#ifndef __HTC_EGPIO_H__
|
#ifndef __HTC_EGPIO_H__
|
||||||
#define __HTC_EGPIO_H__
|
#define __HTC_EGPIO_H__
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
|
|
||||||
/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */
|
/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */
|
||||||
#define HTC_EGPIO_OUTPUT (~0)
|
#define HTC_EGPIO_OUTPUT (~0)
|
||||||
#define HTC_EGPIO_INPUT 0
|
#define HTC_EGPIO_INPUT 0
|
||||||
|
|
|
@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
|
||||||
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
|
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
|
||||||
RPI_FIRMWARE_GET_TURBO = 0x00030009,
|
RPI_FIRMWARE_GET_TURBO = 0x00030009,
|
||||||
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
|
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
|
||||||
|
RPI_FIRMWARE_GET_STC = 0x0003000b,
|
||||||
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
|
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
|
||||||
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
|
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
|
||||||
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
|
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
|
||||||
|
@ -72,12 +73,22 @@ enum rpi_firmware_property_tag {
|
||||||
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
|
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
|
||||||
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
|
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
|
||||||
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
|
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
|
||||||
|
RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
|
||||||
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
|
RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030,
|
||||||
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
|
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
|
||||||
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
|
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
|
||||||
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
|
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
|
||||||
RPI_FIRMWARE_SET_TURBO = 0x00038009,
|
RPI_FIRMWARE_SET_TURBO = 0x00038009,
|
||||||
|
RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
|
||||||
RPI_FIRMWARE_SET_DOMAIN_STATE = 0x00038030,
|
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 */
|
/* Dispmanx TAGS */
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
|
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_VIRTUAL_OFFSET = 0x00040009,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
|
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
|
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_RELEASE = 0x00048001,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
|
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
|
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_VIRTUAL_OFFSET = 0x00044009,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
|
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
|
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
|
||||||
|
RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
|
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
|
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
|
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_VIRTUAL_OFFSET = 0x00048009,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
||||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
|
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,
|
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
|
||||||
|
|
||||||
|
|
|
@ -1437,7 +1437,7 @@ config PERF_USE_VMALLOC
|
||||||
See tools/perf/design.txt for details
|
See tools/perf/design.txt for details
|
||||||
|
|
||||||
config PC104
|
config PC104
|
||||||
bool "PC/104 support"
|
bool "PC/104 support" if EXPERT
|
||||||
help
|
help
|
||||||
Expose PC/104 form factor device drivers and options available for
|
Expose PC/104 form factor device drivers and options available for
|
||||||
selection and configuration. Enable this option if your target
|
selection and configuration. Enable this option if your target
|
||||||
|
|
|
@ -99,7 +99,7 @@ int monitor_device(const char *device_name,
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fprintf(stdout, "GPIO EVENT %" PRIu64 ": ", event.timestamp);
|
fprintf(stdout, "GPIO EVENT %llu: ", event.timestamp);
|
||||||
switch (event.id) {
|
switch (event.id) {
|
||||||
case GPIOEVENT_EVENT_RISING_EDGE:
|
case GPIOEVENT_EVENT_RISING_EDGE:
|
||||||
fprintf(stdout, "rising edge");
|
fprintf(stdout, "rising edge");
|
||||||
|
|
Loading…
Reference in a new issue