This is the bulk of the GPIO changes for the v4.14 cycle:
Core changes - Allow the GPIO irqchip to allocate IRQs dynamically. This is an important change on systems where only a restricted number of IRQs, lesser than the number of GPIO lines, can be utilized. Now we can allocate these on a first-come-first-served basis instead of hogging up valuable IRQ lines. - Serious fix-up of the kerneldoc documentation and inclusion into the kerneldoc builds. - Pulled in the IRQ simulator from the IRQ core tree and use this in the GPIO mockup driver for exhaustive testing of interrupt abilities. New drivers - New driver for ThunderX and OCTEON-TX. This is especially interesting as it picks up improvements from the IRQ core that allow us to handle fasteoi ACKs upwards in a hierarchy when there are IRQ flag latches on several levels in a hierarchy. Very interesting work here. - New subdriver for Renesas R-Car r8a7745 (RZ/G1E). Misc - Several fixes and improvements for Xilinx Zynq GPIO. - Support an enablement GPIO for the 74x164 GPIO. - Switch a bunch of chips to use devres to allocate irq descriptors. - A bunch of constification fixes. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJZrmRvAAoJEEEQszewGV1zFd8P/0wwsPFfCY5tjqMwYcu2VIzA ZEPlN/Z14Xr/JC7X5N18qWaZSdqAP94do8fn1Utqr6mEOY71BAAmt1dRH3M651nz dyAnb5s8IlnFNrv2C3ksG4ArQP72y3uag7b/9fcDPSFBjQKHXP9zI5qhvxJI8XFY iesWkwkQayDzbKvm/bFWugclYjSNZCwtzGn2OD0zhh8vKchQBEdLYuiV06iEuvh4 dkfpH5UhingJ0gMgMj3VLXvnaSPOQy321mnnF8cmHIwelZR8ij3JPQzirKB/cvTe fj/INc9/gXFOepFcEaQcWwspeXOXCjOajqfCyeLKLigj44E7pbv4HeTLJmQtCWv/ fBlHnzjEJG7zZi8JOuKeMwMSc/6GPHBhlmZ4GjpMtIeNXQ8V2oosLbvSd5/whtPg u9QuDDeTJwjm1HY3kBNa50BKYrAAKIATHxnYAlGrDTf/9ea5Ld7AT/IfeGHS2AQR nV6I0byRYCxEVZUTPeYOMoHDNGgVgA9VPAhUUjLj6r6Kx2bS4Pn7KNvSNx24SQTU wP+rWDXRNJzIMr9+sWj3yAksYZPQSpV2+y/VizeHZA7ssv3ZzqKzfWPARhQy/ypF GN72LObdxaW01GjN9bJ8x4KxBj+tIo2lLXYIK5TdKZy+LRxnsbCK6JGa5gFxopQh 325SOqkLlhaS2P6A2nHC =TYNw -----END PGP SIGNATURE----- Merge tag 'gpio-v4.14-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 the GPIO changes for the v4.14 cycle. Not so much changes this time, phew. David Daney and Bartosz Golaszewski did all the really interesting work in infrastructure improvement across GPIO and IRQ core, hats off for them and to tglx and Marc Z for general help with these patch sets. Core changes: - Allow the GPIO irqchip to allocate IRQs dynamically. This is an important change on systems where only a restricted number of IRQs, lesser than the number of GPIO lines, can be utilized. Now we can allocate these on a first-come-first-served basis instead of hogging up valuable IRQ lines. - Serious fix-up of the kerneldoc documentation and inclusion into the kerneldoc builds. - Pulled in the IRQ simulator from the IRQ core tree and use this in the GPIO mockup driver for exhaustive testing of interrupt abilities. New drivers: - New driver for ThunderX and OCTEON-TX. This is especially interesting as it picks up improvements from the IRQ core that allow us to handle fasteoi ACKs upwards in a hierarchy when there are IRQ flag latches on several levels in a hierarchy. Very interesting work here. - New subdriver for Renesas R-Car r8a7745 (RZ/G1E). Misc: - Several fixes and improvements for Xilinx Zynq GPIO. - Support an enablement GPIO for the 74x164 GPIO. - Switch a bunch of chips to use devres to allocate irq descriptors. - A bunch of constification fixes" * tag 'gpio-v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (63 commits) gpio: mockup: remove unused variable gc gpio: pl061: constify amba_id Revert "gpiolib: request the gpio before querying its direction" gpio: twl6040: remove unneeded forward declaration gpio: zevio: make gpio_chip const gpio: add gpio_add_lookup_tables() to add several tables at once gpio: rcar: Add r8a7745 (RZ/G1E) support gpio: brcmstb: check return value of gpiochip_irqchip_add() MAINTAINERS: Add entry for THUNDERX GPIO Driver. gpio: Add gpio driver support for ThunderX and OCTEON-TX gpio: mockup: use irq_sim gpio: mxs: use devres for irq generic chip gpio: mxc: use devres for irq generic chip gpio: pch: use devres for irq generic chip gpio: ml-ioh: use devres for irq generic chip gpio: sta2x11: use devres for irq generic chip gpio: sta2x11: disallow unbinding the driver gpio: mxs: disallow unbinding the driver gpio: mxc: disallow unbinding the driver gpio: aspeed: Remove reference to clock name in debounce warning message ...
This commit is contained in:
commit
70b8e9eb3b
@ -12,6 +12,9 @@ Required properties:
|
||||
1 = active low
|
||||
- registers-number: Number of daisy-chained shift registers
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO connected to the OE (Output Enable) pin.
|
||||
|
||||
Example:
|
||||
|
||||
gpio5: gpio5@0 {
|
||||
|
@ -18,7 +18,7 @@ Required properties:
|
||||
Optional properties:
|
||||
|
||||
- interrupt-parent : The parent interrupt controller, optional if inherited
|
||||
- clocks : A phandle to the HPLL clock node for debounce timings
|
||||
- clocks : A phandle to the clock to use for debounce timings
|
||||
|
||||
The gpio and interrupt properties are further described in their respective
|
||||
bindings documentation:
|
||||
|
@ -1,7 +1,10 @@
|
||||
Davinci/Keystone GPIO controller bindings
|
||||
|
||||
Required Properties:
|
||||
- compatible: should be "ti,dm6441-gpio", "ti,keystone-gpio"
|
||||
- compatible: should be "ti,dm6441-gpio": for Davinci da850 SoCs
|
||||
"ti,keystone-gpio": for Keystone 2 66AK2H/K, 66AK2L,
|
||||
66AK2E SoCs
|
||||
"ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
|
||||
|
||||
- reg: Physical base address of the controller and the size of memory mapped
|
||||
registers.
|
||||
@ -20,7 +23,21 @@ Required Properties:
|
||||
- ti,ngpio: The number of GPIO pins supported.
|
||||
|
||||
- ti,davinci-gpio-unbanked: The number of GPIOs that have an individual interrupt
|
||||
line to processor.
|
||||
line to processor.
|
||||
|
||||
- clocks: Should contain the device's input clock, and should be defined as per
|
||||
the appropriate clock bindings consumer usage in,
|
||||
|
||||
Documentation/devicetree/bindings/clock/keystone-gate.txt
|
||||
for 66AK2HK/66AK2L/66AK2E SoCs or,
|
||||
|
||||
Documentation/devicetree/bindings/clock/ti,sci-clk.txt
|
||||
for 66AK2G SoCs
|
||||
|
||||
- clock-names: Name should be "gpio";
|
||||
|
||||
Currently clock-names and clocks are needed for all keystone 2 platforms
|
||||
Davinci platforms do not have DT clocks as of now.
|
||||
|
||||
The GPIO controller also acts as an interrupt controller. It uses the default
|
||||
two cells specifier as described in Documentation/devicetree/bindings/
|
||||
@ -60,3 +77,73 @@ leds {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
Example for 66AK2G:
|
||||
|
||||
gpio0: gpio@2603000 {
|
||||
compatible = "ti,k2g-gpio", "ti,keystone-gpio";
|
||||
reg = <0x02603000 0x100>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <GIC_SPI 432 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 433 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 434 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 435 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 436 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 437 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 438 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 439 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 440 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
ti,ngpio = <144>;
|
||||
ti,davinci-gpio-unbanked = <0>;
|
||||
clocks = <&k2g_clks 0x001b 0x0>;
|
||||
clock-names = "gpio";
|
||||
};
|
||||
|
||||
Example for 66AK2HK/66AK2L/66AK2E:
|
||||
|
||||
gpio0: gpio@260bf00 {
|
||||
compatible = "ti,keystone-gpio";
|
||||
reg = <0x0260bf00 0x100>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
/* HW Interrupts mapped to GPIO pins */
|
||||
interrupts = <GIC_SPI 120 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 121 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 122 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 123 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 124 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 125 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 126 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 127 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 128 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 129 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 130 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 131 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 132 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 133 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 134 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 135 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 136 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 137 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 138 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 139 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 140 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 141 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 142 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 143 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 144 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 145 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 146 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 147 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 148 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 149 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 150 IRQ_TYPE_EDGE_RISING>,
|
||||
<GIC_SPI 151 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkgpio>;
|
||||
clock-names = "gpio";
|
||||
ti,ngpio = <32>;
|
||||
ti,davinci-gpio-unbanked = <32>;
|
||||
};
|
||||
|
@ -5,7 +5,9 @@ functionality. Each pair serves 32 GPIOs. The VF610 has 5 instances of
|
||||
each, and each PORT module has its own interrupt.
|
||||
|
||||
Required properties for GPIO node:
|
||||
- compatible : Should be "fsl,<soc>-gpio", currently "fsl,vf610-gpio"
|
||||
- compatible : Should be "fsl,<soc>-gpio", below is supported list:
|
||||
"fsl,vf610-gpio"
|
||||
"fsl,imx7ulp-gpio"
|
||||
- reg : The first reg tuple represents the PORT module, the second tuple
|
||||
the GPIO module.
|
||||
- interrupts : Should be the port interrupt shared by all 32 pins.
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should contain one of the following.
|
||||
- compatible: should contain one or more of the following:
|
||||
- "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7778": for R8A7778 (R-Mobile M1) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
|
||||
@ -13,7 +14,14 @@ Required Properties:
|
||||
- "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller.
|
||||
- "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller.
|
||||
- "renesas,gpio-rcar": for generic R-Car GPIO controller.
|
||||
- "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
|
||||
- "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
|
||||
- "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 GPIO controller.
|
||||
- "renesas,gpio-rcar": deprecated.
|
||||
|
||||
When compatible with the generic version nodes must list the
|
||||
SoC-specific version corresponding to the platform first followed by
|
||||
the generic version.
|
||||
|
||||
- reg: Base address and length of each memory resource used by the GPIO
|
||||
controller hardware module.
|
||||
@ -43,7 +51,7 @@ interrupt-controller/interrupts.txt.
|
||||
Example: R8A7779 (R-Car H1) GPIO controller nodes
|
||||
|
||||
gpio0: gpio@ffc40000 {
|
||||
compatible = "renesas,gpio-r8a7779", "renesas,gpio-rcar";
|
||||
compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio";
|
||||
reg = <0xffc40000 0x2c>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 141 0x4>;
|
||||
@ -55,7 +63,7 @@ Example: R8A7779 (R-Car H1) GPIO controller nodes
|
||||
};
|
||||
...
|
||||
gpio6: gpio@ffc46000 {
|
||||
compatible = "renesas,gpio-r8a7779", "renesas,gpio-rcar";
|
||||
compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio";
|
||||
reg = <0xffc46000 0x2c>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 147 0x4>;
|
||||
|
45
Documentation/driver-api/gpio.rst
Normal file
45
Documentation/driver-api/gpio.rst
Normal file
@ -0,0 +1,45 @@
|
||||
===================================
|
||||
General Purpose Input/Output (GPIO)
|
||||
===================================
|
||||
|
||||
Core
|
||||
====
|
||||
|
||||
.. kernel-doc:: include/linux/gpio/driver.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib.c
|
||||
:export:
|
||||
|
||||
Legacy API
|
||||
==========
|
||||
|
||||
The functions listed in this section are deprecated. The GPIO descriptor based
|
||||
API described above should be used in new code.
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-legacy.c
|
||||
:export:
|
||||
|
||||
ACPI support
|
||||
============
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-acpi.c
|
||||
:export:
|
||||
|
||||
Device tree support
|
||||
===================
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-of.c
|
||||
:export:
|
||||
|
||||
Device-managed API
|
||||
==================
|
||||
|
||||
.. kernel-doc:: drivers/gpio/devres.c
|
||||
:export:
|
||||
|
||||
sysfs helpers
|
||||
=============
|
||||
|
||||
.. kernel-doc:: drivers/gpio/gpiolib-sysfs.c
|
||||
:export:
|
@ -44,6 +44,7 @@ available subsections can be seen below.
|
||||
uio-howto
|
||||
firmware/index
|
||||
pinctl
|
||||
gpio
|
||||
misc_devices
|
||||
|
||||
.. only:: subproject and html
|
||||
|
@ -13018,6 +13018,11 @@ M: Yehezkel Bernat <yehezkel.bernat@intel.com>
|
||||
S: Maintained
|
||||
F: drivers/thunderbolt/
|
||||
|
||||
THUNDERX GPIO DRIVER
|
||||
M: David Daney <david.daney@cavium.com>
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-thunderx.c
|
||||
|
||||
TI AM437X VPFE DRIVER
|
||||
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
@ -311,7 +311,7 @@ config GPIO_MOCKUP
|
||||
depends on GPIOLIB && SYSFS
|
||||
select GPIO_SYSFS
|
||||
select GPIOLIB_IRQCHIP
|
||||
select IRQ_WORK
|
||||
select IRQ_SIM
|
||||
help
|
||||
This enables GPIO Testing driver, which provides a way to test GPIO
|
||||
subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
|
||||
@ -450,6 +450,15 @@ config GPIO_TS4800
|
||||
help
|
||||
This driver support TS-4800 FPGA GPIO controllers.
|
||||
|
||||
config GPIO_THUNDERX
|
||||
tristate "Cavium ThunderX/OCTEON-TX GPIO"
|
||||
depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
|
||||
depends on PCI_MSI && IRQ_DOMAIN_HIERARCHY
|
||||
select IRQ_FASTEOI_HIERARCHY_HANDLERS
|
||||
help
|
||||
Say yes here to support the on-chip GPIO lines on the ThunderX
|
||||
and OCTEON-TX families of SoCs.
|
||||
|
||||
config GPIO_TZ1090
|
||||
bool "Toumaz Xenif TZ1090 GPIO support"
|
||||
depends on SOC_TZ1090
|
||||
@ -1065,6 +1074,21 @@ config GPIO_TPS65912
|
||||
help
|
||||
This driver supports TPS65912 gpio chip
|
||||
|
||||
config GPIO_TPS68470
|
||||
bool "TPS68470 GPIO"
|
||||
depends on MFD_TPS68470
|
||||
help
|
||||
Select this option to enable GPIO driver for the TPS68470
|
||||
chip family.
|
||||
There are 7 GPIOs and few sensor related GPIOs supported
|
||||
by the TPS68470. While the 7 GPIOs can be configured as
|
||||
input or output as appropriate, the sensor related GPIOs
|
||||
are "output only" GPIOs.
|
||||
|
||||
This driver config is bool, as the GPIO functionality
|
||||
of the TPS68470 must be available before dependent
|
||||
drivers are loaded.
|
||||
|
||||
config GPIO_TWL4030
|
||||
tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
|
||||
depends on TWL4030_CORE
|
||||
|
@ -113,6 +113,7 @@ obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
|
||||
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
|
||||
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
|
||||
obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
|
||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
||||
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
|
||||
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
|
||||
@ -121,6 +122,7 @@ obj-$(CONFIG_GPIO_TPS65218) += gpio-tps65218.o
|
||||
obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o
|
||||
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
||||
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
|
||||
obj-$(CONFIG_GPIO_TPS68470) += gpio-tps68470.o
|
||||
obj-$(CONFIG_GPIO_TS4800) += gpio-ts4800.o
|
||||
obj-$(CONFIG_GPIO_TS4900) += gpio-ts4900.o
|
||||
obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o
|
||||
|
@ -132,6 +132,7 @@ EXPORT_SYMBOL(devm_gpiod_get_index);
|
||||
* @index: index of the GPIO to obtain in the consumer
|
||||
* @child: firmware node (child of @dev)
|
||||
* @flags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* GPIO descriptors returned from this function are automatically disposed on
|
||||
* driver detach.
|
||||
@ -271,6 +272,7 @@ EXPORT_SYMBOL(devm_gpiod_get_array_optional);
|
||||
|
||||
/**
|
||||
* devm_gpiod_put - Resource-managed gpiod_put()
|
||||
* @dev: GPIO consumer
|
||||
* @desc: GPIO descriptor to dispose of
|
||||
*
|
||||
* Dispose of a GPIO descriptor obtained with devm_gpiod_get() or
|
||||
@ -286,6 +288,7 @@ EXPORT_SYMBOL(devm_gpiod_put);
|
||||
|
||||
/**
|
||||
* devm_gpiod_put_array - Resource-managed gpiod_put_array()
|
||||
* @dev: GPIO consumer
|
||||
* @descs: GPIO descriptor array to dispose of
|
||||
*
|
||||
* Dispose of an array of GPIO descriptors obtained with devm_gpiod_get_array().
|
||||
|
@ -9,6 +9,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@ -31,6 +32,7 @@ struct gen_74x164_chip {
|
||||
* numbering, store the bytes in reverse order.
|
||||
*/
|
||||
u8 buffer[0];
|
||||
struct gpio_desc *gpiod_oe;
|
||||
};
|
||||
|
||||
static int __gen_74x164_write_config(struct gen_74x164_chip *chip)
|
||||
@ -126,6 +128,13 @@ static int gen_74x164_probe(struct spi_device *spi)
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->gpiod_oe = devm_gpiod_get_optional(&spi->dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(chip->gpiod_oe))
|
||||
return PTR_ERR(chip->gpiod_oe);
|
||||
|
||||
gpiod_set_value_cansleep(chip->gpiod_oe, 1);
|
||||
|
||||
spi_set_drvdata(spi, chip);
|
||||
|
||||
chip->gpio_chip.label = spi->modalias;
|
||||
@ -164,6 +173,7 @@ static int gen_74x164_remove(struct spi_device *spi)
|
||||
{
|
||||
struct gen_74x164_chip *chip = spi_get_drvdata(spi);
|
||||
|
||||
gpiod_set_value_cansleep(chip->gpiod_oe, 0);
|
||||
gpiochip_remove(&chip->gpio_chip);
|
||||
mutex_destroy(&chip->lock);
|
||||
|
||||
|
@ -71,7 +71,7 @@ static int altr_a10sr_gpio_direction_output(struct gpio_chip *gc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct gpio_chip altr_a10sr_gc = {
|
||||
static const struct gpio_chip altr_a10sr_gc = {
|
||||
.label = "altr_a10sr_gpio",
|
||||
.owner = THIS_MODULE,
|
||||
.get = altr_a10sr_gpio_get,
|
||||
|
@ -324,8 +324,8 @@ skip_irq:
|
||||
return 0;
|
||||
teardown:
|
||||
of_mm_gpiochip_remove(&altera_gc->mmchip);
|
||||
pr_err("%s: registration failed with status %d\n",
|
||||
node->full_name, ret);
|
||||
pr_err("%pOF: registration failed with status %d\n",
|
||||
node, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -834,7 +834,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
|
||||
gpio->clk = of_clk_get(pdev->dev.of_node, 0);
|
||||
if (IS_ERR(gpio->clk)) {
|
||||
dev_warn(&pdev->dev,
|
||||
"No HPLL clock phandle provided, debouncing disabled\n");
|
||||
"Failed to get clock from devicetree, debouncing disabled\n");
|
||||
gpio->clk = NULL;
|
||||
}
|
||||
|
||||
|
@ -339,6 +339,7 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
|
||||
struct brcmstb_gpio_priv *priv = bank->parent_priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
int err;
|
||||
|
||||
bank->irq_chip.name = dev_name(dev);
|
||||
bank->irq_chip.irq_mask = brcmstb_gpio_irq_mask;
|
||||
@ -355,8 +356,6 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
|
||||
dev_warn(dev,
|
||||
"Couldn't get wake IRQ - GPIOs will not be able to wake from sleep");
|
||||
} else {
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Set wakeup capability before requesting wakeup
|
||||
* interrupt, so we can process boot-time "wakeups"
|
||||
@ -383,8 +382,10 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
|
||||
if (priv->can_wake)
|
||||
bank->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
|
||||
|
||||
gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
err = gpiochip_irqchip_add(&bank->gc, &bank->irq_chip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (err)
|
||||
return err;
|
||||
gpiochip_set_chained_irqchip(&bank->gc, &bank->irq_chip,
|
||||
priv->parent_irq, brcmstb_gpio_irq_handler);
|
||||
|
||||
@ -483,7 +484,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
gc->of_node = np;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = np->full_name;
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", dev->of_node);
|
||||
gc->base = gpio_base;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
gc->of_xlate = brcmstb_gpio_of_xlate;
|
||||
|
@ -166,7 +166,7 @@ of_err:
|
||||
static int davinci_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
static int ctrl_num, bank_base;
|
||||
int gpio, bank;
|
||||
int gpio, bank, ret = 0;
|
||||
unsigned ngpio, nbank;
|
||||
struct davinci_gpio_controller *chips;
|
||||
struct davinci_gpio_platform_data *pdata;
|
||||
@ -232,10 +232,23 @@ static int davinci_gpio_probe(struct platform_device *pdev)
|
||||
for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++)
|
||||
chips->regs[bank] = gpio_base + offset_array[bank];
|
||||
|
||||
gpiochip_add_data(&chips->chip, chips);
|
||||
ret = devm_gpiochip_add_data(dev, &chips->chip, chips);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
platform_set_drvdata(pdev, chips);
|
||||
davinci_gpio_irq_setup(pdev);
|
||||
ret = davinci_gpio_irq_setup(pdev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/* Revert the static variable increments */
|
||||
ctrl_num--;
|
||||
bank_base -= ngpio;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
@ -477,8 +490,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
|
||||
|
||||
clk = devm_clk_get(dev, "gpio");
|
||||
if (IS_ERR(clk)) {
|
||||
printk(KERN_ERR "Error %ld getting gpio clock?\n",
|
||||
PTR_ERR(clk));
|
||||
dev_err(dev, "Error %ld getting gpio clock\n", PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
ret = clk_prepare_enable(clk);
|
||||
|
@ -76,8 +76,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Setup pointers to chip functions */
|
||||
gc->label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
|
||||
GFP_KERNEL);
|
||||
gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
|
||||
if (!gc->label) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
@ -96,8 +95,7 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
err0:
|
||||
iounmap(regs);
|
||||
pr_err("%s: GPIO chip registration failed\n",
|
||||
pdev->dev.of_node->full_name);
|
||||
pr_err("%pOF: GPIO chip registration failed\n", pdev->dev.of_node);
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
@ -367,7 +367,7 @@ static int grgpio_probe(struct platform_device *ofdev)
|
||||
gc->of_node = np;
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->to_irq = grgpio_to_irq;
|
||||
gc->label = np->full_name;
|
||||
gc->label = devm_kasprintf(&ofdev->dev, GFP_KERNEL, "%pOF", np);
|
||||
gc->base = -1;
|
||||
|
||||
err = of_property_read_u32(np, "nbits", &prop);
|
||||
|
@ -2,6 +2,7 @@
|
||||
* GPIO interface for IT87xx Super I/O chips
|
||||
*
|
||||
* Author: Diego Elio Pettenò <flameeyes@flameeyes.eu>
|
||||
* Copyright (c) 2017 Google, Inc.
|
||||
*
|
||||
* Based on it87_wdt.c by Oliver Schuster
|
||||
* gpio-it8761e.c by Denis Turischev
|
||||
@ -39,6 +40,7 @@
|
||||
#define IT8728_ID 0x8728
|
||||
#define IT8732_ID 0x8732
|
||||
#define IT8761_ID 0x8761
|
||||
#define IT8772_ID 0x8772
|
||||
|
||||
/* IO Ports */
|
||||
#define REG 0x2e
|
||||
@ -314,6 +316,7 @@ static int __init it87_gpio_init(void)
|
||||
break;
|
||||
case IT8728_ID:
|
||||
case IT8732_ID:
|
||||
case IT8772_ID:
|
||||
gpio_ba_reg = 0x62;
|
||||
it87_gpio->io_size = 8;
|
||||
it87_gpio->output_base = 0xc8;
|
||||
|
@ -82,7 +82,7 @@ static const struct regmap_irq max77620_gpio_irqs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip max77620_gpio_irq_chip = {
|
||||
static const struct regmap_irq_chip max77620_gpio_irq_chip = {
|
||||
.name = "max77620-gpio",
|
||||
.irqs = max77620_gpio_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
|
||||
|
@ -168,7 +168,9 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(gchip->clk))
|
||||
return PTR_ERR(gchip->clk);
|
||||
|
||||
clk_prepare_enable(gchip->clk);
|
||||
ret = clk_prepare_enable(gchip->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&gchip->lock);
|
||||
|
||||
|
@ -391,9 +391,10 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int rv;
|
||||
|
||||
gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base,
|
||||
handle_simple_irq);
|
||||
gc = devm_irq_alloc_generic_chip(chip->dev, "ioh_gpio", 1, irq_start,
|
||||
chip->base, handle_simple_irq);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -406,10 +407,11 @@ static int ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
|
||||
ct->chip.irq_disable = ioh_irq_disable;
|
||||
ct->chip.irq_enable = ioh_irq_enable;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num),
|
||||
IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ioh_gpio_probe(struct pci_dev *pdev,
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/irq_sim.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
@ -47,18 +47,12 @@ enum {
|
||||
struct gpio_mockup_line_status {
|
||||
int dir;
|
||||
bool value;
|
||||
bool irq_enabled;
|
||||
};
|
||||
|
||||
struct gpio_mockup_irq_context {
|
||||
struct irq_work work;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct gpio_mockup_chip {
|
||||
struct gpio_chip gc;
|
||||
struct gpio_mockup_line_status *lines;
|
||||
struct gpio_mockup_irq_context irq_ctx;
|
||||
struct irq_sim irqsim;
|
||||
struct dentry *dbg_dir;
|
||||
};
|
||||
|
||||
@ -144,65 +138,11 @@ static int gpio_mockup_name_lines(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
return chip->irq_base + offset;
|
||||
}
|
||||
|
||||
static void gpio_mockup_irqmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
chip->lines[data->irq - gc->irq_base].irq_enabled = false;
|
||||
}
|
||||
|
||||
static void gpio_mockup_irqunmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
chip->lines[data->irq - gc->irq_base].irq_enabled = true;
|
||||
}
|
||||
|
||||
static struct irq_chip gpio_mockup_irqchip = {
|
||||
.name = GPIO_MOCKUP_NAME,
|
||||
.irq_mask = gpio_mockup_irqmask,
|
||||
.irq_unmask = gpio_mockup_irqunmask,
|
||||
};
|
||||
|
||||
static void gpio_mockup_handle_irq(struct irq_work *work)
|
||||
{
|
||||
struct gpio_mockup_irq_context *irq_ctx;
|
||||
|
||||
irq_ctx = container_of(work, struct gpio_mockup_irq_context, work);
|
||||
handle_simple_irq(irq_to_desc(irq_ctx->irq));
|
||||
}
|
||||
|
||||
static int gpio_mockup_irqchip_setup(struct device *dev,
|
||||
struct gpio_mockup_chip *chip)
|
||||
{
|
||||
struct gpio_chip *gc = &chip->gc;
|
||||
int irq_base, i;
|
||||
|
||||
irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0);
|
||||
if (irq_base < 0)
|
||||
return irq_base;
|
||||
|
||||
gc->irq_base = irq_base;
|
||||
gc->irqchip = &gpio_mockup_irqchip;
|
||||
|
||||
for (i = 0; i < gc->ngpio; i++) {
|
||||
irq_set_chip(irq_base + i, gc->irqchip);
|
||||
irq_set_chip_data(irq_base + i, gc);
|
||||
irq_set_handler(irq_base + i, &handle_simple_irq);
|
||||
irq_modify_status(irq_base + i,
|
||||
IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
|
||||
}
|
||||
|
||||
init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq);
|
||||
|
||||
return 0;
|
||||
return irq_sim_irqnum(&chip->irqsim, offset);
|
||||
}
|
||||
|
||||
static ssize_t gpio_mockup_event_write(struct file *file,
|
||||
@ -213,7 +153,6 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
||||
struct gpio_mockup_chip *chip;
|
||||
struct seq_file *sfile;
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_chip *gc;
|
||||
int rv, val;
|
||||
|
||||
rv = kstrtoint_from_user(usr_buf, size, 0, &val);
|
||||
@ -226,13 +165,9 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
||||
priv = sfile->private;
|
||||
desc = priv->desc;
|
||||
chip = priv->chip;
|
||||
gc = &chip->gc;
|
||||
|
||||
if (chip->lines[priv->offset].irq_enabled) {
|
||||
gpiod_set_value_cansleep(desc, val);
|
||||
priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
|
||||
irq_work_queue(&priv->chip->irq_ctx.work);
|
||||
}
|
||||
gpiod_set_value_cansleep(desc, val);
|
||||
irq_sim_fire(&chip->irqsim, priv->offset);
|
||||
|
||||
return size;
|
||||
}
|
||||
@ -319,7 +254,7 @@ static int gpio_mockup_add(struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpio_mockup_irqchip_setup(dev, chip);
|
||||
ret = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -348,8 +348,8 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
|
||||
ret = gpiochip_add_data(gc, mpc8xxx_gc);
|
||||
if (ret) {
|
||||
pr_err("%s: GPIO chip registration failed with status %d\n",
|
||||
np->full_name, ret);
|
||||
pr_err("%pOF: GPIO chip registration failed with status %d\n",
|
||||
np, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -265,8 +265,8 @@ static int platform_msic_gpio_probe(struct platform_device *pdev)
|
||||
int i;
|
||||
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "no IRQ line\n");
|
||||
return -EINVAL;
|
||||
dev_err(dev, "no IRQ line: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
if (!pdata || !pdata->gpio_base) {
|
||||
|
@ -66,6 +66,7 @@ struct mxc_gpio_port {
|
||||
int irq_high;
|
||||
struct irq_domain *domain;
|
||||
struct gpio_chip gc;
|
||||
struct device *dev;
|
||||
u32 both_edges;
|
||||
};
|
||||
|
||||
@ -324,29 +325,31 @@ static int gpio_set_wake_irq(struct irq_data *d, u32 enable)
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct mxc_gpio_port *port = gc->private;
|
||||
u32 gpio_idx = d->hwirq;
|
||||
int ret;
|
||||
|
||||
if (enable) {
|
||||
if (port->irq_high && (gpio_idx >= 16))
|
||||
enable_irq_wake(port->irq_high);
|
||||
ret = enable_irq_wake(port->irq_high);
|
||||
else
|
||||
enable_irq_wake(port->irq);
|
||||
ret = enable_irq_wake(port->irq);
|
||||
} else {
|
||||
if (port->irq_high && (gpio_idx >= 16))
|
||||
disable_irq_wake(port->irq_high);
|
||||
ret = disable_irq_wake(port->irq_high);
|
||||
else
|
||||
disable_irq_wake(port->irq);
|
||||
ret = disable_irq_wake(port->irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int rv;
|
||||
|
||||
gc = irq_alloc_generic_chip("gpio-mxc", 1, irq_base,
|
||||
port->base, handle_level_irq);
|
||||
gc = devm_irq_alloc_generic_chip(port->dev, "gpio-mxc", 1, irq_base,
|
||||
port->base, handle_level_irq);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
gc->private = port;
|
||||
@ -361,10 +364,11 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
|
||||
ct->regs.ack = GPIO_ISR;
|
||||
ct->regs.mask = GPIO_IMR;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
|
||||
IRQ_NOREQUEST, 0);
|
||||
rv = devm_irq_setup_generic_chip(port->dev, gc, IRQ_MSK(32),
|
||||
IRQ_GC_INIT_NESTED_LOCK,
|
||||
IRQ_NOREQUEST, 0);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void mxc_gpio_get_hw(struct platform_device *pdev)
|
||||
@ -418,6 +422,8 @@ static int mxc_gpio_probe(struct platform_device *pdev)
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
port->dev = &pdev->dev;
|
||||
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
port->base = devm_ioremap_resource(&pdev->dev, iores);
|
||||
if (IS_ERR(port->base))
|
||||
@ -507,6 +513,7 @@ static struct platform_driver mxc_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-mxc",
|
||||
.of_match_table = mxc_gpio_dt_ids,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = mxc_gpio_probe,
|
||||
.id_table = mxc_gpio_devtype,
|
||||
|
@ -66,6 +66,7 @@ struct mxs_gpio_port {
|
||||
int irq;
|
||||
struct irq_domain *domain;
|
||||
struct gpio_chip gc;
|
||||
struct device *dev;
|
||||
enum mxs_gpio_id devid;
|
||||
u32 both_edges;
|
||||
};
|
||||
@ -209,9 +210,10 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int rv;
|
||||
|
||||
gc = irq_alloc_generic_chip("gpio-mxs", 2, irq_base,
|
||||
port->base, handle_level_irq);
|
||||
gc = devm_irq_alloc_generic_chip(port->dev, "gpio-mxs", 2, irq_base,
|
||||
port->base, handle_level_irq);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -242,10 +244,11 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||
ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR;
|
||||
ct->handler = handle_level_irq;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
|
||||
IRQ_NOREQUEST, 0);
|
||||
rv = devm_irq_setup_generic_chip(port->dev, gc, IRQ_MSK(32),
|
||||
IRQ_GC_INIT_NESTED_LOCK,
|
||||
IRQ_NOREQUEST, 0);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int mxs_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||
@ -304,6 +307,7 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
||||
if (port->id < 0)
|
||||
return port->id;
|
||||
port->devid = (enum mxs_gpio_id) of_id->data;
|
||||
port->dev = &pdev->dev;
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
if (port->irq < 0)
|
||||
return port->irq;
|
||||
@ -379,6 +383,7 @@ static struct platform_driver mxs_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-mxs",
|
||||
.of_match_table = mxs_gpio_dt_ids,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = mxs_gpio_probe,
|
||||
.id_table = mxs_gpio_ids,
|
||||
|
@ -1247,6 +1247,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
if (bank->dbck_flag)
|
||||
clk_unprepare(bank->dbck);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -187,10 +187,9 @@ static int pca953x_write_regs_8(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
|
||||
static int pca953x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
{
|
||||
__le16 word = cpu_to_le16(get_unaligned((u16 *)val));
|
||||
u16 word = get_unaligned((u16 *)val);
|
||||
|
||||
return i2c_smbus_write_word_data(chip->client,
|
||||
reg << 1, (__force u16)word);
|
||||
return i2c_smbus_write_word_data(chip->client, reg << 1, word);
|
||||
}
|
||||
|
||||
static int pca957x_write_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
@ -241,8 +240,7 @@ static int pca953x_read_regs_16(struct pca953x_chip *chip, int reg, u8 *val)
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(chip->client, reg << 1);
|
||||
val[0] = (u16)ret & 0xFF;
|
||||
val[1] = (u16)ret >> 8;
|
||||
put_unaligned(ret, (u16 *)val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -337,9 +337,10 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int rv;
|
||||
|
||||
gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base,
|
||||
handle_simple_irq);
|
||||
gc = devm_irq_alloc_generic_chip(chip->dev, "pch_gpio", 1, irq_start,
|
||||
chip->base, handle_simple_irq);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -351,10 +352,11 @@ static int pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
|
||||
ct->chip.irq_unmask = pch_irq_unmask;
|
||||
ct->chip.irq_set_type = pch_irq_type;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num),
|
||||
IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int pch_gpio_probe(struct pci_dev *pdev,
|
||||
|
@ -405,7 +405,7 @@ static const struct dev_pm_ops pl061_dev_pm_ops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct amba_id pl061_ids[] = {
|
||||
static const struct amba_id pl061_ids[] = {
|
||||
{
|
||||
.id = 0x00041061,
|
||||
.mask = 0x000fffff,
|
||||
|
@ -451,7 +451,9 @@ static irqreturn_t pxa_gpio_demux_handler(int in_irq, void *d)
|
||||
for_each_set_bit(n, &gedr, BITS_PER_LONG) {
|
||||
loop = 1;
|
||||
|
||||
generic_handle_irq(gpio_to_irq(gpio + n));
|
||||
generic_handle_irq(
|
||||
irq_find_mapping(pchip->irqdomain,
|
||||
gpio + n));
|
||||
}
|
||||
}
|
||||
handled += loop;
|
||||
@ -465,9 +467,9 @@ static irqreturn_t pxa_gpio_direct_handler(int in_irq, void *d)
|
||||
struct pxa_gpio_chip *pchip = d;
|
||||
|
||||
if (in_irq == pchip->irq0) {
|
||||
generic_handle_irq(gpio_to_irq(0));
|
||||
generic_handle_irq(irq_find_mapping(pchip->irqdomain, 0));
|
||||
} else if (in_irq == pchip->irq1) {
|
||||
generic_handle_irq(gpio_to_irq(1));
|
||||
generic_handle_irq(irq_find_mapping(pchip->irqdomain, 1));
|
||||
} else {
|
||||
pr_err("%s() unknown irq %d\n", __func__, in_irq);
|
||||
return IRQ_NONE;
|
||||
|
@ -370,6 +370,16 @@ static const struct of_device_id gpio_rcar_of_table[] = {
|
||||
.compatible = "renesas,gpio-r8a7796",
|
||||
/* Gen3 GPIO is identical to Gen2. */
|
||||
.data = &gpio_rcar_info_gen2,
|
||||
}, {
|
||||
.compatible = "renesas,rcar-gen1-gpio",
|
||||
.data = &gpio_rcar_info_gen1,
|
||||
}, {
|
||||
.compatible = "renesas,rcar-gen2-gpio",
|
||||
.data = &gpio_rcar_info_gen2,
|
||||
}, {
|
||||
.compatible = "renesas,rcar-gen3-gpio",
|
||||
/* Gen3 GPIO is identical to Gen2. */
|
||||
.data = &gpio_rcar_info_gen2,
|
||||
}, {
|
||||
.compatible = "renesas,gpio-rcar",
|
||||
.data = &gpio_rcar_info_gen1,
|
||||
|
@ -324,9 +324,11 @@ static int gsta_alloc_irq_chip(struct gsta_gpio *chip)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
int rv;
|
||||
|
||||
gc = irq_alloc_generic_chip(KBUILD_MODNAME, 1, chip->irq_base,
|
||||
chip->reg_base, handle_simple_irq);
|
||||
gc = devm_irq_alloc_generic_chip(chip->dev, KBUILD_MODNAME, 1,
|
||||
chip->irq_base,
|
||||
chip->reg_base, handle_simple_irq);
|
||||
if (!gc)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -338,8 +340,11 @@ static int gsta_alloc_irq_chip(struct gsta_gpio *chip)
|
||||
ct->chip.irq_enable = gsta_irq_enable;
|
||||
|
||||
/* FIXME: this makes at most 32 interrupts. Request 0 by now */
|
||||
irq_setup_generic_chip(gc, 0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */, 0,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
rv = devm_irq_setup_generic_chip(chip->dev, gc,
|
||||
0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */,
|
||||
0, IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* Set up all all 128 interrupts: code from setup_generic_chip */
|
||||
{
|
||||
@ -432,6 +437,7 @@ static int gsta_probe(struct platform_device *dev)
|
||||
static struct platform_driver sta2x11_gpio_platform_driver = {
|
||||
.driver = {
|
||||
.name = "sta2x11-gpio",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = gsta_probe,
|
||||
};
|
||||
|
@ -191,7 +191,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(tb10x_gpio->base))
|
||||
return PTR_ERR(tb10x_gpio->base);
|
||||
|
||||
tb10x_gpio->gc.label = of_node_full_name(dn);
|
||||
tb10x_gpio->gc.label =
|
||||
devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
|
||||
tb10x_gpio->gc.parent = &pdev->dev;
|
||||
tb10x_gpio->gc.owner = THIS_MODULE;
|
||||
tb10x_gpio->gc.direction_input = tb10x_gpio_direction_in;
|
||||
|
@ -67,8 +67,8 @@
|
||||
struct tegra_gpio_info;
|
||||
|
||||
struct tegra_gpio_bank {
|
||||
int bank;
|
||||
int irq;
|
||||
unsigned int bank;
|
||||
unsigned int irq;
|
||||
spinlock_t lvl_lock[4];
|
||||
spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -112,13 +112,14 @@ static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg)
|
||||
return __raw_readl(tgi->regs + reg);
|
||||
}
|
||||
|
||||
static int tegra_gpio_compose(int bank, int port, int bit)
|
||||
static unsigned int tegra_gpio_compose(unsigned int bank, unsigned int port,
|
||||
unsigned int bit)
|
||||
{
|
||||
return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7);
|
||||
}
|
||||
|
||||
static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg,
|
||||
int gpio, int value)
|
||||
unsigned int gpio, u32 value)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@ -128,22 +129,22 @@ static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg,
|
||||
tegra_gpio_writel(tgi, val, reg);
|
||||
}
|
||||
|
||||
static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio)
|
||||
static void tegra_gpio_enable(struct tegra_gpio_info *tgi, unsigned int gpio)
|
||||
{
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 1);
|
||||
}
|
||||
|
||||
static void tegra_gpio_disable(struct tegra_gpio_info *tgi, int gpio)
|
||||
static void tegra_gpio_disable(struct tegra_gpio_info *tgi, unsigned int gpio)
|
||||
{
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 0);
|
||||
}
|
||||
|
||||
static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
static int tegra_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
return pinctrl_request_gpio(offset);
|
||||
}
|
||||
|
||||
static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
static void tegra_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
|
||||
@ -151,17 +152,18 @@ static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
tegra_gpio_disable(tgi, offset);
|
||||
}
|
||||
|
||||
static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static void tegra_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_OUT(tgi, offset), offset, value);
|
||||
}
|
||||
|
||||
static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
static int tegra_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
int bval = BIT(GPIO_BIT(offset));
|
||||
unsigned int bval = BIT(GPIO_BIT(offset));
|
||||
|
||||
/* If gpio is in output mode then read from the out value */
|
||||
if (tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)) & bval)
|
||||
@ -170,7 +172,8 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
return !!(tegra_gpio_readl(tgi, GPIO_IN(tgi, offset)) & bval);
|
||||
}
|
||||
|
||||
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
static int tegra_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
|
||||
@ -179,8 +182,9 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
static int tegra_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
|
||||
@ -190,7 +194,8 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
static int tegra_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
u32 pin_mask = BIT(GPIO_BIT(offset));
|
||||
@ -212,7 +217,7 @@ static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
|
||||
struct tegra_gpio_bank *bank = &tgi->bank_info[GPIO_BANK(offset)];
|
||||
unsigned int debounce_ms = DIV_ROUND_UP(debounce, 1000);
|
||||
unsigned long flags;
|
||||
int port;
|
||||
unsigned int port;
|
||||
|
||||
if (!debounce_ms) {
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset),
|
||||
@ -250,7 +255,7 @@ static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
return tegra_gpio_set_debounce(chip, offset, debounce);
|
||||
}
|
||||
|
||||
static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
|
||||
@ -261,7 +266,7 @@ static void tegra_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
|
||||
}
|
||||
@ -270,7 +275,7 @@ static void tegra_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
|
||||
}
|
||||
@ -279,20 +284,18 @@ static void tegra_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq;
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1);
|
||||
}
|
||||
|
||||
static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type;
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
int port = GPIO_PORT(gpio);
|
||||
int lvl_type;
|
||||
int val;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
@ -323,7 +326,7 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
ret = gpiochip_lock_as_irq(&tgi->gc, gpio);
|
||||
if (ret) {
|
||||
dev_err(tgi->dev,
|
||||
"unable to lock Tegra GPIO %d as IRQ\n", gpio);
|
||||
"unable to lock Tegra GPIO %u as IRQ\n", gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -351,17 +354,15 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
struct tegra_gpio_info *tgi = bank->tgi;
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq;
|
||||
|
||||
gpiochip_unlock_as_irq(&tgi->gc, gpio);
|
||||
}
|
||||
|
||||
static void tegra_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
int port;
|
||||
int pin;
|
||||
unsigned int port, pin, gpio;
|
||||
bool unmasked = false;
|
||||
int gpio;
|
||||
u32 lvl;
|
||||
unsigned long sta;
|
||||
struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
@ -389,7 +390,8 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
generic_handle_irq(gpio_to_irq(gpio + pin));
|
||||
generic_handle_irq(irq_find_mapping(tgi->irq_domain,
|
||||
gpio + pin));
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,8 +406,7 @@ static int tegra_gpio_resume(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
int b;
|
||||
int p;
|
||||
unsigned int b, p;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
@ -413,7 +414,8 @@ static int tegra_gpio_resume(struct device *dev)
|
||||
struct tegra_gpio_bank *bank = &tgi->bank_info[b];
|
||||
|
||||
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
||||
unsigned int gpio = (b<<5) | (p<<3);
|
||||
unsigned int gpio = (b << 5) | (p << 3);
|
||||
|
||||
tegra_gpio_writel(tgi, bank->cnf[p],
|
||||
GPIO_CNF(tgi, gpio));
|
||||
|
||||
@ -444,15 +446,15 @@ static int tegra_gpio_suspend(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
int b;
|
||||
int p;
|
||||
unsigned int b, p;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (b = 0; b < tgi->bank_count; b++) {
|
||||
struct tegra_gpio_bank *bank = &tgi->bank_info[b];
|
||||
|
||||
for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
|
||||
unsigned int gpio = (b<<5) | (p<<3);
|
||||
unsigned int gpio = (b << 5) | (p << 3);
|
||||
|
||||
bank->cnf[p] = tegra_gpio_readl(tgi,
|
||||
GPIO_CNF(tgi, gpio));
|
||||
bank->out[p] = tegra_gpio_readl(tgi,
|
||||
@ -483,7 +485,7 @@ static int tegra_gpio_suspend(struct device *dev)
|
||||
static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
{
|
||||
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
|
||||
int gpio = d->hwirq;
|
||||
unsigned int gpio = d->hwirq;
|
||||
u32 port, bit, mask;
|
||||
|
||||
port = GPIO_PORT(gpio);
|
||||
@ -507,14 +509,14 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
|
||||
static int dbg_gpio_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = s->private;
|
||||
int i;
|
||||
int j;
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0; i < tgi->bank_count; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
int gpio = tegra_gpio_compose(i, j, 0);
|
||||
unsigned int gpio = tegra_gpio_compose(i, j, 0);
|
||||
|
||||
seq_printf(s,
|
||||
"%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
|
||||
"%u:%u %02x %02x %02x %02x %02x %02x %06x\n",
|
||||
i, j,
|
||||
tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)),
|
||||
tegra_gpio_readl(tgi, GPIO_OE(tgi, gpio)),
|
||||
@ -542,7 +544,7 @@ static const struct file_operations debug_fops = {
|
||||
|
||||
static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
|
||||
{
|
||||
(void) debugfs_create_file("tegra_gpio", S_IRUGO,
|
||||
(void) debugfs_create_file("tegra_gpio", 0444,
|
||||
NULL, tgi, &debug_fops);
|
||||
}
|
||||
|
||||
@ -566,35 +568,25 @@ static struct lock_class_key gpio_lock_class;
|
||||
|
||||
static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct tegra_gpio_soc_config *config;
|
||||
struct tegra_gpio_info *tgi;
|
||||
struct resource *res;
|
||||
struct tegra_gpio_bank *bank;
|
||||
unsigned int gpio, i, j;
|
||||
int ret;
|
||||
int gpio;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
config = of_device_get_match_data(&pdev->dev);
|
||||
if (!config) {
|
||||
dev_err(&pdev->dev, "Error: No device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
|
||||
if (!tgi)
|
||||
return -ENODEV;
|
||||
|
||||
tgi->soc = config;
|
||||
tgi->soc = of_device_get_match_data(&pdev->dev);
|
||||
tgi->dev = &pdev->dev;
|
||||
|
||||
for (;;) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ,
|
||||
tgi->bank_count);
|
||||
if (!res)
|
||||
break;
|
||||
tgi->bank_count++;
|
||||
}
|
||||
ret = platform_irq_count(pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tgi->bank_count = ret;
|
||||
|
||||
if (!tgi->bank_count) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource\n");
|
||||
return -ENODEV;
|
||||
@ -626,13 +618,13 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, tgi);
|
||||
|
||||
if (config->debounce_supported)
|
||||
if (tgi->soc->debounce_supported)
|
||||
tgi->gc.set_config = tegra_gpio_set_config;
|
||||
|
||||
tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
|
||||
tgi->bank_info = devm_kcalloc(&pdev->dev, tgi->bank_count,
|
||||
sizeof(*tgi->bank_info), GFP_KERNEL);
|
||||
if (!tgi->bank_info)
|
||||
return -ENODEV;
|
||||
return -ENOMEM;
|
||||
|
||||
tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
|
||||
tgi->gc.ngpio,
|
||||
@ -641,15 +633,15 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < tgi->bank_count; i++) {
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource\n");
|
||||
return -ENODEV;
|
||||
ret = platform_get_irq(pdev, i);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bank = &tgi->bank_info[i];
|
||||
bank->bank = i;
|
||||
bank->irq = res->start;
|
||||
bank->irq = ret;
|
||||
bank->tgi = tgi;
|
||||
}
|
||||
|
||||
@ -661,6 +653,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
for (i = 0; i < tgi->bank_count; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
int gpio = tegra_gpio_compose(i, j, 0);
|
||||
|
||||
tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
|
||||
}
|
||||
}
|
||||
|
639
drivers/gpio/gpio-thunderx.c
Normal file
639
drivers/gpio/gpio-thunderx.c
Normal file
@ -0,0 +1,639 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Cavium Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
|
||||
#define GPIO_RX_DAT 0x0
|
||||
#define GPIO_TX_SET 0x8
|
||||
#define GPIO_TX_CLR 0x10
|
||||
#define GPIO_CONST 0x90
|
||||
#define GPIO_CONST_GPIOS_MASK 0xff
|
||||
#define GPIO_BIT_CFG 0x400
|
||||
#define GPIO_BIT_CFG_TX_OE BIT(0)
|
||||
#define GPIO_BIT_CFG_PIN_XOR BIT(1)
|
||||
#define GPIO_BIT_CFG_INT_EN BIT(2)
|
||||
#define GPIO_BIT_CFG_INT_TYPE BIT(3)
|
||||
#define GPIO_BIT_CFG_FIL_MASK GENMASK(11, 4)
|
||||
#define GPIO_BIT_CFG_FIL_CNT_SHIFT 4
|
||||
#define GPIO_BIT_CFG_FIL_SEL_SHIFT 8
|
||||
#define GPIO_BIT_CFG_TX_OD BIT(12)
|
||||
#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK(25, 16)
|
||||
#define GPIO_INTR 0x800
|
||||
#define GPIO_INTR_INTR BIT(0)
|
||||
#define GPIO_INTR_INTR_W1S BIT(1)
|
||||
#define GPIO_INTR_ENA_W1C BIT(2)
|
||||
#define GPIO_INTR_ENA_W1S BIT(3)
|
||||
#define GPIO_2ND_BANK 0x1400
|
||||
|
||||
#define GLITCH_FILTER_400NS ((4u << GPIO_BIT_CFG_FIL_SEL_SHIFT) | \
|
||||
(9u << GPIO_BIT_CFG_FIL_CNT_SHIFT))
|
||||
|
||||
struct thunderx_gpio;
|
||||
|
||||
struct thunderx_line {
|
||||
struct thunderx_gpio *txgpio;
|
||||
unsigned int line;
|
||||
unsigned int fil_bits;
|
||||
};
|
||||
|
||||
struct thunderx_gpio {
|
||||
struct gpio_chip chip;
|
||||
u8 __iomem *register_base;
|
||||
struct irq_domain *irqd;
|
||||
struct msix_entry *msix_entries; /* per line MSI-X */
|
||||
struct thunderx_line *line_entries; /* per line irq info */
|
||||
raw_spinlock_t lock;
|
||||
unsigned long invert_mask[2];
|
||||
unsigned long od_mask[2];
|
||||
int base_msi;
|
||||
};
|
||||
|
||||
static unsigned int bit_cfg_reg(unsigned int line)
|
||||
{
|
||||
return 8 * line + GPIO_BIT_CFG;
|
||||
}
|
||||
|
||||
static unsigned int intr_reg(unsigned int line)
|
||||
{
|
||||
return 8 * line + GPIO_INTR;
|
||||
}
|
||||
|
||||
static bool thunderx_gpio_is_gpio_nowarn(struct thunderx_gpio *txgpio,
|
||||
unsigned int line)
|
||||
{
|
||||
u64 bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line));
|
||||
|
||||
return (bit_cfg & GPIO_BIT_CFG_PIN_SEL_MASK) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check (and WARN) that the pin is available for GPIO. We will not
|
||||
* allow modification of the state of non-GPIO pins from this driver.
|
||||
*/
|
||||
static bool thunderx_gpio_is_gpio(struct thunderx_gpio *txgpio,
|
||||
unsigned int line)
|
||||
{
|
||||
bool rv = thunderx_gpio_is_gpio_nowarn(txgpio, line);
|
||||
|
||||
WARN_RATELIMIT(!rv, "Pin %d not available for GPIO\n", line);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_request(struct gpio_chip *chip, unsigned int line)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
|
||||
return thunderx_gpio_is_gpio(txgpio, line) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_dir_in(struct gpio_chip *chip, unsigned int line)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
|
||||
if (!thunderx_gpio_is_gpio(txgpio, line))
|
||||
return -EIO;
|
||||
|
||||
raw_spin_lock(&txgpio->lock);
|
||||
clear_bit(line, txgpio->invert_mask);
|
||||
clear_bit(line, txgpio->od_mask);
|
||||
writeq(txgpio->line_entries[line].fil_bits,
|
||||
txgpio->register_base + bit_cfg_reg(line));
|
||||
raw_spin_unlock(&txgpio->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_set(struct gpio_chip *chip, unsigned int line,
|
||||
int value)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
int bank = line / 64;
|
||||
int bank_bit = line % 64;
|
||||
|
||||
void __iomem *reg = txgpio->register_base +
|
||||
(bank * GPIO_2ND_BANK) + (value ? GPIO_TX_SET : GPIO_TX_CLR);
|
||||
|
||||
writeq(BIT_ULL(bank_bit), reg);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_dir_out(struct gpio_chip *chip, unsigned int line,
|
||||
int value)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
u64 bit_cfg = txgpio->line_entries[line].fil_bits | GPIO_BIT_CFG_TX_OE;
|
||||
|
||||
if (!thunderx_gpio_is_gpio(txgpio, line))
|
||||
return -EIO;
|
||||
|
||||
raw_spin_lock(&txgpio->lock);
|
||||
|
||||
thunderx_gpio_set(chip, line, value);
|
||||
|
||||
if (test_bit(line, txgpio->invert_mask))
|
||||
bit_cfg |= GPIO_BIT_CFG_PIN_XOR;
|
||||
|
||||
if (test_bit(line, txgpio->od_mask))
|
||||
bit_cfg |= GPIO_BIT_CFG_TX_OD;
|
||||
|
||||
writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(line));
|
||||
|
||||
raw_spin_unlock(&txgpio->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_get_direction(struct gpio_chip *chip, unsigned int line)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
u64 bit_cfg;
|
||||
|
||||
if (!thunderx_gpio_is_gpio_nowarn(txgpio, line))
|
||||
/*
|
||||
* Say it is input for now to avoid WARNing on
|
||||
* gpiochip_add_data(). We will WARN if someone
|
||||
* requests it or tries to use it.
|
||||
*/
|
||||
return 1;
|
||||
|
||||
bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line));
|
||||
|
||||
return !(bit_cfg & GPIO_BIT_CFG_TX_OE);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_set_config(struct gpio_chip *chip,
|
||||
unsigned int line,
|
||||
unsigned long cfg)
|
||||
{
|
||||
bool orig_invert, orig_od, orig_dat, new_invert, new_od;
|
||||
u32 arg, sel;
|
||||
u64 bit_cfg;
|
||||
int bank = line / 64;
|
||||
int bank_bit = line % 64;
|
||||
int ret = -ENOTSUPP;
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
void __iomem *reg = txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_SET;
|
||||
|
||||
if (!thunderx_gpio_is_gpio(txgpio, line))
|
||||
return -EIO;
|
||||
|
||||
raw_spin_lock(&txgpio->lock);
|
||||
orig_invert = test_bit(line, txgpio->invert_mask);
|
||||
new_invert = orig_invert;
|
||||
orig_od = test_bit(line, txgpio->od_mask);
|
||||
new_od = orig_od;
|
||||
orig_dat = ((readq(reg) >> bank_bit) & 1) ^ orig_invert;
|
||||
bit_cfg = readq(txgpio->register_base + bit_cfg_reg(line));
|
||||
switch (pinconf_to_config_param(cfg)) {
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
/*
|
||||
* Weird, setting open-drain mode causes signal
|
||||
* inversion. Note this so we can compensate in the
|
||||
* dir_out function.
|
||||
*/
|
||||
set_bit(line, txgpio->invert_mask);
|
||||
new_invert = true;
|
||||
set_bit(line, txgpio->od_mask);
|
||||
new_od = true;
|
||||
ret = 0;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
clear_bit(line, txgpio->invert_mask);
|
||||
new_invert = false;
|
||||
clear_bit(line, txgpio->od_mask);
|
||||
new_od = false;
|
||||
ret = 0;
|
||||
break;
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
arg = pinconf_to_config_argument(cfg);
|
||||
if (arg > 1228) { /* 15 * 2^15 * 2.5nS maximum */
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
arg *= 400; /* scale to 2.5nS clocks. */
|
||||
sel = 0;
|
||||
while (arg > 15) {
|
||||
sel++;
|
||||
arg++; /* always round up */
|
||||
arg >>= 1;
|
||||
}
|
||||
txgpio->line_entries[line].fil_bits =
|
||||
(sel << GPIO_BIT_CFG_FIL_SEL_SHIFT) |
|
||||
(arg << GPIO_BIT_CFG_FIL_CNT_SHIFT);
|
||||
bit_cfg &= ~GPIO_BIT_CFG_FIL_MASK;
|
||||
bit_cfg |= txgpio->line_entries[line].fil_bits;
|
||||
writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(line));
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
raw_spin_unlock(&txgpio->lock);
|
||||
|
||||
/*
|
||||
* If currently output and OPEN_DRAIN changed, install the new
|
||||
* settings
|
||||
*/
|
||||
if ((new_invert != orig_invert || new_od != orig_od) &&
|
||||
(bit_cfg & GPIO_BIT_CFG_TX_OE))
|
||||
ret = thunderx_gpio_dir_out(chip, line, orig_dat ^ new_invert);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_get(struct gpio_chip *chip, unsigned int line)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
int bank = line / 64;
|
||||
int bank_bit = line % 64;
|
||||
u64 read_bits = readq(txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_RX_DAT);
|
||||
u64 masked_bits = read_bits & BIT_ULL(bank_bit);
|
||||
|
||||
if (test_bit(line, txgpio->invert_mask))
|
||||
return masked_bits == 0;
|
||||
else
|
||||
return masked_bits != 0;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
int bank;
|
||||
u64 set_bits, clear_bits;
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
|
||||
for (bank = 0; bank <= chip->ngpio / 64; bank++) {
|
||||
set_bits = bits[bank] & mask[bank];
|
||||
clear_bits = ~bits[bank] & mask[bank];
|
||||
writeq(set_bits, txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_SET);
|
||||
writeq(clear_bits, txgpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_CLR);
|
||||
}
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
|
||||
writeq(GPIO_INTR_INTR,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1C,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
|
||||
writeq(GPIO_INTR_ENA_W1S,
|
||||
txline->txgpio->register_base + intr_reg(txline->line));
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_set_type(struct irq_data *data,
|
||||
unsigned int flow_type)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
u64 bit_cfg;
|
||||
|
||||
irqd_set_trigger_type(data, flow_type);
|
||||
|
||||
bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN;
|
||||
|
||||
if (flow_type & IRQ_TYPE_EDGE_BOTH) {
|
||||
irq_set_handler_locked(data, handle_fasteoi_ack_irq);
|
||||
bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
|
||||
} else {
|
||||
irq_set_handler_locked(data, handle_fasteoi_mask_irq);
|
||||
}
|
||||
|
||||
raw_spin_lock(&txgpio->lock);
|
||||
if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) {
|
||||
bit_cfg |= GPIO_BIT_CFG_PIN_XOR;
|
||||
set_bit(txline->line, txgpio->invert_mask);
|
||||
} else {
|
||||
clear_bit(txline->line, txgpio->invert_mask);
|
||||
}
|
||||
clear_bit(txline->line, txgpio->od_mask);
|
||||
writeq(bit_cfg, txgpio->register_base + bit_cfg_reg(txline->line));
|
||||
raw_spin_unlock(&txgpio->lock);
|
||||
|
||||
return IRQ_SET_MASK_OK;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_enable(struct irq_data *data)
|
||||
{
|
||||
irq_chip_enable_parent(data);
|
||||
thunderx_gpio_irq_unmask(data);
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_disable(struct irq_data *data)
|
||||
{
|
||||
thunderx_gpio_irq_mask(data);
|
||||
irq_chip_disable_parent(data);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_request_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
struct irq_data *parent_data = data->parent_data;
|
||||
int r;
|
||||
|
||||
r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (parent_data && parent_data->chip->irq_request_resources) {
|
||||
r = parent_data->chip->irq_request_resources(parent_data);
|
||||
if (r)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_irq_release_resources(struct irq_data *data)
|
||||
{
|
||||
struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
|
||||
struct thunderx_gpio *txgpio = txline->txgpio;
|
||||
struct irq_data *parent_data = data->parent_data;
|
||||
|
||||
if (parent_data && parent_data->chip->irq_release_resources)
|
||||
parent_data->chip->irq_release_resources(parent_data);
|
||||
|
||||
gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts are chained from underlying MSI-X vectors. We have
|
||||
* these irq_chip functions to be able to handle level triggering
|
||||
* semantics and other acknowledgment tasks associated with the GPIO
|
||||
* mechanism.
|
||||
*/
|
||||
static struct irq_chip thunderx_gpio_irq_chip = {
|
||||
.name = "GPIO",
|
||||
.irq_enable = thunderx_gpio_irq_enable,
|
||||
.irq_disable = thunderx_gpio_irq_disable,
|
||||
.irq_ack = thunderx_gpio_irq_ack,
|
||||
.irq_mask = thunderx_gpio_irq_mask,
|
||||
.irq_mask_ack = thunderx_gpio_irq_mask_ack,
|
||||
.irq_unmask = thunderx_gpio_irq_unmask,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.irq_request_resources = thunderx_gpio_irq_request_resources,
|
||||
.irq_release_resources = thunderx_gpio_irq_release_resources,
|
||||
.irq_set_type = thunderx_gpio_irq_set_type,
|
||||
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED
|
||||
};
|
||||
|
||||
static int thunderx_gpio_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = d->host_data;
|
||||
|
||||
if (hwirq >= txgpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
if (!thunderx_gpio_is_gpio_nowarn(txgpio, hwirq))
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_translate(struct irq_domain *d,
|
||||
struct irq_fwspec *fwspec,
|
||||
irq_hw_number_t *hwirq,
|
||||
unsigned int *type)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = d->host_data;
|
||||
|
||||
if (WARN_ON(fwspec->param_count < 2))
|
||||
return -EINVAL;
|
||||
if (fwspec->param[0] >= txgpio->chip.ngpio)
|
||||
return -EINVAL;
|
||||
*hwirq = fwspec->param[0];
|
||||
*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
|
||||
unsigned int nr_irqs, void *arg)
|
||||
{
|
||||
struct thunderx_line *txline = arg;
|
||||
|
||||
return irq_domain_set_hwirq_and_chip(d, virq, txline->line,
|
||||
&thunderx_gpio_irq_chip, txline);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
|
||||
.map = thunderx_gpio_irq_map,
|
||||
.alloc = thunderx_gpio_irq_alloc,
|
||||
.translate = thunderx_gpio_irq_translate
|
||||
};
|
||||
|
||||
static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
|
||||
|
||||
return irq_find_mapping(txgpio->irqd, offset);
|
||||
}
|
||||
|
||||
static int thunderx_gpio_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
void __iomem * const *tbl;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct thunderx_gpio *txgpio;
|
||||
struct gpio_chip *chip;
|
||||
int ngpio, i;
|
||||
int err = 0;
|
||||
|
||||
txgpio = devm_kzalloc(dev, sizeof(*txgpio), GFP_KERNEL);
|
||||
if (!txgpio)
|
||||
return -ENOMEM;
|
||||
|
||||
raw_spin_lock_init(&txgpio->lock);
|
||||
chip = &txgpio->chip;
|
||||
|
||||
pci_set_drvdata(pdev, txgpio);
|
||||
|
||||
err = pcim_enable_device(pdev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to enable PCI device: err %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to iomap PCI device: err %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tbl = pcim_iomap_table(pdev);
|
||||
txgpio->register_base = tbl[0];
|
||||
if (!txgpio->register_base) {
|
||||
dev_err(dev, "Cannot map PCI resource\n");
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pdev->subsystem_device == 0xa10a) {
|
||||
/* CN88XX has no GPIO_CONST register*/
|
||||
ngpio = 50;
|
||||
txgpio->base_msi = 48;
|
||||
} else {
|
||||
u64 c = readq(txgpio->register_base + GPIO_CONST);
|
||||
|
||||
ngpio = c & GPIO_CONST_GPIOS_MASK;
|
||||
txgpio->base_msi = (c >> 8) & 0xff;
|
||||
}
|
||||
|
||||
txgpio->msix_entries = devm_kzalloc(dev,
|
||||
sizeof(struct msix_entry) * ngpio,
|
||||
GFP_KERNEL);
|
||||
if (!txgpio->msix_entries) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
txgpio->line_entries = devm_kzalloc(dev,
|
||||
sizeof(struct thunderx_line) * ngpio,
|
||||
GFP_KERNEL);
|
||||
if (!txgpio->line_entries) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ngpio; i++) {
|
||||
u64 bit_cfg = readq(txgpio->register_base + bit_cfg_reg(i));
|
||||
|
||||
txgpio->msix_entries[i].entry = txgpio->base_msi + (2 * i);
|
||||
txgpio->line_entries[i].line = i;
|
||||
txgpio->line_entries[i].txgpio = txgpio;
|
||||
/*
|
||||
* If something has already programmed the pin, use
|
||||
* the existing glitch filter settings, otherwise go
|
||||
* to 400nS.
|
||||
*/
|
||||
txgpio->line_entries[i].fil_bits = bit_cfg ?
|
||||
(bit_cfg & GPIO_BIT_CFG_FIL_MASK) : GLITCH_FILTER_400NS;
|
||||
|
||||
if ((bit_cfg & GPIO_BIT_CFG_TX_OE) && (bit_cfg & GPIO_BIT_CFG_TX_OD))
|
||||
set_bit(i, txgpio->od_mask);
|
||||
if (bit_cfg & GPIO_BIT_CFG_PIN_XOR)
|
||||
set_bit(i, txgpio->invert_mask);
|
||||
}
|
||||
|
||||
|
||||
/* Enable all MSI-X for interrupts on all possible lines. */
|
||||
err = pci_enable_msix_range(pdev, txgpio->msix_entries, ngpio, ngpio);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Push GPIO specific irqdomain on hierarchy created as a side
|
||||
* effect of the pci_enable_msix()
|
||||
*/
|
||||
txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain,
|
||||
0, 0, of_node_to_fwnode(dev->of_node),
|
||||
&thunderx_gpio_irqd_ops, txgpio);
|
||||
if (!txgpio->irqd)
|
||||
goto out;
|
||||
|
||||
/* Push on irq_data and the domain for each line. */
|
||||
for (i = 0; i < ngpio; i++) {
|
||||
err = irq_domain_push_irq(txgpio->irqd,
|
||||
txgpio->msix_entries[i].vector,
|
||||
&txgpio->line_entries[i]);
|
||||
if (err < 0)
|
||||
dev_err(dev, "irq_domain_push_irq: %d\n", err);
|
||||
}
|
||||
|
||||
chip->label = KBUILD_MODNAME;
|
||||
chip->parent = dev;
|
||||
chip->owner = THIS_MODULE;
|
||||
chip->request = thunderx_gpio_request;
|
||||
chip->base = -1; /* System allocated */
|
||||
chip->can_sleep = false;
|
||||
chip->ngpio = ngpio;
|
||||
chip->get_direction = thunderx_gpio_get_direction;
|
||||
chip->direction_input = thunderx_gpio_dir_in;
|
||||
chip->get = thunderx_gpio_get;
|
||||
chip->direction_output = thunderx_gpio_dir_out;
|
||||
chip->set = thunderx_gpio_set;
|
||||
chip->set_multiple = thunderx_gpio_set_multiple;
|
||||
chip->set_config = thunderx_gpio_set_config;
|
||||
chip->to_irq = thunderx_gpio_to_irq;
|
||||
err = devm_gpiochip_add_data(dev, chip, txgpio);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
|
||||
ngpio, chip->base);
|
||||
return 0;
|
||||
out:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void thunderx_gpio_remove(struct pci_dev *pdev)
|
||||
{
|
||||
int i;
|
||||
struct thunderx_gpio *txgpio = pci_get_drvdata(pdev);
|
||||
|
||||
for (i = 0; i < txgpio->chip.ngpio; i++)
|
||||
irq_domain_pop_irq(txgpio->irqd,
|
||||
txgpio->msix_entries[i].vector);
|
||||
|
||||
irq_domain_remove(txgpio->irqd);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
}
|
||||
|
||||
static const struct pci_device_id thunderx_gpio_id_table[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA00A) },
|
||||
{ 0, } /* end of table */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, thunderx_gpio_id_table);
|
||||
|
||||
static struct pci_driver thunderx_gpio_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = thunderx_gpio_id_table,
|
||||
.probe = thunderx_gpio_probe,
|
||||
.remove = thunderx_gpio_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(thunderx_gpio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Cavium Inc. ThunderX/OCTEON-TX GPIO Driver");
|
||||
MODULE_LICENSE("GPL");
|
176
drivers/gpio/gpio-tps68470.c
Normal file
176
drivers/gpio/gpio-tps68470.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* GPIO driver for TPS68470 PMIC
|
||||
*
|
||||
* Copyright (C) 2017 Intel Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Antti Laakso <antti.laakso@intel.com>
|
||||
* Tianshu Qiu <tian.shu.qiu@intel.com>
|
||||
* Jian Xu Zheng <jian.xu.zheng@intel.com>
|
||||
* Yuning Pu <yuning.pu@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mfd/tps68470.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define TPS68470_N_LOGIC_OUTPUT 3
|
||||
#define TPS68470_N_REGULAR_GPIO 7
|
||||
#define TPS68470_N_GPIO (TPS68470_N_LOGIC_OUTPUT + TPS68470_N_REGULAR_GPIO)
|
||||
|
||||
struct tps68470_gpio_data {
|
||||
struct regmap *tps68470_regmap;
|
||||
struct gpio_chip gc;
|
||||
};
|
||||
|
||||
static int tps68470_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
|
||||
struct regmap *regmap = tps68470_gpio->tps68470_regmap;
|
||||
unsigned int reg = TPS68470_REG_GPDO;
|
||||
int val, ret;
|
||||
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO) {
|
||||
offset -= TPS68470_N_REGULAR_GPIO;
|
||||
reg = TPS68470_REG_SGPO;
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, reg, &val);
|
||||
if (ret) {
|
||||
dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n",
|
||||
TPS68470_REG_SGPO);
|
||||
return ret;
|
||||
}
|
||||
return !!(val & BIT(offset));
|
||||
}
|
||||
|
||||
/* Return 0 if output, 1 if input */
|
||||
static int tps68470_gpio_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
|
||||
struct regmap *regmap = tps68470_gpio->tps68470_regmap;
|
||||
int val, ret;
|
||||
|
||||
/* rest are always outputs */
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO)
|
||||
return 0;
|
||||
|
||||
ret = regmap_read(regmap, TPS68470_GPIO_CTL_REG_A(offset), &val);
|
||||
if (ret) {
|
||||
dev_err(tps68470_gpio->gc.parent, "reg 0x%x read failed\n",
|
||||
TPS68470_GPIO_CTL_REG_A(offset));
|
||||
return ret;
|
||||
}
|
||||
|
||||
val &= TPS68470_GPIO_MODE_MASK;
|
||||
return val >= TPS68470_GPIO_MODE_OUT_CMOS ? 0 : 1;
|
||||
}
|
||||
|
||||
static void tps68470_gpio_set(struct gpio_chip *gc, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
|
||||
struct regmap *regmap = tps68470_gpio->tps68470_regmap;
|
||||
unsigned int reg = TPS68470_REG_GPDO;
|
||||
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO) {
|
||||
reg = TPS68470_REG_SGPO;
|
||||
offset -= TPS68470_N_REGULAR_GPIO;
|
||||
}
|
||||
|
||||
regmap_update_bits(regmap, reg, BIT(offset), value ? BIT(offset) : 0);
|
||||
}
|
||||
|
||||
static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
|
||||
struct regmap *regmap = tps68470_gpio->tps68470_regmap;
|
||||
|
||||
/* rest are always outputs */
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO)
|
||||
return 0;
|
||||
|
||||
/* Set the initial value */
|
||||
tps68470_gpio_set(gc, offset, value);
|
||||
|
||||
return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
|
||||
TPS68470_GPIO_MODE_MASK,
|
||||
TPS68470_GPIO_MODE_OUT_CMOS);
|
||||
}
|
||||
|
||||
static int tps68470_gpio_input(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
|
||||
struct regmap *regmap = tps68470_gpio->tps68470_regmap;
|
||||
|
||||
/* rest are always outputs */
|
||||
if (offset >= TPS68470_N_REGULAR_GPIO)
|
||||
return -EINVAL;
|
||||
|
||||
return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
|
||||
TPS68470_GPIO_MODE_MASK, 0x00);
|
||||
}
|
||||
|
||||
static const char *tps68470_names[TPS68470_N_GPIO] = {
|
||||
"gpio.0", "gpio.1", "gpio.2", "gpio.3",
|
||||
"gpio.4", "gpio.5", "gpio.6",
|
||||
"s_enable", "s_idle", "s_resetn",
|
||||
};
|
||||
|
||||
static int tps68470_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps68470_gpio_data *tps68470_gpio;
|
||||
int ret;
|
||||
|
||||
tps68470_gpio = devm_kzalloc(&pdev->dev, sizeof(*tps68470_gpio),
|
||||
GFP_KERNEL);
|
||||
if (!tps68470_gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
tps68470_gpio->tps68470_regmap = dev_get_drvdata(pdev->dev.parent);
|
||||
tps68470_gpio->gc.label = "tps68470-gpio";
|
||||
tps68470_gpio->gc.owner = THIS_MODULE;
|
||||
tps68470_gpio->gc.direction_input = tps68470_gpio_input;
|
||||
tps68470_gpio->gc.direction_output = tps68470_gpio_output;
|
||||
tps68470_gpio->gc.get = tps68470_gpio_get;
|
||||
tps68470_gpio->gc.get_direction = tps68470_gpio_get_direction;
|
||||
tps68470_gpio->gc.set = tps68470_gpio_set;
|
||||
tps68470_gpio->gc.can_sleep = true;
|
||||
tps68470_gpio->gc.names = tps68470_names;
|
||||
tps68470_gpio->gc.ngpio = TPS68470_N_GPIO;
|
||||
tps68470_gpio->gc.base = -1;
|
||||
tps68470_gpio->gc.parent = &pdev->dev;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &tps68470_gpio->gc,
|
||||
tps68470_gpio);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register gpio_chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, tps68470_gpio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver tps68470_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "tps68470-gpio",
|
||||
},
|
||||
.probe = tps68470_gpio_probe,
|
||||
};
|
||||
|
||||
builtin_platform_driver(tps68470_gpio_driver)
|
@ -32,8 +32,6 @@
|
||||
|
||||
#include <linux/mfd/twl6040.h>
|
||||
|
||||
static struct gpio_chip twl6040gpo_chip;
|
||||
|
||||
static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct twl6040 *twl6040 = dev_get_drvdata(chip->parent->parent);
|
||||
|
@ -527,13 +527,12 @@ static void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
|
||||
|
||||
ret = of_property_read_u32(node, "reg", &addr);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "invalid reg on %s\n",
|
||||
node->full_name);
|
||||
dev_err(priv->dev, "invalid reg on %pOF\n", node);
|
||||
continue;
|
||||
}
|
||||
if (addr >= 3) {
|
||||
dev_err(priv->dev, "index %u in %s out of range\n",
|
||||
addr, node->full_name);
|
||||
dev_err(priv->dev, "index %u in %pOF out of range\n",
|
||||
addr, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -543,8 +542,7 @@ static void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
|
||||
|
||||
ret = tz1090_gpio_bank_probe(&info);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failure registering %s\n",
|
||||
node->full_name);
|
||||
dev_err(priv->dev, "failure registering %pOF\n", node);
|
||||
of_node_put(node);
|
||||
continue;
|
||||
}
|
||||
|
@ -30,10 +30,16 @@
|
||||
|
||||
#define VF610_GPIO_PER_PORT 32
|
||||
|
||||
struct fsl_gpio_soc_data {
|
||||
/* SoCs has a Port Data Direction Register (PDDR) */
|
||||
bool have_paddr;
|
||||
};
|
||||
|
||||
struct vf610_gpio_port {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *base;
|
||||
void __iomem *gpio_base;
|
||||
const struct fsl_gpio_soc_data *sdata;
|
||||
u8 irqc[VF610_GPIO_PER_PORT];
|
||||
int irq;
|
||||
};
|
||||
@ -43,6 +49,7 @@ struct vf610_gpio_port {
|
||||
#define GPIO_PCOR 0x08
|
||||
#define GPIO_PTOR 0x0c
|
||||
#define GPIO_PDIR 0x10
|
||||
#define GPIO_PDDR 0x14
|
||||
|
||||
#define PORT_PCR(n) ((n) * 0x4)
|
||||
#define PORT_PCR_IRQC_OFFSET 16
|
||||
@ -61,8 +68,13 @@ struct vf610_gpio_port {
|
||||
|
||||
static struct irq_chip vf610_gpio_irq_chip;
|
||||
|
||||
static const struct fsl_gpio_soc_data imx_data = {
|
||||
.have_paddr = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id vf610_gpio_dt_ids[] = {
|
||||
{ .compatible = "fsl,vf610-gpio" },
|
||||
{ .compatible = "fsl,vf610-gpio", .data = NULL, },
|
||||
{ .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@ -79,8 +91,18 @@ static inline u32 vf610_gpio_readl(void __iomem *reg)
|
||||
static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
struct vf610_gpio_port *port = gpiochip_get_data(gc);
|
||||
unsigned long mask = BIT(gpio);
|
||||
void __iomem *addr;
|
||||
|
||||
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR) & BIT(gpio));
|
||||
if (port->sdata && port->sdata->have_paddr) {
|
||||
mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
|
||||
addr = mask ? port->gpio_base + GPIO_PDOR :
|
||||
port->gpio_base + GPIO_PDIR;
|
||||
return !!(vf610_gpio_readl(addr) & BIT(gpio));
|
||||
} else {
|
||||
return !!(vf610_gpio_readl(port->gpio_base + GPIO_PDIR)
|
||||
& BIT(gpio));
|
||||
}
|
||||
}
|
||||
|
||||
static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
@ -96,12 +118,28 @@ static void vf610_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
|
||||
static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||
{
|
||||
struct vf610_gpio_port *port = gpiochip_get_data(chip);
|
||||
unsigned long mask = BIT(gpio);
|
||||
u32 val;
|
||||
|
||||
if (port->sdata && port->sdata->have_paddr) {
|
||||
val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
|
||||
val &= ~mask;
|
||||
vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
|
||||
}
|
||||
|
||||
return pinctrl_gpio_direction_input(chip->base + gpio);
|
||||
}
|
||||
|
||||
static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
|
||||
int value)
|
||||
{
|
||||
struct vf610_gpio_port *port = gpiochip_get_data(chip);
|
||||
unsigned long mask = BIT(gpio);
|
||||
|
||||
if (port->sdata && port->sdata->have_paddr)
|
||||
vf610_gpio_writel(mask, port->gpio_base + GPIO_PDDR);
|
||||
|
||||
vf610_gpio_set(chip, gpio, value);
|
||||
|
||||
return pinctrl_gpio_direction_output(chip->base + gpio);
|
||||
@ -216,6 +254,8 @@ static struct irq_chip vf610_gpio_irq_chip = {
|
||||
|
||||
static int vf610_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id = of_match_device(vf610_gpio_dt_ids,
|
||||
&pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct vf610_gpio_port *port;
|
||||
@ -227,6 +267,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
port->sdata = of_id->data;
|
||||
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
port->base = devm_ioremap_resource(dev, iores);
|
||||
if (IS_ERR(port->base))
|
||||
|
@ -360,8 +360,8 @@ static int xgpio_probe(struct platform_device *pdev)
|
||||
/* Call the OF gpio helper to setup and register the GPIO device */
|
||||
status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
|
||||
if (status) {
|
||||
pr_err("%s: error in probe function with status %d\n",
|
||||
np->full_name, status);
|
||||
pr_err("%pOF: error in probe function with status %d\n",
|
||||
np, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ static int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static struct gpio_chip zevio_gpio_chip = {
|
||||
static const struct gpio_chip zevio_gpio_chip = {
|
||||
.direction_input = zevio_gpio_direction_input,
|
||||
.direction_output = zevio_gpio_direction_output,
|
||||
.set = zevio_gpio_set,
|
||||
|
@ -60,13 +60,13 @@
|
||||
#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \
|
||||
ZYNQ##str##_GPIO_BANK5_NGPIO - 1)
|
||||
|
||||
|
||||
/* Register offsets for the GPIO device */
|
||||
/* LSW Mask & Data -WO */
|
||||
#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK))
|
||||
/* MSW Mask & Data -WO */
|
||||
#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK))
|
||||
/* Data Register-RW */
|
||||
#define ZYNQ_GPIO_DATA_OFFSET(BANK) (0x040 + (4 * BANK))
|
||||
#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK))
|
||||
/* Direction mode reg-RW */
|
||||
#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK))
|
||||
@ -98,6 +98,19 @@
|
||||
|
||||
/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */
|
||||
#define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0)
|
||||
#define GPIO_QUIRK_DATA_RO_BUG BIT(1)
|
||||
|
||||
struct gpio_regs {
|
||||
u32 datamsw[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 datalsw[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 dirm[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 outen[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 int_en[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 int_dis[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 int_type[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 int_polarity[ZYNQMP_GPIO_MAX_BANK];
|
||||
u32 int_any[ZYNQMP_GPIO_MAX_BANK];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zynq_gpio - gpio device private data structure
|
||||
@ -106,6 +119,7 @@
|
||||
* @clk: clock resource for this controller
|
||||
* @irq: interrupt for the GPIO device
|
||||
* @p_data: pointer to platform data
|
||||
* @context: context registers
|
||||
*/
|
||||
struct zynq_gpio {
|
||||
struct gpio_chip chip;
|
||||
@ -113,16 +127,18 @@ struct zynq_gpio {
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
const struct zynq_platform_data *p_data;
|
||||
struct gpio_regs context;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct zynq_platform_data - zynq gpio platform data structure
|
||||
* @label: string to store in gpio->label
|
||||
* @quirks: Flags is used to identify the platform
|
||||
* @ngpio: max number of gpio pins
|
||||
* @max_bank: maximum number of gpio banks
|
||||
* @bank_min: this array represents bank's min pin
|
||||
* @bank_max: this array represents bank's max pin
|
||||
*/
|
||||
*/
|
||||
struct zynq_platform_data {
|
||||
const char *label;
|
||||
u32 quirks;
|
||||
@ -146,6 +162,17 @@ static int zynq_gpio_is_zynq(struct zynq_gpio *gpio)
|
||||
return !!(gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_IS_ZYNQ);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpio_data_ro_bug - test if HW bug exists or not
|
||||
* @gpio: Pointer to driver data struct
|
||||
*
|
||||
* Return: 0 if bug doesnot exist, 1 if bug exists.
|
||||
*/
|
||||
static int gpio_data_ro_bug(struct zynq_gpio *gpio)
|
||||
{
|
||||
return !!(gpio->p_data->quirks & GPIO_QUIRK_DATA_RO_BUG);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank
|
||||
* for a given pin in the GPIO device
|
||||
@ -154,6 +181,7 @@ static int zynq_gpio_is_zynq(struct zynq_gpio *gpio)
|
||||
* pin
|
||||
* @bank_pin_num: an output parameter used to return pin number within a bank
|
||||
* for the given gpio pin
|
||||
* @gpio: gpio device data structure
|
||||
*
|
||||
* Returns the bank number and pin offset within the bank.
|
||||
*/
|
||||
@ -166,11 +194,11 @@ static inline void zynq_gpio_get_bank_pin(unsigned int pin_num,
|
||||
|
||||
for (bank = 0; bank < gpio->p_data->max_bank; bank++) {
|
||||
if ((pin_num >= gpio->p_data->bank_min[bank]) &&
|
||||
(pin_num <= gpio->p_data->bank_max[bank])) {
|
||||
*bank_num = bank;
|
||||
*bank_pin_num = pin_num -
|
||||
gpio->p_data->bank_min[bank];
|
||||
return;
|
||||
(pin_num <= gpio->p_data->bank_max[bank])) {
|
||||
*bank_num = bank;
|
||||
*bank_pin_num = pin_num -
|
||||
gpio->p_data->bank_min[bank];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,9 +225,28 @@ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin)
|
||||
|
||||
zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio);
|
||||
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
|
||||
if (gpio_data_ro_bug(gpio)) {
|
||||
if (zynq_gpio_is_zynq(gpio)) {
|
||||
if (bank_num <= 1) {
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
} else {
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_OFFSET(bank_num));
|
||||
}
|
||||
} else {
|
||||
if (bank_num <= 2) {
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
} else {
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_OFFSET(bank_num));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_RO_OFFSET(bank_num));
|
||||
}
|
||||
return (data >> bank_pin_num) & 1;
|
||||
}
|
||||
|
||||
@ -263,7 +310,7 @@ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin)
|
||||
* as inputs.
|
||||
*/
|
||||
if (zynq_gpio_is_zynq(gpio) && bank_num == 0 &&
|
||||
(bank_pin_num == 7 || bank_pin_num == 8))
|
||||
(bank_pin_num == 7 || bank_pin_num == 8))
|
||||
return -EINVAL;
|
||||
|
||||
/* clear the bit in direction mode reg to set the pin as input */
|
||||
@ -464,13 +511,14 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
|
||||
writel_relaxed(int_any,
|
||||
gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_MASK) {
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_chip_handler_name_locked(irq_data,
|
||||
&zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL);
|
||||
} else {
|
||||
&zynq_gpio_level_irqchip,
|
||||
handle_fasteoi_irq, NULL);
|
||||
else
|
||||
irq_set_chip_handler_name_locked(irq_data,
|
||||
&zynq_gpio_edge_irqchip, handle_level_irq, NULL);
|
||||
}
|
||||
&zynq_gpio_edge_irqchip,
|
||||
handle_level_irq, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -530,7 +578,6 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
|
||||
|
||||
/**
|
||||
* zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device
|
||||
* @irq: irq number of the gpio bank where interrupt has occurred
|
||||
* @desc: irq descriptor instance of the 'irq'
|
||||
*
|
||||
* This function reads the Interrupt Status Register of each bank to get the
|
||||
@ -560,14 +607,73 @@ static void zynq_gpio_irqhandler(struct irq_desc *desc)
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
static void zynq_gpio_save_context(struct zynq_gpio *gpio)
|
||||
{
|
||||
unsigned int bank_num;
|
||||
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
|
||||
gpio->context.datalsw[bank_num] =
|
||||
readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num));
|
||||
gpio->context.datamsw[bank_num] =
|
||||
readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num));
|
||||
gpio->context.dirm[bank_num] = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
gpio->context.int_en[bank_num] = readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTMASK_OFFSET(bank_num));
|
||||
gpio->context.int_type[bank_num] =
|
||||
readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
|
||||
gpio->context.int_polarity[bank_num] =
|
||||
readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
|
||||
gpio->context.int_any[bank_num] =
|
||||
readl_relaxed(gpio->base_addr +
|
||||
ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||
}
|
||||
}
|
||||
|
||||
static void zynq_gpio_restore_context(struct zynq_gpio *gpio)
|
||||
{
|
||||
unsigned int bank_num;
|
||||
|
||||
for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) {
|
||||
writel_relaxed(gpio->context.datalsw[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.datamsw[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.dirm[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_DIRM_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.int_en[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_INTEN_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.int_type[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_INTTYPE_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.int_polarity[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_INTPOL_OFFSET(bank_num));
|
||||
writel_relaxed(gpio->context.int_any[bank_num],
|
||||
gpio->base_addr +
|
||||
ZYNQ_GPIO_INTANY_OFFSET(bank_num));
|
||||
}
|
||||
}
|
||||
|
||||
static int __maybe_unused zynq_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct irq_data *data = irq_get_irq_data(irq);
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
|
||||
if (!irqd_is_wakeup_set(data))
|
||||
if (!irqd_is_wakeup_set(data)) {
|
||||
zynq_gpio_save_context(gpio);
|
||||
return pm_runtime_force_suspend(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -577,9 +683,14 @@ static int __maybe_unused zynq_gpio_resume(struct device *dev)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
struct irq_data *data = irq_get_irq_data(irq);
|
||||
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (!irqd_is_wakeup_set(data))
|
||||
return pm_runtime_force_resume(dev);
|
||||
if (!irqd_is_wakeup_set(data)) {
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
zynq_gpio_restore_context(gpio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -602,7 +713,7 @@ static int __maybe_unused zynq_gpio_runtime_resume(struct device *dev)
|
||||
return clk_prepare_enable(gpio->clk);
|
||||
}
|
||||
|
||||
static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
static int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -615,7 +726,7 @@ static int zynq_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
static void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
pm_runtime_put(chip->parent);
|
||||
}
|
||||
@ -623,11 +734,12 @@ static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
|
||||
SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
|
||||
zynq_gpio_runtime_resume, NULL)
|
||||
zynq_gpio_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct zynq_platform_data zynqmp_gpio_def = {
|
||||
.label = "zynqmp_gpio",
|
||||
.quirks = GPIO_QUIRK_DATA_RO_BUG,
|
||||
.ngpio = ZYNQMP_GPIO_NR_GPIOS,
|
||||
.max_bank = ZYNQMP_GPIO_MAX_BANK,
|
||||
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP),
|
||||
@ -646,7 +758,7 @@ static const struct zynq_platform_data zynqmp_gpio_def = {
|
||||
|
||||
static const struct zynq_platform_data zynq_gpio_def = {
|
||||
.label = "zynq_gpio",
|
||||
.quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ,
|
||||
.quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ | GPIO_QUIRK_DATA_RO_BUG,
|
||||
.ngpio = ZYNQ_GPIO_NR_GPIOS,
|
||||
.max_bank = ZYNQ_GPIO_MAX_BANK,
|
||||
.bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(),
|
||||
|
@ -61,7 +61,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
|
||||
#ifdef CONFIG_PINCTRL
|
||||
/**
|
||||
* acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO
|
||||
* @chip: GPIO chip
|
||||
* @gdev: GPIO device
|
||||
* @pin: ACPI GPIO pin number from GpioIo/GpioInt resource
|
||||
*
|
||||
* Function takes ACPI GpioIo/GpioInt pin number as a parameter and
|
||||
@ -763,7 +763,7 @@ struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
||||
* The function is idempotent, though each time it runs it will configure GPIO
|
||||
* pin direction according to the flags in GpioInt resource.
|
||||
*
|
||||
* Return: Linux IRQ number (>%0) on success, negative errno on failure.
|
||||
* Return: Linux IRQ number (> %0) on success, negative errno on failure.
|
||||
*/
|
||||
int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
{
|
||||
|
@ -78,8 +78,8 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
|
||||
&gpiospec);
|
||||
if (ret) {
|
||||
pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
|
||||
__func__, propname, np->full_name, index);
|
||||
pr_debug("%s: can't parse '%s' property of node '%pOF[%d]'\n",
|
||||
__func__, propname, np, index);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
@ -93,8 +93,8 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
||||
if (IS_ERR(desc))
|
||||
goto out;
|
||||
|
||||
pr_debug("%s: parsed '%s' property of node '%s[%d]' - status (%d)\n",
|
||||
__func__, propname, np->full_name, index,
|
||||
pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
|
||||
__func__, propname, np, index,
|
||||
PTR_ERR_OR_ZERO(desc));
|
||||
|
||||
out:
|
||||
@ -273,14 +273,13 @@ static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags
|
||||
* of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
|
||||
* @gc: pointer to the gpio_chip structure
|
||||
* @np: device node of the GPIO chip
|
||||
* @gpio_spec: gpio specifier as found in the device tree
|
||||
* @gpiospec: GPIO specifier as found in the device tree
|
||||
* @flags: a flags pointer to fill in
|
||||
*
|
||||
* This is simple translation function, suitable for the most 1:1 mapped
|
||||
* gpio chips. This function performs only one sanity check: whether gpio
|
||||
* GPIO chips. This function performs only one sanity check: whether GPIO
|
||||
* is less than ngpios (that is specified in the gpio_chip).
|
||||
*/
|
||||
int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||
@ -337,7 +336,7 @@ int of_mm_gpiochip_add_data(struct device_node *np,
|
||||
int ret = -ENOMEM;
|
||||
struct gpio_chip *gc = &mm_gc->gc;
|
||||
|
||||
gc->label = kstrdup(np->full_name, GFP_KERNEL);
|
||||
gc->label = kasprintf(GFP_KERNEL, "%pOF", np);
|
||||
if (!gc->label)
|
||||
goto err0;
|
||||
|
||||
@ -362,8 +361,7 @@ err2:
|
||||
err1:
|
||||
kfree(gc->label);
|
||||
err0:
|
||||
pr_err("%s: GPIO chip registration failed with status %d\n",
|
||||
np->full_name, ret);
|
||||
pr_err("%pOF: GPIO chip registration failed with status %d\n", np, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_mm_gpiochip_add_data);
|
||||
@ -418,8 +416,8 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
group_names_propname,
|
||||
index, &name);
|
||||
if (strlen(name)) {
|
||||
pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n",
|
||||
np->full_name);
|
||||
pr_err("%pOF: Group name of numeric GPIO ranges must be the empty string.\n",
|
||||
np);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -434,14 +432,14 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
} else {
|
||||
/* npins == 0: special range */
|
||||
if (pinspec.args[1]) {
|
||||
pr_err("%s: Illegal gpio-range format.\n",
|
||||
np->full_name);
|
||||
pr_err("%pOF: Illegal gpio-range format.\n",
|
||||
np);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!group_names) {
|
||||
pr_err("%s: GPIO group range requested but no %s property.\n",
|
||||
np->full_name, group_names_propname);
|
||||
pr_err("%pOF: GPIO group range requested but no %s property.\n",
|
||||
np, group_names_propname);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -452,8 +450,8 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
|
||||
break;
|
||||
|
||||
if (!strlen(name)) {
|
||||
pr_err("%s: Group name of GPIO group range cannot be the empty string.\n",
|
||||
np->full_name);
|
||||
pr_err("%pOF: Group name of GPIO group range cannot be the empty string.\n",
|
||||
np);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -540,8 +540,8 @@ static struct class gpio_class = {
|
||||
|
||||
/**
|
||||
* gpiod_export - export a GPIO through sysfs
|
||||
* @gpio: gpio to make available, already requested
|
||||
* @direction_may_change: true if userspace may change gpio direction
|
||||
* @desc: GPIO to make available, already requested
|
||||
* @direction_may_change: true if userspace may change GPIO direction
|
||||
* Context: arch_initcall or later
|
||||
*
|
||||
* When drivers want to make a GPIO accessible to userspace after they
|
||||
@ -649,7 +649,7 @@ static int match_export(struct device *dev, const void *desc)
|
||||
* gpiod_export_link - create a sysfs link to an exported GPIO node
|
||||
* @dev: device under which to create symlink
|
||||
* @name: name of the symlink
|
||||
* @gpio: gpio to create symlink to, already exported
|
||||
* @desc: GPIO to create symlink to, already exported
|
||||
*
|
||||
* Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
|
||||
* node. Caller is responsible for unlinking.
|
||||
@ -680,7 +680,7 @@ EXPORT_SYMBOL_GPL(gpiod_export_link);
|
||||
|
||||
/**
|
||||
* gpiod_unexport - reverse effect of gpiod_export()
|
||||
* @gpio: gpio to make unavailable
|
||||
* @desc: GPIO to make unavailable
|
||||
*
|
||||
* This is implicit on gpiod_free().
|
||||
*/
|
||||
|
@ -84,7 +84,12 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a GPIO number to its descriptor
|
||||
* gpio_to_desc - Convert a GPIO number to its descriptor
|
||||
* @gpio: global GPIO number
|
||||
*
|
||||
* Returns:
|
||||
* The GPIO descriptor associated with the given GPIO, or %NULL if no GPIO
|
||||
* with the given number exists in the system.
|
||||
*/
|
||||
struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||
{
|
||||
@ -111,7 +116,14 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
|
||||
EXPORT_SYMBOL_GPL(gpio_to_desc);
|
||||
|
||||
/**
|
||||
* Get the GPIO descriptor corresponding to the given hw number for this chip.
|
||||
* gpiochip_get_desc - get the GPIO descriptor corresponding to the given
|
||||
* hardware number for this chip
|
||||
* @chip: GPIO chip
|
||||
* @hwnum: hardware number of the GPIO for this chip
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the GPIO descriptor or %ERR_PTR(-EINVAL) if no GPIO exists
|
||||
* in the given chip for the specified hardware number.
|
||||
*/
|
||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
|
||||
u16 hwnum)
|
||||
@ -125,9 +137,14 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a GPIO descriptor to the integer namespace.
|
||||
* desc_to_gpio - convert a GPIO descriptor to the integer namespace
|
||||
* @desc: GPIO descriptor
|
||||
*
|
||||
* This should disappear in the future but is needed since we still
|
||||
* use GPIO numbers for error messages and sysfs nodes
|
||||
* use GPIO numbers for error messages and sysfs nodes.
|
||||
*
|
||||
* Returns:
|
||||
* The global GPIO number for the GPIO specified by its descriptor.
|
||||
*/
|
||||
int desc_to_gpio(const struct gpio_desc *desc)
|
||||
{
|
||||
@ -254,7 +271,7 @@ static int gpiodev_add_to_list(struct gpio_device *gdev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Convert a GPIO name to its descriptor
|
||||
*/
|
||||
static struct gpio_desc *gpio_name_to_desc(const char * const name)
|
||||
@ -878,7 +895,7 @@ out_free_le:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* gpio_ioctl() - ioctl handler for the GPIO chardev
|
||||
*/
|
||||
static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
@ -1077,11 +1094,9 @@ static void gpiochip_setup_devs(void)
|
||||
/**
|
||||
* gpiochip_add_data() - register a gpio_chip
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* Context: potentially before irqs will work
|
||||
* @data: driver-private data associated with this chip
|
||||
*
|
||||
* Returns a negative errno if the chip can't be registered, such as
|
||||
* because the chip->base is invalid or already associated with a
|
||||
* different chip. Otherwise it returns zero as a success code.
|
||||
* Context: potentially before irqs will work
|
||||
*
|
||||
* When gpiochip_add_data() is called very early during boot, so that GPIOs
|
||||
* can be freely used, the chip->parent device must be registered before
|
||||
@ -1093,6 +1108,11 @@ static void gpiochip_setup_devs(void)
|
||||
*
|
||||
* If chip->base is negative, this requests dynamic assignment of
|
||||
* a range of valid GPIOs.
|
||||
*
|
||||
* Returns:
|
||||
* A negative errno if the chip can't be registered, such as because the
|
||||
* chip->base is invalid or already associated with a different chip.
|
||||
* Otherwise it returns zero as a success code.
|
||||
*/
|
||||
int gpiochip_add_data(struct gpio_chip *chip, void *data)
|
||||
{
|
||||
@ -1287,6 +1307,10 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data);
|
||||
|
||||
/**
|
||||
* gpiochip_get_data() - get per-subdriver data for the chip
|
||||
* @chip: GPIO chip
|
||||
*
|
||||
* Returns:
|
||||
* The per-subdriver data for the chip.
|
||||
*/
|
||||
void *gpiochip_get_data(struct gpio_chip *chip)
|
||||
{
|
||||
@ -1370,13 +1394,16 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
|
||||
* devm_gpiochip_add_data() - Resource manager piochip_add_data()
|
||||
* @dev: the device pointer on which irq_chip belongs to.
|
||||
* @chip: the chip to register, with chip->base initialized
|
||||
* @data: driver-private data associated with this chip
|
||||
*
|
||||
* Context: potentially before irqs will work
|
||||
*
|
||||
* Returns a negative errno if the chip can't be registered, such as
|
||||
* because the chip->base is invalid or already associated with a
|
||||
* different chip. Otherwise it returns zero as a success code.
|
||||
*
|
||||
* The gpio chip automatically be released when the device is unbound.
|
||||
*
|
||||
* Returns:
|
||||
* A negative errno if the chip can't be registered, such as because the
|
||||
* chip->base is invalid or already associated with a different chip.
|
||||
* Otherwise it returns zero as a success code.
|
||||
*/
|
||||
int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
|
||||
void *data)
|
||||
@ -1422,7 +1449,7 @@ EXPORT_SYMBOL_GPL(devm_gpiochip_remove);
|
||||
/**
|
||||
* gpiochip_find() - iterator for locating a specific gpio_chip
|
||||
* @data: data to pass to match function
|
||||
* @callback: Callback function to check gpio_chip
|
||||
* @match: Callback function to check gpio_chip
|
||||
*
|
||||
* Similar to bus_find_device. It returns a reference to a gpio_chip as
|
||||
* determined by a user supplied @match callback. The callback should return
|
||||
@ -1604,6 +1631,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||
{
|
||||
struct gpio_chip *chip = d->host_data;
|
||||
|
||||
if (!gpiochip_irqchip_irq_valid(chip, hwirq))
|
||||
return -ENXIO;
|
||||
|
||||
irq_set_chip_data(irq, chip);
|
||||
/*
|
||||
* This lock class tells lockdep that GPIO irqs are in a different
|
||||
@ -1670,7 +1700,9 @@ static void gpiochip_irq_relres(struct irq_data *d)
|
||||
|
||||
static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return irq_find_mapping(chip->irqdomain, offset);
|
||||
if (!gpiochip_irqchip_irq_valid(chip, offset))
|
||||
return -ENXIO;
|
||||
return irq_create_mapping(chip->irqdomain, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1746,9 +1778,6 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
struct lock_class_key *lock_key)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
bool irq_base_set = false;
|
||||
unsigned int offset;
|
||||
unsigned irq_base = 0;
|
||||
|
||||
if (!gpiochip || !irqchip)
|
||||
return -EINVAL;
|
||||
@ -1774,7 +1803,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
* conflicting triggers. Tell the user, and reset to NONE.
|
||||
*/
|
||||
if (WARN(of_node && type != IRQ_TYPE_NONE,
|
||||
"%s: Ignoring %d default trigger\n", of_node->full_name, type))
|
||||
"%pOF: Ignoring %d default trigger\n", of_node, type))
|
||||
type = IRQ_TYPE_NONE;
|
||||
if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
|
||||
acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
|
||||
@ -1805,25 +1834,6 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
|
||||
irqchip->irq_release_resources = gpiochip_irq_relres;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the mapping since the irqchip shall be orthogonal to
|
||||
* any gpiochip calls. If the first_irq was zero, this is
|
||||
* necessary to allocate descriptors for all IRQs.
|
||||
*/
|
||||
for (offset = 0; offset < gpiochip->ngpio; offset++) {
|
||||
if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
|
||||
continue;
|
||||
irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
|
||||
if (!irq_base_set) {
|
||||
/*
|
||||
* Store the base into the gpiochip to be used when
|
||||
* unmapping the irqs.
|
||||
*/
|
||||
gpiochip->irq_base = irq_base;
|
||||
irq_base_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
acpi_gpiochip_request_interrupts(gpiochip);
|
||||
|
||||
return 0;
|
||||
@ -1930,11 +1940,14 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
|
||||
/**
|
||||
* gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
|
||||
* @chip: the gpiochip to add the range for
|
||||
* @pinctrl_name: the dev_name() of the pin controller to map to
|
||||
* @pinctl_name: the dev_name() of the pin controller to map to
|
||||
* @gpio_offset: the start offset in the current gpio_chip number space
|
||||
* @pin_offset: the start offset in the pin controller number space
|
||||
* @npins: the number of pins from the offset of each pin space (GPIO and
|
||||
* pin controller) to accumulate in this range
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success, or a negative error-code on failure.
|
||||
*/
|
||||
int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
|
||||
unsigned int gpio_offset, unsigned int pin_offset,
|
||||
@ -2179,7 +2192,8 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
|
||||
|
||||
/**
|
||||
* gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor
|
||||
* @desc: GPIO descriptor to request
|
||||
* @chip: GPIO chip
|
||||
* @hwnum: hardware number of the GPIO for which to request the descriptor
|
||||
* @label: label for the GPIO
|
||||
*
|
||||
* Function allows GPIO chip drivers to request and use their own GPIO
|
||||
@ -2187,6 +2201,10 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested);
|
||||
* function will not increase reference count of the GPIO chip module. This
|
||||
* allows the GPIO chip module to be unloaded as needed (we assume that the
|
||||
* GPIO chip driver handles freeing the GPIOs it has requested).
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the GPIO descriptor, or an ERR_PTR()-encoded negative error
|
||||
* code on failure.
|
||||
*/
|
||||
struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
|
||||
const char *label)
|
||||
@ -2368,12 +2386,13 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
|
||||
EXPORT_SYMBOL_GPL(gpiod_direction_output);
|
||||
|
||||
/**
|
||||
* gpiod_set_debounce - sets @debounce time for a @gpio
|
||||
* @gpio: the gpio to set debounce time
|
||||
* @debounce: debounce time is microseconds
|
||||
* gpiod_set_debounce - sets @debounce time for a GPIO
|
||||
* @desc: descriptor of the GPIO for which to set debounce time
|
||||
* @debounce: debounce time in microseconds
|
||||
*
|
||||
* returns -ENOTSUPP if the controller does not support setting
|
||||
* debounce.
|
||||
* Returns:
|
||||
* 0 on success, %-ENOTSUPP if the controller doesn't support setting the
|
||||
* debounce time.
|
||||
*/
|
||||
int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
|
||||
{
|
||||
@ -2980,6 +2999,23 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
|
||||
|
||||
/**
|
||||
* gpiod_add_lookup_tables() - register GPIO device consumers
|
||||
* @tables: list of tables of consumers to register
|
||||
* @n: number of tables in the list
|
||||
*/
|
||||
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&gpio_lookup_lock);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
list_add_tail(&tables[i]->list, &gpio_lookup_list);
|
||||
|
||||
mutex_unlock(&gpio_lookup_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
|
||||
* @array_size: number of elements in the descriptor / value arrays
|
||||
@ -3322,6 +3358,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index);
|
||||
* @propname: name of the firmware property representing the GPIO
|
||||
* @index: index of the GPIO to obtain in the consumer
|
||||
* @dflags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* This function can be used for drivers that get their configuration
|
||||
* from firmware.
|
||||
@ -3330,6 +3367,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_index);
|
||||
* underlying firmware interface and then makes sure that the GPIO
|
||||
* descriptor is requested before it is returned to the caller.
|
||||
*
|
||||
* Returns:
|
||||
* On successful request the GPIO pin is configured in accordance with
|
||||
* provided @dflags.
|
||||
*
|
||||
|
@ -219,7 +219,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||
/*
|
||||
* Return the GPIO number of the passed descriptor relative to its chip
|
||||
*/
|
||||
static int __maybe_unused gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
|
||||
{
|
||||
return desc - &desc->gdev->descs[0];
|
||||
}
|
||||
|
@ -180,8 +180,27 @@ struct gpio_chip {
|
||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||
* device tree automatically may have an OF translation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @of_node:
|
||||
*
|
||||
* Pointer to a device tree node representing this GPIO controller.
|
||||
*/
|
||||
struct device_node *of_node;
|
||||
int of_gpio_n_cells;
|
||||
|
||||
/**
|
||||
* @of_gpio_n_cells:
|
||||
*
|
||||
* Number of cells used to form the GPIO specifier.
|
||||
*/
|
||||
unsigned int of_gpio_n_cells;
|
||||
|
||||
/**
|
||||
* @of_xlate:
|
||||
*
|
||||
* Callback to translate a device tree GPIO specifier into a chip-
|
||||
* relative GPIO number and flags.
|
||||
*/
|
||||
int (*of_xlate)(struct gpio_chip *gc,
|
||||
const struct of_phandle_args *gpiospec, u32 *flags);
|
||||
#endif
|
||||
@ -327,11 +346,10 @@ int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
|
||||
|
||||
/**
|
||||
* struct gpio_pin_range - pin range controlled by a gpio chip
|
||||
* @head: list for maintaining set of pin ranges, used internally
|
||||
* @node: list for maintaining set of pin ranges, used internally
|
||||
* @pctldev: pinctrl device which handles corresponding pins
|
||||
* @range: actual range of pins controlled by a gpio controller
|
||||
*/
|
||||
|
||||
struct gpio_pin_range {
|
||||
struct list_head node;
|
||||
struct pinctrl_dev *pctldev;
|
||||
|
@ -60,11 +60,14 @@ struct gpiod_lookup_table {
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table);
|
||||
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n);
|
||||
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table);
|
||||
#else
|
||||
static inline
|
||||
void gpiod_add_lookup_table(struct gpiod_lookup_table *table) {}
|
||||
static inline
|
||||
void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) {}
|
||||
static inline
|
||||
void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) {}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user