summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-05 14:00:30 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-05 14:00:30 -0700
commit3f7e82379fc91102d82ed89822bd4242c83e40d5 (patch)
treef0be8a42c4de8009b4d9d37f401b5087d999a147
parent1f2dc7f5b6c1fffdb24e776b9d3529bd9414aa2c (diff)
parent74910e15ab25f95f162bc4d4a634d029186543ce (diff)
Merge tag 'gpio-v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO updates from Linus Walleij: "This is the bulk of GPIO changes for the v5.8 kernel cycle. Core changes: - A new GPIO aggregator driver has been merged: this can join a few select GPIO lines into a new aggregated GPIO chip. This can be used for security: a process can be granted access to only these lines, for example for industrial control. Another way to use this is to reexpose certain select lines to a virtual machine or container. - Warn if the gpio-line-names is too long in he DT parser core. - GPIO lines can now be looked up by line name in addition to being looked up by offset. New drivers: - A new generic regmap GPIO driver has been merged. Too many regmap drivers are starting to look like each other so we need to create some common ground and try to move drivers over to using that. - The F7188X driver now supports F81865. Driver improvements: - Large improvements to the PCA953x expander, get multiple lines and several cleanups. - Large improvements to the DesignWare DWAPB driver, and Sergey Semin has volunteered to maintain it. - PL061 can now be built as a module, this is part of a bigger effort to make the ARM platforms more modular" * tag 'gpio-v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (77 commits) gpio: pca953x: Drop unneeded ACPI_PTR() MAINTAINERS: Add gpio regmap section gpio: add a reusable generic gpio_chip using regmap gpiolib: Introduce gpiochip_irqchip_add_domain() gpio: gpiolib: Allow GPIO IRQs to lazy disable gpiolib: Separate GPIO_GET_LINEINFO_WATCH_IOCTL conditional gpio: rcar: Fix runtime PM imbalance on error gpio: pca935x: Allow IRQ support for driver built as a module gpio: pxa: Add COMPILE_TEST support dt-bindings: gpio: Add renesas,em-gio bindings MAINTAINERS: Fix file name for DesignWare GPIO DT schema gpio: dwapb: Remove unneeded has_irq member in struct dwapb_port_property gpio: dwapb: Don't use IRQ 0 as valid Linux interrupt gpio: dwapb: avoid error message for optional IRQ gpio: dwapb: Call acpi_gpiochip_free_interrupts() on GPIO chip de-registration gpio: max730x: bring gpiochip_add_data after port config MAINTAINERS: Add GPIO Aggregator section docs: gpio: Add GPIO Aggregator documentation gpio: Add GPIO Aggregator gpiolib: Add support for GPIO lookup by line name ...
-rw-r--r--Documentation/admin-guide/gpio/gpio-aggregator.rst111
-rw-r--r--Documentation/admin-guide/gpio/index.rst1
-rw-r--r--Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml70
-rw-r--r--Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml134
-rw-r--r--Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt65
-rw-r--r--Documentation/driver-api/gpio/board.rst15
-rw-r--r--MAINTAINERS16
-rw-r--r--drivers/gpio/Kconfig24
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/TODO4
-rw-r--r--drivers/gpio/gpio-aggregator.c568
-rw-r--r--drivers/gpio/gpio-dwapb.c248
-rw-r--r--drivers/gpio/gpio-f7188x.c33
-rw-r--r--drivers/gpio/gpio-ftgpio010.c2
-rw-r--r--drivers/gpio/gpio-ich.c2
-rw-r--r--drivers/gpio/gpio-max730x.c12
-rw-r--r--drivers/gpio/gpio-mb86s7x.c28
-rw-r--r--drivers/gpio/gpio-merrifield.c10
-rw-r--r--drivers/gpio/gpio-mlxbf2.c5
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c2
-rw-r--r--drivers/gpio/gpio-pca953x.c96
-rw-r--r--drivers/gpio/gpio-pch.c73
-rw-r--r--drivers/gpio/gpio-pl061.c9
-rw-r--r--drivers/gpio/gpio-rcar.c4
-rw-r--r--drivers/gpio/gpio-regmap.c349
-rw-r--r--drivers/gpio/gpio-tegra186.c1
-rw-r--r--drivers/gpio/gpio-xgene-sb.c14
-rw-r--r--drivers/gpio/gpiolib-acpi.c6
-rw-r--r--drivers/gpio/gpiolib-devprop.c5
-rw-r--r--drivers/gpio/gpiolib-of.c10
-rw-r--r--drivers/gpio/gpiolib.c165
-rw-r--r--drivers/gpio/gpiolib.h27
-rw-r--r--drivers/i2c/busses/i2c-i801.c6
-rw-r--r--drivers/mfd/intel_quark_i2c_gpio.c1
-rw-r--r--drivers/mfd/sm501.c24
-rw-r--r--include/linux/gpio/driver.h48
-rw-r--r--include/linux/gpio/machine.h17
-rw-r--r--include/linux/gpio/regmap.h86
-rw-r--r--include/linux/platform_data/gpio-dwapb.h1
-rw-r--r--tools/gpio/lsgpio.c12
40 files changed, 1859 insertions, 447 deletions
diff --git a/Documentation/admin-guide/gpio/gpio-aggregator.rst b/Documentation/admin-guide/gpio/gpio-aggregator.rst
new file mode 100644
index 000000000000..5cd1e7221756
--- /dev/null
+++ b/Documentation/admin-guide/gpio/gpio-aggregator.rst
@@ -0,0 +1,111 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+GPIO Aggregator
+===============
+
+The GPIO Aggregator provides a mechanism to aggregate GPIOs, and expose them as
+a new gpio_chip. This supports the following use cases.
+
+
+Aggregating GPIOs using Sysfs
+-----------------------------
+
+GPIO controllers are exported to userspace using /dev/gpiochip* character
+devices. Access control to these devices is provided by standard UNIX file
+system permissions, on an all-or-nothing basis: either a GPIO controller is
+accessible for a user, or it is not.
+
+The GPIO Aggregator provides access control for a set of one or more GPIOs, by
+aggregating them into a new gpio_chip, which can be assigned to a group or user
+using standard UNIX file ownership and permissions. Furthermore, this
+simplifies and hardens exporting GPIOs to a virtual machine, as the VM can just
+grab the full GPIO controller, and no longer needs to care about which GPIOs to
+grab and which not, reducing the attack surface.
+
+Aggregated GPIO controllers are instantiated and destroyed by writing to
+write-only attribute files in sysfs.
+
+ /sys/bus/platform/drivers/gpio-aggregator/
+
+ "new_device" ...
+ Userspace may ask the kernel to instantiate an aggregated GPIO
+ controller by writing a string describing the GPIOs to
+ aggregate to the "new_device" file, using the format
+
+ .. code-block:: none
+
+ [<gpioA>] [<gpiochipB> <offsets>] ...
+
+ Where:
+
+ "<gpioA>" ...
+ is a GPIO line name,
+
+ "<gpiochipB>" ...
+ is a GPIO chip label, and
+
+ "<offsets>" ...
+ is a comma-separated list of GPIO offsets and/or
+ GPIO offset ranges denoted by dashes.
+
+ Example: Instantiate a new GPIO aggregator by aggregating GPIO
+ line 19 of "e6052000.gpio" and GPIO lines 20-21 of
+ "e6050000.gpio" into a new gpio_chip:
+
+ .. code-block:: sh
+
+ $ echo 'e6052000.gpio 19 e6050000.gpio 20-21' > new_device
+
+ "delete_device" ...
+ Userspace may ask the kernel to destroy an aggregated GPIO
+ controller after use by writing its device name to the
+ "delete_device" file.
+
+ Example: Destroy the previously-created aggregated GPIO
+ controller, assumed to be "gpio-aggregator.0":
+
+ .. code-block:: sh
+
+ $ echo gpio-aggregator.0 > delete_device
+
+
+Generic GPIO Driver
+-------------------
+
+The GPIO Aggregator can also be used as a generic driver for a simple
+GPIO-operated device described in DT, without a dedicated in-kernel driver.
+This is useful in industrial control, and is not unlike e.g. spidev, which
+allows the user to communicate with an SPI device from userspace.
+
+Binding a device to the GPIO Aggregator is performed either by modifying the
+gpio-aggregator driver, or by writing to the "driver_override" file in Sysfs.
+
+Example: If "door" is a GPIO-operated device described in DT, using its own
+compatible value::
+
+ door {
+ compatible = "myvendor,mydoor";
+
+ gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>,
+ <&gpio2 20 GPIO_ACTIVE_LOW>;
+ gpio-line-names = "open", "lock";
+ };
+
+it can be bound to the GPIO Aggregator by either:
+
+1. Adding its compatible value to ``gpio_aggregator_dt_ids[]``,
+2. Binding manually using "driver_override":
+
+.. code-block:: sh
+
+ $ echo gpio-aggregator > /sys/bus/platform/devices/door/driver_override
+ $ echo door > /sys/bus/platform/drivers/gpio-aggregator/bind
+
+After that, a new gpiochip "door" has been created:
+
+.. code-block:: sh
+
+ $ gpioinfo door
+ gpiochip12 - 2 lines:
+ line 0: "open" unused input active-high
+ line 1: "lock" unused input active-high
diff --git a/Documentation/admin-guide/gpio/index.rst b/Documentation/admin-guide/gpio/index.rst
index a244ba4e87d5..ef2838638e96 100644
--- a/Documentation/admin-guide/gpio/index.rst
+++ b/Documentation/admin-guide/gpio/index.rst
@@ -7,6 +7,7 @@ gpio
.. toctree::
:maxdepth: 1
+ gpio-aggregator
sysfs
.. only:: subproject and html
diff --git a/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml b/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml
new file mode 100644
index 000000000000..8bdef812c87c
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/renesas,em-gio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas EMMA Mobile General Purpose I/O Interface
+
+maintainers:
+ - Magnus Damm <magnus.damm@gmail.com>
+
+properties:
+ compatible:
+ const: renesas,em-gio
+
+ reg:
+ items:
+ - description: First set of contiguous registers
+ - description: Second set of contiguous registers
+
+ interrupts:
+ items:
+ - description: Interrupt for the first set of 16 GPIO ports
+ - description: Interrupt for the second set of 16 GPIO ports
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+ ngpios:
+ minimum: 1
+ maximum: 32
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - gpio-controller
+ - '#gpio-cells'
+ - gpio-ranges
+ - ngpios
+ - interrupt-controller
+ - '#interrupt-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ gpio0: gpio@e0050000 {
+ compatible = "renesas,em-gio";
+ reg = <0xe0050000 0x2c>, <0xe0050040 0x20>;
+ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pfc 0 0 32>;
+ ngpios = <32>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
new file mode 100644
index 000000000000..04a3c51e1dc1
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
@@ -0,0 +1,134 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/snps,dw-apb-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare APB GPIO controller
+
+description: |
+ Synopsys DesignWare GPIO controllers have a configurable number of ports,
+ each of which are intended to be represented as child nodes with the generic
+ GPIO-controller properties as desribed in this bindings file.
+
+maintainers:
+ - Hoan Tran <hoan@os.amperecomputing.com>
+ - Serge Semin <fancer.lancer@gmail.com>
+
+properties:
+ $nodename:
+ pattern: "^gpio@[0-9a-f]+$"
+
+ compatible:
+ const: snps,dw-apb-gpio
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+ items:
+ - description: APB interface clock source
+ - description: DW GPIO debounce reference clock source
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: bus
+ - const: db
+
+ resets:
+ maxItems: 1
+
+patternProperties:
+ "^gpio-(port|controller)@[0-9a-f]+$":
+ type: object
+ properties:
+ compatible:
+ const: snps,dw-apb-gpio-port
+
+ reg:
+ maxItems: 1
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ snps,nr-gpios:
+ description: The number of GPIO pins exported by the port.
+ default: 32
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 1
+ maximum: 32
+
+ interrupts:
+ description: |
+ The interrupts to the parent controller raised when GPIOs generate
+ the interrupts. If the controller provides one combined interrupt
+ for all GPIOs, specify a single interrupt. If the controller provides
+ one interrupt for each GPIO, provide a list of interrupts that
+ correspond to each of the GPIO pins.
+ minItems: 1
+ maxItems: 32
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ required:
+ - compatible
+ - reg
+ - gpio-controller
+ - '#gpio-cells'
+
+ dependencies:
+ interrupt-controller: [ interrupts ]
+
+ additionalProperties: false
+
+additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+
+examples:
+ - |
+ gpio: gpio@20000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x20000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porta: gpio-port@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ reg = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <8>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&vic1>;
+ interrupts = <0>;
+ };
+
+ portb: gpio-port@1 {
+ compatible = "snps,dw-apb-gpio-port";
+ reg = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <8>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt b/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
deleted file mode 100644
index 839dd32ffe11..000000000000
--- a/Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-* Synopsys DesignWare APB GPIO controller
-
-Required properties:
-- compatible : Should contain "snps,dw-apb-gpio"
-- reg : Address and length of the register set for the device.
-- #address-cells : should be 1 (for addressing port subnodes).
-- #size-cells : should be 0 (port subnodes).
-
-The GPIO controller has a configurable number of ports, each of which are
-represented as child nodes with the following properties:
-
-Required properties:
-- compatible : "snps,dw-apb-gpio-port"
-- gpio-controller : Marks the device node as a gpio controller.
-- #gpio-cells : Should be two. The first cell is the pin number and
- the second cell is used to specify the gpio polarity:
- 0 = active high
- 1 = active low
-- reg : The integer port index of the port, a single cell.
-
-Optional properties:
-- interrupt-controller : The first port may be configured to be an interrupt
-controller.
-- #interrupt-cells : Specifies the number of cells needed to encode an
- interrupt. Shall be set to 2. The first cell defines the interrupt number,
- the second encodes the triger flags encoded as described in
- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-- interrupts : The interrupts to the parent controller raised when GPIOs
- generate the interrupts. If the controller provides one combined interrupt
- for all GPIOs, specify a single interrupt. If the controller provides one
- interrupt for each GPIO, provide a list of interrupts that correspond to each
- of the GPIO pins. When specifying multiple interrupts, if any are unconnected,
- use the interrupts-extended property to specify the interrupts and set the
- interrupt controller handle for unused interrupts to 0.
-- snps,nr-gpios : The number of pins in the port, a single cell.
-- resets : Reset line for the controller.
-
-Example:
-
-gpio: gpio@20000 {
- compatible = "snps,dw-apb-gpio";
- reg = <0x20000 0x1000>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- porta: gpio@0 {
- compatible = "snps,dw-apb-gpio-port";
- gpio-controller;
- #gpio-cells = <2>;
- snps,nr-gpios = <8>;
- reg = <0>;
- interrupt-controller;
- #interrupt-cells = <2>;
- interrupt-parent = <&vic1>;
- interrupts = <0>;
- };
-
- portb: gpio@1 {
- compatible = "snps,dw-apb-gpio-port";
- gpio-controller;
- #gpio-cells = <2>;
- snps,nr-gpios = <8>;
- reg = <1>;
- };
-};
diff --git a/Documentation/driver-api/gpio/board.rst b/Documentation/driver-api/gpio/board.rst
index ce91518bf9f4..191fa867826a 100644
--- a/Documentation/driver-api/gpio/board.rst
+++ b/Documentation/driver-api/gpio/board.rst
@@ -113,13 +113,15 @@ files that desire to do so need to include the following header::
GPIOs are mapped by the means of tables of lookups, containing instances of the
gpiod_lookup structure. Two macros are defined to help declaring such mappings::
- GPIO_LOOKUP(chip_label, chip_hwnum, con_id, flags)
- GPIO_LOOKUP_IDX(chip_label, chip_hwnum, con_id, idx, flags)
+ GPIO_LOOKUP(key, chip_hwnum, con_id, flags)
+ GPIO_LOOKUP_IDX(key, chip_hwnum, con_id, idx, flags)
where
- - chip_label is the label of the gpiod_chip instance providing the GPIO
- - chip_hwnum is the hardware number of the GPIO within the chip
+ - key is either the label of the gpiod_chip instance providing the GPIO, or
+ the GPIO line name
+ - chip_hwnum is the hardware number of the GPIO within the chip, or U16_MAX
+ to indicate that key is a GPIO line name
- con_id is the name of the GPIO function from the device point of view. It
can be NULL, in which case it will match any function.
- idx is the index of the GPIO within the function.
@@ -135,7 +137,10 @@ where
In the future, these flags might be extended to support more properties.
-Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
+Note that:
+ 1. GPIO line names are not guaranteed to be globally unique, so the first
+ match found will be used.
+ 2. GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0.
A lookup table can then be defined as follows, with an empty entry defining its
end. The 'dev_id' field of the table is the identifier of the device that will
diff --git a/MAINTAINERS b/MAINTAINERS
index 49955212a803..c0d5ddd655ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7283,6 +7283,13 @@ F: Documentation/firmware-guide/acpi/gpio-properties.rst
F: drivers/gpio/gpiolib-acpi.c
F: drivers/gpio/gpiolib-acpi.h
+GPIO AGGREGATOR
+M: Geert Uytterhoeven <geert+renesas@glider.be>
+L: linux-gpio@vger.kernel.org
+S: Supported
+F: Documentation/admin-guide/gpio/gpio-aggregator.rst
+F: drivers/gpio/gpio-aggregator.c
+
GPIO IR Transmitter
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
@@ -7296,6 +7303,12 @@ S: Maintained
F: drivers/gpio/gpio-mockup.c
F: tools/testing/selftests/gpio/
+GPIO REGMAP
+R: Michael Walle <michael@walle.cc>
+S: Maintained
+F: drivers/gpio/gpio-regmap.c
+F: include/linux/gpio/regmap.h
+
GPIO SUBSYSTEM
M: Linus Walleij <linus.walleij@linaro.org>
M: Bartosz Golaszewski <bgolaszewski@baylibre.com>
@@ -16368,9 +16381,10 @@ F: drivers/tty/serial/8250/8250_lpss.c
SYNOPSYS DESIGNWARE APB GPIO DRIVER
M: Hoan Tran <hoan@os.amperecomputing.com>
+M: Serge Semin <fancer.lancer@gmail.com>
L: linux-gpio@vger.kernel.org
S: Maintained
-F: Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
+F: Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml
F: drivers/gpio/gpio-dwapb.c
SYNOPSYS DESIGNWARE AXI DMAC DRIVER
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 1b96169d84f7..bcacd9c74aa8 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -73,6 +73,10 @@ config GPIO_GENERIC
depends on HAS_IOMEM # Only for IOMEM drivers
tristate
+config GPIO_REGMAP
+ depends on REGMAP
+ tristate
+
# put drivers in the right section, in alphabetical order
# This symbol is selected by both I2C and SPI expanders
@@ -422,7 +426,7 @@ config GPIO_OMAP
Say yes here to enable GPIO support for TI OMAP SoCs.
config GPIO_PL061
- bool "PrimeCell PL061 GPIO support"
+ tristate "PrimeCell PL061 GPIO support"
depends on ARM_AMBA
select IRQ_DOMAIN
select GPIOLIB_IRQCHIP
@@ -439,7 +443,7 @@ config GPIO_PMIC_EIC_SPRD
config GPIO_PXA
bool "PXA GPIO support"
- depends on ARCH_PXA || ARCH_MMP
+ depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST
help
Say yes here to support the PXA GPIO device
@@ -638,7 +642,7 @@ config GPIO_XGENE
config GPIO_XGENE_SB
tristate "APM X-Gene GPIO standby controller support"
- depends on ARCH_XGENE && OF_GPIO
+ depends on (ARCH_XGENE || COMPILE_TEST)
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
select IRQ_DOMAIN_HIERARCHY
@@ -952,7 +956,7 @@ config GPIO_PCA953X
config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x"
- depends on GPIO_PCA953X=y
+ depends on GPIO_PCA953X
select GPIOLIB_IRQCHIP
help
Say yes here to enable the pca953x to be used as an interrupt
@@ -1541,6 +1545,18 @@ config GPIO_VIPERBOARD
endmenu
+config GPIO_AGGREGATOR
+ tristate "GPIO Aggregator"
+ help
+ Say yes here to enable the GPIO Aggregator, which provides a way to
+ aggregate existing GPIO lines into a new virtual GPIO chip.
+ This can serve the following purposes:
+ - Assign permissions for a collection of GPIO lines to a user,
+ - Export a collection of GPIO lines to a virtual machine,
+ - Provide a generic driver for a GPIO-operated device in an
+ industrial control context, to be operated from userspace using
+ the GPIO chardev interface.
+
config GPIO_MOCKUP
tristate "GPIO Testing Driver"
select IRQ_SIM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b2cfc21a97f3..1e4894e0bf0f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
# Device drivers. Generally keep list sorted alphabetically
+obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
# directly supported by gpio-generic
@@ -25,6 +26,7 @@ obj-$(CONFIG_GPIO_74XX_MMIO) += gpio-74xx-mmio.o
obj-$(CONFIG_GPIO_ADNP) += gpio-adnp.o
obj-$(CONFIG_GPIO_ADP5520) += gpio-adp5520.o
obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
+obj-$(CONFIG_GPIO_AGGREGATOR) += gpio-aggregator.o
obj-$(CONFIG_GPIO_ALTERA_A10SR) += gpio-altera-a10sr.o
obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o
obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index 3a44e6ae52bd..b989c9352da2 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -99,6 +99,10 @@ similar and probe a proper driver in the gpiolib subsystem.
In some cases it makes sense to create a GPIO chip from the local driver
for a few GPIOs. Those should stay where they are.
+At the same time it makes sense to get rid of code duplication in existing or
+new coming drivers. For example, gpio-ml-ioh should be incorporated into
+gpio-pch. In similar way gpio-intel-mid into gpio-pxa.
+
Generic MMIO GPIO
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
new file mode 100644
index 000000000000..9b0adbdddbfc
--- /dev/null
+++ b/drivers/gpio/gpio-aggregator.c
@@ -0,0 +1,568 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// GPIO Aggregator
+//
+// Copyright (C) 2019-2020 Glider bv
+
+#define DRV_NAME "gpio-aggregator"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/ctype.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/idr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+
+/*
+ * GPIO Aggregator sysfs interface
+ */
+
+struct gpio_aggregator {
+ struct gpiod_lookup_table *lookups;
+ struct platform_device *pdev;
+ char args[];
+};
+
+static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */
+static DEFINE_IDR(gpio_aggregator_idr);
+
+static char *get_arg(char **args)
+{
+ char *start = *args, *end;
+
+ start = skip_spaces(start);
+ if (!*start)
+ return NULL;
+
+ if (*start == '"') {
+ /* Quoted arg */
+ end = strchr(++start, '"');
+ if (!end)
+ return ERR_PTR(-EINVAL);
+ } else {
+ /* Unquoted arg */
+ for (end = start; *end && !isspace(*end); end++) ;
+ }
+
+ if (*end)
+ *end++ = '\0';
+
+ *args = end;
+ return start;
+}
+
+static bool isrange(const char *s)
+{
+ size_t n;
+
+ if (IS_ERR_OR_NULL(s))
+ return false;
+
+ while (1) {
+ n = strspn(s, "0123456789");
+ if (!n)
+ return false;
+
+ s += n;
+
+ switch (*s++) {
+ case '\0':
+ return true;
+
+ case '-':
+ case ',':
+ break;
+
+ default:
+ return false;
+ }
+ }
+}
+
+static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
+ int hwnum, unsigned int *n)
+{
+ struct gpiod_lookup_table *lookups;
+
+ lookups = krealloc(aggr->lookups, struct_size(lookups, table, *n + 2),
+ GFP_KERNEL);
+ if (!lookups)
+ return -ENOMEM;
+
+ lookups->table[*n] =
+ (struct gpiod_lookup)GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0);
+
+ (*n)++;
+ memset(&lookups->table[*n], 0, sizeof(lookups->table[*n]));
+
+ aggr->lookups = lookups;
+ return 0;
+}
+
+static int aggr_parse(struct gpio_aggregator *aggr)
+{
+ unsigned int first_index, last_index, i, n = 0;
+ char *name, *offsets, *first, *last, *next;
+ char *args = aggr->args;
+ int error;
+
+ for (name = get_arg(&args), offsets = get_arg(&args); name;
+ offsets = get_arg(&args)) {
+ if (IS_ERR(name)) {
+ pr_err("Cannot get GPIO specifier: %pe\n", name);
+ return PTR_ERR(name);
+ }
+
+ if (!isrange(offsets)) {
+ /* Named GPIO line */
+ error = aggr_add_gpio(aggr, name, U16_MAX, &n);
+ if (error)
+ return error;
+
+ name = offsets;
+ continue;
+ }
+
+ /* GPIO chip + offset(s) */
+ for (first = offsets; *first; first = next) {
+ next = strchrnul(first, ',');
+ if (*next)
+ *next++ = '\0';
+
+ last = strchr(first, '-');
+ if (last)
+ *last++ = '\0';
+
+ if (kstrtouint(first, 10, &first_index)) {
+ pr_err("Cannot parse GPIO index %s\n", first);
+ return -EINVAL;
+ }
+
+ if (!last) {
+ last_index = first_index;
+ } else if (kstrtouint(last, 10, &last_index)) {
+ pr_err("Cannot parse GPIO index %s\n", last);
+ return -EINVAL;
+ }
+