summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-18 02:39:42 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-18 02:39:42 +0200
commit1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76 (patch)
tree725aff1150489e706b2b8b854b195a7a50dc6501
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jik... (diff)
parentMIPS: do away with ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB (diff)
downloadlinux-1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76.tar.xz
linux-1eccc6e1529ec7ad1cebbd2c97ceb2a1a39f7d76.zip
Merge tag 'gpio-v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for kernel cycle v4.7: Core infrastructural changes: - Support for natively single-ended GPIO driver stages. This means that if the hardware has registers to configure open drain or open source configuration, we use that rather than (as we did before) try to emulate it by switching the line to an input to get high impedance. This is also documented throughly in Documentation/gpio/driver.txt for those of you who did not understand one word of what I just wrote. - Start to do away with the unnecessarily complex and unitelligible ARCH_REQUIRE_GPIOLIB and ARCH_WANT_OPTIONAL_GPIOLIB, another evolutional artifact from the time when the GPIO subsystem was unmaintained. Archs can now just select GPIOLIB and be done with it, cleanups to arches will trickle in for the next kernel. Some minor archs ACKed the changes immediately so these are included in this pull request. - Advancing the use of the data pointer inside the GPIO device for storing driver data by switching the PowerPC, Super-H Unicore and a few other subarches or subsystem drivers in ALSA SoC, Input, serial, SSB, staging etc to use it. - The initialization now reads the input/output state of the GPIO lines, so that each GPIO descriptor knows - if this callback is implemented - whether the line is input or output. This also reflects nicely in userspace "lsgpio". - It is now possible to name GPIO producer names, line names, from the device tree. (Platform data has been supported for a while). I bet we will get a similar mechanism for ACPI one of those days. This makes is possible to get sensible producer names for e.g. GPIO rails in "lsgpio" in userspace. New drivers: - New driver for the Loongson1. - The XLP driver now supports Broadcom Vulcan ARM64. - The IT87 driver now supports IT8620 and IT8628. - The PCA953X driver now supports Galileo Gen2. Driver improvements: - MCP23S08 was switched to use the gpiolib irqchip helpers and now also suppors level-triggered interrupts. - 74x164 and RCAR now supports the .set_multiple() callback - AMDPT was converted to use generic GPIO. - TC3589x, TPS65218, SX150X, F7188X, MENZ127, VX855, WM831X, WM8994 support the new single ended callback for open drain and in some cases open source. - Implement the .get_direction() callback for a few more drivers like PL061, Xgene. Cleanups: - Paul Gortmaker combed through the drivers and de-modularized those who are not really modules. - Move the GPIO poweroff DT bindings to the power subdir where they belong. - Rename gpio-generic.c to gpio-mmio.c, which is much more to the point. That's what it is handling, nothing more, nothing less" * tag 'gpio-v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (126 commits) MIPS: do away with ARCH_[WANT_OPTIONAL|REQUIRE]_GPIOLIB gpio: zevio: make it explicitly non-modular gpio: timberdale: make it explicitly non-modular gpio: stmpe: make it explicitly non-modular gpio: sodaville: make it explicitly non-modular pinctrl: sh-pfc: Let gpio_chip.to_irq() return zero on error gpio: dwapb: Add ACPI device ID for DWAPB GPIO controller on X-Gene platforms gpio: dt-bindings: add wd,mbl-gpio bindings gpio: of: make it possible to name GPIO lines gpio: make gpiod_to_irq() return negative for NO_IRQ gpio: xgene: implement .get_direction() gpio: xgene: Enable ACPI support for X-Gene GFC GPIO driver gpio: tegra: Implement gpio_get_direction callback gpio: set up initial state from .get_direction() gpio: rename gpio-generic.c into gpio-mmio.c gpio: generic: fix GPIO_GENERIC_PLATFORM is set to module case gpio: dwapb: add gpio-signaled acpi event support gpio: dwapb: convert device node to fwnode gpio: dwapb: remove name from dwapb_port_property gpio/qoriq: select IRQ_DOMAIN ...
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-74x164.txt4
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt20
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-xlp.txt3
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio.txt26
-rw-r--r--Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt38
-rw-r--r--Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt (renamed from Documentation/devicetree/bindings/gpio/gpio-poweroff.txt)0
-rw-r--r--Documentation/devicetree/bindings/power/reset/gpio-restart.txt (renamed from Documentation/devicetree/bindings/gpio/gpio-restart.txt)0
-rw-r--r--Documentation/gpio/driver.txt97
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/alpha/Kconfig1
-rw-r--r--arch/arc/plat-axs10x/Kconfig2
-rw-r--r--arch/arc/plat-tb10x/Kconfig2
-rw-r--r--arch/avr32/Kconfig2
-rw-r--r--arch/cris/Kconfig2
-rw-r--r--arch/m68k/Kconfig.cpu2
-rw-r--r--arch/metag/Kconfig.soc1
-rw-r--r--arch/mips/Kconfig32
-rw-r--r--arch/mips/alchemy/Kconfig2
-rw-r--r--arch/mips/pic32/Kconfig2
-rw-r--r--arch/nios2/Kconfig1
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_gpt.c15
-rw-r--r--arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c6
-rw-r--r--arch/powerpc/sysdev/cpm1.c36
-rw-r--r--arch/powerpc/sysdev/cpm_common.c18
-rw-r--r--arch/powerpc/sysdev/ppc4xx_gpio.c17
-rw-r--r--arch/powerpc/sysdev/simple_gpio.c13
-rw-r--r--arch/sh/boards/mach-sdk7786/gpio.c4
-rw-r--r--arch/sh/boards/mach-x3proto/gpio.c4
-rw-r--r--arch/sparc/Kconfig1
-rw-r--r--arch/unicore32/kernel/gpio.c4
-rw-r--r--arch/xtensa/Kconfig1
-rw-r--r--drivers/gpio/Kconfig22
-rw-r--r--drivers/gpio/Makefile6
-rw-r--r--drivers/gpio/gpio-74x164.c25
-rw-r--r--drivers/gpio/gpio-amdpt.c123
-rw-r--r--drivers/gpio/gpio-bcm-kona.c14
-rw-r--r--drivers/gpio/gpio-brcmstb.c1
-rw-r--r--drivers/gpio/gpio-dwapb.c78
-rw-r--r--drivers/gpio/gpio-f7188x.c52
-rw-r--r--drivers/gpio/gpio-it87.c10
-rw-r--r--drivers/gpio/gpio-loongson1.c102
-rw-r--r--drivers/gpio/gpio-mb86s7x.c10
-rw-r--r--drivers/gpio/gpio-mc9s08dz60.c12
-rw-r--r--drivers/gpio/gpio-mcp23s08.c111
-rw-r--r--drivers/gpio/gpio-menz127.c22
-rw-r--r--drivers/gpio/gpio-mmio.c (renamed from drivers/gpio/gpio-generic.c)2
-rw-r--r--drivers/gpio/gpio-moxart.c7
-rw-r--r--drivers/gpio/gpio-mvebu.c5
-rw-r--r--drivers/gpio/gpio-octeon.c26
-rw-r--r--drivers/gpio/gpio-omap.c42
-rw-r--r--drivers/gpio/gpio-palmas.c13
-rw-r--r--drivers/gpio/gpio-pca953x.c42
-rw-r--r--drivers/gpio/gpio-pl061.c26
-rw-r--r--drivers/gpio/gpio-rc5t583.c12
-rw-r--r--drivers/gpio/gpio-rcar.c20
-rw-r--r--drivers/gpio/gpio-sodaville.c28
-rw-r--r--drivers/gpio/gpio-sta2x11.c8
-rw-r--r--drivers/gpio/gpio-stmpe.c31
-rw-r--r--drivers/gpio/gpio-sx150x.c100
-rw-r--r--drivers/gpio/gpio-tc3589x.c69
-rw-r--r--drivers/gpio/gpio-tegra.c485
-rw-r--r--drivers/gpio/gpio-timberdale.c35
-rw-r--r--drivers/gpio/gpio-tpic2810.c35
-rw-r--r--drivers/gpio/gpio-tps65218.c45
-rw-r--r--drivers/gpio/gpio-tps6586x.c13
-rw-r--r--drivers/gpio/gpio-tps65910.c16
-rw-r--r--drivers/gpio/gpio-vx855.c23
-rw-r--r--drivers/gpio/gpio-wm831x.c25
-rw-r--r--drivers/gpio/gpio-wm8994.c25
-rw-r--r--drivers/gpio/gpio-xgene-sb.c15
-rw-r--r--drivers/gpio/gpio-xgene.c30
-rw-r--r--drivers/gpio/gpio-xlp.c25
-rw-r--r--drivers/gpio/gpio-zevio.c21
-rw-r--r--drivers/gpio/gpio-zx.c14
-rw-r--r--drivers/gpio/gpio-zynq.c4
-rw-r--r--drivers/gpio/gpiolib-of.c66
-rw-r--r--drivers/gpio/gpiolib.c133
-rw-r--r--drivers/gpio/gpiolib.h4
-rw-r--r--drivers/input/keyboard/adp5588-keys.c10
-rw-r--r--drivers/input/keyboard/adp5589-keys.c12
-rw-r--r--drivers/input/touchscreen/ad7879.c10
-rw-r--r--drivers/mfd/intel_quark_i2c_gpio.c3
-rw-r--r--drivers/pinctrl/sh-pfc/gpio.c2
-rw-r--r--drivers/platform/x86/intel_pmic_gpio.c6
-rw-r--r--drivers/soc/fsl/qe/gpio.c20
-rw-r--r--drivers/ssb/driver_gpio.c33
-rw-r--r--drivers/staging/vme/devices/vme_pio2_gpio.c17
-rw-r--r--drivers/tty/serial/max310x.c12
-rw-r--r--drivers/tty/serial/sc16is7xx.c16
-rw-r--r--include/linux/gpio/driver.h25
-rw-r--r--include/linux/i2c/sx150x.h82
-rw-r--r--include/linux/platform_data/gpio-dwapb.h3
-rw-r--r--kernel/irq/irqdomain.c1
-rw-r--r--sound/soc/codecs/rt5677.c17
-rw-r--r--sound/soc/codecs/wm5100.c16
-rw-r--r--sound/soc/codecs/wm8903.c17
-rw-r--r--sound/soc/codecs/wm8962.c15
-rw-r--r--sound/soc/codecs/wm8996.c16
-rw-r--r--sound/soc/soc-ac97.c8
-rw-r--r--tools/gpio/Makefile2
-rw-r--r--tools/gpio/lsgpio.c2
101 files changed, 1566 insertions, 1169 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt
index cc2608021f26..ce1b2231bf5d 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-74x164.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-74x164.txt
@@ -1,7 +1,9 @@
* Generic 8-bits shift register GPIO driver
Required properties:
-- compatible : Should be "fairchild,74hc595"
+- compatible: Should contain one of the following:
+ "fairchild,74hc595"
+ "nxp,74lvc594"
- reg : chip select number
- gpio-controller : Marks the device node as a gpio controller.
- #gpio-cells : Should be two. The first cell is the pin number and
diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
index 120bc4971cf3..4b6cc632ca5c 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
@@ -1,9 +1,10 @@
-* Freescale MPC512x/MPC8xxx/Layerscape GPIO controller
+* Freescale MPC512x/MPC8xxx/QorIQ/Layerscape GPIO controller
Required properties:
- compatible : Should be "fsl,<soc>-gpio"
The following <soc>s are known to be supported:
- mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq.
+ mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq,
+ ls1021a, ls1043a, ls2080a.
- reg : Address and length of the register set for the device
- interrupts : Should be the port interrupt shared by all 32 pins.
- #gpio-cells : Should be two. The first cell is the pin number and
@@ -15,7 +16,7 @@ Optional properties:
- little-endian : GPIO registers are used as little endian. If not
present registers are used as big endian by default.
-Example:
+Example of gpio-controller node for a mpc5125 SoC:
gpio0: gpio@1100 {
compatible = "fsl,mpc5125-gpio";
@@ -24,3 +25,16 @@ gpio0: gpio@1100 {
interrupts = <78 0x8>;
status = "okay";
};
+
+Example of gpio-controller node for a ls2080a SoC:
+
+gpio0: gpio@2300000 {
+ compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio";
+ reg = <0x0 0x2300000 0x0 0x10000>;
+ interrupts = <0 36 0x4>; /* Level high type */
+ gpio-controller;
+ little-endian;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xlp.txt b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt
index 262ee4ddf2cb..28662d83a43e 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-xlp.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-xlp.txt
@@ -3,6 +3,8 @@ Netlogic XLP Family GPIO
This GPIO driver is used for following Netlogic XLP SoCs:
XLP832, XLP316, XLP208, XLP980, XLP532
+This GPIO driver is also compatible with GPIO controller found on
+Broadcom Vulcan ARM64.
Required properties:
-------------------
@@ -13,6 +15,7 @@ Required properties:
- "netlogic,xlp208-gpio": For Netlogic XLP208
- "netlogic,xlp980-gpio": For Netlogic XLP980
- "netlogic,xlp532-gpio": For Netlogic XLP532
+ - "brcm,vulcan-gpio": For Broadcom Vulcan ARM64
- reg: Physical base address and length of the controller's registers.
- #gpio-cells: Should be two. The first cell is the pin number and the second
cell is used to specify optional parameters (currently unused).
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 069cdf6f9dac..68d28f62a6f4 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -131,6 +131,13 @@ Every GPIO controller node must contain both an empty "gpio-controller"
property, and a #gpio-cells integer property, which indicates the number of
cells in a gpio-specifier.
+Some system-on-chips (SoCs) use the concept of GPIO banks. A GPIO bank is an
+instance of a hardware IP core on a silicon die, usually exposed to the
+programmer as a coherent range of I/O addresses. Usually each such bank is
+exposed in the device tree as an individual gpio-controller node, reflecting
+the fact that the hardware was synthesized by reusing the same IP block a
+few times over.
+
Optionally, a GPIO controller may have a "ngpios" property. This property
indicates the number of in-use slots of available slots for GPIOs. The
typical example is something like this: the hardware register is 32 bits
@@ -145,6 +152,21 @@ additional bitmask is needed to specify which GPIOs are actually in use,
and which are dummies. The bindings for this case has not yet been
specified, but should be specified if/when such hardware appears.
+Optionally, a GPIO controller may have a "gpio-line-names" property. This is
+an array of strings defining the names of the GPIO lines going out of the
+GPIO controller. This name should be the most meaningful producer name
+for the system, such as a rail name indicating the usage. Package names
+such as pin name are discouraged: such lines have opaque names (since they
+are by definition generic purpose) and such names are usually not very
+helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are
+reasonable line names as they describe what the line is used for. "GPIO0"
+is not a good name to give to a GPIO line. Placeholders are discouraged:
+rather use the "" (blank string) if the use of the GPIO line is undefined
+in your design. The names are assigned starting from line offset 0 from
+left to right from the passed array. An incomplete array (where the number
+of passed named are less than ngpios) will still be used up until the last
+provided valid line index.
+
Example:
gpio-controller@00000000 {
@@ -153,6 +175,10 @@ gpio-controller@00000000 {
gpio-controller;
#gpio-cells = <2>;
ngpios = <18>;
+ gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R",
+ "LED G", "LED B", "Col A", "Col B", "Col C", "Col D",
+ "Row A", "Row B", "Row C", "Row D", "NMI button",
+ "poweroff", "reset";
}
The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism
diff --git a/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt b/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt
new file mode 100644
index 000000000000..038c3a6a1f4d
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/wd,mbl-gpio.txt
@@ -0,0 +1,38 @@
+Bindings for the Western Digital's MyBook Live memory-mapped GPIO controllers.
+
+The Western Digital MyBook Live has two memory-mapped GPIO controllers.
+Both GPIO controller only have a single 8-bit data register, where GPIO
+state can be read and/or written.
+
+Required properties:
+ - compatible: should be "wd,mbl-gpio"
+ - reg-names: must contain
+ "dat" - data register
+ - reg: address + size pairs describing the GPIO register sets;
+ order must correspond with the order of entries in reg-names
+ - #gpio-cells: must be set to 2. The first cell is the pin number and
+ the second cell is used to specify the gpio polarity:
+ 0 = active high
+ 1 = active low
+ - gpio-controller: Marks the device node as a gpio controller.
+
+Optional properties:
+ - no-output: GPIOs are read-only.
+
+Examples:
+ gpio0: gpio0@e0000000 {
+ compatible = "wd,mbl-gpio";
+ reg-names = "dat";
+ reg = <0xe0000000 0x1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ gpio1: gpio1@e0100000 {
+ compatible = "wd,mbl-gpio";
+ reg-names = "dat";
+ reg = <0xe0100000 0x1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ no-output;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-poweroff.txt b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt
index d4eab9227ea4..d4eab9227ea4 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-poweroff.txt
+++ b/Documentation/devicetree/bindings/power/reset/gpio-poweroff.txt
diff --git a/Documentation/devicetree/bindings/gpio/gpio-restart.txt b/Documentation/devicetree/bindings/power/reset/gpio-restart.txt
index af3701bc15c4..af3701bc15c4 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-restart.txt
+++ b/Documentation/devicetree/bindings/power/reset/gpio-restart.txt
diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index bbeec415f406..6cb35a78eff4 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -68,6 +68,103 @@ control callbacks) if it is expected to call GPIO APIs from atomic context
on -RT (inside hard IRQ handlers and similar contexts). Normally this should
not be required.
+
+GPIOs with open drain/source support
+------------------------------------
+
+Open drain (CMOS) or open collector (TTL) means the line is not actively driven
+high: instead you provide the drain/collector as output, so when the transistor
+is not open, it will present a high-impedance (tristate) to the external rail.
+
+
+ CMOS CONFIGURATION TTL CONFIGURATION
+
+ ||--- out +--- out
+ in ----|| |/
+ ||--+ in ----|
+ | |\
+ GND GND
+
+This configuration is normally used as a way to achieve one of two things:
+
+- Level-shifting: to reach a logical level higher than that of the silicon
+ where the output resides.
+
+- inverse wire-OR on an I/O line, for example a GPIO line, making it possible
+ for any driving stage on the line to drive it low even if any other output
+ to the same line is simultaneously driving it high. A special case of this
+ is driving the SCL and SCA lines of an I2C bus, which is by definition a
+ wire-OR bus.
+
+Both usecases require that the line be equipped with a pull-up resistor. This
+resistor will make the line tend to high level unless one of the transistors on
+the rail actively pulls it down.
+
+The level on the line will go as high as the VDD on the pull-up resistor, which
+may be higher than the level supported by the transistor, achieveing a
+level-shift to the higher VDD.
+
+Integrated electronics often have an output driver stage in the form of a CMOS
+"totem-pole" with one N-MOS and one P-MOS transistor where one of them drives
+the line high and one of them drives the line low. This is called a push-pull
+output. The "totem-pole" looks like so:
+
+ VDD
+ |
+ OD ||--+
+ +--/ ---o|| P-MOS-FET
+ | ||--+
+IN --+ +----- out
+ | ||--+
+ +--/ ----|| N-MOS-FET
+ OS ||--+
+ |
+ GND
+
+The desired output signal (e.g. coming directly from some GPIO output register)
+arrives at IN. The switches named "OD" and "OS" are normally closed, creating
+a push-pull circuit.
+
+Consider the little "switches" named "OD" and "OS" that enable/disable the
+P-MOS or N-MOS transistor right after the split of the input. As you can see,
+either transistor will go totally numb if this switch is open. The totem-pole
+is then halved and give high impedance instead of actively driving the line
+high or low respectively. That is usually how software-controlled open
+drain/source works.
+
+Some GPIO hardware come in open drain / open source configuration. Some are
+hard-wired lines that will only support open drain or open source no matter
+what: there is only one transistor there. Some are software-configurable:
+by flipping a bit in a register the output can be configured as open drain
+or open source, in practice by flicking open the switches labeled "OD" and "OS"
+in the drawing above.
+
+By disabling the P-MOS transistor, the output can be driven between GND and
+high impedance (open drain), and by disabling the N-MOS transistor, the output
+can be driven between VDD and high impedance (open source). In the first case,
+a pull-up resistor is needed on the outgoing rail to complete the circuit, and
+in the second case, a pull-down resistor is needed on the rail.
+
+Hardware that supports open drain or open source or both, can implement a
+special callback in the gpio_chip: .set_single_ended() that takes an enum flag
+telling whether to configure the line as open drain, open source or push-pull.
+This will happen in response to the GPIO_OPEN_DRAIN or GPIO_OPEN_SOURCE flag
+set in the machine file, or coming from other hardware descriptions.
+
+If this state can not be configured in hardware, i.e. if the GPIO hardware does
+not support open drain/open source in hardware, the GPIO library will instead
+use a trick: when a line is set as output, if the line is flagged as open
+drain, and the IN output value is low, it will be driven low as usual. But
+if the IN output value is set to high, it will instead *NOT* be driven high,
+instead it will be switched to input, as input mode is high impedance, thus
+achieveing an "open drain emulation" of sorts: electrically the behaviour will
+be identical, with the exception of possible hardware glitches when switching
+the mode of the line.
+
+For open source configuration the same principle is used, just that instead
+of actively driving the line low, it is set to input.
+
+
GPIO drivers providing IRQs
---------------------------
It is custom that GPIO drivers (GPIO chips) are also providing interrupts,
diff --git a/MAINTAINERS b/MAINTAINERS
index 1dd9335de071..8267754b9427 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4902,6 +4902,7 @@ M: Alexandre Courbot <gnurou@gmail.com>
L: linux-gpio@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git
S: Maintained
+F: Documentation/devicetree/bindings/gpio/
F: Documentation/gpio/
F: Documentation/ABI/testing/gpio-cdev
F: Documentation/ABI/obsolete/sysfs-gpio
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 9d8a85801ed1..fe99f894e57d 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -13,7 +13,6 @@ config ALPHA
select GENERIC_IRQ_PROBE
select AUTO_IRQ_AFFINITY if SMP
select GENERIC_IRQ_SHOW
- select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
diff --git a/arch/arc/plat-axs10x/Kconfig b/arch/arc/plat-axs10x/Kconfig
index 426ac4b8bb39..c54d1ae57fe0 100644
--- a/arch/arc/plat-axs10x/Kconfig
+++ b/arch/arc/plat-axs10x/Kconfig
@@ -13,7 +13,7 @@ menuconfig ARC_PLAT_AXS10X
select OF_GPIO
select MIGHT_HAVE_PCI
select GENERIC_IRQ_CHIP
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
help
Support for the ARC AXS10x Software Development Platforms.
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
index d14b3d3c5dfd..149e0917645d 100644
--- a/arch/arc/plat-tb10x/Kconfig
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -21,7 +21,7 @@ menuconfig ARC_PLAT_TB10X
select PINCTRL
select PINCTRL_TB10X
select PINMUX
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select GPIO_TB10X
select TB10X_IRQC
help
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index b6878eb64884..18b88779e701 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -74,7 +74,7 @@ config PLATFORM_AT32AP
select SUBARCH_AVR32B
select MMU
select PERFORMANCE_COUNTERS
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select GENERIC_ALLOCATOR
select HAVE_FB_ATMEL
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index e086f9e93728..99bda1ba3d2f 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -61,7 +61,7 @@ config CRIS
select CLONE_BACKWARDS2
select OLD_SIGSUSPEND
select OLD_SIGACTION
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select IRQ_DOMAIN if ETRAX_ARCH_V32
select OF if ETRAX_ARCH_V32
select OF_EARLY_FLATTREE if ETRAX_ARCH_V32
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 0dfcf1281e9c..c1beb5ae181f 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -22,11 +22,11 @@ config M68KCLASSIC
config COLDFIRE
bool "Coldfire CPU family support"
- select ARCH_REQUIRE_GPIOLIB
select ARCH_HAVE_CUSTOM_GPIO_H
select CPU_HAS_NO_BITFIELDS
select CPU_HAS_NO_MULDIV64
select GENERIC_CSUM
+ select GPIOLIB
select HAVE_CLK
endchoice
diff --git a/arch/metag/Kconfig.soc b/arch/metag/Kconfig.soc
index 973640f46752..50f979c2b02d 100644
--- a/arch/metag/Kconfig.soc
+++ b/arch/metag/Kconfig.soc
@@ -16,7 +16,6 @@ config META21_FPGA
config SOC_TZ1090
bool "Toumaz Xenif TZ1090 SoC (Comet)"
- select ARCH_WANT_OPTIONAL_GPIOLIB
select IMGPDC_IRQ
select METAG_LNKGET_AROUND_CACHE
select METAG_META21
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 3ee1ea61b2dc..d2ac1174ee17 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -79,7 +79,7 @@ config MIPS_ALCHEMY
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_APM_EMULATION
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select SYS_SUPPORTS_ZBOOT
select COMMON_CLK
@@ -98,7 +98,7 @@ config AR7
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_MIPS16
select SYS_SUPPORTS_ZBOOT_UART16550
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select VLYNQ
select HAVE_CLK
help
@@ -122,11 +122,11 @@ config ATH25
config ATH79
bool "Atheros AR71XX/AR724X/AR913X based boards"
select ARCH_HAS_RESET_CONTROLLER
- select ARCH_REQUIRE_GPIOLIB
select BOOT_RAW
select CEVT_R4K
select CSRC_R4K
select DMA_NONCOHERENT
+ select GPIOLIB
select HAVE_CLK
select COMMON_CLK
select CLKDEV_LOOKUP
@@ -170,7 +170,6 @@ config BMIPS_GENERIC
select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USB_OHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
- select ARCH_WANT_OPTIONAL_GPIOLIB
help
Build a generic DT-based kernel image that boots on select
BCM33xx cable modem chips, BCM63xx DSL chips, and BCM7xxx set-top
@@ -179,7 +178,6 @@ config BMIPS_GENERIC
config BCM47XX
bool "Broadcom BCM47XX based boards"
- select ARCH_WANT_OPTIONAL_GPIOLIB
select BOOT_RAW
select CEVT_R4K
select CSRC_R4K
@@ -211,7 +209,7 @@ config BCM63XX
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_HAS_EARLY_PRINTK
select SWAP_IO_SPACE
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select HAVE_CLK
select MIPS_L1_CACHE_SHIFT_4
help
@@ -305,7 +303,7 @@ config MACH_INGENIC
select SYS_SUPPORTS_ZBOOT_UART16550
select DMA_NONCOHERENT
select IRQ_MIPS_CPU
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select COMMON_CLK
select GENERIC_IRQ_CHIP
select BUILTIN_DTB
@@ -325,7 +323,7 @@ config LANTIQ
select SYS_SUPPORTS_MIPS16
select SYS_SUPPORTS_MULTITHREADING
select SYS_HAS_EARLY_PRINTK
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select SWAP_IO_SPACE
select BOOT_RAW
select CLKDEV_LOOKUP
@@ -377,7 +375,6 @@ config MACH_LOONGSON64
config MACH_PISTACHIO
bool "IMG Pistachio SoC based boards"
- select ARCH_REQUIRE_GPIOLIB
select BOOT_ELF32
select BOOT_RAW
select CEVT_R4K
@@ -385,6 +382,7 @@ config MACH_PISTACHIO
select COMMON_CLK
select CSRC_R4K
select DMA_MAYBE_COHERENT
+ select GPIOLIB
select IRQ_MIPS_CPU
select LIBFDT
select MFD_SYSCON
@@ -406,13 +404,13 @@ config MACH_PISTACHIO
config MACH_XILFPGA
bool "MIPSfpga Xilinx based boards"
- select ARCH_REQUIRE_GPIOLIB
select BOOT_ELF32
select BOOT_RAW
select BUILTIN_DTB
select CEVT_R4K
select COMMON_CLK
select CSRC_R4K
+ select GPIOLIB
select IRQ_MIPS_CPU
select LIBFDT
select MIPS_CPU_SCACHE
@@ -536,7 +534,7 @@ config MACH_VR41XX
select CSRC_R4K
select SYS_HAS_CPU_VR41XX
select SYS_SUPPORTS_MIPS16
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
config NXP_STB220
bool "NXP STB220 board"
@@ -856,7 +854,7 @@ config MIKROTIK_RB532
select SYS_SUPPORTS_LITTLE_ENDIAN
select SWAP_IO_SPACE
select BOOT_RAW
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select MIPS_L1_CACHE_SHIFT_4
help
Support the Mikrotik(tm) RouterBoard 532 series,
@@ -879,7 +877,7 @@ config CAVIUM_OCTEON_SOC
select HW_HAS_PCI
select ZONE_DMA32
select HOLES_IN_ZONE
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select LIBFDT
select USE_OF
select ARCH_SPARSEMEM_ENABLE
@@ -937,7 +935,7 @@ config NLM_XLP_BOARD
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL
select ARCH_PHYS_ADDR_T_64BIT
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_HIGHMEM
@@ -1077,7 +1075,7 @@ config MIPS_CLOCK_VSYSCALL
def_bool CSRC_R4K || CLKSRC_MIPS_GIC
config GPIO_TXX9
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
bool
config FW_CFE
@@ -1342,7 +1340,7 @@ config CPU_LOONGSON3
select CPU_SUPPORTS_HUGEPAGES
select WEAK_ORDERING
select WEAK_REORDERING_BEYOND_LLSC
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
help
The Loongson 3 processor implements the MIPS64R2 instruction
set with many extensions.
@@ -1362,7 +1360,7 @@ config CPU_LOONGSON2F
bool "Loongson 2F"
depends on SYS_HAS_CPU_LOONGSON2F
select CPU_LOONGSON2
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
help
The Loongson 2F processor implements the MIPS III instruction set
with many extensions.
diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index 7fa24881b708..88b4d6a792c1 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -20,7 +20,7 @@ config MIPS_MTX1
config MIPS_DB1XXX
bool "Alchemy DB1XXX / PB1XXX boards"
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select HW_HAS_PCI
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_HAS_EARLY_PRINTK
diff --git a/arch/mips/pic32/Kconfig b/arch/mips/pic32/Kconfig
index 1985971b9890..527d37da05ac 100644
--- a/arch/mips/pic32/Kconfig
+++ b/arch/mips/pic32/Kconfig
@@ -14,7 +14,7 @@ config PIC32MZDA
select SYS_HAS_EARLY_PRINTK
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select COMMON_CLK
select CLKDEV_LOOKUP
select LIBFDT
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
index 437555424bda..87ca653eb5f3 100644
--- a/arch/nios2/Kconfig
+++ b/arch/nios2/Kconfig
@@ -1,6 +1,5 @@
config NIOS2
def_bool y
- select ARCH_WANT_OPTIONAL_GPIOLIB
select CLKSRC_OF
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
index 3048e34db6d8..22645a7c6b8a 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c
@@ -278,14 +278,9 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
* GPIOLIB hooks
*/
#if defined(CONFIG_GPIOLIB)
-static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc)
-{
- return container_of(gc, struct mpc52xx_gpt_priv, gc);
-}
-
static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
- struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+ struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc);
return (in_be32(&gpt->regs->status) >> 8) & 1;
}
@@ -293,7 +288,7 @@ static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio)
static void
mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v)
{
- struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+ struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc);
unsigned long flags;
u32 r;
@@ -307,7 +302,7 @@ mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v)
static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
- struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc);
+ struct mpc52xx_gpt_priv *gpt = gpiochip_get_data(gc);
unsigned long flags;
dev_dbg(gpt->dev, "%s: gpio:%d\n", __func__, gpio);
@@ -354,9 +349,9 @@ mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node)
clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK,
MPC52xx_GPT_MODE_MS_GPIO);
- rc = gpiochip_add(&gpt->gc);
+ rc = gpiochip_add_data(&gpt->gc, gpt);
if (rc)
- dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc);
+ dev_err(gpt->dev, "gpiochip_add_data() failed; rc=%i\n", rc);
dev_dbg(gpt->dev, "%s() complete.\n", __func__);
}
diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
index 15e8021ddef9..dbcd0303afed 100644
--- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
+++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
@@ -16,7 +16,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/i2c.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
@@ -99,7 +99,7 @@ static void mcu_power_off(void)
static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct mcu *mcu = container_of(gc, struct mcu, gc);
+ struct mcu *mcu = gpiochip_get_data(gc);
u8 bit = 1 << (4 + gpio);
mutex_lock(&mcu->lock);
@@ -136,7 +136,7 @@ static int mcu_gpiochip_add(struct mcu *mcu)
gc->direction_output = mcu_gpio_dir_out;
gc->of_node = np;
- return gpiochip_add(gc);
+ return gpiochip_add_data(gc, mcu);
}
static int mcu_gpiochip_remove(struct mcu *mcu)
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 8ed65365be50..6c110994d902 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -532,15 +532,9 @@ struct cpm1_gpio16_chip {
u16 cpdata;
};
-static inline struct cpm1_gpio16_chip *
-to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
-}
-
static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
{
- struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be16(&iop->dat);
@@ -560,7 +554,7 @@ static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
int value)
{
- struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
if (value)
@@ -574,7 +568,7 @@ static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
@@ -588,7 +582,7 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
@@ -606,7 +600,7 @@ static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ struct cpm1_gpio16_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
@@ -642,7 +636,7 @@ int cpm1_gpiochip_add16(struct device_node *np)
gc->get = cpm1_gpio16_get;
gc->set = cpm1_gpio16_set;
- return of_mm_gpiochip_add(np, mm_gc);
+ return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
}
struct cpm1_gpio32_chip {
@@ -653,15 +647,9 @@ struct cpm1_gpio32_chip {
u32 cpdata;
};
-static inline struct cpm1_gpio32_chip *
-to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
-}
-
static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
{
- struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be32(&iop->dat);
@@ -681,7 +669,7 @@ static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
int value)
{
- struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
if (value)
@@ -695,7 +683,7 @@ static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -709,7 +697,7 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -727,7 +715,7 @@ static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ struct cpm1_gpio32_chip *cpm1_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -763,7 +751,7 @@ int cpm1_gpiochip_add32(struct device_node *np)
gc->get = cpm1_gpio32_get;
gc->set = cpm1_gpio32_set;
- return of_mm_gpiochip_add(np, mm_gc);
+ return of_mm_gpiochip_add_data(np, mm_gc, cpm1_gc);
}
static int cpm_init_par_io(void)
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index 9d32465eddb1..0ac12e5fd8ab 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -80,15 +80,9 @@ struct cpm2_gpio32_chip {
u32 cpdata;
};
-static inline struct cpm2_gpio32_chip *
-to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
-}
-
static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
{
- struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
cpm2_gc->cpdata = in_be32(&iop->dat);
@@ -108,7 +102,7 @@ static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
int value)
{
- struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(&mm_gc->gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
if (value)
@@ -122,7 +116,7 @@ static void __cpm2_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -136,7 +130,7 @@ static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -154,7 +148,7 @@ static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
+ struct cpm2_gpio32_chip *cpm2_gc = gpiochip_get_data(gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
@@ -190,6 +184,6 @@ int cpm2_gpiochip_add32(struct device_node *np)
gc->get = cpm2_gpio32_get;
gc->set = cpm2_gpio32_set;
- return of_mm_gpiochip_add(np, mm_gc);
+ return of_mm_gpiochip_add_data(np, mm_gc, cpm2_gc);
}
#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */
diff --git a/arch/powerpc/sysdev/ppc4xx_gpio.c b/arch/powerpc/sysdev/ppc4xx_gpio.c
index d7a7ef135b9f..5382d04dd872 100644
--- a/arch/powerpc/sysdev/ppc4xx_gpio.c
+++ b/arch/powerpc/sysdev/ppc4xx_gpio.c
@@ -27,7 +27,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/types.h>
#include <linux/slab.h>
@@ -67,12 +67,6 @@ struct ppc4xx_gpio_chip {
* There are a maximum of 32 gpios in each gpio controller.
*/
-static inline struct ppc4xx_gpio_chip *
-to_ppc4xx_gpiochip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct ppc4xx_gpio_chip, mm_gc);
-}
-
static int ppc4xx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
@@ -96,8 +90,7 @@ __ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static void
ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc);
+ struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
@@ -112,7 +105,7 @@ ppc4xx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static int ppc4xx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc);
+ struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
unsigned long flags;
@@ -142,7 +135,7 @@ static int
ppc4xx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct ppc4xx_gpio_chip *chip = to_ppc4xx_gpiochip(mm_gc);
+ struct ppc4xx_gpio_chip *chip = gpiochip_get_data(gc);
struct ppc4xx_gpio __iomem *regs = mm_gc->regs;
unsigned long flags;
@@ -200,7 +193,7 @@ static int __init ppc4xx_add_gpiochips(void)
gc->get = ppc4xx_gpio_get;
gc->set = ppc4xx_gpio_set;
- ret = of_mm_gpiochip_add(np, mm_gc);
+ ret = of_mm_gpiochip_add_data(np, mm_gc, ppc4xx_gc);
if (ret)
goto err;
continue;
diff --git a/arch/powerpc/sysdev/simple_gpio.c b/arch/powerpc/sysdev/simple_gpio.c
index 56ce8ca3281b..ef470b470b04 100644
--- a/arch/powerpc/sysdev/simple_gpio.c
+++ b/arch/powerpc/sysdev/simple_gpio.c
@@ -19,7 +19,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <asm/prom.h>
#include "simple_gpio.h"
@@ -32,11 +32,6 @@ struct u8_gpio_chip {
u8 data;
};
-static struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct u8_gpio_chip, mm_gc);
-}
-
static u8 u8_pin2mask(unsigned int pin)
{
return 1 << (8 - 1 - pin);
@@ -52,7 +47,7 @@ static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio)
static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc);
+ struct u8_gpio_chip *u8_gc = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&u8_gc->lock, flags);
@@ -80,7 +75,7 @@ static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
{
- struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc);
+ struct u8_gpio_chip *u8_gc = gpiochip_get_data(&mm_gc->gc);
u8_gc->data = in_8(mm_gc->regs);
}
@@ -108,7 +103,7 @@ static int __init u8_simple_gpiochip_add(struct device_node *np)
gc->get = u8_gpio_get;
gc->set = u8_gpio_set;
- ret = of_mm_gpiochip_add(np, mm_gc);
+ ret = of_mm_gpiochip_add_data(np, mm_gc, u8_gc);
if (ret)
goto err;
return 0;
diff --git a/arch/sh/boards/mach-sdk7786/gpio.c b/arch/sh/boards/mach-sdk7786/gpio.c
index f71ce09d4e15..47997010b77a 100644
--- a/arch/sh/boards/mach-sdk7786/gpio.c
+++ b/arch/sh/boards/mach-sdk7786/gpio.c
@@ -9,7 +9,7 @@
*/
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -44,6 +44,6 @@ static struct gpio_chip usrgpir_gpio_chip = {
static int __init usrgpir_gpio_setup(void)
{
- return gpiochip_add(&usrgpir_gpio_chip);
+ return gpiochip_add_data(&usrgpir_gpio_chip, NULL);
}
device_initcall(usrgpir_gpio_setup);
diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c
index 1fb2cbee25f2..cea88b0effa2 100644
--- a/arch/sh/boards/mach-x3proto/gpio.c
+++ b/arch/sh/boards/mach-x3proto/gpio.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -107,7 +107,7 @@ int __init x3proto_gpio_setup(void)
if (unlikely(ilsel < 0))
return ilsel;
- ret = gpiochip_add(&x3proto_gpio_chip);
+ ret = gpiochip_add_data(&x3proto_gpio_chip, NULL);
if (unlikely(ret))
goto err_gpio;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index d5003812c748..db0a26cffa97 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -21,7 +21,6 @@ config SPARC
select HAVE_ARCH_KGDB if !SMP || SPARC64
select HAVE_ARCH_TRACEHOOK
select SYSCTL_EXCEPTION_TRACE
- select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select RTC_CLASS
select RTC_DRV_M48T59
diff --git a/arch/unicore32/kernel/gpio.c b/arch/unicore32/kernel/gpio.c
index 5ab23794ea17..49347a0e9288 100644
--- a/arch/unicore32/kernel/gpio.c
+++ b/arch/unicore32/kernel/gpio.c
@@ -14,6 +14,8 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/gpio/driver.h>
+/* FIXME: needed for gpio_set_value() - convert to use descriptors or hogs */
#include <linux/gpio.h>
#include <mach/hardware.h>
@@ -118,5 +120,5 @@ void __init puv3_init_gpio(void)
* gpio_set_value(GPO_SET_V2, 1);
*/
#endif
- gpiochip_add(&puv3_gpio_chip);
+ gpiochip_add_data(&puv3_gpio_chip, NULL);
}
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index e832d3e9835e..85257afe71c3 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -5,7 +5,6 @@ config XTENSA
def_bool y
select ARCH_WANT_FRAME_POINTERS
select ARCH_WANT_IPC_PARSE_VERSION
- select ARCH_WANT_OPTIONAL_GPIOLIB
select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select COMMON_CLK
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 5f3429f0bf46..d00e7b67be9a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -33,7 +33,6 @@ config ARCH_REQUIRE_GPIOLIB
menuconfig GPIOLIB
bool "GPIO Support"
- depends on ARCH_WANT_OPTIONAL_GPIOLIB || ARCH_REQUIRE_GPIOLIB
help
This enables GPIO support through the generic GPIO library.
You only need to enable this, if you also want to enable
@@ -49,7 +48,7 @@ config GPIO_DEVRES
config OF_GPIO
def_bool y
- depends on OF
+ depends on OF || COMPILE_TEST
config GPIO_ACPI
def_bool y
@@ -122,6 +121,7 @@ config GPIO_ALTERA
config GPIO_AMDPT
tristate "AMD Promontory GPIO support"
depends on ACPI
+ select GPIO_GENERIC
help
driver for GPIO functionality on Promontory IOHub
Require ACPI ASL code to enumerate as a platform device.
@@ -303,6 +303,7 @@ config GPIO_MPC8XXX
FSL_SOC_BOOKE || PPC_86xx || ARCH_LAYERSCAPE || ARM || \
COMPILE_TEST
select GPIO_GENERIC
+ select IRQ_DOMAIN
help
Say Y here if you're going to use hardware that connects to the
MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
@@ -399,6 +400,11 @@ config GPIO_TB10X
select GENERIC_IRQ_CHIP
select OF_GPIO
+config GPIO_TEGRA
+ bool
+ default y
+ depends on ARCH_TEGRA || COMPILE_TEST
+
config GPIO_TS4800
tristate "TS-4800 DIO blocks and compatibles"
depends on OF_GPIO
@@ -473,7 +479,7 @@ config GPIO_XILINX
config GPIO_XLP
tristate "Netlogic XLP GPIO support"
- depends on CPU_XLP && OF_GPIO
+ depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || COMPILE_TEST)
select GPIOLIB_IRQCHIP
help
This driver provides support for GPIO interface on Netlogic XLP MIPS64
@@ -510,6 +516,13 @@ config GPIO_ZX
help
Say yes here to support the GPIO device on ZTE ZX SoCs.
+config GPIO_LOONGSON1
+ tristate "Loongson1 GPIO support"
+ depends on MACH_LOONGSON32
+ select GPIO_GENERIC
+ help
+ Say Y or M here to support GPIO on Loongson1 SoCs.
+
endmenu
menu "Port-mapped I/O GPIO drivers"
@@ -557,7 +570,7 @@ config GPIO_IT87
Say yes here to support GPIO functionality of IT87xx Super I/O chips.
This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and
- supports the IT8761E Super I/O chip as well.
+ supports the IT8761E, IT8620E and IT8628E Super I/O chip as well.
To compile this driver as a module, choose M here: the module will
be called gpio_it87
@@ -1091,6 +1104,7 @@ menu "SPI or I2C GPIO expanders"
config GPIO_MCP23S08
tristate "Microchip MCP23xxx I/O expander"
+ select GPIOLIB_IRQCHIP
help
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
I/O expanders.
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1e0b74f3b1ed..991598ea3fba 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,9 @@ obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
+# directly supported by gpio-generic
+gpio-generic-$(CONFIG_GPIO_GENERIC) += gpio-mmio.o
+
obj-$(CONFIG_GPIO_104_DIO_48E) += gpio-104-dio-48e.o
obj-$(CONFIG_GPIO_104_IDIO_16) += gpio-104-idio-16.o
obj-$(CONFIG_GPIO_104_IDI_48) += gpio-104-idi-48.o
@@ -95,7 +98,7 @@ obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
-obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
+obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
@@ -127,3 +130,4 @@ obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o
obj-$(CONFIG_GPIO_ZX) += gpio-zx.o
+obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index c81224ff2dca..80f9ddf13343 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -75,6 +75,29 @@ static void gen_74x164_set_value(struct gpio_chip *gc,
mutex_unlock(&chip->lock);
}
+static void gen_74x164_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct gen_74x164_chip *chip = gpiochip_get_data(gc);
+ unsigned int i, idx, shift;
+ u8 bank, bankmask;
+
+ mutex_lock(&chip->lock);
+ for (i = 0, bank = chip->registers - 1; i < chip->registers;
+ i++, bank--) {
+ idx = i / sizeof(*mask);
+ shift = i % sizeof(*mask) * BITS_PER_BYTE;
+ bankmask = mask[idx] >> shift;
+ if (!bankmask)
+ continue;
+
+ chip->buffer[bank] &= ~bankmask;
+ chip->buffer[bank] |= bankmask & (bits[idx] >> shift);
+ }
+ __gen_74x164_write_config(chip);
+ mutex_unlock(&chip->lock);
+}
+
static int gen_74x164_direction_output(struct gpio_chip *gc,
unsigned offset, int val)
{
@@ -114,6 +137,7 @@ static int gen_74x164_probe(struct spi_device *spi)
chip->gpio_chip.direction_output = gen_74x164_direction_output;
chip->gpio_chip.get = gen_74x164_get_value;
chip->gpio_chip.set = gen_74x164_set_value;
+ chip->gpio_chip.set_multiple = gen_74x164_set_multiple;
chip->gpio_chip.base = -1;
chip->registers = nregs;
@@ -153,6 +177,7 @@ static int gen_74x164_remove(struct spi_device *spi)
static const struct of_device_id gen_74x164_dt_ids[] = {
{ .compatible = "fairchild,74hc595" },
+ { .compatible = "nxp,74lvc594" },
{},
};
MODULE_DEVICE_TABLE(of, gen_74x164_dt_ids);
diff --git a/drivers/gpio/gpio-amdpt.c b/drivers/gpio/gpio-amdpt.c
index c2484046e8e9..9b78dc837603 100644
--- a/drivers/gpio/gpio-amdpt.c
+++ b/drivers/gpio/gpio-amdpt.c
@@ -28,7 +28,6 @@
struct pt_gpio_chip {
struct gpio_chip gc;
void __iomem *reg_base;
- spinlock_t lock;
};
static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
@@ -39,19 +38,19 @@ static int pt_gpio_request(struct gpio_chip *gc, unsigned offset)
dev_dbg(gc->parent, "pt_gpio_request offset=%x\n", offset);
- spin_lock_irqsave(&pt_gpio->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
if (using_pins & BIT(offset)) {
dev_warn(gc->parent, "PT GPIO pin %x reconfigured\n",
offset);
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return -EINVAL;
}
writel(using_pins | BIT(offset), pt_gpio->reg_base + PT_SYNC_REG);
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
return 0;
}
@@ -62,111 +61,17 @@ static void pt_gpio_free(struct gpio_chip *gc, unsigned offset)
unsigned long flags;
u32 using_pins;
- spin_lock_irqsave(&pt_gpio->lock, flags);
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
using_pins = readl(pt_gpio->reg_base + PT_SYNC_REG);
using_pins &= ~BIT(offset);
writel(using_pins, pt_gpio->reg_base + PT_SYNC_REG);
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
dev_dbg(gc->parent, "pt_gpio_free offset=%x\n", offset);
}
-static void pt_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value)
-{
- struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
- unsigned long flags;
- u32 data;
-
- dev_dbg(gc->parent, "pt_gpio_set_value offset=%x, value=%x\n",
- offset, value);
-
- spin_lock_irqsave(&pt_gpio->lock, flags);
-
- data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
- data &= ~BIT(offset);
- if (value)
- data |= BIT(offset);
- writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG);
-
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
-}
-
-static int pt_gpio_get_value(struct gpio_chip *gc, unsigned offset)
-{
- struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
- unsigned long flags;
- u32 data;
-
- spin_lock_irqsave(&pt_gpio->lock, flags);
-
- data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
-
- /* configure as output */
- if (data & BIT(offset))
- data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
- else /* configure as input */
- data = readl(pt_gpio->reg_base + PT_INPUTDATA_REG);
-
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
-
- data >>= offset;
- data &= 1;
-
- dev_dbg(gc->parent, "pt_gpio_get_value offset=%x, value=%x\n",
- offset, data);
-
- return data;
-}
-
-static int pt_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
-{
- struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
- unsigned long flags;
- u32 data;
-
- dev_dbg(gc->parent, "pt_gpio_dirction_input offset=%x\n", offset);
-
- spin_lock_irqsave(&pt_gpio->lock, flags);
-
- data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
- data &= ~BIT(offset);
- writel(data, pt_gpio->reg_base + PT_DIRECTION_REG);
-
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
-
- return 0;
-}
-
-static int pt_gpio_direction_output(struct gpio_chip *gc,
- unsigned offset, int value)
-{
- struct pt_gpio_chip *pt_gpio = gpiochip_get_data(gc);
- unsigned long flags;
- u32 data;
-
- dev_dbg(gc->parent, "pt_gpio_direction_output offset=%x, value=%x\n",
- offset, value);
-
- spin_lock_irqsave(&pt_gpio->lock, flags);
-
- data = readl(pt_gpio->reg_base + PT_OUTPUTDATA_REG);
- if (value)
- data |= BIT(offset);
- else
- data &= ~BIT(offset);
- writel(data, pt_gpio->reg_base + PT_OUTPUTDATA_REG);
-
- data = readl(pt_gpio->reg_base + PT_DIRECTION_REG);
- data |= BIT(offset);
- writel(data, pt_gpio->reg_base + PT_DIRECTION_REG);
-
- spin_unlock_irqrestore(&pt_gpio->lock, flags);
-
- return 0;
-}
-
static int pt_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -196,18 +101,19 @@ static int pt_gpio_probe(struct platform_device *pdev)
return PTR_ERR(pt_gpio->reg_base);
}
- spin_lock_init(&pt_gpio->lock);
+ ret = bgpio_init(&pt_gpio->gc, dev, 4,
+ pt_gpio->reg_base + PT_INPUTDATA_REG,
+ pt_gpio->reg_base + PT_OUTPUTDATA_REG, NULL,
+ pt_gpio->reg_base + PT_DIRECTION_REG, NULL,
+ BGPIOF_READ_OUTPUT_REG_SET);
+ if (ret) {
+ dev_err(&pdev->dev, "bgpio_init failed\n");
+ return ret;
+ }
- pt_gpio->gc.label = pdev->name;
pt_gpio->gc.owner = THIS_MODULE;
- pt_gpio->gc.parent = dev;
pt_gpio->gc.request = pt_gpio_request;
pt_gpio->gc.free = pt_gpio_free;
- pt_gpio->gc.direction_input = pt_gpio_direction_input;
- pt_gpio->gc.direction_output = pt_gpio_direction_output;
- pt_gpio->gc.get = pt_gpio_get_value;
- pt_gpio->gc.set = pt_gpio_set_value;
- pt_gpio->gc.base = -1;
pt_gpio->gc.ngpio = PT_TOTAL_GPIO;
#if defined(CONFIG_OF_GPIO)
pt_gpio->gc.of_node = pdev->dev.of_node;
@@ -239,6 +145,7 @@ static int pt_gpio_remove(struct platform_device *pdev)
static const struct acpi_device_id pt_gpio_acpi_match[] = {
{ "AMDF030", 0 },
+ { "AMDIF030", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, pt_gpio_acpi_match);
diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c
index 2fd38d598f3d..9aabc48ff5de 100644
--- a/drivers/gpio/gpio-bcm-kona.c
+++ b/drivers/gpio/gpio-bcm-kona.c
@@ -1,4 +1,7 @@
/*
+ * Broadcom Kona GPIO Driver
+ *
+ * Author: Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>
* Copyright (C) 2012-2014 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
@@ -17,7 +20,7 @@
#include <linux/gpio.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
@@ -502,8 +505,6 @@ static struct of_device_id const bcm_kona_gpio_of_match[] = {
{}
};
-MODULE_DEVICE_TABLE(of, bcm_kona_gpio_of_match);
-
/*
* This lock class tells lockdep that GPIO irqs are in a different
* category than their parents, so it won't report false recursion.
@@ -659,9 +660,4 @@ static struct platform_driver bcm_kona_gpio_driver = {
},
.probe = bcm_kona_gpio_probe,
};
-
-module_platform_driver(bcm_kona_gpio_driver);
-
-MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>");
-MODULE_DESCRIPTION("Broadcom Kona GPIO Driver");
-MODULE_LICENSE("GPL v2");
+builtin_platform_driver(bcm_kona_gpio_driver);
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c
index 42d51c59ed50..e6489143721a 100644
--- a/drivers/gpio/gpio-brcmstb.c
+++ b/drivers/gpio/gpio-brcmstb.c
@@ -461,6 +461,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
bank->id = num_banks;
if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
dev_err(dev, "Invalid bank width %d\n", bank_width);
+ err = -EINVAL;
goto fail;
} else {
bank->width = bank_width;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 597de1ef497b..34779bb375de 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -7,6 +7,7 @@
*
* All enquiries to support@picochip.com
*/
+#include <linux/acpi.h>
#include <linux/gpio/driver.h>
/* FIXME: for gpio_get_value(), replace this with direct register read */
#include <linux/gpio.h>
@@ -22,10 +23,13 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/spinlock.h>
#include <linux/platform_data/gpio-dwapb.h>
#include <linux/slab.h>
+#include "gpiolib.h"
+
#define GPIO_SWPORTA_DR 0x00
#define GPIO_SWPORTA_DDR 0x04
#define GPIO_SWPORTB_DR 0x0c
@@ -290,14 +294,14 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
struct dwapb_port_property *pp)
{
struct gpio_chip *gc = &port->gc;
- struct device_node *node = pp->node;
+ struct fwnode_handle *fwnode = pp->fwnode;
struct irq_chip_generic *irq_gc = NULL;
unsigned int hwirq, ngpio = gc->ngpio;
struct irq_chip_type *ct;
int err, i;
- gpio->domain = irq_domain_add_linear(node, ngpio,
- &irq_generic_chip_ops, gpio);
+ gpio->domain = irq_domain_create_linear(fwnode, ngpio,
+ &irq_generic_chip_ops, gpio);
if (!gpio->domain)
return;
@@ -409,13 +413,13 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
NULL, false);
if (err) {
- dev_err(gpio->dev, "failed to init gpio chip for %s\n",
- pp->name);
+ dev_err(gpio->dev, "failed to init gpio chip for port%d\n",
+ port->idx);
return err;
}
#ifdef CONFIG_OF_GPIO
- port->gc.of_node = pp->node;
+ port->gc.of_node = to_of_node(pp->fwnode);
#endif
port->gc.ngpio = pp->ngpio;
port->gc.base = pp->gpio_base;
@@ -429,11 +433,15 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
err = gpiochip_add_data(&port->gc, port);
if (err)
- dev_err(gpio->dev, "failed to register gpiochip for %s\n",
- pp->name);
+ dev_err(gpio->dev, "failed to register gpiochip for port%d\n",
+ port->idx);
else
port->is_registered = true;
+ /* Add GPIO-signaled ACPI event support */
+ if (pp->irq)
+ acpi_gpiochip_request_interrupts(&port->gc);
+
return err;
}
@@ -447,19 +455,15 @@ static void dwapb_gpio_unregister(struct dwapb_gpio *gpio)
}
static struct dwapb_platform_data *
-dwapb_gpio_get_pdata_of(struct device *dev)
+dwapb_gpio_get_pdata(struct device *dev)
{
- struct device_node *node, *port_np;
+ struct fwnode_handle *fwnode;
struct dwapb_platform_data *pdata;
struct dwapb_port_property *pp;
int nports;
int i;
- node = dev->of_node;
- if (!IS_ENABLED(CONFIG_OF_GPIO) || !node)
- return ERR_PTR(-ENODEV);
-
- nports = of_get_child_count(node);
+ nports = device_get_child_node_count(dev);
if (nports == 0)
return ERR_PTR(-ENODEV);
@@ -474,21 +478,22 @@ dwapb_gpio_get_pdata_of(struct device *dev)
pdata->nports = nports;
i = 0;
- for_each_child_of_node(node, port_np) {
+ device_for_each_child_node(dev, fwnode) {
pp = &pdata->properties[i++];
- pp->node = port_np;
+ pp->fwnode = fwnode;
- if (of_property_read_u32(port_np, "reg", &pp->idx) ||
+ if (fwnode_property_read_u32(fwnode, "reg", &pp->idx) ||
pp->idx >= DWAPB_MAX_PORTS) {
- dev_err(dev, "missing/invalid port index for %s\n",
- port_np->full_name);
+ dev_err(dev,
+ "missing/invalid port index for port%d\n", i);
return ERR_PTR(-EINVAL);
}
- if (of_property_read_u32(port_np, "snps,nr-gpios",
+ if (fwnode_property_read_u32(fwnode, "snps,nr-gpios",
&pp->ngpio)) {
- dev_info(dev, "failed to get number of gpios for %s\n",
- port_np->full_name);
+ dev_info(dev,
+ "failed to get number of gpios for port%d\n",
+ i);
pp->ngpio = 32;
}
@@ -496,18 +501,19 @@ dwapb_gpio_get_pdata_of(struct device *dev)
* Only port A can provide interrupts in all configurations of
* the IP.
*/
- if (pp->idx == 0 &&
- of_property_read_bool(port_np, "interrupt-controller")) {
- pp->irq = irq_of_parse_and_map(port_np, 0);
- if (!pp->irq) {
- dev_warn(dev, "no irq for bank %s\n",
- port_np->full_name);
- }
+ if (dev->of_node && pp->idx == 0 &&
+ fwnode_property_read_bool(fwnode,
+ "interrupt-controller")) {
+ pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
+ if (!pp->irq)
+ dev_warn(dev, "no irq for port%d\n", pp->idx);
}
+ if (has_acpi_companion(dev) && pp->idx == 0)
+ pp->irq = platform_get_irq(to_platform_device(dev), 0);
+
pp->irq_shared = false;
pp->gpio_base = -1;
- pp->name = port_np->full_name;
}
return pdata;
@@ -523,7 +529,7 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
struct dwapb_platform_data *pdata = dev_get_platdata(dev);
if (!pdata) {
- pdata = dwapb_gpio_get_pdata_of(dev);
+ pdata = dwapb_gpio_get_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
@@ -580,6 +586,13 @@ static const struct of_device_id dwapb_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dwapb_of_match);
+static const struct acpi_device_id dwapb_acpi_match[] = {
+ {"HISI0181", 0},
+ {"APMC0D07", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
+
#ifdef CONFIG_PM_SLEEP
static int dwapb_gpio_suspend(struct device *dev)
{
@@ -674,6 +687,7 @@ static struct platform_driver dwapb_gpio_driver = {
.name = "gpio-dwapb",
.pm = &dwapb_gpio_pm_ops,
.of_match_table = of_match_ptr(dwapb_of_match),
+ .acpi_match_table = ACPI_PTR(dwapb_acpi_match),
},
.probe = dwapb_gpio_probe,
.remove = dwapb_gpio_remove,
diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index daac2d480db1..05aa538c3767 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -15,7 +15,8 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/bitops.h>
#define DRVNAME "gpio-f7188x"
@@ -129,6 +130,9 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
static int f7188x_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value);
static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
+static int f7188x_gpio_set_single_ended(struct gpio_chip *gc,
+ unsigned offset,
+ enum single_ended_mode mode);
#define F7188X_GPIO_BANK(_base, _ngpio, _regbase) \
{ \
@@ -139,6 +143,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
.get = f7188x_gpio_get, \
.direction_output = f7188x_gpio_direction_out, \
.set = f7188x_gpio_set, \
+ .set_single_ended = f7188x_gpio_set_single_ended, \
.base = _base, \
.ngpio = _ngpio, \
.can_sleep = true, \
@@ -217,7 +222,7 @@ static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
superio_select(sio->addr, SIO_LD_GPIO);
dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
- dir &= ~(1 << offset);
+ dir &= ~BIT(offset);
superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
superio_exit(sio->addr);
@@ -238,7 +243,7 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
superio_select(sio->addr, SIO_LD_GPIO);
dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
- dir = !!(dir & (1 << offset));
+ dir = !!(dir & BIT(offset));
if (dir)
data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
else
@@ -246,7 +251,7 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
superio_exit(sio->addr);
- return !!(data & 1 << offset);
+ return !!(data & BIT(offset));
}
static int f7188x_gpio_direction_out(struct gpio_chip *chip,
@@ -264,13 +269,13 @@ static int f7188x_gpio_direction_out(struct gpio_chip *chip,
data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
if (value)
- data_out |= (1 << offset);
+ data_out |= BIT(offset);
else
- data_out &= ~(1 << offset);
+ data_out &= ~BIT(offset);
superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
- dir |= (1 << offset);
+ dir |= BIT(offset);
superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
superio_exit(sio->addr);
@@ -292,14 +297,43 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
if (value)
- data_out |= (1 << offset);
+ data_out |= BIT(offset);
else
- data_out &= ~(1 << offset);
+ data_out &= ~BIT(offset);
superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
superio_exit(sio->addr);
}
+static int f7188x_gpio_set_single_ended(struct gpio_chip *chip,
+ unsigned offset,
+ enum single_ended_mode mode)
+{
+ int err;
+ struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
+ struct f7188x_sio *sio = bank->data->sio;
+ u8 data;
+
+ if (mode != LINE_MODE_OPEN_DRAIN &&
+ mode != LINE_MODE_PUSH_PULL)
+ return -ENOTSUPP;
+
+ err = superio_enter(sio->addr);
+ if (err)
+ return err;
+ superio_select(sio->addr, SIO_LD_GPIO);
+
+ data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
+ if (mode == LINE_MODE_OPEN_DRAIN)
+ data &= ~BIT(offset);
+ else
+ data |= BIT(offset);
+ superio_outb(sio->addr, gpio_out_mode(bank->regbase), data);
+
+ superio_exit(sio->addr);
+ return 0;
+}
+
/*
* Platform device and driver.
*/
diff --git a/drivers/gpio/gpio-it87.c b/drivers/gpio/gpio-it87.c
index b219c82414bf..63a962d18cd6 100644
--- a/drivers/gpio/gpio-it87.c
+++ b/drivers/gpio/gpio-it87.c
@@ -34,6 +34,8 @@
/* Chip Id numbers */
#define NO_DEV_ID 0xffff
+#define IT8620_ID 0x8620
+#define IT8628_ID 0x8628
#define IT8728_ID 0x8728
#define IT8732_ID 0x8732
#define IT8761_ID 0x8761
@@ -302,6 +304,14 @@ static int __init it87_gpio_init(void)
it87_gpio->chip = it87_template_chip;
switch (chip_type) {
+ case IT8620_ID:
+ case IT8628_ID:
+ gpio_ba_reg = 0x62;
+ it87_gpio->io_size = 11;
+ it87_gpio->output_base = 0xc8;
+ it87_gpio->simple_size = 0;
+ it87_gpio->chip.ngpio = 64;
+ break;
case IT8728_ID:
case IT8732_ID:
gpio_ba_reg = 0x62;
diff --git a/drivers/gpio/gpio-loongson1.c b/drivers/gpio/gpio-loongson1.c
new file mode 100644
index 000000000000..10c09bdd8514
--- /dev/null
+++ b/drivers/gpio/gpio-loongson1.c
@@ -0,0 +1,102 @@
+/*
+ * GPIO Driver for Loongson 1 SoC
+ *
+ * Copyright (C) 2015-2016 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+
+/* Loongson 1 GPIO Register Definitions */
+#define GPIO_CFG 0x0
+#define GPIO_DIR 0x10
+#define GPIO_DATA 0x20
+#define GPIO_OUTPUT 0x30
+
+static void __iomem *gpio_reg_base;
+
+static int ls1x_gpio_request(struct gpio_chip *gc, unsigned int offset)
+{
+ unsigned long pinmask = gc->pin2mask(gc, offset);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+ __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) | pinmask,
+ gpio_reg_base + GPIO_CFG);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+
+ return 0;
+}
+
+static void ls1x_gpio_free(struct gpio_chip *gc, unsigned int offset)
+{
+ unsigned long pinmask = gc->pin2mask(gc, offset);
+ unsigned long flags;
+
+ spin_lock_irqsave(&gc->bgpio_lock, flags);
+ __raw_writel(__raw_readl(gpio_reg_base + GPIO_CFG) & ~pinmask,
+ gpio_reg_base + GPIO_CFG);
+ spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static int ls1x_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct gpio_chip *gc;
+ struct resource *res;
+ int ret;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "failed to get I/O memory\n");
+ return -EINVAL;
+ }
+
+ gpio_reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(gpio_reg_base))
+ return PTR_ERR(gpio_reg_base);
+
+ ret = bgpio_init(gc, dev, 4, gpio_reg_base + GPIO_DATA,
+ gpio_reg_base + GPIO_OUTPUT, NULL,
+ NULL, gpio_reg_base + GPIO_DIR, 0);
+ if (ret)
+ goto err;
+
+ gc->owner = THIS_MODULE;
+ gc->request = ls1x_gpio_request;
+ gc->free = ls1x_gpio_free;
+ gc->base = pdev->id * 32;
+
+ ret = devm_gpiochip_add_data(dev, gc, NULL);
+ if (ret)
+ goto err;
+
+ platform_set_drvdata(pdev, gc);
+ dev_info(dev, "Loongson1 GPIO driver registered\n");
+
+ return 0;
+err:
+ dev_err(dev, "failed to register GPIO device\n");
+ return ret;
+}
+
+static struct platform_driver ls1x_gpio_driver = {
+ .probe = ls1x_gpio_probe,
+ .driver = {
+ .name = "ls1x-gpio",
+ },
+};
+
+module_platform_driver(ls1x_gpio_driver);
+
+MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
+MODULE_DESCRIPTION("Loongson1 GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
index 7fffc1d6c055..d55af50e7034 100644
--- a/drivers/gpio/gpio-mb86s7x.c
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -17,7 +17,6 @@
#include <linux/io.h>
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/module.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/ioport.h>
@@ -185,8 +184,6 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
gchip->gc.parent = &pdev->dev;
gchip->gc.base = -1;
- platform_set_drvdata(pdev, gchip);
-
ret = gpiochip_add_data(&gchip->gc, gchip);
if (ret) {
dev_err(&pdev->dev, "couldn't register gpio driver\n");
@@ -210,7 +207,6 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = {
{ .compatible = "fujitsu,mb86s70-gpio" },
{ /* sentinel */ }
};
-MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
static struct platform_driver mb86s70_gpio_driver = {
.driver = {
@@ -225,8 +221,4 @@ static int __init mb86s70_gpio_init(void)
{
return platform_driver_register(&mb86s70_gpio_driver);
}
-module_init(mb86s70_gpio_init);
-
-MODULE_DESCRIPTION("MB86S7x GPIO Driver");
-MODULE_ALIAS("platform:mb86s70-gpio");
-MODULE_LICENSE("GPL");
+device_initcall(mb86s70_gpio_init);
diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c
index 14f252f9eb29..2fcad5b9cca5 100644
--- a/drivers/gpio/gpio-mc9s08dz60.c
+++ b/drivers/gpio/gpio-mc9s08dz60.c
@@ -15,7 +15,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
@@ -111,8 +111,6 @@ static const struct i2c_device_id mc9s08dz60_id[] = {
{},
};
-MODULE_DEVICE_TABLE(i2c, mc9s08dz60_id);
-
static struct i2c_driver mc9s08dz60_i2c_driver = {
.driver = {
.name = "mc9s08dz60",
@@ -120,10 +118,4 @@ static struct i2c_driver mc9s08dz60_i2c_driver = {
.probe = mc9s08dz60_probe,
.id_table = mc9s08dz60_id,
};
-
-module_i2c_driver(mc9s08dz60_i2c_driver);
-
-MODULE_AUTHOR("Freescale Semiconductor, Inc. "
- "Wu Guoxing <b39297@freescale.com>");
-MODULE_DESCRIPTION("mc9s08dz60 gpio function on mx35 3ds board");
-MODULE_LICENSE("GPL v2");
+builtin_i2c_driver(mc9s08dz60_i2c_driver);
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 47e486910aab..ac22efc1840e 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -77,7 +77,6 @@ struct mcp23s08 {
/* lock protects the cached values */
struct mutex lock;
struct mutex irq_lock;
- struct irq_domain *irq_domain;
struct gpio_chip chip;
@@ -96,11 +95,6 @@ struct mcp23s08_driver_data {
struct mcp23s08 chip[];
};
-/* This lock class tells lockdep that GPIO irqs are in a different
- * category than their parents, so it won't report false recursion.
- */
-static struct lock_class_key gpio_lock_class;
-
/*----------------------------------------------------------------------*/
#if IS_ENABLED(CONFIG_I2C)
@@ -368,8 +362,9 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
for (i = 0; i < mcp->chip.ngpio; i++) {
if ((BIT(i) & mcp->cache[MCP_INTF]) &&
((BIT(i) & intcap & mcp->irq_rise) ||
- (mcp->irq_fall & ~intcap & BIT(i)))) {
- child_irq = irq_find_mapping(mcp->irq_domain, i);
+ (mcp->irq_fall & ~intcap & BIT(i)) ||
+ (BIT(i) & mcp->cache[MCP_INTCON]))) {
+ child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
handle_nested_irq(child_irq);
}
}
@@ -377,16 +372,10 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int mcp23s08_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct mcp23s08 *mcp = gpiochip_get_data(chip);
-
- return irq_find_mapping(mcp->irq_domain, offset);
-}
-
static void mcp23s08_irq_mask(struct irq_data *data)
{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mcp23s08 *mcp = gpiochip_get_data(gc);
unsigned int pos = data->hwirq;
mcp->cache[MCP_GPINTEN] &= ~BIT(pos);
@@ -394,7 +383,8 @@ static void mcp23s08_irq_mask(struct irq_data *data)
static void mcp23s08_irq_unmask(struct irq_data *data)
{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mcp23s08 *mcp = gpiochip_get_data(gc);
unsigned int pos = data->hwirq;
mcp->cache[MCP_GPINTEN] |= BIT(pos);
@@ -402,7 +392,8 @@ static void mcp23s08_irq_unmask(struct irq_data *data)
static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mcp23s08 *mcp = gpiochip_get_data(gc);
unsigned int pos = data->hwirq;
int status = 0;
@@ -418,6 +409,12 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
mcp->cache[MCP_INTCON] &= ~BIT(pos);
mcp->irq_rise &= ~BIT(pos);
mcp->irq_fall |= BIT(pos);
+ } else if (type & IRQ_TYPE_LEVEL_HIGH) {
+ mcp->cache[MCP_INTCON] |= BIT(pos);
+ mcp->cache[MCP_DEFVAL] &= ~BIT(pos);
+ } else if (type & IRQ_TYPE_LEVEL_LOW) {
+ mcp->cache[MCP_INTCON] |= BIT(pos);
+ mcp->cache[MCP_DEFVAL] |= BIT(pos);
} else
return -EINVAL;
@@ -426,14 +423,16 @@ static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
static void mcp23s08_irq_bus_lock(struct irq_data *data)
{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mcp23s08 *mcp = gpiochip_get_data(gc);
mutex_lock(&mcp->irq_lock);
}
static void mcp23s08_irq_bus_unlock(struct irq_data *data)
{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+ struct mcp23s08 *mcp = gpiochip_get_data(gc);
mutex_lock(&mcp->lock);
mcp->ops->write(mcp, MCP_GPINTEN, mcp->cache[MCP_GPINTEN]);
@@ -443,27 +442,6 @@ static void mcp23s08_irq_bus_unlock(struct irq_data *data)
mutex_unlock(&mcp->irq_lock);
}
-static int mcp23s08_irq_reqres(struct irq_data *data)
-{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
-
- if (gpiochip_lock_as_irq(&mcp->chip, data->hwirq)) {
- dev_err(mcp->chip.parent,
- "unable to lock HW IRQ %lu for IRQ usage\n",
- data->hwirq);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void mcp23s08_irq_relres(struct irq_data *data)
-{
- struct mcp23s08 *mcp = irq_data_get_irq_chip_data(data);
-
- gpiochip_unlock_as_irq(&mcp->chip, data->hwirq);
-}
-
static struct irq_chip mcp23s08_irq_chip = {
.name = "gpio-mcp23xxx",
.irq_mask = mcp23s08_irq_mask,
@@ -471,24 +449,16 @@ static struct irq_chip mcp23s08_irq_chip = {
.irq_set_type = mcp23s08_irq_set_type,
.irq_bus_lock = mcp23s08_irq_bus_lock,
.irq_bus_sync_unlock = mcp23s08_irq_bus_unlock,
- .irq_request_resources = mcp23s08_irq_reqres,
- .irq_release_resources = mcp23s08_irq_relres,
};
static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
{
struct gpio_chip *chip = &mcp->chip;
- int err, irq, j;
+ int err;
unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED;
mutex_init(&mcp->irq_lock);
- mcp->irq_domain = irq_domain_add_linear(chip->parent->of_node,
- chip->ngpio,
- &irq_domain_simple_ops, mcp);
- if (!mcp->irq_domain)
- return -ENODEV;
-
if (mcp->irq_active_high)
irqflags |= IRQF_TRIGGER_HIGH;
else
@@ -503,30 +473,23 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return err;
}
- chip->to_irq = mcp23s08_gpio_to_irq;
-
- for (j = 0; j < mcp->chip.ngpio; j++) {
- irq = irq_create_mapping(mcp->irq_domain, j);
- irq_set_lockdep_class(irq, &gpio_lock_class);
- irq_set_chip_data(irq, mcp);
- irq_set_chip(irq, &mcp23s08_irq_chip);
- irq_set_nested_thread(irq, true);
- irq_set_noprobe(irq);
+ err = gpiochip_irqchip_add(chip,
+ &mcp23s08_irq_chip,
+ 0,
+ handle_simple_irq,
+ IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(chip->parent,
+ "could not connect irqchip to gpiochip: %d\n", err);
+ return err;
}
- return 0;
-}
-static void mcp23s08_irq_teardown(struct mcp23s08 *mcp)
-{
- unsigned int irq, i;
+ gpiochip_set_chained_irqchip(chip,
+ &mcp23s08_irq_chip,
+ mcp->irq,
+ NULL);
- for (i = 0; i < mcp->chip.ngpio; i++) {
- irq = irq_find_mapping(mcp->irq_domain, i);
- if (irq > 0)
- irq_dispose_mapping(irq);
- }
-
- irq_domain_remove(mcp->irq_domain);
+ return 0;
}
/*----------------------------------------------------------------------*/
@@ -721,7 +684,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (mcp->irq && mcp->irq_controller) {
status = mcp23s08_irq_setup(mcp);
if (status) {
- mcp23s08_irq_teardown(mcp);
goto fail;
}
}
@@ -847,9 +809,6 @@ static int mcp230xx_remove(struct i2c_client *client)
{
struct mcp23s08 *mcp = i2c_get_clientdata(client);
- if (client->irq && mcp->irq_controller)
- mcp23s08_irq_teardown(mcp);
-
gpiochip_remove(&mcp->chip);
kfree(mcp);
@@ -1017,8 +976,6 @@ static int mcp23s08_remove(struct spi_device *spi)
if (!data->mcp[addr])
continue;
- if (spi->irq && data->mcp[addr]->irq_controller)
- mcp23s08_irq_teardown(data->mcp[addr]);
gpiochip_remove(&data->mcp[addr]->chip);
}
diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c
index c5c9599a3a71..cc103aff45e4 100644
--- a/drivers/gpio/gpio-menz127.c
+++ b/drivers/gpio/gpio-menz127.c
@@ -35,7 +35,6 @@
struct men_z127_gpio {
struct gpio_chip gc;
void __iomem *reg_base;
- struct mcb_device *mdev;
struct resource *mem;
};
@@ -43,7 +42,7 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
unsigned debounce)
{
struct men_z127_gpio *priv = gpiochip_get_data(gc);
- struct device *dev = &priv->mdev->dev;
+ struct device *dev = gc->parent;
unsigned int rnd;
u32 db_en, db_cnt;
@@ -88,21 +87,25 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
return 0;
}
-static int men_z127_request(struct gpio_chip *gc, unsigned gpio_pin)
+static int men_z127_set_single_ended(struct gpio_chip *gc,
+ unsigned offset,
+ enum single_ended_mode mode)
{
struct men_z127_gpio *priv = gpiochip_get_data(gc);
u32 od_en;
- if (gpio_pin >= gc->ngpio)
- return -EINVAL;
+ if (mode != LINE_MODE_OPEN_DRAIN &&
+ mode != LINE_MODE_PUSH_PULL)
+ return -ENOTSUPP;
spin_lock(&gc->bgpio_lock);
od_en = readl(priv->reg_base + MEN_Z127_ODER);
- if (gpiochip_line_is_open_drain(gc, gpio_pin))
- od_en |= BIT(gpio_pin);
+ if (mode == LINE_MODE_OPEN_DRAIN)
+ od_en |= BIT(offset);
else
- od_en &= ~BIT(gpio_pin);
+ /* Implicitly LINE_MODE_PUSH_PULL */
+ od_en &= ~BIT(offset);
writel(od_en, priv->reg_base + MEN_Z127_ODER);
spin_unlock(&gc->bgpio_lock);
@@ -135,7 +138,6 @@ static int men_z127_probe(struct mcb_device *mdev,
goto err_release;
}
- men_z127_gpio->mdev = mdev;
mcb_set_drvdata(mdev, men_z127_gpio);
ret = bgpio_init(&men_z127_gpio->gc, &mdev->dev, 4,
@@ -148,7 +150,7 @@ static int men_z127_probe(struct mcb_device *mdev,
goto err_unmap;
men_z127_gpio->gc.set_debounce = men_z127_debounce;
- men_z127_gpio->gc.request = men_z127_request;
+ men_z127_gpio->gc.set_single_ended = men_z127_set_single_ended;
ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio);
if (ret) {
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-mmio.c
index 54cddfa98f50..6c1cb3b8c02c 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-mmio.c
@@ -549,7 +549,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
}
EXPORT_SYMBOL_GPL(bgpio_init);
-#ifdef CONFIG_GPIO_GENERIC_PLATFORM
+#if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM)
static void __iomem *bgpio_map(struct platform_device *pdev,
const char *name,
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index f02d0b490978..d58d38906ba6 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -15,7 +15,6 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/platform_device.h>
-#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
@@ -82,8 +81,4 @@ static struct platform_driver moxart_gpio_driver = {
},
.probe = moxart_gpio_probe,
};
-module_platform_driver(moxart_gpio_driver);
-
-MODULE_DESCRIPTION("MOXART GPIO chip driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
+builtin_platform_driver(moxart_gpio_driver);
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 11c6582ef0a6..cd5dc27320a2 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -34,7 +34,7 @@
*/
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/slab.h>
@@ -557,7 +557,6 @@ static const struct of_device_id mvebu_gpio_of_match[] = {
/* sentinel */
},
};
-MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match);
static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
{
@@ -838,4 +837,4 @@ static struct platform_driver mvebu_gpio_driver = {
.suspend = mvebu_gpio_suspend,
.resume = mvebu_gpio_resume,
};
-module_platform_driver(mvebu_gpio_driver);
+builtin_platform_driver(mvebu_gpio_driver);
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
index 47aead1ed1cc..96a8a8cb2729 100644
--- a/drivers/gpio/gpio-octeon.c
+++ b/drivers/gpio/gpio-octeon.c
@@ -83,6 +83,7 @@ static int octeon_gpio_probe(struct platform_device *pdev)
struct octeon_gpio *gpio;
struct gpio_chip *chip;
struct resource *res_mem;
+ void __iomem *reg_base;
int err = 0;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -91,21 +92,11 @@ static int octeon_gpio_probe(struct platform_device *pdev)
chip = &gpio->chip;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res_mem == NULL) {
- dev_err(&pdev->dev, "found no memory resource\n");
- err = -ENXIO;
- goto out;
- }
- if (!devm_request_mem_region(&pdev->dev, res_mem->start,
- resource_size(res_mem),
- res_mem->name)) {
- dev_err(&pdev->dev, "request_mem_region failed\n");
- err = -ENXIO;
- goto out;
- }
- gpio->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
- resource_size(res_mem));
+ reg_base = devm_ioremap_resource(&pdev->dev, res_mem);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+ gpio->register_base = (u64)reg_base;
pdev->dev.platform_data = chip;
chip->label = "octeon-gpio";
chip->parent = &pdev->dev;
@@ -119,14 +110,13 @@ static int octeon_gpio_probe(struct platform_device *pdev)
chip->set = octeon_gpio_set;
err = devm_gpiochip_add_data(&pdev->dev, chip, gpio);
if (err)
- goto out;
+ return err;
dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n");
-out:
- return err;
+ return 0;
}
-static struct of_device_id octeon_gpio_match[] = {
+static const struct of_device_id octeon_gpio_match[] = {
{
.compatible = "cavium,octeon-3860-gpio",
},
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 551dfa9d97ab..b98ede78c9d8 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -611,51 +611,12 @@ static inline void omap_set_gpio_irqenable(struct gpio_bank *bank,
omap_disable_gpio_irqbank(bank, BIT(offset));
}
-/*
- * Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register.
- * 1510 does not seem to have a wake-up register. If JTAG is connected
- * to the target, system will wake up always on GPIO events. While
- * system is running all registered GPIO interrupts need to have wake-up
- * enabled. When system is suspended, only selected GPIO interrupts need
- * to have wake-up enabled.
- */
-static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset,
- int enable)
-{
- u32 gpio_bit = BIT(offset);
- unsigned long flags;
-
- if (bank->non_wakeup_gpios & gpio_bit) {
- dev_err(bank->chip.parent,
- "Unable to modify wakeup on non-wakeup GPIO%d\n",
- offset);
- return -EINVAL;
- }
-
- raw_spin_lock_irqsave(&bank->lock, flags);
- if (enable)
- bank->context.wake_en |= gpio_bit;
- else
- bank->context.wake_en &= ~gpio_bit;
-
- writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en);
- raw_spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
-}
-
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
- unsigned offset = d->hwirq;
- int ret;
- ret = omap_set_gpio_wakeup(bank, offset, enable);
- if (!ret)
- ret = irq_set_irq_wake(bank->irq, enable);
-
- return ret;
+ return irq_set_irq_wake(bank->irq, enable);
}
static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -1187,6 +1148,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
irqc->name = dev_name(&pdev->dev);
+ irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
bank->irq = platform_get_irq(pdev, 0);
if (bank->irq <= 0) {
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index 6f27b3d94d53..e248707ca39e 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -20,7 +20,7 @@
#include <linux/gpio.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/mfd/palmas.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -218,14 +218,3 @@ static int __init palmas_gpio_init(void)
return platform_driver_register(&palmas_gpio_driver);
}
subsys_initcall(palmas_gpio_init);
-
-static void __exit palmas_gpio_exit(void)
-{
- platform_driver_unregister(&palmas_gpio_driver);
-}
-module_exit(palmas_gpio_exit);
-
-MODULE_ALIAS("platform:palmas-gpio");
-MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("GPIO driver for TI Palmas series PMICs");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index e66084c295fb..5e3be32ebb8d 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -38,8 +38,13 @@
#define PCA957X_MSK 6
#define PCA957X_INTS 7
+#define PCAL953X_IN_LATCH 34
+#define PCAL953X_INT_MASK 37
+#define PCAL953X_INT_STAT 38
+
#define PCA_GPIO_MASK 0x00FF
#define PCA_INT 0x0100
+#define PCA_PCAL 0x0200
#define PCA953X_TYPE 0x1000
#define PCA957X_TYPE 0x2000
#define PCA_TYPE_MASK 0xF000
@@ -77,7 +82,7 @@ static const struct i2c_device_id pca953x_id[] = {
MODULE_DEVICE_TABLE(i2c, pca953x_id);
static const struct acpi_device_id pca953x_acpi_ids[] = {
- { "INT3491", 16 | PCA953X_TYPE | PCA_INT, },
+ { "INT3491", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
{ }
};
MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
@@ -437,6 +442,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 new_irqs;
int level, i;
+ u8 invert_irq_mask[MAX_BANK];
+
+ if (chip->driver_data & PCA_PCAL) {
+ /* Enable latch on interrupt-enabled inputs */
+ pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
+
+ for (i = 0; i < NBANK(chip); i++)
+ invert_irq_mask[i] = ~chip->irq_mask[i];
+
+ /* Unmask enabled interrupts */
+ pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask);
+ }
/* Look for any newly setup interrupt */
for (i = 0; i < NBANK(chip); i++) {
@@ -498,6 +515,29 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
u8 trigger[MAX_BANK];
int ret, i, offset = 0;
+ if (chip->driver_data & PCA_PCAL) {
+ /* Read the current interrupt status from the device */
+ ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, trigger);
+ if (ret)
+ return false;
+
+ /* Check latched inputs and clear interrupt status */
+ ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat);
+ if (ret)
+ return false;
+
+ for (i = 0; i < NBANK(chip); i++) {
+ /* Apply filter for rising/falling edge selection */
+ pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) |
+ (cur_stat[i] & chip->irq_trig_raise[i]);
+ pending[i] &= trigger[i];
+ if (pending[i])
+ pending_seen = true;
+ }
+
+ return pending_seen;
+ }
+
switch (chip->chip_type) {
case PCA953X_TYPE:
offset = PCA953X_INPUT;
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 5cb38212bbc0..6e3c1430616f 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -1,6 +1,8 @@
/*
* Copyright (C) 2008, 2009 Provigent Ltd.
*
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -11,7 +13,7 @@
*/
#include <linux/spinlock.h>
#include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
@@ -59,15 +61,19 @@ struct pl061_gpio {
#endif
};
+static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
+{
+ struct pl061_gpio *chip = gpiochip_get_data(gc);
+
+ return !(readb(chip->base + GPIODIR) & BIT(offset));
+}
+
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = gpiochip_get_data(gc);
unsigned long flags;
unsigned char gpiodir;
- if (offset >= gc->ngpio)
- return -EINVAL;
-
spin_lock_irqsave(&chip->lock, flags);
gpiodir = readb(chip->base + GPIODIR);
gpiodir &= ~(BIT(offset));
@@ -84,9 +90,6 @@ static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
unsigned long flags;
unsigned char gpiodir;
- if (offset >= gc->ngpio)
- return -EINVAL;
-
spin_lock_irqsave(&chip->lock, flags);
writeb(!!value << offset, chip->base + (BIT(offset + 2)));
gpiodir = readb(chip->base + GPIODIR);
@@ -319,6 +322,7 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
chip->gc.free = gpiochip_generic_free;
}
+ chip->gc.get_direction = pl061_get_direction;
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
@@ -429,8 +433,6 @@ static struct amba_id pl061_ids[] = {
{ 0, 0 },
};
-MODULE_DEVICE_TABLE(amba, pl061_ids);
-
static struct amba_driver pl061_gpio_driver = {
.drv = {
.name = "pl061_gpio",
@@ -446,8 +448,4 @@ static int __init pl061_gpio_init(void)
{
return amba_driver_register(&pl061_gpio_driver);
}
-module_init(pl061_gpio_init);
-
-MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
-MODULE_DESCRIPTION("PL061 GPIO driver");
-MODULE_LICENSE("GPL");
+device_initcall(pl061_gpio_init);
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
index 1d6100fa312a..3b4dc1a9a68d 100644
--- a/drivers/gpio/gpio-rc5t583.c
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/gpio.h>
@@ -152,14 +151,3 @@ static int __init rc5t583_gpio_init(void)
return platform_driver_register(&rc5t583_gpio_driver);
}
subsys_initcall(rc5t583_gpio_init);
-
-static void __exit rc5t583_gpio_exit(void)
-{
- platform_driver_unregister(&rc5t583_gpio_driver);
-}
-module_exit(rc5t583_gpio_exit);
-
-MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_DESCRIPTION("GPIO interface for RC5T583");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:rc5t583-gpio");
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 4d9a315cfd43..681c93fb9e70 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -284,6 +284,25 @@ static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
spin_unlock_irqrestore(&p->lock, flags);
}
+static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct gpio_rcar_priv *p = gpiochip_get_data(chip);
+ unsigned long flags;
+ u32 val, bankmask;
+
+ bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
+ if (!bankmask)
+ return;
+
+ spin_lock_irqsave(&p->lock, flags);
+ val = gpio_rcar_read(p, OUTDT);
+ val &= ~bankmask;
+ val |= (bankmask & bits[0]);
+ gpio_rcar_write(p, OUTDT, val);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+
static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
@@ -425,6 +444,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->get = gpio_rcar_get;
gpio_chip->direction_output = gpio_rcar_direction_output;
gpio_chip->set = gpio_rcar_set;
+ gpio_chip->set_multiple = gpio_rcar_set_multiple;
gpio_chip->label = name;
gpio_chip->parent = dev;
gpio_chip->owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index e3cb6772f6ec..7da9e6c4546a 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -3,6 +3,8 @@
*
* Copyright (c) 2010, 2011 Intel Corporation
*
+ * Author: Hans J. Koch <hjk@linutronix.de>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License 2 as published
* by the Free Software Foundation.
@@ -15,7 +17,6 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/of_irq.h>
@@ -257,34 +258,17 @@ done:
return ret;
}
-static void sdv_gpio_remove(struct pci_dev *pdev)
-{
- struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev);
-
- free_irq(pdev->irq, sd);
- irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS);
-
- gpiochip_remove(&sd->chip);
- pci_release_region(pdev, GPIO_BAR);
- iounmap(sd->gpio_pub_base);
- pci_disable_device(pdev);
- kfree(sd);
-}
-
static const struct pci_device_id sdv_gpio_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_SDV_GPIO) },
{ 0, },
};
static struct pci_driver sdv_gpio_driver = {
+ .driver = {
+ .suppress_bind_attrs = true,
+ },
.name = DRV_NAME,
.id_table = sdv_gpio_pci_ids,
.probe = sdv_gpio_probe,
- .remove = sdv_gpio_remove,
};
-
-module_pci_driver(sdv_gpio_driver);
-
-MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
-MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
-MODULE_LICENSE("GPL v2");
+builtin_pci_driver(sdv_gpio_driver);
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 0d5b8c525dd9..853ca23cad88 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -20,7 +20,7 @@
*
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/gpio.h>
@@ -432,8 +432,4 @@ static struct platform_driver sta2x11_gpio_platform_driver = {
},
.probe = gsta_probe,
};
-
-module_platform_driver(sta2x11_gpio_platform_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("sta2x11_gpio GPIO driver");
+builtin_platform_driver(sta2x11_gpio_platform_driver);
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 5197edf1acfd..6f7af28b8966 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -5,7 +5,6 @@
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -413,23 +412,13 @@ out_free:
return ret;
}
-static int stmpe_gpio_remove(struct platform_device *pdev)
-{
- struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
- struct stmpe *stmpe = stmpe_gpio->stmpe;
-
- gpiochip_remove(&stmpe_gpio->chip);
- stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
- kfree(stmpe_gpio);
-
- return 0;
-}
-
static struct platform_driver stmpe_gpio_driver = {
- .driver.name = "stmpe-gpio",
- .driver.owner = THIS_MODULE,
+ .driver = {
+ .suppress_bind_attrs = true,
+ .name = "stmpe-gpio",
+ .owner = THIS_MODULE,
+ },
.probe = stmpe_gpio_probe,
- .remove = stmpe_gpio_remove,
};
static int __init stmpe_gpio_init(void)
@@ -437,13 +426,3 @@ static int __init stmpe_gpio_init(void)
return platform_driver_register(&stmpe_gpio_driver);
}
subsys_initcall(stmpe_gpio_init);
-
-static void __exit stmpe_gpio_exit(void)
-{
- platform_driver_unregister(&stmpe_gpio_driver);
-}
-module_exit(stmpe_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("STMPExxxx GPIO driver");
-MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index d387eb524bf3..a177ebd921d5 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -1,5 +1,9 @@
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
*
+ * Driver for Semtech SX150X I2C GPIO Expanders
+ *
+ * Author: Gregory Bean <gbean@codeaurora.org>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
@@ -19,10 +23,8 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/i2c/sx150x.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -82,6 +84,57 @@ struct sx150x_device_data {
} pri;
};
+/**
+ * struct sx150x_platform_data - config data for SX150x driver
+ * @gpio_base: The index number of the first GPIO assigned to this
+ * GPIO expander. The expander will create a block of
+ * consecutively numbered gpios beginning at the given base,
+ * with the size of the block depending on the model of the
+ * expander chip.
+ * @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO
+ * instead of as an oscillator, increasing the size of the
+ * GP(I)O pool created by this expander by one. The
+ * output-only GPO pin will be added at the end of the block.
+ * @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor
+ * for each IO line in the expander. Setting the bit at
+ * position n will enable the pull-up for the IO at
+ * the corresponding offset. For chips with fewer than
+ * 16 IO pins, high-end bits are ignored.
+ * @io_pulldn_ena: A bit-mask which enables-or disables the pull-down
+ * resistor for each IO line in the expander. Setting the
+ * bit at position n will enable the pull-down for the IO at
+ * the corresponding offset. For chips with fewer than
+ * 16 IO pins, high-end bits are ignored.
+ * @io_polarity: A bit-mask which enables polarity inversion for each IO line
+ * in the expander. Setting the bit at position n inverts
+ * the polarity of that IO line, while clearing it results
+ * in normal polarity. For chips with fewer than 16 IO pins,
+ * high-end bits are ignored.
+ * @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line
+ * is connected, via which it reports interrupt events
+ * across all GPIO lines. This must be a real,
+ * pre-existing IRQ line.
+ * Setting this value < 0 disables the irq_chip functionality
+ * of the driver.
+ * @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based
+ * IRQ lines will appear. Similarly to gpio_base, the expander
+ * will create a block of irqs beginning at this number.
+ * This value is ignored if irq_summary is < 0.
+ * @reset_during_probe: If set to true, the driver will trigger a full
+ * reset of the chip at the beginning of the probe
+ * in order to place it in a known state.
+ */
+struct sx150x_platform_data {
+ unsigned gpio_base;
+ bool oscio_is_gpo;
+ u16 io_pullup_ena;
+ u16 io_pulldn_ena;
+ u16 io_polarity;
+ int irq_summary;
+ unsigned irq_base;
+ bool reset_during_probe;
+};
+
struct sx150x_chip {
struct gpio_chip gpio_chip;
struct i2c_client *client;
@@ -354,6 +407,32 @@ static void sx150x_gpio_set(struct gpio_chip *gc, unsigned offset, int val)
mutex_unlock(&chip->lock);
}
+static int sx150x_gpio_set_single_ended(struct gpio_chip *gc,
+ unsigned offset,
+ enum single_ended_mode mode)
+{
+ struct sx150x_chip *chip = gpiochip_get_data(gc);
+
+ /* On the SX160X 789 we can set open drain */
+ if (chip->dev_cfg->model != SX150X_789)
+ return -ENOTSUPP;
+
+ if (mode == LINE_MODE_PUSH_PULL)
+ return sx150x_write_cfg(chip,
+ offset,
+ 1,
+ chip->dev_cfg->pri.x789.reg_drain,
+ 0);
+
+ if (mode == LINE_MODE_OPEN_DRAIN)
+ return sx150x_write_cfg(chip,
+ offset,
+ 1,
+ chip->dev_cfg->pri.x789.reg_drain,
+ 1);
+ return -ENOTSUPP;
+}
+
static int sx150x_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct sx150x_chip *chip = gpiochip_get_data(gc);
@@ -508,6 +587,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
chip->gpio_chip.direction_output = sx150x_gpio_direction_output;
chip->gpio_chip.get = sx150x_gpio_get;
chip->gpio_chip.set = sx150x_gpio_set;
+ chip->gpio_chip.set_single_ended = sx150x_gpio_set_single_ended;
chip->gpio_chip.base = pdata->gpio_base;
chip->gpio_chip.can_sleep = true;
chip->gpio_chip.ngpio = chip->dev_cfg->ngpios;
@@ -597,12 +677,6 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
if (chip->dev_cfg->model == SX150X_789) {
err = sx150x_init_io(chip,
- chip->dev_cfg->pri.x789.reg_drain,
- pdata->io_open_drain_ena);
- if (err < 0)
- return err;
-
- err = sx150x_init_io(chip,
chip->dev_cfg->pri.x789.reg_polarity,
pdata->io_polarity);
if (err < 0)
@@ -718,13 +792,3 @@ static int __init sx150x_init(void)
return i2c_add_driver(&sx150x_driver);
}
subsys_initcall(sx150x_init);
-
-static void __exit sx150x_exit(void)
-{
- return i2c_del_driver(&sx150x_driver);
-}
-module_exit(sx150x_exit);
-
-MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
-MODULE_DESCRIPTION("Driver for Semtech SX150X I2C GPIO Expanders");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 4f566e6b81f1..2e35ed3abbcf 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -6,14 +6,14 @@
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/of.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc3589x.h>
+#include <linux/bitops.h>
/*
* These registers are modified under the irq bus lock and cached to avoid
@@ -39,7 +39,7 @@ static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
- u8 mask = 1 << (offset % 8);
+ u8 mask = BIT(offset % 8);
int ret;
ret = tc3589x_reg_read(tc3589x, reg);
@@ -55,7 +55,7 @@ static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
unsigned pos = offset % 8;
- u8 data[] = {!!val << pos, 1 << pos};
+ u8 data[] = {val ? BIT(pos) : 0, BIT(pos)};
tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
}
@@ -70,7 +70,7 @@ static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
tc3589x_gpio_set(chip, offset, val);
- return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos);
+ return tc3589x_set_bits(tc3589x, reg, BIT(pos), BIT(pos));
}
static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
@@ -81,7 +81,47 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
u8 reg = TC3589x_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
- return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
+ return tc3589x_set_bits(tc3589x, reg, BIT(pos), 0);
+}
+
+static int tc3589x_gpio_single_ended(struct gpio_chip *chip,
+ unsigned offset,
+ enum single_ended_mode mode)
+{
+ struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
+ struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
+ /*
+ * These registers are alterated at each second address
+ * ODM bit 0 = drive to GND or Hi-Z (open drain)
+ * ODM bit 1 = drive to VDD or Hi-Z (open source)
+ */
+ u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2;
+ u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2;
+ unsigned pos = offset % 8;
+ int ret;
+
+ switch(mode) {
+ case LINE_MODE_OPEN_DRAIN:
+ /* Set open drain mode */
+ ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0);
+ if (ret)
+ return ret;
+ /* Enable open drain/source mode */
+ return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
+ case LINE_MODE_OPEN_SOURCE:
+ /* Set open source mode */
+ ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos));
+ if (ret)
+ return ret;
+ /* Enable open drain/source mode */
+ return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
+ case LINE_MODE_PUSH_PULL:
+ /* Disable open drain/source mode */
+ return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0);
+ default:
+ break;
+ }
+ return -ENOTSUPP;
}
static struct gpio_chip template_chip = {
@@ -91,6 +131,7 @@ static struct gpio_chip template_chip = {
.get = tc3589x_gpio_get,
.direction_output = tc3589x_gpio_direction_output,
.set = tc3589x_gpio_set,
+ .set_single_ended = tc3589x_gpio_single_ended,
.can_sleep = true,
};
@@ -100,7 +141,7 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
+ int mask = BIT(offset % 8);
if (type == IRQ_TYPE_EDGE_BOTH) {
tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
@@ -165,7 +206,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
+ int mask = BIT(offset % 8);
tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
}
@@ -176,7 +217,7 @@ static void tc3589x_gpio_irq_unmask(struct irq_data *d)
struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
int offset = d->hwirq;
int regoffset = offset / 8;
- int mask = 1 << (offset % 8);
+ int mask = BIT(offset % 8);
tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
}
@@ -311,13 +352,3 @@ static int __init tc3589x_gpio_init(void)
return platform_driver_register(&tc3589x_gpio_driver);
}
subsys_initcall(tc3589x_gpio_init);
-
-static void __exit tc3589x_gpio_exit(void)
-{
- platform_driver_unregister(&tc3589x_gpio_driver);
-}
-module_exit(tc3589x_gpio_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("TC3589x GPIO driver");
-MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 790bb111b2cb..ec891a27952f 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -35,24 +35,27 @@
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
#define GPIO_BIT(x) ((x) & 0x7)
-#define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \
+#define GPIO_REG(tgi, x) (GPIO_BANK(x) * tgi->soc->bank_stride + \
GPIO_PORT(x) * 4)
-#define GPIO_CNF(x) (GPIO_REG(x) + 0x00)
-#define GPIO_OE(x) (GPIO_REG(x) + 0x10)
-#define GPIO_OUT(x) (GPIO_REG(x) + 0X20)
-#define GPIO_IN(x) (GPIO_REG(x) + 0x30)
-#define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40)
-#define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50)
-#define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60)
-#define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70)
-
-#define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00)
-#define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10)
-#define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20)
-#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40)
-#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50)
-#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60)
+#define GPIO_CNF(t, x) (GPIO_REG(t, x) + 0x00)
+#define GPIO_OE(t, x) (GPIO_REG(t, x) + 0x10)
+#define GPIO_OUT(t, x) (GPIO_REG(t, x) + 0X20)
+#define GPIO_IN(t, x) (GPIO_REG(t, x) + 0x30)
+#define GPIO_INT_STA(t, x) (GPIO_REG(t, x) + 0x40)
+#define GPIO_INT_ENB(t, x) (GPIO_REG(t, x) + 0x50)
+#define GPIO_INT_LVL(t, x) (GPIO_REG(t, x) + 0x60)
+#define GPIO_INT_CLR(t, x) (GPIO_REG(t, x) + 0x70)
+#define GPIO_DBC_CNT(t, x) (GPIO_REG(t, x) + 0xF0)
+
+
+#define GPIO_MSK_CNF(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x00)
+#define GPIO_MSK_OE(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x10)
+#define GPIO_MSK_OUT(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0X20)
+#define GPIO_MSK_DBC_EN(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x30)
+#define GPIO_MSK_INT_STA(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x40)
+#define GPIO_MSK_INT_ENB(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x50)
+#define GPIO_MSK_INT_LVL(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x60)
#define GPIO_INT_LVL_MASK 0x010101
#define GPIO_INT_LVL_EDGE_RISING 0x000101
@@ -61,10 +64,13 @@
#define GPIO_INT_LVL_LEVEL_HIGH 0x000001
#define GPIO_INT_LVL_LEVEL_LOW 0x000000
+struct tegra_gpio_info;
+
struct tegra_gpio_bank {
int bank;
int irq;
spinlock_t lvl_lock[4];
+ spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */
#ifdef CONFIG_PM_SLEEP
u32 cnf[4];
u32 out[4];
@@ -72,25 +78,39 @@ struct tegra_gpio_bank {
u32 int_enb[4];
u32 int_lvl[4];
u32 wake_enb[4];
+ u32 dbc_enb[4];
#endif
+ u32 dbc_cnt[4];
+ struct tegra_gpio_info *tgi;
};
-static struct device *dev;
-static struct irq_domain *irq_domain;
-static void __iomem *regs;
-static u32 tegra_gpio_bank_count;
-static u32 tegra_gpio_bank_stride;
-static u32 tegra_gpio_upper_offset;
-static struct tegra_gpio_bank *tegra_gpio_banks;
+struct tegra_gpio_soc_config {
+ bool debounce_supported;
+ u32 bank_stride;
+ u32 upper_offset;
+};
+
+struct tegra_gpio_info {
+ struct device *dev;
+ void __iomem *regs;
+ struct irq_domain *irq_domain;
+ struct tegra_gpio_bank *bank_info;
+ const struct tegra_gpio_soc_config *soc;
+ struct gpio_chip gc;
+ struct irq_chip ic;
+ struct lock_class_key lock_class;
+ u32 bank_count;
+};
-static inline void tegra_gpio_writel(u32 val, u32 reg)
+static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi,
+ u32 val, u32 reg)
{
- __raw_writel(val, regs + reg);
+ __raw_writel(val, tgi->regs + reg);
}
-static inline u32 tegra_gpio_readl(u32 reg)
+static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg)
{
- return __raw_readl(regs + reg);
+ return __raw_readl(tgi->regs + reg);
}
static int tegra_gpio_compose(int bank, int port, int bit)
@@ -98,24 +118,25 @@ static int tegra_gpio_compose(int bank, int port, int bit)
return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7);
}
-static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
+static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg,
+ int gpio, int value)
{
u32 val;
val = 0x100 << GPIO_BIT(gpio);
if (value)
val |= 1 << GPIO_BIT(gpio);
- tegra_gpio_writel(val, reg);
+ tegra_gpio_writel(tgi, val, reg);
}
-static void tegra_gpio_enable(int gpio)
+static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio)
{
- tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
+ tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 1);
}
-static void tegra_gpio_disable(int gpio)
+static void tegra_gpio_disable(struct tegra_gpio_info *tgi, int gpio)
{
- tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
+ tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 0);
}
static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -125,83 +146,138 @@ static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
{
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
pinctrl_free_gpio(offset);
- tegra_gpio_disable(offset);
+ tegra_gpio_disable(tgi, offset);
}
static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, 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)
{
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+ int bval = BIT(GPIO_BIT(offset));
+
/* If gpio is in output mode then read from the out value */
- if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1)
- return (tegra_gpio_readl(GPIO_OUT(offset)) >>
- GPIO_BIT(offset)) & 0x1;
+ if (tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)) & bval)
+ return !!(tegra_gpio_readl(tgi, GPIO_OUT(tgi, offset)) & bval);
- return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
+ return !!(tegra_gpio_readl(tgi, GPIO_IN(tgi, offset)) & bval);
}
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
- tegra_gpio_enable(offset);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+ tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
+ tegra_gpio_enable(tgi, offset);
return 0;
}
static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
tegra_gpio_set(chip, offset, value);
- tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
- tegra_gpio_enable(offset);
+ tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
+ tegra_gpio_enable(tgi, offset);
return 0;
}
-static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+static int tegra_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
{
- return irq_find_mapping(irq_domain, offset);
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+ u32 pin_mask = BIT(GPIO_BIT(offset));
+ u32 cnf, oe;
+
+ cnf = tegra_gpio_readl(tgi, GPIO_CNF(tgi, offset));
+ if (!(cnf & pin_mask))
+ return -EINVAL;
+
+ oe = tegra_gpio_readl(tgi, GPIO_OE(tgi, offset));
+
+ return (oe & pin_mask) ? GPIOF_DIR_OUT : GPIOF_DIR_IN;
}
-static struct gpio_chip tegra_gpio_chip = {
- .label = "tegra-gpio",
- .request = tegra_gpio_request,
- .free = tegra_gpio_free,
- .direction_input = tegra_gpio_direction_input,
- .get = tegra_gpio_get,
- .direction_output = tegra_gpio_direction_output,
- .set = tegra_gpio_set,
- .to_irq = tegra_gpio_to_irq,
- .base = 0,
-};
+static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
+ unsigned int debounce)
+{
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+ 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;
+
+ if (!debounce_ms) {
+ tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset),
+ offset, 0);
+ return 0;
+ }
+
+ debounce_ms = min(debounce_ms, 255U);
+ port = GPIO_PORT(offset);
+
+ /* There is only one debounce count register per port and hence
+ * set the maximum of current and requested debounce time.
+ */
+ spin_lock_irqsave(&bank->dbc_lock[port], flags);
+ if (bank->dbc_cnt[port] < debounce_ms) {
+ tegra_gpio_writel(tgi, debounce_ms, GPIO_DBC_CNT(tgi, offset));
+ bank->dbc_cnt[port] = debounce_ms;
+ }
+ spin_unlock_irqrestore(&bank->dbc_lock[port], flags);
+
+ tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), offset, 1);
+
+ return 0;
+}
+
+static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+ return irq_find_mapping(tgi->irq_domain, offset);
+}
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;
- tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
+ tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
}
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;
- tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
+ tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
}
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;
- tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
+ 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;
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;
@@ -233,23 +309,24 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return -EINVAL;
}
- ret = gpiochip_lock_as_irq(&tegra_gpio_chip, gpio);
+ ret = gpiochip_lock_as_irq(&tgi->gc, gpio);
if (ret) {
- dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio);
+ dev_err(tgi->dev,
+ "unable to lock Tegra GPIO %d as IRQ\n", gpio);
return ret;
}
spin_lock_irqsave(&bank->lvl_lock[port], flags);
- val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+ val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
val |= lvl_type << GPIO_BIT(gpio);
- tegra_gpio_writel(val, GPIO_INT_LVL(gpio));
+ tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio));
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
- tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
- tegra_gpio_enable(gpio);
+ tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0);
+ tegra_gpio_enable(tgi, gpio);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
irq_set_handler_locked(d, handle_level_irq);
@@ -261,9 +338,11 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
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;
- gpiochip_unlock_as_irq(&tegra_gpio_chip, gpio);
+ gpiochip_unlock_as_irq(&tgi->gc, gpio);
}
static void tegra_gpio_irq_handler(struct irq_desc *desc)
@@ -271,19 +350,24 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
int port;
int pin;
int unmasked = 0;
+ int gpio;
+ u32 lvl;
+ unsigned long sta;
struct irq_chip *chip = irq_desc_get_chip(desc);
struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc);
+ struct tegra_gpio_info *tgi = bank->tgi;
chained_irq_enter(chip, desc);
for (port = 0; port < 4; port++) {
- int gpio = tegra_gpio_compose(bank->bank, port, 0);
- unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) &
- tegra_gpio_readl(GPIO_INT_ENB(gpio));
- u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+ gpio = tegra_gpio_compose(bank->bank, port, 0);
+ sta = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)) &
+ tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
+ lvl = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
for_each_set_bit(pin, &sta, 8) {
- tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
+ tegra_gpio_writel(tgi, 1 << pin,
+ GPIO_INT_CLR(tgi, gpio));
/* if gpio is edge triggered, clear condition
* before executing the handler so that we don't
@@ -306,22 +390,37 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
#ifdef CONFIG_PM_SLEEP
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;
local_irq_save(flags);
- for (b = 0; b < tegra_gpio_bank_count; b++) {
- struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+ 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);
- tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio));
- tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio));
- tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio));
- tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
- tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
+ tegra_gpio_writel(tgi, bank->cnf[p],
+ GPIO_CNF(tgi, gpio));
+
+ if (tgi->soc->debounce_supported) {
+ tegra_gpio_writel(tgi, bank->dbc_cnt[p],
+ GPIO_DBC_CNT(tgi, gpio));
+ tegra_gpio_writel(tgi, bank->dbc_enb[p],
+ GPIO_MSK_DBC_EN(tgi, gpio));
+ }
+
+ tegra_gpio_writel(tgi, bank->out[p],
+ GPIO_OUT(tgi, gpio));
+ tegra_gpio_writel(tgi, bank->oe[p],
+ GPIO_OE(tgi, gpio));
+ tegra_gpio_writel(tgi, bank->int_lvl[p],
+ GPIO_INT_LVL(tgi, gpio));
+ tegra_gpio_writel(tgi, bank->int_enb[p],
+ GPIO_INT_ENB(tgi, gpio));
}
}
@@ -331,25 +430,39 @@ static int tegra_gpio_resume(struct device *dev)
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;
local_irq_save(flags);
- for (b = 0; b < tegra_gpio_bank_count; b++) {
- struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+ 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);
- bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio));
- bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio));
- bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
- bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
- bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+ bank->cnf[p] = tegra_gpio_readl(tgi,
+ GPIO_CNF(tgi, gpio));
+ bank->out[p] = tegra_gpio_readl(tgi,
+ GPIO_OUT(tgi, gpio));
+ bank->oe[p] = tegra_gpio_readl(tgi,
+ GPIO_OE(tgi, gpio));
+ if (tgi->soc->debounce_supported) {
+ bank->dbc_enb[p] = tegra_gpio_readl(tgi,
+ GPIO_MSK_DBC_EN(tgi, gpio));
+ bank->dbc_enb[p] = (bank->dbc_enb[p] << 8) |
+ bank->dbc_enb[p];
+ }
+
+ bank->int_enb[p] = tegra_gpio_readl(tgi,
+ GPIO_INT_ENB(tgi, gpio));
+ bank->int_lvl[p] = tegra_gpio_readl(tgi,
+ GPIO_INT_LVL(tgi, gpio));
/* Enable gpio irq for wake up source */
- tegra_gpio_writel(bank->wake_enb[p],
- GPIO_INT_ENB(gpio));
+ tegra_gpio_writel(tgi, bank->wake_enb[p],
+ GPIO_INT_ENB(tgi, gpio));
}
}
local_irq_restore(flags);
@@ -382,22 +495,23 @@ 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;
- for (i = 0; i < tegra_gpio_bank_count; i++) {
+ for (i = 0; i < tgi->bank_count; i++) {
for (j = 0; j < 4; j++) {
int gpio = tegra_gpio_compose(i, j, 0);
seq_printf(s,
"%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
i, j,
- tegra_gpio_readl(GPIO_CNF(gpio)),
- tegra_gpio_readl(GPIO_OE(gpio)),
- tegra_gpio_readl(GPIO_OUT(gpio)),
- tegra_gpio_readl(GPIO_IN(gpio)),
- tegra_gpio_readl(GPIO_INT_STA(gpio)),
- tegra_gpio_readl(GPIO_INT_ENB(gpio)),
- tegra_gpio_readl(GPIO_INT_LVL(gpio)));
+ tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_OE(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_OUT(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_IN(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio)),
+ tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)));
}
}
return 0;
@@ -405,7 +519,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
static int dbg_gpio_open(struct inode *inode, struct file *file)
{
- return single_open(file, dbg_gpio_show, &inode->i_private);
+ return single_open(file, dbg_gpio_show, inode->i_private);
}
static const struct file_operations debug_fops = {
@@ -415,66 +529,28 @@ static const struct file_operations debug_fops = {
.release = single_release,
};
-static void tegra_gpio_debuginit(void)
+static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
{
(void) debugfs_create_file("tegra_gpio", S_IRUGO,
- NULL, NULL, &debug_fops);
+ NULL, tgi, &debug_fops);
}
#else
-static inline void tegra_gpio_debuginit(void)
+static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
{
}
#endif
-static struct irq_chip tegra_gpio_irq_chip = {
- .name = "GPIO",
- .irq_ack = tegra_gpio_irq_ack,
- .irq_mask = tegra_gpio_irq_mask,
- .irq_unmask = tegra_gpio_irq_unmask,
- .irq_set_type = tegra_gpio_irq_set_type,
- .irq_shutdown = tegra_gpio_irq_shutdown,
-#ifdef CONFIG_PM_SLEEP
- .irq_set_wake = tegra_gpio_irq_set_wake,
-#endif
-};
-
static const struct dev_pm_ops tegra_gpio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
};
-struct tegra_gpio_soc_config {
- u32 bank_stride;
- u32 upper_offset;
-};
-
-static struct tegra_gpio_soc_config tegra20_gpio_config = {
- .bank_stride = 0x80,
- .upper_offset = 0x800,
-};
-
-static struct tegra_gpio_soc_config tegra30_gpio_config = {
- .bank_stride = 0x100,
- .upper_offset = 0x80,
-};
-
-static const struct of_device_id tegra_gpio_of_match[] = {
- { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
- { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
- { },
-};
-
-/* This lock class tells lockdep that GPIO irqs are in a different
- * category than their parents, so it won't report false recursion.
- */
-static struct lock_class_key gpio_lock_class;
-
static int tegra_gpio_probe(struct platform_device *pdev)
{
- const struct of_device_id *match;
- struct tegra_gpio_soc_config *config;
+ const struct tegra_gpio_soc_config *config;
+ struct tegra_gpio_info *tgi;
struct resource *res;
struct tegra_gpio_bank *bank;
int ret;
@@ -482,102 +558,153 @@ static int tegra_gpio_probe(struct platform_device *pdev)
int i;
int j;
- dev = &pdev->dev;
-
- match = of_match_device(tegra_gpio_of_match, &pdev->dev);
- if (!match) {
+ config = of_device_get_match_data(&pdev->dev);
+ if (!config) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
- config = (struct tegra_gpio_soc_config *)match->data;
- tegra_gpio_bank_stride = config->bank_stride;
- tegra_gpio_upper_offset = config->upper_offset;
+ tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
+ if (!tgi)
+ return -ENODEV;
+
+ tgi->soc = config;
+ tgi->dev = &pdev->dev;
for (;;) {
- res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ,
+ tgi->bank_count);
if (!res)
break;
- tegra_gpio_bank_count++;
+ tgi->bank_count++;
}
- if (!tegra_gpio_bank_count) {
+ if (!tgi->bank_count) {
dev_err(&pdev->dev, "Missing IRQ resource\n");
return -ENODEV;
}
- tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32;
+ tgi->gc.label = "tegra-gpio";
+ tgi->gc.request = tegra_gpio_request;
+ tgi->gc.free = tegra_gpio_free;
+ tgi->gc.direction_input = tegra_gpio_direction_input;
+ tgi->gc.get = tegra_gpio_get;
+ tgi->gc.direction_output = tegra_gpio_direction_output;
+ tgi->gc.set = tegra_gpio_set;
+ tgi->gc.get_direction = tegra_gpio_get_direction;
+ tgi->gc.to_irq = tegra_gpio_to_irq;
+ tgi->gc.base = 0;
+ tgi->gc.ngpio = tgi->bank_count * 32;
+ tgi->gc.parent = &pdev->dev;
+ tgi->gc.of_node = pdev->dev.of_node;
+
+ tgi->ic.name = "GPIO";
+ tgi->ic.irq_ack = tegra_gpio_irq_ack;
+ tgi->ic.irq_mask = tegra_gpio_irq_mask;
+ tgi->ic.irq_unmask = tegra_gpio_irq_unmask;
+ tgi->ic.irq_set_type = tegra_gpio_irq_set_type;
+ tgi->ic.irq_shutdown = tegra_gpio_irq_shutdown;
+#ifdef CONFIG_PM_SLEEP
+ tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake;
+#endif
+
+ platform_set_drvdata(pdev, tgi);
+
+ if (config->debounce_supported)
+ tgi->gc.set_debounce = tegra_gpio_set_debounce;
- tegra_gpio_banks = devm_kzalloc(&pdev->dev,
- tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
- GFP_KERNEL);
- if (!tegra_gpio_banks)
+ tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
+ sizeof(*tgi->bank_info), GFP_KERNEL);
+ if (!tgi->bank_info)
return -ENODEV;
- irq_domain = irq_domain_add_linear(pdev->dev.of_node,
- tegra_gpio_chip.ngpio,
- &irq_domain_simple_ops, NULL);
- if (!irq_domain)
+ tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
+ tgi->gc.ngpio,
+ &irq_domain_simple_ops, NULL);
+ if (!tgi->irq_domain)
return -ENODEV;
- for (i = 0; i < tegra_gpio_bank_count; i++) {
+ 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;
}
- bank = &tegra_gpio_banks[i];
+ bank = &tgi->bank_info[i];
bank->bank = i;
bank->irq = res->start;
+ bank->tgi = tgi;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
+ tgi->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tgi->regs))
+ return PTR_ERR(tgi->regs);
- for (i = 0; i < tegra_gpio_bank_count; i++) {
+ 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(0x00, GPIO_INT_ENB(gpio));
+ tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
}
}
- tegra_gpio_chip.of_node = pdev->dev.of_node;
-
- ret = devm_gpiochip_add_data(&pdev->dev, &tegra_gpio_chip, NULL);
+ ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
if (ret < 0) {
- irq_domain_remove(irq_domain);
+ irq_domain_remove(tgi->irq_domain);
return ret;
}
- for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
- int irq = irq_create_mapping(irq_domain, gpio);
+ for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) {
+ int irq = irq_create_mapping(tgi->irq_domain, gpio);
/* No validity check; all Tegra GPIOs are valid IRQs */
- bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
+ bank = &tgi->bank_info[GPIO_BANK(gpio)];
- irq_set_lockdep_class(irq, &gpio_lock_class);
+ irq_set_lockdep_class(irq, &tgi->lock_class);
irq_set_chip_data(irq, bank);
- irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip,
- handle_simple_irq);
+ irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
}
- for (i = 0; i < tegra_gpio_bank_count; i++) {
- bank = &tegra_gpio_banks[i];
+ for (i = 0; i < tgi->bank_count; i++) {
+ bank = &tgi->bank_info[i];
irq_set_chained_handler_and_data(bank->irq,
tegra_gpio_irq_handler, bank);
- for (j = 0; j < 4; j++)
+ for (j = 0; j < 4; j++) {
spin_lock_init(&bank->lvl_lock[j]);
+ spin_lock_init(&bank->dbc_lock[j]);
+ }
}
- tegra_gpio_debuginit();
+ tegra_gpio_debuginit(tgi);
return 0;
}
+static const struct tegra_gpio_soc_config tegra20_gpio_config = {
+ .bank_stride = 0x80,
+ .upper_offset = 0x800,
+};
+
+static const struct tegra_gpio_soc_config tegra30_gpio_config = {
+ .bank_stride = 0x100,
+ .upper_offset = 0x80,
+};
+
+static const struct tegra_gpio_soc_config tegra210_gpio_config = {
+ .debounce_supported = true,
+ .bank_stride = 0x100,
+ .upper_offset = 0x80,
+};
+
+static const struct of_device_id tegra_gpio_of_match[] = {
+ { .compatible = "nvidia,tegra210-gpio", .data = &tegra210_gpio_config },
+ { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
+ { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
+ { },
+};
+
static struct platform_driver tegra_gpio_driver = {
.driver = {
.name = "tegra-gpio",
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 85ed608c2b27..181f86ce00cd 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -1,5 +1,6 @@
/*
* Timberdale FPGA GPIO driver
+ * Author: Mocean Laboratories
* Copyright (c) 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +21,7 @@
* Timberdale FPGA GPIO
*/
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
@@ -290,40 +291,14 @@ static int timbgpio_probe(struct platform_device *pdev)
return 0;
}
-static int timbgpio_remove(struct platform_device *pdev)
-{
- struct timbgpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct timbgpio *tgpio = platform_get_drvdata(pdev);
- int irq = platform_get_irq(pdev, 0);
-
- if (irq >= 0 && tgpio->irq_base > 0) {
- int i;
- for (i = 0; i < pdata->nr_pins; i++) {
- irq_set_chip(tgpio->irq_base + i, NULL);
- irq_set_chip_data(tgpio->irq_base + i, NULL);
- }
-
- irq_set_handler(irq, NULL);
- irq_set_handler_data(irq, NULL);
- }
-
- return 0;
-}
-
static struct platform_driver timbgpio_platform_driver = {
.driver = {
- .name = DRIVER_NAME,
+ .name = DRIVER_NAME,
+ .suppress_bind_attrs = true,
},
.probe = timbgpio_probe,
- .remove = timbgpio_remove,
};
/*--------------------------------------------------------------------------*/
-module_platform_driver(timbgpio_platform_driver);
-
-MODULE_DESCRIPTION("Timberdale GPIO driver");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Mocean Laboratories");
-MODULE_ALIAS("platform:"DRIVER_NAME);
-
+builtin_platform_driver(timbgpio_platform_driver);
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index 9f020aa4b067..cace79c1b70a 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -57,39 +57,34 @@ static int tpic2810_direction_output(struct gpio_chip *chip,
return 0;
}
-static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value)
+static void tpic2810_set_mask_bits(struct gpio_chip *chip, u8 mask, u8 bits)
{
struct tpic2810 *gpio = gpiochip_get_data(chip);
+ u8 buffer;
+ int err;
mutex_lock(&gpio->lock);
- if (value)
- gpio->buffer |= BIT(offset);
- else
- gpio->buffer &= ~BIT(offset);
+ buffer = gpio->buffer & ~mask;
+ buffer |= (mask & bits);
- i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND,
- gpio->buffer);
+ err = i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND,
+ buffer);
+ if (!err)
+ gpio->buffer = buffer;
mutex_unlock(&gpio->lock);
}
+static void tpic2810_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ tpic2810_set_mask_bits(chip, BIT(offset), value ? BIT(offset) : 0);
+}
+
static void tpic2810_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
- struct tpic2810 *gpio = gpiochip_get_data(chip);
-
- mutex_lock(&gpio->lock);
-
- /* clear bits under mask */
- gpio->buffer &= ~(*mask);
- /* set bits under mask */
- gpio->buffer |= ((*mask) & (*bits));
-
- i2c_smbus_write_byte_data(gpio->client, TPIC2810_WS_COMMAND,
- gpio->buffer);
-
- mutex_unlock(&gpio->lock);
+ tpic2810_set_mask_bits(chip, *mask, *bits);
}
static struct gpio_chip template_chip = {
diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c
index 313c0e484607..0eaeac8de9de 100644
--- a/drivers/gpio/gpio-tps65218.c
+++ b/drivers/gpio/gpio-tps65218.c
@@ -101,16 +101,6 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
break;
case 1:
- /* GP02 is push-pull by default, can be set as open drain. */
- if (gpiochip_line_is_open_drain(gc, offset)) {
- ret = tps65218_clear_bits(tps65218,
- TPS65218_REG_CONFIG1,
- TPS65218_CONFIG1_GPO2_BUF,
- TPS65218_PROTECT_L1);
- if (ret)
- return ret;
- }
-
/* Setup GPO2 */
ret = tps65218_clear_bits(tps65218, TPS65218_REG_CONFIG1,
TPS65218_CONFIG1_IO1_SEL,
@@ -148,6 +138,40 @@ static int tps65218_gpio_request(struct gpio_chip *gc, unsigned offset)
return 0;
}
+static int tps65218_gpio_set_single_ended(struct gpio_chip *gc,
+ unsigned offset,
+ enum single_ended_mode mode)
+{
+ struct tps65218_gpio *tps65218_gpio = gpiochip_get_data(gc);
+ struct tps65218 *tps65218 = tps65218_gpio->tps65218;
+
+ switch (offset) {
+ case 0:
+ case 2:
+ /* GPO1 is hardwired to be open drain */
+ if (mode == LINE_MODE_OPEN_DRAIN)
+ return 0;
+ return -ENOTSUPP;
+ case 1:
+ /* GPO2 is push-pull by default, can be set as open drain. */
+ if (mode == LINE_MODE_OPEN_DRAIN)
+ return tps65218_clear_bits(tps65218,
+ TPS65218_REG_CONFIG1,
+ TPS65218_CONFIG1_GPO2_BUF,
+ TPS65218_PROTECT_L1);
+ if (mode == LINE_MODE_PUSH_PULL)
+ return tps65218_set_bits(tps65218,
+ TPS65218_REG_CONFIG1,
+ TPS65218_CONFIG1_GPO2_BUF,
+ TPS65218_CONFIG1_GPO2_BUF,
+ TPS65218_PROTECT_L1);
+ return -ENOTSUPP;
+ default:
+ break;
+ }
+ return -ENOTSUPP;
+}
+
static struct gpio_chip template_chip = {
.label = "gpio-tps65218",
.owner = THIS_MODULE,
@@ -156,6 +180,7 @@ static struct gpio_chip template_chip = {
.direction_input = tps65218_gpio_input,
.get = tps65218_gpio_get,
.set = tps65218_gpio_set,
+ .set_single_ended = tps65218_gpio_set_single_ended,
.can_sleep = true,
.ngpio = 3,
.base = -1,
diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c
index c88bdc8ee2c9..6b15e68a314f 100644
--- a/drivers/gpio/gpio-tps6586x.c
+++ b/drivers/gpio/gpio-tps6586x.c
@@ -24,7 +24,7 @@
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/mfd/tps6586x.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -140,14 +140,3 @@ static int __init tps6586x_gpio_init(void)
return platform_driver_register(&tps6586x_gpio_driver);
}
subsys_initcall(tps6586x_gpio_init);
-
-static void __exit tps6586x_gpio_exit(void)
-{
- platform_driver_unregister(&tps6586x_gpio_driver);
-}
-module_exit(tps6586x_gpio_exit);
-
-MODULE_ALIAS("platform:tps6586x-gpio");
-MODULE_DESCRIPTION("GPIO interface for TPS6586X PMIC");
-MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
index cdbd7c740043..0ae6a5a54ea8 100644
--- a/drivers/gpio/gpio-tps65910.c
+++ b/drivers/gpio/gpio-tps65910.c
@@ -4,7 +4,7 @@
* Copyright 2010 Texas Instruments Inc.
*
* Author: Graeme Gregory <gg@slimlogic.co.uk>
- * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
*
* 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
@@ -14,7 +14,7 @@
*/
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
@@ -193,15 +193,3 @@ static int __init tps65910_gpio_init(void)
return platform_driver_register(&tps65910_gpio_driver);
}
subsys_initcall(tps65910_gpio_init);
-
-static void __exit tps65910_gpio_exit(void)
-{
- platform_driver_unregister(&tps65910_gpio_driver);
-}
-module_exit(tps65910_gpio_exit);
-
-MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
-MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>");
-MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:tps65910-gpio");
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 8cdb9f7ec7e0..4e450121129b 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -186,6 +186,28 @@ static int vx855gpio_direction_output(struct gpio_chip *gpio,
return 0;
}
+static int vx855gpio_set_single_ended(struct gpio_chip *gpio,
+ unsigned int nr,
+ enum single_ended_mode mode)
+{
+ /* The GPI cannot be single-ended */
+ if (nr < NR_VX855_GPI)
+ return -EINVAL;
+
+ /* The GPO's are push-pull */
+ if (nr < NR_VX855_GPInO) {
+ if (mode != LINE_MODE_PUSH_PULL)
+ return -ENOTSUPP;
+ return 0;
+ }
+
+ /* The GPIO's are open drain */
+ if (mode != LINE_MODE_OPEN_DRAIN)
+ return -ENOTSUPP;
+
+ return 0;
+}
+
static const char *vx855gpio_names[NR_VX855_GP] = {
"VX855_GPI0", "VX855_GPI1", "VX855_GPI2", "VX855_GPI3", "VX855_GPI4",
"VX855_GPI5", "VX855_GPI6", "VX855_GPI7", "VX855_GPI8", "VX855_GPI9",
@@ -209,6 +231,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg)
c->direction_output = vx855gpio_direction_output;
c->get = vx855gpio_get;
c->set = vx855gpio_set;
+ c->set_single_ended = vx855gpio_set_single_ended;
c->dbg_show = NULL;
c->base = 0;
c->ngpio = NR_VX855_GP;
diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c
index 18cb0f534b91..41ec7834059a 100644
--- a/drivers/gpio/gpio-wm831x.c
+++ b/drivers/gpio/gpio-wm831x.c
@@ -132,6 +132,28 @@ static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
}
+static int wm831x_set_single_ended(struct gpio_chip *chip,
+ unsigned int offset,
+ enum single_ended_mode mode)
+{
+ struct wm831x_gpio *wm831x_gpio = gpiochip_get_data(chip);
+ struct wm831x *wm831x = wm831x_gpio->wm831x;
+ int reg = WM831X_GPIO1_CONTROL + offset;
+
+ switch (mode) {
+ case LINE_MODE_OPEN_DRAIN:
+ return wm831x_set_bits(wm831x, reg,
+ WM831X_GPN_OD_MASK, WM831X_GPN_OD);
+ case LINE_MODE_PUSH_PULL:
+ return wm831x_set_bits(wm831x, reg,
+ WM831X_GPN_OD_MASK, 0);
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
#ifdef CONFIG_DEBUG_FS
static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
@@ -216,7 +238,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
pull,
powerdomain,
reg & WM831X_GPN_POL ? "" : " inverted",
- reg & WM831X_GPN_OD ? "open-drain" : "CMOS",
+ reg & WM831X_GPN_OD ? "open-drain" : "push-pull",
tristated ? " tristated" : "",
reg);
}
@@ -234,6 +256,7 @@ static struct gpio_chip template_chip = {
.set = wm831x_gpio_set,
.to_irq = wm831x_gpio_to_irq,
.set_debounce = wm831x_gpio_set_debounce,
+ .set_single_ended = wm831x_set_single_ended,
.dbg_show = wm831x_gpio_dbg_show,
.can_sleep = true,
};
diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c
index b089df99a0d0..744af388c949 100644
--- a/drivers/gpio/gpio-wm8994.c
+++ b/drivers/gpio/gpio-wm8994.c
@@ -103,6 +103,28 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
}
+static int wm8994_gpio_set_single_ended(struct gpio_chip *chip,
+ unsigned int offset,
+ enum single_ended_mode mode)
+{
+ struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
+ struct wm8994 *wm8994 = wm8994_gpio->wm8994;
+
+ switch (mode) {
+ case LINE_MODE_OPEN_DRAIN:
+ return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
+ WM8994_GPN_OP_CFG_MASK,
+ WM8994_GPN_OP_CFG);
+ case LINE_MODE_PUSH_PULL:
+ return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
+ WM8994_GPN_OP_CFG_MASK, 0);
+ default:
+ break;
+ }
+
+ return -ENOTSUPP;
+}
+
static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip);
@@ -217,7 +239,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
if (reg & WM8994_GPN_OP_CFG)
seq_printf(s, "open drain ");
else
- seq_printf(s, "CMOS ");
+ seq_printf(s, "push-pull ");
seq_printf(s, "%s (%x)\n",
wm8994_gpio_fn(reg & WM8994_GPN_FN_MASK), reg);
@@ -235,6 +257,7 @@ static struct gpio_chip template_chip = {
.get = wm8994_gpio_get,
.direction_output = wm8994_gpio_direction_out,
.set = wm8994_gpio_set,
+ .set_single_ended = wm8994_gpio_set_single_ended,
.to_irq = wm8994_gpio_to_irq,
.dbg_show = wm8994_gpio_dbg_show,
.can_sleep = true,
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index 31cbcb84cfaf..033258634b8c 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -216,23 +216,10 @@ static int xgene_gpio_sb_domain_alloc(struct irq_domain *domain,
&parent_fwspec);
}
-static void xgene_gpio_sb_domain_free(struct irq_domain *domain,
- unsigned int virq,
- unsigned int nr_irqs)
-{
- struct irq_data *d;
- unsigned int i;
-
- for (i = 0; i < nr_irqs; i++) {
- d = irq_domain_get_irq_data(domain, virq + i);
- irq_domain_reset_irq_data(d);
- }
-}
-
static const struct irq_domain_ops xgene_gpio_sb_domain_ops = {
.translate = xgene_gpio_sb_domain_translate,
.alloc = xgene_gpio_sb_domain_alloc,
- .free = xgene_gpio_sb_domain_free,
+ .free = irq_domain_free_irqs_common,
.activate = xgene_gpio_sb_domain_activate,
.deactivate = xgene_gpio_sb_domain_deactivate,
};
diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c
index 0dc916191689..40a8881c2ce8 100644
--- a/drivers/gpio/gpio-xgene.c
+++ b/drivers/gpio/gpio-xgene.c
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <linux/module.h>
+#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -85,6 +85,17 @@ static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
spin_unlock_irqrestore(&chip->lock, flags);
}
+static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct xgene_gpio *chip = gpiochip_get_data(gc);
+ unsigned long bank_offset, bit_offset;
+
+ bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
+ bit_offset = GPIO_BIT_OFFSET(offset);
+
+ return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
+}
+
static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
{
struct xgene_gpio *chip = gpiochip_get_data(gc);
@@ -189,6 +200,7 @@ static int xgene_gpio_probe(struct platform_device *pdev)
spin_lock_init(&gpio->lock);
gpio->chip.parent = &pdev->dev;
+ gpio->chip.get_direction = xgene_gpio_get_direction;
gpio->chip.direction_input = xgene_gpio_dir_in;
gpio->chip.direction_output = xgene_gpio_dir_out;
gpio->chip.get = xgene_gpio_get;
@@ -216,19 +228,21 @@ static const struct of_device_id xgene_gpio_of_match[] = {
{ .compatible = "apm,xgene-gpio", },
{},
};
-MODULE_DEVICE_TABLE(of, xgene_gpio_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_gpio_acpi_match[] = {
+ { "APMC0D14", 0 },
+ { },
+};
+#endif
static struct platform_driver xgene_gpio_driver = {
.driver = {
.name = "xgene-gpio",
.of_match_table = xgene_gpio_of_match,
+ .acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
.pm = XGENE_GPIO_PM_OPS,
},
.probe = xgene_gpio_probe,
};
-
-module_platform_driver(xgene_gpio_driver);
-
-MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
-MODULE_DESCRIPTION("APM X-Gene GPIO driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(xgene_gpio_driver);
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index aa5813d2deb1..08897dc11915 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -85,7 +85,8 @@ enum {
XLP_GPIO_VARIANT_XLP316,
XLP_GPIO_VARIANT_XLP208,
XLP_GPIO_VARIANT_XLP980,
- XLP_GPIO_VARIANT_XLP532
+ XLP_GPIO_VARIANT_XLP532,
+ GPIO_VARIANT_VULCAN
};
struct xlp_gpio_priv {
@@ -285,6 +286,10 @@ static const struct of_device_id xlp_gpio_of_ids[] = {
.compatible = "netlogic,xlp532-gpio",
.data = (void *)XLP_GPIO_VARIANT_XLP532,
},
+ {
+ .compatible = "brcm,vulcan-gpio",
+ .data = (void *)GPIO_VARIANT_VULCAN,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
@@ -347,6 +352,7 @@ static int xlp_gpio_probe(struct platform_device *pdev)
break;
case XLP_GPIO_VARIANT_XLP980:
case XLP_GPIO_VARIANT_XLP532:
+ case GPIO_VARIANT_VULCAN:
priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN;
priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV;
priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT;
@@ -354,7 +360,12 @@ static int xlp_gpio_probe(struct platform_device *pdev)
priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL;
priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00;
- ngpio = (soc_type == XLP_GPIO_VARIANT_XLP980) ? 66 : 67;
+ if (soc_type == XLP_GPIO_VARIANT_XLP980)
+ ngpio = 66;
+ else if (soc_type == XLP_GPIO_VARIANT_XLP532)
+ ngpio = 67;
+ else
+ ngpio = 70;
break;
default:
dev_err(&pdev->dev, "Unknown Processor type!\n");
@@ -377,10 +388,14 @@ static int xlp_gpio_probe(struct platform_device *pdev)
gc->get = xlp_gpio_get;
spin_lock_init(&priv->lock);
- irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
- if (irq_base < 0) {
+ /* XLP has fixed IRQ range for GPIO interrupts */
+ if (soc_type == GPIO_VARIANT_VULCAN)
+ irq_base = irq_alloc_descs(-1, 0, gc->ngpio, 0);
+ else
+ irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0);
+ if (IS_ERR_VALUE(irq_base)) {
dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
- return -ENODEV;
+ return irq_base;
}
err = gpiochip_add_data(gc, priv);
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index cda6d922be98..e23ef7b9451d 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -10,7 +10,7 @@
#include <linux/spinlock.h>
#include <linux/errno.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/of_device.h>
@@ -203,32 +203,17 @@ static int zevio_gpio_probe(struct platform_device *pdev)
return 0;
}
-static int zevio_gpio_remove(struct platform_device *pdev)
-{
- struct zevio_gpio *controller = platform_get_drvdata(pdev);
-
- of_mm_gpiochip_remove(&controller->chip);
-
- return 0;
-}
-
static const struct of_device_id zevio_gpio_of_match[] = {
{ .compatible = "lsi,zevio-gpio", },
{ },
};
-MODULE_DEVICE_TABLE(of, zevio_gpio_of_match);
-
static struct platform_driver zevio_gpio_driver = {
.driver = {
.name = "gpio-zevio",
.of_match_table = zevio_gpio_of_match,
+ .suppress_bind_attrs = true,
},
.probe = zevio_gpio_probe,
- .remove = zevio_gpio_remove,
};
-module_platform_driver(zevio_gpio_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Fabian Vogt <fabian@ritter-vogt.de>");
-MODULE_DESCRIPTION("LSI ZEVIO SoC GPIO driver");
+builtin_platform_driver(zevio_gpio_driver);
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index 47c79fa65670..93de8be0d885 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -1,4 +1,8 @@
/*
+ * ZTE ZX296702 GPIO driver
+ *
+ * Author: Jun Nie <jun.nie@linaro.org>
+ *
* Copyright (C) 2015 Linaro Ltd.
*
* This program is free software; you can redistribute it and/or modify
@@ -10,7 +14,7 @@
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/irqchip/chained_irq.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -282,7 +286,6 @@ static const struct of_device_id zx_gpio_match[] = {
},
{ },
};
-MODULE_DEVICE_TABLE(of, zx_gpio_match);
static struct platform_driver zx_gpio_driver = {
.probe = zx_gpio_probe,
@@ -291,9 +294,4 @@ static struct platform_driver zx_gpio_driver = {
.of_match_table = of_match_ptr(zx_gpio_match),
},
};
-
-module_platform_driver(zx_gpio_driver)
-
-MODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>");
-MODULE_DESCRIPTION("ZTE ZX296702 GPIO driver");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(zx_gpio_driver)
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 66d3d247d76d..75c6355b018d 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -713,7 +713,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
- return ret;
+ goto err_pm_dis;
/* report a bug if gpio chip registration fails */
ret = gpiochip_add_data(chip, gpio);
@@ -745,6 +745,8 @@ err_rm_gpiochip:
gpiochip_remove(chip);
err_pm_put:
pm_runtime_put(&pdev->dev);
+err_pm_dis:
+ pm_runtime_disable(&pdev->dev);
return ret;
}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 42a4bb7cf49a..d22dcc38179d 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -196,21 +196,68 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
}
/**
+ * of_gpiochip_set_names() - set up the names of the lines
+ * @chip: GPIO chip whose lines should be named, if possible
+ */
+static void of_gpiochip_set_names(struct gpio_chip *gc)
+{
+ struct gpio_device *gdev = gc->gpiodev;
+ struct device_node *np = gc->of_node;
+ int i;
+ int nstrings;
+
+ nstrings = of_property_count_strings(np, "gpio-line-names");
+ if (nstrings <= 0)
+ /* Lines names not present */
+ return;
+
+ /* This is normally not what you want */
+ if (gdev->ngpio != nstrings)
+ dev_info(&gdev->dev, "gpio-line-names specifies %d line "
+ "names but there are %d lines on the chip\n",
+ nstrings, gdev->ngpio);
+
+ /*
+ * Make sure to not index beyond the end of the number of descriptors
+ * of the GPIO device.
+ */
+ for (i = 0; i < gdev->ngpio; i++) {
+ const char *name;
+ int ret;
+
+ ret = of_property_read_string_index(np,
+ "gpio-line-names",
+ i,
+ &name);
+ if (ret) {
+ if (ret != -ENODATA)
+ dev_err(&gdev->dev,
+ "unable to name line %d: %d\n",
+ i, ret);
+ break;
+ }
+ gdev->descs[i].name = name;
+ }
+}
+
+/**
* of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
* @chip: gpio chip to act on
*
* This is only used by of_gpiochip_add to request/set GPIO initial
* configuration.
+ * It retures error if it fails otherwise 0 on success.
*/
-static void of_gpiochip_scan_gpios(struct gpio_chip *chip)
+static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
{
struct gpio_desc *desc = NULL;
struct device_node *np;
const char *name;
enum gpio_lookup_flags lflags;
enum gpiod_flags dflags;
+ int ret;
- for_each_child_of_node(chip->of_node, np) {
+ for_each_available_child_of_node(chip->of_node, np) {
if (!of_property_read_bool(np, "gpio-hog"))
continue;
@@ -218,9 +265,12 @@ static void of_gpiochip_scan_gpios(struct gpio_chip *chip)
if (IS_ERR(desc))
continue;
- if (gpiod_hog(desc, name, lflags, dflags))
- continue;
+ ret = gpiod_hog(desc, name, lflags, dflags);
+ if (ret < 0)
+ return ret;
}
+
+ return 0;
}
/**
@@ -440,11 +490,13 @@ int of_gpiochip_add(struct gpio_chip *chip)
if (status)
return status;
- of_node_get(chip->of_node);
+ /* If the chip defines names itself, these take precedence */
+ if (!chip->names)
+ of_gpiochip_set_names(chip);
- of_gpiochip_scan_gpios(chip);
+ of_node_get(chip->of_node);
- return 0;
+ return of_gpiochip_scan_gpios(chip);
}
void of_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index b747c76fd2b1..d407f904a31c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -622,14 +622,31 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
struct gpio_desc *desc = &gdev->descs[i];
desc->gdev = gdev;
-
- /* REVISIT: most hardware initializes GPIOs as inputs (often
- * with pullups enabled) so power usage is minimized. Linux
- * code should set the gpio direction first thing; but until
- * it does, and in case chip->get_direction is not set, we may
- * expose the wrong direction in sysfs.
+ /*
+ * REVISIT: most hardware initializes GPIOs as inputs
+ * (often with pullups enabled) so power usage is
+ * minimized. Linux code should set the gpio direction
+ * first thing; but until it does, and in case
+ * chip->get_direction is not set, we may expose the
+ * wrong direction in sysfs.
*/
- desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
+
+ if (chip->get_direction) {
+ /*
+ * If we have .get_direction, set up the initial
+ * direction flag from the hardware.
+ */
+ int dir = chip->get_direction(chip, i);
+
+ if (!dir)
+ set_bit(FLAG_IS_OUT, &desc->flags);
+ } else if (!chip->direction_input) {
+ /*
+ * If the chip lacks the .direction_input callback
+ * we logically assume all lines are outputs.
+ */
+ set_bit(FLAG_IS_OUT, &desc->flags);
+ }
}
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1547,8 +1564,8 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input);
static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
{
- struct gpio_chip *chip;
- int status = -EINVAL;
+ struct gpio_chip *gc = desc->gdev->chip;
+ int ret;
/* GPIOs used for IRQs shall not be set as output */
if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
@@ -1558,28 +1575,50 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
return -EIO;
}
- /* Open drain pin should not be driven to 1 */
- if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
- return gpiod_direction_input(desc);
-
- /* Open source pin should not be driven to 0 */
- if (!value && test_bit(FLAG_OPEN_SOURCE, &desc->flags))
- return gpiod_direction_input(desc);
+ if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
+ /* First see if we can enable open drain in hardware */
+ if (gc->set_single_ended) {
+ ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
+ LINE_MODE_OPEN_DRAIN);
+ if (!ret)
+ goto set_output_value;
+ }
+ /* Emulate open drain by not actively driving the line high */
+ if (value)
+ return gpiod_direction_input(desc);
+ }
+ else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
+ if (gc->set_single_ended) {
+ ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
+ LINE_MODE_OPEN_SOURCE);
+ if (!ret)
+ goto set_output_value;
+ }
+ /* Emulate open source by not actively driving the line low */
+ if (!value)
+ return gpiod_direction_input(desc);
+ } else {
+ /* Make sure to disable open drain/source hardware, if any */
+ if (gc->set_single_ended)
+ gc->set_single_ended(gc,
+ gpio_chip_hwgpio(desc),
+ LINE_MODE_PUSH_PULL);
+ }
- chip = desc->gdev->chip;
- if (!chip->set || !chip->direction_output) {
+set_output_value:
+ if (!gc->set || !gc->direction_output) {
gpiod_warn(desc,
"%s: missing set() or direction_output() operations\n",
__func__);
return -EIO;
}
- status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value);
- if (status == 0)
+ ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), value);
+ if (!ret)
set_bit(FLAG_IS_OUT, &desc->flags);
trace_gpio_value(desc_to_gpio(desc), 0, value);
- trace_gpio_direction(desc_to_gpio(desc), 0, status);
- return status;
+ trace_gpio_direction(desc_to_gpio(desc), 0, ret);
+ return ret;
}
/**
@@ -1841,10 +1880,10 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
}
}
-static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
- unsigned int array_size,
- struct gpio_desc **desc_array,
- int *value_array)
+void gpiod_set_array_value_complex(bool raw, bool can_sleep,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array)
{
int i = 0;
@@ -1950,8 +1989,8 @@ void gpiod_set_raw_array_value(unsigned int array_size,
{
if (!desc_array)
return;
- gpiod_set_array_value_priv(true, false, array_size, desc_array,
- value_array);
+ gpiod_set_array_value_complex(true, false, array_size, desc_array,
+ value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
@@ -1972,8 +2011,8 @@ void gpiod_set_array_value(unsigned int array_size,
{
if (!desc_array)
return;
- gpiod_set_array_value_priv(false, false, array_size, desc_array,
- value_array);
+ gpiod_set_array_value_complex(false, false, array_size, desc_array,
+ value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value);
@@ -1998,13 +2037,22 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep);
*/
int gpiod_to_irq(const struct gpio_desc *desc)
{
- struct gpio_chip *chip;
- int offset;
+ struct gpio_chip *chip;
+ int offset;
VALIDATE_DESC(desc);
chip = desc->gdev->chip;
offset = gpio_chip_hwgpio(desc);
- return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
+ if (chip->to_irq) {
+ int retirq = chip->to_irq(chip, offset);
+
+ /* Zero means NO_IRQ */
+ if (!retirq)
+ return -ENXIO;
+
+ return retirq;
+ }
+ return -ENXIO;
}
EXPORT_SYMBOL_GPL(gpiod_to_irq);
@@ -2176,8 +2224,8 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
might_sleep_if(extra_checks);
if (!desc_array)
return;
- gpiod_set_array_value_priv(true, true, array_size, desc_array,
- value_array);
+ gpiod_set_array_value_complex(true, true, array_size, desc_array,
+ value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
@@ -2199,8 +2247,8 @@ void gpiod_set_array_value_cansleep(unsigned int array_size,
might_sleep_if(extra_checks);
if (!desc_array)
return;
- gpiod_set_array_value_priv(false, true, array_size, desc_array,
- value_array);
+ gpiod_set_array_value_complex(false, true, array_size, desc_array,
+ value_array);
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
@@ -2726,15 +2774,16 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
local_desc = gpiochip_request_own_desc(chip, hwnum, name);
if (IS_ERR(local_desc)) {
- pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
- name, chip->label, hwnum);
- return PTR_ERR(local_desc);
+ status = PTR_ERR(local_desc);
+ pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
+ name, chip->label, hwnum, status);
+ return status;
}
status = gpiod_configure_flags(desc, name, dflags);
if (status < 0) {
- pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
- name, chip->label, hwnum);
+ pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n",
+ name, chip->label, hwnum, status);
gpiochip_free_own_desc(desc);
return status;
}
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index e30e5fdb1214..2d9ea5e0cab3 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -141,6 +141,10 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags);
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
+void gpiod_set_array_value_complex(bool raw, bool can_sleep,
+ unsigned int array_size,
+ struct gpio_desc **desc_array,
+ int *value_array);
extern struct spinlock gpio_lock;
extern struct list_head gpio_devices;
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 21a62d0fa764..53fe9a3fb620 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -73,7 +73,7 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
#ifdef CONFIG_GPIOLIB
static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int val;
@@ -93,7 +93,7 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
static void adp5588_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
@@ -112,7 +112,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
@@ -130,7 +130,7 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
static int adp5588_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+ struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
@@ -210,7 +210,7 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
mutex_init(&kpad->gpio_lock);
- error = gpiochip_add(&kpad->gc);
+ error = gpiochip_add_data(&kpad->gc, kpad);
if (error) {
dev_err(dev, "gpiochip_add failed, err: %d\n", error);
return error;
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index c01a1d648f9f..32d94c63dc33 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -387,7 +387,7 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
#ifdef CONFIG_GPIOLIB
static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
@@ -399,7 +399,7 @@ static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
static void adp5589_gpio_set_value(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
@@ -418,7 +418,7 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip,
static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
@@ -438,7 +438,7 @@ static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
static int adp5589_gpio_direction_output(struct gpio_chip *chip,
unsigned off, int val)
{
- struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ struct adp5589_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
int ret;
@@ -525,9 +525,9 @@ static int adp5589_gpio_add(struct adp5589_kpad *kpad)
mutex_init(&kpad->gpio_lock);
- error = gpiochip_add(&kpad->gc);
+ error = gpiochip_add_data(&kpad->gc, kpad);
if (error) {
- dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+ dev_err(dev, "gpiochip_add_data() failed, err: %d\n", error);
return error;
}
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 69d299d5dd00..e4bf1103e6f8 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -379,7 +379,7 @@ static const struct attribute_group ad7879_attr_group = {
static int ad7879_gpio_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
@@ -393,7 +393,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
static int ad7879_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int level)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
@@ -412,7 +412,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
u16 val;
mutex_lock(&ts->mutex);
@@ -425,7 +425,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static void ad7879_gpio_set_value(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct ad7879 *ts = container_of(chip, struct ad7879, gc);
+ struct ad7879 *ts = gpiochip_get_data(chip);
mutex_lock(&ts->mutex);
if (value)
@@ -456,7 +456,7 @@ static int ad7879_gpio_add(struct ad7879 *ts,
ts->gc.owner = THIS_MODULE;
ts->gc.parent = ts->dev;
- ret = gpiochip_add(&ts->gc);
+ ret = gpiochip_add_data(&ts->gc, ts);
if (ret)
dev_err(ts->dev, "failed to register gpio %d\n",
ts->gc.base);
diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index bdc5e27222c0..a24b35fc2b5b 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -219,8 +219,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
return -ENOMEM;
/* Set the properties for portA */
- pdata->properties->node = NULL;
- pdata->properties->name = "intel-quark-x1000-gpio-portA";
+ pdata->properties->fwnode = NULL;
pdata->properties->idx = 0;
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
diff --git a/drivers/pinctrl/sh-pfc/gpio.c b/drivers/pinctrl/sh-pfc/gpio.c
index a6681b8b17c3..97dff6a09ff0 100644
--- a/drivers/pinctrl/sh-pfc/gpio.c
+++ b/drivers/pinctrl/sh-pfc/gpio.c
@@ -212,7 +212,7 @@ static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset)
}
}
- return -ENOSYS;
+ return 0;
found:
return pfc->irqs[i];
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c
index 0e73fd10ba72..63b371d6ee55 100644
--- a/drivers/platform/x86/intel_pmic_gpio.c
+++ b/drivers/platform/x86/intel_pmic_gpio.c
@@ -30,7 +30,7 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <asm/intel_scu_ipc.h>
#include <linux/device.h>
#include <linux/intel_pmic_gpio.h>
@@ -174,7 +174,7 @@ static int pmic_irq_type(struct irq_data *data, unsigned type)
static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip);
+ struct pmic_gpio *pg = gpiochip_get_data(chip);
return pg->irq_base + offset;
}
@@ -279,7 +279,7 @@ static int platform_pmic_gpio_probe(struct platform_device *pdev)
mutex_init(&pg->buslock);
pg->chip.parent = dev;
- retval = gpiochip_add(&pg->chip);
+ retval = gpiochip_add_data(&pg->chip, pg);
if (retval) {
pr_err("Can not add pmic gpio chip\n");
goto err;
diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c
index 65845712571c..333eb2215a57 100644
--- a/drivers/soc/fsl/qe/gpio.c
+++ b/drivers/soc/fsl/qe/gpio.c
@@ -18,6 +18,8 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/gpio/driver.h>
+/* FIXME: needed for gpio_to_chip() get rid of this */
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/export.h>
@@ -37,15 +39,9 @@ struct qe_gpio_chip {
struct qe_pio_regs saved_regs;
};
-static inline struct qe_gpio_chip *
-to_qe_gpio_chip(struct of_mm_gpio_chip *mm_gc)
-{
- return container_of(mm_gc, struct qe_gpio_chip, mm_gc);
-}
-
static void qe_gpio_save_regs(struct of_mm_gpio_chip *mm_gc)
{
- struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(&mm_gc->gc);
struct qe_pio_regs __iomem *regs = mm_gc->regs;
qe_gc->cpdata = in_be32(&regs->cpdata);
@@ -69,7 +65,7 @@ static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
struct qe_pio_regs __iomem *regs = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (QE_PIO_PINS - 1 - gpio);
@@ -89,7 +85,7 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&qe_gc->lock, flags);
@@ -104,7 +100,7 @@ static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
- struct qe_gpio_chip *qe_gc = to_qe_gpio_chip(mm_gc);
+ struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc);
unsigned long flags;
qe_gpio_set(gc, gpio, val);
@@ -165,7 +161,7 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index)
}
mm_gc = to_of_mm_gpio_chip(gc);
- qe_gc = to_qe_gpio_chip(mm_gc);
+ qe_gc = gpiochip_get_data(gc);
spin_lock_irqsave(&qe_gc->lock, flags);
@@ -302,7 +298,7 @@ static int __init qe_add_gpiochips(void)
gc->get = qe_gpio_get;
gc->set = qe_gpio_set;
- ret = of_mm_gpiochip_add(np, mm_gc);
+ ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc);
if (ret)
goto err;
continue;
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c
index f92e266d48f8..180e027b1c8a 100644
--- a/drivers/ssb/driver_gpio.c
+++ b/drivers/ssb/driver_gpio.c
@@ -8,7 +8,7 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
@@ -22,15 +22,10 @@
* Shared
**************************************************/
-static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip)
-{
- return container_of(chip, struct ssb_bus, gpio);
-}
-
#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
if (bus->bustype == SSB_BUSTYPE_SSB)
return irq_find_mapping(bus->irq_domain, gpio);
@@ -45,7 +40,7 @@ static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
return !!ssb_chipco_gpio_in(&bus->chipco, 1 << gpio);
}
@@ -53,7 +48,7 @@ static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
}
@@ -61,7 +56,7 @@ static void ssb_gpio_chipco_set_value(struct gpio_chip *chip, unsigned gpio,
static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 0);
return 0;
@@ -70,7 +65,7 @@ static int ssb_gpio_chipco_direction_input(struct gpio_chip *chip,
static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_chipco_gpio_outen(&bus->chipco, 1 << gpio, 1 << gpio);
ssb_chipco_gpio_out(&bus->chipco, 1 << gpio, value ? 1 << gpio : 0);
@@ -79,7 +74,7 @@ static int ssb_gpio_chipco_direction_output(struct gpio_chip *chip,
static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_chipco_gpio_control(&bus->chipco, 1 << gpio, 0);
/* clear pulldown */
@@ -92,7 +87,7 @@ static int ssb_gpio_chipco_request(struct gpio_chip *chip, unsigned gpio)
static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
/* clear pullup */
ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
@@ -246,7 +241,7 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
if (err)
return err;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, bus);
if (err) {
ssb_gpio_irq_chipco_domain_exit(bus);
return err;
@@ -263,7 +258,7 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
return !!ssb_extif_gpio_in(&bus->extif, 1 << gpio);
}
@@ -271,7 +266,7 @@ static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
}
@@ -279,7 +274,7 @@ static void ssb_gpio_extif_set_value(struct gpio_chip *chip, unsigned gpio,
static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 0);
return 0;
@@ -288,7 +283,7 @@ static int ssb_gpio_extif_direction_input(struct gpio_chip *chip,
static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
unsigned gpio, int value)
{
- struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+ struct ssb_bus *bus = gpiochip_get_data(chip);
ssb_extif_gpio_outen(&bus->extif, 1 << gpio, 1 << gpio);
ssb_extif_gpio_out(&bus->extif, 1 << gpio, value ? 1 << gpio : 0);
@@ -439,7 +434,7 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus)
if (err)
return err;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, bus);
if (err) {
ssb_gpio_irq_extif_domain_exit(bus);
return err;
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index df992c3cb5ce..6d361201d98c 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -17,7 +17,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ctype.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/slab.h>
#include <linux/vme.h>
@@ -25,16 +25,11 @@
static const char driver_name[] = "pio2_gpio";
-static struct pio2_card *gpio_to_pio2_card(struct gpio_chip *chip)
-{
- return container_of(chip, struct pio2_card, gc);
-}
-
static int pio2_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
u8 reg;
int retval;
- struct pio2_card *card = gpio_to_pio2_card(chip);
+ struct pio2_card *card = gpiochip_get_data(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
@@ -71,7 +66,7 @@ static void pio2_gpio_set(struct gpio_chip *chip,
{
u8 reg;
int retval;
- struct pio2_card *card = gpio_to_pio2_card(chip);
+ struct pio2_card *card = gpiochip_get_data(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
@@ -100,7 +95,7 @@ static void pio2_gpio_set(struct gpio_chip *chip,
static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
{
int data;
- struct pio2_card *card = gpio_to_pio2_card(chip);
+ struct pio2_card *card = gpiochip_get_data(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == OUTPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
@@ -119,7 +114,7 @@ static int pio2_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
static int pio2_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
{
int data;
- struct pio2_card *card = gpio_to_pio2_card(chip);
+ struct pio2_card *card = gpiochip_get_data(chip);
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
@@ -205,7 +200,7 @@ int pio2_gpio_init(struct pio2_card *card)
card->gc.set = pio2_gpio_set;
/* This function adds a memory mapped GPIO chip */
- retval = gpiochip_add(&card->gc);
+ retval = gpiochip_add_data(&card->gc, card);
if (retval) {
dev_err(&card->vdev->dev, "Unable to register GPIO\n");
kfree(card->gc.label);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 3f98165b479c..3f6e0ab725fe 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -17,7 +17,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -1036,7 +1036,7 @@ static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
unsigned int val;
- struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
val = max310x_port_read(port, MAX310X_GPIODATA_REG);
@@ -1046,7 +1046,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
@@ -1055,7 +1055,7 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
- struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIOCFG_REG, 1 << (offset % 4), 0);
@@ -1066,7 +1066,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int max310x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+ struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
@@ -1183,7 +1183,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4;
s->gpio.can_sleep = 1;
- ret = gpiochip_add(&s->gpio);
+ ret = gpiochip_add_data(&s->gpio, s);
if (ret)
goto out_uart;
#endif
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 025a4264430e..e6393619405a 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -17,7 +17,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1104,8 +1104,7 @@ static const struct uart_ops sc16is7xx_ops = {
static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
{
unsigned int val;
- struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
- gpio);
+ struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
val = sc16is7xx_port_read(port, SC16IS7XX_IOSTATE_REG);
@@ -1115,8 +1114,7 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
- struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
- gpio);
+ struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
@@ -1126,8 +1124,7 @@ static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
- struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
- gpio);
+ struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IODIR_REG, BIT(offset), 0);
@@ -1138,8 +1135,7 @@ static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
- struct sc16is7xx_port *s = container_of(chip, struct sc16is7xx_port,
- gpio);
+ struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
@@ -1210,7 +1206,7 @@ static int sc16is7xx_probe(struct device *dev,
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr_gpio;
s->gpio.can_sleep = 1;
- ret = gpiochip_add(&s->gpio);
+ ret = gpiochip_add_data(&s->gpio, s);
if (ret)
goto out_thread;
}
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index bee976f82788..50882e09289b 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -20,6 +20,18 @@ struct gpio_device;
#ifdef CONFIG_GPIOLIB
/**
+ * enum single_ended_mode - mode for single ended operation
+ * @LINE_MODE_PUSH_PULL: normal mode for a GPIO line, drive actively high/low
+ * @LINE_MODE_OPEN_DRAIN: set line to be open drain
+ * @LINE_MODE_OPEN_SOURCE: set line to be open source
+ */
+enum single_ended_mode {
+ LINE_MODE_PUSH_PULL,
+ LINE_MODE_OPEN_DRAIN,
+ LINE_MODE_OPEN_SOURCE,
+};
+
+/**
* struct gpio_chip - abstract a GPIO controller
* @label: a functional name for the GPIO device, such as a part
* number or the name of the SoC IP-block implementing it.
@@ -38,7 +50,15 @@ struct gpio_device;
* @set: assigns output value for signal "offset"
* @set_multiple: assigns output values for multiple signals defined by "mask"
* @set_debounce: optional hook for setting debounce time for specified gpio in
- * interrupt triggered gpio chips
+ * interrupt triggered gpio chips
+ * @set_single_ended: optional hook for setting a line as open drain, open
+ * source, or non-single ended (restore from open drain/source to normal
+ * push-pull mode) this should be implemented if the hardware supports
+ * open drain or open source settings. The GPIOlib will otherwise try
+ * to emulate open drain/source by not actively driving lines high/low
+ * if a consumer request this. The driver may return -ENOTSUPP if e.g.
+ * it supports just open drain but not open source and is called
+ * with LINE_MODE_OPEN_SOURCE as mode argument.
* @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
* implementation may not sleep
* @dbg_show: optional routine to show contents in debugfs; default code
@@ -130,6 +150,9 @@ struct gpio_chip {
int (*set_debounce)(struct gpio_chip *chip,
unsigned offset,
unsigned debounce);
+ int (*set_single_ended)(struct gpio_chip *chip,
+ unsigned offset,
+ enum single_ended_mode mode);
int (*to_irq)(struct gpio_chip *chip,
unsigned offset);
diff --git a/include/linux/i2c/sx150x.h b/include/linux/i2c/sx150x.h
deleted file mode 100644
index 52baa79d69a7..000000000000
--- a/include/linux/i2c/sx150x.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Driver for the Semtech SX150x I2C GPIO Expanders
- *
- * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-#ifndef __LINUX_I2C_SX150X_H
-#define __LINUX_I2C_SX150X_H
-
-/**
- * struct sx150x_platform_data - config data for SX150x driver
- * @gpio_base: The index number of the first GPIO assigned to this
- * GPIO expander. The expander will create a block of
- * consecutively numbered gpios beginning at the given base,
- * with the size of the block depending on the model of the
- * expander chip.
- * @oscio_is_gpo: If set to true, the driver will configure OSCIO as a GPO
- * instead of as an oscillator, increasing the size of the
- * GP(I)O pool created by this expander by one. The
- * output-only GPO pin will be added at the end of the block.
- * @io_pullup_ena: A bit-mask which enables or disables the pull-up resistor
- * for each IO line in the expander. Setting the bit at
- * position n will enable the pull-up for the IO at
- * the corresponding offset. For chips with fewer than
- * 16 IO pins, high-end bits are ignored.
- * @io_pulldn_ena: A bit-mask which enables-or disables the pull-down
- * resistor for each IO line in the expander. Setting the
- * bit at position n will enable the pull-down for the IO at
- * the corresponding offset. For chips with fewer than
- * 16 IO pins, high-end bits are ignored.
- * @io_open_drain_ena: A bit-mask which enables-or disables open-drain
- * operation for each IO line in the expander. Setting the
- * bit at position n enables open-drain operation for
- * the IO at the corresponding offset. Clearing the bit
- * enables regular push-pull operation for that IO.
- * For chips with fewer than 16 IO pins, high-end bits
- * are ignored.
- * @io_polarity: A bit-mask which enables polarity inversion for each IO line
- * in the expander. Setting the bit at position n inverts
- * the polarity of that IO line, while clearing it results
- * in normal polarity. For chips with fewer than 16 IO pins,
- * high-end bits are ignored.
- * @irq_summary: The 'summary IRQ' line to which the GPIO expander's INT line
- * is connected, via which it reports interrupt events
- * across all GPIO lines. This must be a real,
- * pre-existing IRQ line.
- * Setting this value < 0 disables the irq_chip functionality
- * of the driver.
- * @irq_base: The first 'virtual IRQ' line at which our block of GPIO-based
- * IRQ lines will appear. Similarly to gpio_base, the expander
- * will create a block of irqs beginning at this number.
- * This value is ignored if irq_summary is < 0.
- * @reset_during_probe: If set to true, the driver will trigger a full
- * reset of the chip at the beginning of the probe
- * in order to place it in a known state.
- */
-struct sx150x_platform_data {
- unsigned gpio_base;
- bool oscio_is_gpo;
- u16 io_pullup_ena;
- u16 io_pulldn_ena;
- u16 io_open_drain_ena;
- u16 io_polarity;
- int irq_summary;
- unsigned irq_base;
- bool reset_during_probe;
-};
-
-#endif /* __LINUX_I2C_SX150X_H */
diff --git a/include/linux/platform_data/gpio-dwapb.h b/include/linux/platform_data/gpio-dwapb.h
index 28702c849af1..2dc7f4a8ab09 100644
--- a/include/linux/platform_data/gpio-dwapb.h
+++ b/include/linux/platform_data/gpio-dwapb.h
@@ -15,8 +15,7 @@
#define GPIO_DW_APB_H
struct dwapb_port_property {
- struct device_node *node;
- const char *name;
+ struct fwnode_handle *fwnode;
unsigned int idx;
unsigned int ngpio;
unsigned int gpio_base;
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 503c5b9dd030..d65f6f31a5b3 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1100,6 +1100,7 @@ void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq,
}
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
}
+EXPORT_SYMBOL_GPL(irq_domain_free_irqs_common);
/**
* irq_domain_free_irqs_top - Clear handler and handler data, clear irqdata and free parent
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 33e290b703df..60212266d5d1 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -4520,14 +4520,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
}
#ifdef CONFIG_GPIOLIB
-static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip)
-{
- return container_of(chip, struct rt5677_priv, gpio_chip);
-}
-
static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
switch (offset) {
case RT5677_GPIO1 ... RT5677_GPIO5:
@@ -4548,7 +4543,7 @@ static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int rt5677_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
switch (offset) {
case RT5677_GPIO1 ... RT5677_GPIO5:
@@ -4572,7 +4567,7 @@ static int rt5677_gpio_direction_out(struct gpio_chip *chip,
static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
int value, ret;
ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value);
@@ -4584,7 +4579,7 @@ static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset)
static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
switch (offset) {
case RT5677_GPIO1 ... RT5677_GPIO5:
@@ -4638,7 +4633,7 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
{
- struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
struct regmap_irq_chip_data *data = rt5677->irq_data;
int irq;
@@ -4697,7 +4692,7 @@ static void rt5677_init_gpio(struct i2c_client *i2c)
rt5677->gpio_chip.parent = &i2c->dev;
rt5677->gpio_chip.base = -1;
- ret = gpiochip_add(&rt5677->gpio_chip);
+ ret = gpiochip_add_data(&rt5677->gpio_chip, rt5677);
if (ret != 0)
dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 171a23ddd15d..512a9d25fe6f 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -17,6 +17,7 @@
#include <linux/export.h>
#include <linux/pm.h>
#include <linux/gcd.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
@@ -2236,14 +2237,9 @@ static irqreturn_t wm5100_edge_irq(int irq, void *data)
}
#ifdef CONFIG_GPIOLIB
-static inline struct wm5100_priv *gpio_to_wm5100(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm5100_priv, gpio_chip);
-}
-
static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
WM5100_GP1_LVL, !!value << WM5100_GP1_LVL_SHIFT);
@@ -2252,7 +2248,7 @@ static void wm5100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm5100_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
int val, ret;
val = (1 << WM5100_GP1_FN_SHIFT) | (!!value << WM5100_GP1_LVL_SHIFT);
@@ -2268,7 +2264,7 @@ static int wm5100_gpio_direction_out(struct gpio_chip *chip,
static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
unsigned int reg;
int ret;
@@ -2281,7 +2277,7 @@ static int wm5100_gpio_get(struct gpio_chip *chip, unsigned offset)
static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm5100_priv *wm5100 = gpio_to_wm5100(chip);
+ struct wm5100_priv *wm5100 = gpiochip_get_data(chip);
return regmap_update_bits(wm5100->regmap, WM5100_GPIO_CTRL_1 + offset,
WM5100_GP1_FN_MASK | WM5100_GP1_DIR,
@@ -2313,7 +2309,7 @@ static void wm5100_init_gpio(struct i2c_client *i2c)
else
wm5100->gpio_chip.base = -1;
- ret = gpiochip_add(&wm5100->gpio_chip);
+ ret = gpiochip_add_data(&wm5100->gpio_chip, wm5100);
if (ret != 0)
dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret);
}
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index a82b8bc2cfc0..a26ca490cf31 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -20,7 +20,7 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -1766,11 +1766,6 @@ static int wm8903_resume(struct snd_soc_codec *codec)
}
#ifdef CONFIG_GPIOLIB
-static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm8903_priv, gpio_chip);
-}
-
static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
{
if (offset >= WM8903_NUM_GPIO)
@@ -1781,7 +1776,7 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
unsigned int mask, val;
int ret;
@@ -1799,7 +1794,7 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
unsigned int reg;
regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, &reg);
@@ -1810,7 +1805,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset)
static int wm8903_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
unsigned int mask, val;
int ret;
@@ -1828,7 +1823,7 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip,
static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm8903_priv *wm8903 = gpio_to_wm8903(chip);
+ struct wm8903_priv *wm8903 = gpiochip_get_data(chip);
regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset,
WM8903_GP1_LVL_MASK,
@@ -1860,7 +1855,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903)
else
wm8903->gpio_chip.base = -1;
- ret = gpiochip_add(&wm8903->gpio_chip);
+ ret = gpiochip_add_data(&wm8903->gpio_chip, wm8903);
if (ret != 0)
dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret);
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 720a14e0687d..fc164d69a557 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -18,7 +18,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gcd.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/pm_runtime.h>
@@ -3307,14 +3307,9 @@ static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
}
#ifdef CONFIG_GPIOLIB
-static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm8962_priv, gpio_chip);
-}
-
static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
{
- struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
/* The WM8962 GPIOs aren't linearly numbered. For simplicity
* we export linear numbers and error out if the unsupported
@@ -3337,7 +3332,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
struct snd_soc_codec *codec = wm8962->codec;
snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset,
@@ -3347,7 +3342,7 @@ static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm8962_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
+ struct wm8962_priv *wm8962 = gpiochip_get_data(chip);
struct snd_soc_codec *codec = wm8962->codec;
int ret, val;
@@ -3386,7 +3381,7 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec)
else
wm8962->gpio_chip.base = -1;
- ret = gpiochip_add(&wm8962->gpio_chip);
+ ret = gpiochip_add_data(&wm8962->gpio_chip, wm8962);
if (ret != 0)
dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
}
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index f99b34f7647b..a73044251218 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/gcd.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -2139,14 +2140,9 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
}
#ifdef CONFIG_GPIOLIB
-static inline struct wm8996_priv *gpio_to_wm8996(struct gpio_chip *chip)
-{
- return container_of(chip, struct wm8996_priv, gpio_chip);
-}
-
static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+ struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
WM8996_GP1_LVL, !!value << WM8996_GP1_LVL_SHIFT);
@@ -2155,7 +2151,7 @@ static void wm8996_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
static int wm8996_gpio_direction_out(struct gpio_chip *chip,
unsigned offset, int value)
{
- struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+ struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
int val;
val = (1 << WM8996_GP1_FN_SHIFT) | (!!value << WM8996_GP1_LVL_SHIFT);
@@ -2167,7 +2163,7 @@ static int wm8996_gpio_direction_out(struct gpio_chip *chip,
static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+ struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
unsigned int reg;
int ret;
@@ -2180,7 +2176,7 @@ static int wm8996_gpio_get(struct gpio_chip *chip, unsigned offset)
static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct wm8996_priv *wm8996 = gpio_to_wm8996(chip);
+ struct wm8996_priv *wm8996 = gpiochip_get_data(chip);
return regmap_update_bits(wm8996->regmap, WM8996_GPIO_1 + offset,
WM8996_GP1_FN_MASK | WM8996_GP1_DIR,
@@ -2211,7 +2207,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996)
else
wm8996->gpio_chip.base = -1;
- ret = gpiochip_add(&wm8996->gpio_chip);
+ ret = gpiochip_add_data(&wm8996->gpio_chip, wm8996);
if (ret != 0)
dev_err(wm8996->dev, "Failed to add GPIOs: %d\n", ret);
}
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index 7e0acd83b0e6..bc4a55bb3fd9 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -59,8 +59,7 @@ static void soc_ac97_device_release(struct device *dev)
#ifdef CONFIG_GPIOLIB
static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip)
{
- struct snd_ac97_gpio_priv *gpio_priv =
- container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+ struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip);
return gpio_priv->codec;
}
@@ -98,8 +97,7 @@ static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset)
static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
- struct snd_ac97_gpio_priv *gpio_priv =
- container_of(chip, struct snd_ac97_gpio_priv, gpio_chip);
+ struct snd_ac97_gpio_priv *gpio_priv = gpiochip_get_data(chip);
struct snd_soc_codec *codec = gpio_to_codec(chip);
gpio_priv->gpios_set &= ~(1 << offset);
@@ -145,7 +143,7 @@ static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97,
gpio_priv->gpio_chip.parent = codec->dev;
gpio_priv->gpio_chip.base = -1;
- ret = gpiochip_add(&gpio_priv->gpio_chip);
+ ret = gpiochip_add_data(&gpio_priv->gpio_chip, gpio_priv);
if (ret != 0)
dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
return ret;
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile
index 4d198d5c4203..c155d6bc47a7 100644
--- a/tools/gpio/Makefile
+++ b/tools/gpio/Makefile
@@ -1,5 +1,5 @@
CC = $(CROSS_COMPILE)gcc
-CFLAGS += -Wall -g -D_GNU_SOURCE
+CFLAGS += -O2 -Wall -g -D_GNU_SOURCE
all: lsgpio
diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c
index 1124da375942..eb3f56efd215 100644
--- a/tools/gpio/lsgpio.c
+++ b/tools/gpio/lsgpio.c
@@ -147,7 +147,7 @@ void print_usage(void)
int main(int argc, char **argv)
{
- const char *device_name;
+ const char *device_name = NULL;
int ret;
int c;