Merge tag 'gpio-v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 07:45:05 +0000 (08:45 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 23 Oct 2018 07:45:05 +0000 (08:45 +0100)
Pull GPIO updates from Linus Walleij:
 "This is the bulk of GPIO changes for the v4.20 series:

  Core changes:

   - A patch series from Hans Verkuil to make it possible to
     enable/disable IRQs on a GPIO line at runtime and drive GPIO lines
     as output without having to put/get them from scratch.

     The irqchip callbacks have been improved so that they can use only
     the fastpatch callbacks to enable/disable irqs like any normal
     irqchip, especially the gpiod_lock_as_irq() has been improved to be
     callable in fastpath context.

     A bunch of rework had to be done to achieve this but it is a big
     win since I never liked to restrict this to slowpath. The only call
     requireing slowpath was try_module_get() and this is kept at the
     .request_resources() slowpath callback. In the GPIO CEC driver this
     is a big win sine a single line is used for both outgoing and
     incoming traffic, and this needs to use IRQs for incoming traffic
     while actively driving the line for outgoing traffic.

   - Janusz Krzysztofik improved the GPIO array API to pass a "cookie"
     (struct gpio_array) and a bitmap for setting or getting multiple
     GPIO lines at once.

     This improvement orginated in a specific need to speed up an OMAP1
     driver and has led to a much better API and real performance gains
     when the state of the array can be used to bypass a lot of checks
     and code when we want things to go really fast.

     The previous code would minimize the number of calls down to the
     driver callbacks assuming the CPU speed was orders of magnitude
     faster than the I/O latency, but this assumption was wrong on
     several platforms: what we needed to do was to profile and improve
     the speed on the hot path of the array functions and this change is
     now completed.

   - Clean out the painful and hard to grasp BNF experiments from the
     device tree bindings. Future approaches are looking into using JSON
     schema for this purpose. (Rob Herring is floating a patch series.)

  New drivers:

   - The RCAR driver now supports r8a774a1 (RZ/G2M).

   - Synopsys GPIO via CREGs driver.

  Major improvements:

   - Modernization of the EP93xx driver to use irqdomain and other
     contemporary concepts.

   - The ingenic driver has been merged into the Ingenic pin control
     driver and removed from the GPIO subsystem.

   - Debounce support in the ftgpio010 driver"

* tag 'gpio-v4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (116 commits)
  gpio: Clarify kerneldoc on gpiochip_set_chained_irqchip()
  gpio: Remove unused 'irqchip' argument to gpiochip_set_cascaded_irqchip()
  gpio: Drop parent irq assignment during cascade setup
  mmc: pwrseq_simple: Fix incorrect handling of GPIO bitmap
  gpio: fix SNPS_CREG kconfig dependency warning
  gpiolib: Initialize gdev field before is used
  gpio: fix kernel-doc after devres.c file rename
  gpio: fix doc string for devm_gpiochip_add_data() to not talk about irq_chip
  gpio: syscon: Fix possible NULL ptr usage
  gpiolib: Show correct direction from the beginning
  pinctrl: msm: Use init_valid_mask exported function
  gpiolib: Add init_valid_mask exported function
  GPIO: add single-register GPIO via CREG driver
  dt-bindings: Document the Synopsys GPIO via CREG bindings
  gpio: mockup: use device properties instead of platform_data
  gpio: Slightly more helpful debugfs
  gpio: omap: Remove set but not used variable 'dev'
  gpio: omap: drop omap_gpio_list
  Accept partial 'gpio-line-names' property.
  gpio: omap: get rid of the conditional PM runtime calls
  ...

77 files changed:
Documentation/devicetree/bindings/gpio/gpio.txt
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt [new file with mode: 0644]
Documentation/driver-api/gpio/board.rst
Documentation/driver-api/gpio/consumer.rst
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/gpio/index.rst
MAINTAINERS
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-ep93xx/core.c
arch/arm/mach-omap2/pm24xx.c
arch/arm/mach-omap2/pm34xx.c
arch/mips/include/asm/vr41xx/giu.h
arch/x86/platform/ts5500/ts5500.c
drivers/auxdisplay/hd44780.c
drivers/bus/ts-nbus.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-adp5520.c
drivers/gpio/gpio-adp5588.c
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-creg-snps.c [new file with mode: 0644]
drivers/gpio/gpio-davinci.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-htc-egpio.c
drivers/gpio/gpio-max3191x.c
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-siox.c [new file with mode: 0644]
drivers/gpio/gpio-syscon.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-tps65086.c
drivers/gpio/gpio-tps6586x.c
drivers/gpio/gpio-tps65910.c
drivers/gpio/gpio-tps65912.c
drivers/gpio/gpio-ts5500.c
drivers/gpio/gpio-twl4030.c
drivers/gpio/gpio-twl6040.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-viperboard.c
drivers/gpio/gpio-vr41xx.c
drivers/gpio/gpio-vx855.c
drivers/gpio/gpio-wm831x.c
drivers/gpio/gpio-wm8350.c
drivers/gpio/gpio-wm8994.c
drivers/gpio/gpio-xlp.c
drivers/gpio/gpio-xtensa.c
drivers/gpio/gpio-zevio.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-devprop.c
drivers/gpio/gpiolib-devres.c [moved from drivers/gpio/devres.c with 96% similarity]
drivers/gpio/gpiolib-legacy.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/mmc/core/pwrseq_simple.c
drivers/mux/gpio.c
drivers/net/phy/mdio-mux-gpio.c
drivers/pcmcia/soc_common.c
drivers/phy/motorola/phy-mapphone-mdm6600.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/staging/iio/adc/ad7606.c
drivers/tty/serial/serial_mctrl_gpio.c
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
include/linux/platform_data/gpio-davinci.h
include/linux/platform_data/gpio-omap.h
include/linux/platform_data/gpio-ts5500.h [deleted file]
include/uapi/linux/gpio.h

index a7c31de2936202aa2fa9370934e6982ce5222deb..f0ba154b57231577d3a04634b0d6c94869fe8494 100644 (file)
@@ -1,18 +1,9 @@
 Specifying GPIO information for devices
-============================================
+=======================================
 
 1) gpios property
 -----------------
 
-Nodes that makes use of GPIOs should specify them using one or more
-properties, each containing a 'gpio-list':
-
-       gpio-list ::= <single-gpio> [gpio-list]
-       single-gpio ::= <gpio-phandle> <gpio-specifier>
-       gpio-phandle : phandle to gpio controller node
-       gpio-specifier : Array of #gpio-cells specifying specific gpio
-                        (controller specific)
-
 GPIO properties should be named "[<name>-]gpios", with <name> being the purpose
 of this GPIO for the device. While a non-existent <name> is considered valid
 for compatibility reasons (resolving to the "gpios" property), it is not allowed
@@ -33,33 +24,27 @@ The following example could be used to describe GPIO pins used as device enable
 and bit-banged data signals:
 
        gpio1: gpio1 {
-               gpio-controller
-                #gpio-cells = <2>;
-       };
-       gpio2: gpio2 {
-               gpio-controller
-                #gpio-cells = <1>;
+               gpio-controller;
+               #gpio-cells = <2>;
        };
        [...]
 
-       enable-gpios = <&gpio2 2>;
        data-gpios = <&gpio1 12 0>,
                     <&gpio1 13 0>,
                     <&gpio1 14 0>,
                     <&gpio1 15 0>;
 
-Note that gpio-specifier length is controller dependent.  In the
-above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
-only uses one.
+In the above example, &gpio1 uses 2 cells to specify a gpio. The first cell is
+a local offset to the GPIO line and the second cell represent consumer flags,
+such as if the consumer desire the line to be active low (inverted) or open
+drain. This is the recommended practice.
 
-gpio-specifier may encode: bank, pin position inside the bank,
-whether pin is open-drain and whether pin is logically inverted.
+The exact meaning of each specifier cell is controller specific, and must be
+documented in the device tree binding for the device, but it is strongly
+recommended to use the two-cell approach.
 
-Exact meaning of each specifier cell is controller specific, and must
-be documented in the device tree binding for the device.
-
-Most controllers are however specifying a generic flag bitfield
-in the last cell, so for these, use the macros defined in
+Most controllers are specifying a generic flag bitfield in the last cell, so
+for these, use the macros defined in
 include/dt-bindings/gpio/gpio.h whenever possible:
 
 Example of a node using GPIOs:
@@ -236,46 +221,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
 
 Some or all of the GPIOs provided by a GPIO controller may be routed to pins
 on the package via a pin controller. This allows muxing those pins between
-GPIO and other functions.
+GPIO and other functions. It is a fairly common practice among silicon
+engineers.
+
+2.2) Ordinary (numerical) GPIO ranges
+-------------------------------------
 
 It is useful to represent which GPIOs correspond to which pins on which pin
-controllers. The gpio-ranges property described below represents this, and
-contains information structures as follows:
-
-       gpio-range-list ::= <single-gpio-range> [gpio-range-list]
-       single-gpio-range ::= <numeric-gpio-range> | <named-gpio-range>
-       numeric-gpio-range ::=
-                       <pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
-       named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>'
-       pinctrl-phandle : phandle to pin controller node
-       gpio-base : Base GPIO ID in the GPIO controller
-       pinctrl-base : Base pinctrl pin ID in the pin controller
-       count : The number of GPIOs/pins in this range
-
-The "pin controller node" mentioned above must conform to the bindings
-described in ../pinctrl/pinctrl-bindings.txt.
-
-In case named gpio ranges are used (ranges with both <pinctrl-base> and
-<count> set to 0), the property gpio-ranges-group-names contains one string
-for every single-gpio-range in gpio-ranges:
-       gpiorange-names-list ::= <gpiorange-name> [gpiorange-names-list]
-       gpiorange-name : Name of the pingroup associated to the GPIO range in
-                       the respective pin controller.
-
-Elements of gpiorange-names-list corresponding to numeric ranges contain
-the empty string. Elements of gpiorange-names-list corresponding to named
-ranges contain the name of a pin group defined in the respective pin
-controller. The number of pins/GPIOs in the range is the number of pins in
-that pin group.
+controllers. The gpio-ranges property described below represents this with
+a discrete set of ranges mapping pins from the pin controller local number space
+to pins in the GPIO controller local number space.
 
-Previous versions of this binding required all pin controller nodes that
-were referenced by any gpio-ranges property to contain a property named
-#gpio-range-cells with value <3>. This requirement is now deprecated.
-However, that property may still exist in older device trees for
-compatibility reasons, and would still be required even in new device
-trees that need to be compatible with older software.
+The format is: <[pin controller phandle], [GPIO controller offset],
+                [pin controller offset], [number of pins]>;
+
+The GPIO controller offset pertains to the GPIO controller node containing the
+range definition.
+
+The pin controller node referenced by the phandle must conform to the bindings
+described in pinctrl/pinctrl-bindings.txt.
+
+Each offset runs from 0 to N. It is perfectly fine to pile any number of
+ranges with just one pin-to-GPIO line mapping if the ranges are concocted, but
+in practice these ranges are often lumped in discrete sets.
+
+Example:
+
+    gpio-ranges = <&foo 0 20 10>, <&bar 10 50 20>;
 
-Example 1:
+This means:
+- pins 20..29 on pin controller "foo" is mapped to GPIO line 0..9 and
+- pins 50..69 on pin controller "bar" is mapped to GPIO line 10..29
+
+
+Verbose example:
 
        qe_pio_e: gpio-controller@1460 {
                #gpio-cells = <2>;
@@ -289,7 +268,28 @@ Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
 pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's
 pins 50..69.
 
-Example 2:
+
+2.3) GPIO ranges from named pin groups
+--------------------------------------
+
+It is also possible to use pin groups for gpio ranges when pin groups are the
+easiest and most convenient mapping.
+
+Both both <pinctrl-base> and <count> must set to 0 when using named pin groups
+names.
+
+The property gpio-ranges-group-names must contain exactly one string for each
+range.
+
+Elements of gpio-ranges-group-names must contain the name of a pin group
+defined in the respective pin controller. The number of pins/GPIO lines in the
+range is the number of pins in that pin group. The number of pins of that
+group is defined int the implementation and not in the device tree.
+
+If numerical and named pin groups are mixed, the string corresponding to a
+numerical pin range in gpio-ranges-group-names must be empty.
+
+Example:
 
        gpio_pio_i: gpio-controller@14b0 {
                #gpio-cells = <2>;
@@ -306,6 +306,14 @@ Example 2:
                                                "bar";
        };
 
-Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO
-ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
-are named "foo" and "bar".
+Here, three GPIO ranges are defined referring to two pin controllers.
+
+pinctrl1 GPIO ranges are defined using pin numbers whereas the GPIO ranges
+in pinctrl2 are defined using the pin groups named "foo" and "bar".
+
+Previous versions of this binding required all pin controller nodes that
+were referenced by any gpio-ranges property to contain a property named
+#gpio-range-cells with value <3>. This requirement is now deprecated.
+However, that property may still exist in older device trees for
+compatibility reasons, and would still be required even in new device
+trees that need to be compatible with older software.
index 4018ee57a6af5a662a37640262a6dd972daf02de..2889bbcd7416cf4517373946d0212e8a2ffe57f9 100644 (file)
@@ -4,8 +4,10 @@ Required Properties:
 
   - compatible: should contain one or more of the following:
     - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller.
+    - "renesas,gpio-r8a7744": for R8A7744 (RZ/G1N) compatible GPIO controller.
     - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
     - "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
+    - "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller.
     - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
     - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
     - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller.
@@ -22,7 +24,7 @@ Required Properties:
     - "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller.
     - "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller.
     - "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller.
-    - "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 GPIO controller.
+    - "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 or RZ/G2 GPIO controller.
     - "renesas,gpio-rcar": deprecated.
 
     When compatible with the generic version nodes must list the
@@ -38,7 +40,7 @@ Required Properties:
   - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
     cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
     GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
-  - gpio-ranges: Range of pins managed by the GPIO controller.
+  - gpio-ranges: See gpio.txt.
 
 Optional properties:
 
@@ -46,35 +48,44 @@ Optional properties:
     mandatory if the hardware implements a controllable functional clock for
     the GPIO instance.
 
-Please refer to gpio.txt in this directory for details of gpio-ranges property
-and the common GPIO bindings used by client devices.
+  - gpio-reserved-ranges: See gpio.txt.
+
+Please refer to gpio.txt in this directory for the common GPIO bindings used by
+client devices.
 
 The GPIO controller also acts as an interrupt controller. It uses the default
 two cells specifier as described in Documentation/devicetree/bindings/
 interrupt-controller/interrupts.txt.
 
-Example: R8A7779 (R-Car H1) GPIO controller nodes
+Example: R8A77470 (RZ/G1C) GPIO controller nodes
 
-       gpio0: gpio@ffc40000 {
-               compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio";
-               reg = <0xffc40000 0x2c>;
-               interrupt-parent = <&gic>;
-               interrupts = <0 141 0x4>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               gpio-ranges = <&pfc 0 0 32>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
-       };
+       gpio0: gpio@e6050000 {
+                compatible = "renesas,gpio-r8a77470",
+                             "renesas,rcar-gen2-gpio";
+                reg = <0 0xe6050000 0 0x50>;
+                interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
+                #gpio-cells = <2>;
+                gpio-controller;
+                gpio-ranges = <&pfc 0 0 23>;
+                #interrupt-cells = <2>;
+                interrupt-controller;
+                clocks = <&cpg CPG_MOD 912>;
+                power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                resets = <&cpg 912>;
+        };
        ...
-       gpio6: gpio@ffc46000 {
-               compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio";
-               reg = <0xffc46000 0x2c>;
-               interrupt-parent = <&gic>;
-               interrupts = <0 147 0x4>;
-               #gpio-cells = <2>;
-               gpio-controller;
-               gpio-ranges = <&pfc 0 192 9>;
-               interrupt-controller;
-               #interrupt-cells = <2>;
-       };
+       gpio3: gpio@e6053000 {
+                compatible = "renesas,gpio-r8a77470",
+                             "renesas,rcar-gen2-gpio";
+                reg = <0 0xe6053000 0 0x50>;
+                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+                #gpio-cells = <2>;
+                gpio-controller;
+                gpio-ranges = <&pfc 0 96 30>;
+                gpio-reserved-ranges = <17 10>;
+                #interrupt-cells = <2>;
+                interrupt-controller;
+                clocks = <&cpg CPG_MOD 909>;
+                power-domains = <&sysc R8A77470_PD_ALWAYS_ON>;
+                resets = <&cpg 909>;
+        };
diff --git a/Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt b/Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt
new file mode 100644 (file)
index 0000000..1b30812
--- /dev/null
@@ -0,0 +1,21 @@
+Synopsys GPIO via CREG (Control REGisters) driver
+
+Required properties:
+- compatible : "snps,creg-gpio-hsdk" or "snps,creg-gpio-axs10x".
+- reg : Exactly one register range with length 0x4.
+- #gpio-cells : Since the generic GPIO binding is used, the
+  amount of cells must be specified as 2. The first cell is the
+  pin number, the second cell is used to specify optional parameters:
+  See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt.
+- gpio-controller : Marks the device node as a GPIO controller.
+- ngpios: Number of GPIO pins.
+
+Example:
+
+gpio: gpio@f00014b0 {
+       compatible = "snps,creg-gpio-hsdk";
+       reg = <0xf00014b0 0x4>;
+       gpio-controller;
+       #gpio-cells = <2>;
+       ngpios = <2>;
+};
index 2c112553df841444730beee24d30485857d99145..a0f294e2e250c7cb609282859fbc8f07a32c5c45 100644 (file)
@@ -193,3 +193,27 @@ And the table can be added to the board code as follows::
 
 The line will be hogged as soon as the gpiochip is created or - in case the
 chip was created earlier - when the hog table is registered.
+
+Arrays of pins
+--------------
+In addition to requesting pins belonging to a function one by one, a device may
+also request an array of pins assigned to the function.  The way those pins are
+mapped to the device determines if the array qualifies for fast bitmap
+processing.  If yes, a bitmap is passed over get/set array functions directly
+between a caller and a respective .get/set_multiple() callback of a GPIO chip.
+
+In order to qualify for fast bitmap processing, the array must meet the
+following requirements:
+- pin hardware number of array member 0 must also be 0,
+- pin hardware numbers of consecutive array members which belong to the same
+  chip as member 0 does must also match their array indexes.
+
+Otherwise fast bitmap processing path is not used in order to avoid consecutive
+pins which belong to the same chip but are not in hardware order being processed
+separately.
+
+If the array applies for fast bitmap processing path, pins which belong to
+different chips than member 0 does, as well as those with indexes different from
+their hardware pin numbers, are excluded from the fast path, both input and
+output.  Moreover, open drain and open source pins are excluded from fast bitmap
+output processing.
index aa03f389d41d6a794f16607ee076f248848da17a..5e4d8aa68913529ccec1f9fde56b1b28ced62678 100644 (file)
@@ -109,9 +109,11 @@ For a function using multiple GPIOs all of those can be obtained with one call::
                                           enum gpiod_flags flags)
 
 This function returns a struct gpio_descs which contains an array of
-descriptors::
+descriptors.  It also contains a pointer to a gpiolib private structure which,
+if passed back to get/set array functions, may speed up I/O proocessing::
 
        struct gpio_descs {
+               struct gpio_array *info;
                unsigned int ndescs;
                struct gpio_desc *desc[];
        }
@@ -323,29 +325,37 @@ The following functions get or set the values of an array of GPIOs::
 
        int gpiod_get_array_value(unsigned int array_size,
                                  struct gpio_desc **desc_array,
-                                 int *value_array);
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap);
        int gpiod_get_raw_array_value(unsigned int array_size,
                                      struct gpio_desc **desc_array,
-                                     int *value_array);
+                                     struct gpio_array *array_info,
+                                     unsigned long *value_bitmap);
        int gpiod_get_array_value_cansleep(unsigned int array_size,
                                           struct gpio_desc **desc_array,
-                                          int *value_array);
+                                          struct gpio_array *array_info,
+                                          unsigned long *value_bitmap);
        int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
                                           struct gpio_desc **desc_array,
-                                          int *value_array);
-
-       void gpiod_set_array_value(unsigned int array_size,
-                                  struct gpio_desc **desc_array,
-                                  int *value_array)
-       void gpiod_set_raw_array_value(unsigned int array_size,
-                                      struct gpio_desc **desc_array,
-                                      int *value_array)
-       void gpiod_set_array_value_cansleep(unsigned int array_size,
-                                           struct gpio_desc **desc_array,
-                                           int *value_array)
-       void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
-                                               struct gpio_desc **desc_array,
-                                               int *value_array)
+                                          struct gpio_array *array_info,
+                                          unsigned long *value_bitmap);
+
+       int gpiod_set_array_value(unsigned int array_size,
+                                 struct gpio_desc **desc_array,
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap)
+       int gpiod_set_raw_array_value(unsigned int array_size,
+                                     struct gpio_desc **desc_array,
+                                     struct gpio_array *array_info,
+                                     unsigned long *value_bitmap)
+       int gpiod_set_array_value_cansleep(unsigned int array_size,
+                                          struct gpio_desc **desc_array,
+                                          struct gpio_array *array_info,
+                                          unsigned long *value_bitmap)
+       int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
+                                              struct gpio_desc **desc_array,
+                                              struct gpio_array *array_info,
+                                              unsigned long *value_bitmap)
 
 The array can be an arbitrary set of GPIOs. The functions will try to access
 GPIOs belonging to the same bank or chip simultaneously if supported by the
@@ -356,8 +366,9 @@ accessed sequentially.
 The functions take three arguments:
        * array_size    - the number of array elements
        * desc_array    - an array of GPIO descriptors
-       * value_array   - an array to store the GPIOs' values (get) or
-                         an array of values to assign to the GPIOs (set)
+       * array_info    - optional information obtained from gpiod_array_get()
+       * value_bitmap  - a bitmap to store the GPIOs' values (get) or
+                         a bitmap of values to assign to the GPIOs (set)
 
 The descriptor array can be obtained using the gpiod_get_array() function
 or one of its variants. If the group of descriptors returned by that function
@@ -366,16 +377,25 @@ the struct gpio_descs returned by gpiod_get_array()::
 
        struct gpio_descs *my_gpio_descs = gpiod_get_array(...);
        gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc,
-                             my_gpio_values);
+                             my_gpio_descs->info, my_gpio_value_bitmap);
 
 It is also possible to access a completely arbitrary array of descriptors. The
 descriptors may be obtained using any combination of gpiod_get() and
 gpiod_get_array(). Afterwards the array of descriptors has to be setup
-manually before it can be passed to one of the above functions.
+manually before it can be passed to one of the above functions.  In that case,
+array_info should be set to NULL.
 
 Note that for optimal performance GPIOs belonging to the same chip should be
 contiguous within the array of descriptors.
 
+Still better performance may be achieved if array indexes of the descriptors
+match hardware pin numbers of a single chip.  If an array passed to a get/set
+array function matches the one obtained from gpiod_get_array() and array_info
+associated with the array is also passed, the function may take a fast bitmap
+processing path, passing the value_bitmap argument directly to the respective
+.get/set_multiple() callback of the chip.  That allows for utilization of GPIO
+banks as data I/O ports without much loss of performance.
+
 The return value of gpiod_get_array_value() and its variants is 0 on success
 or negative on error. Note the difference to gpiod_get_value(), which returns
 0 or 1 on success to convey the GPIO value. With the array functions, the GPIO
index cbe0242842d1540f833bae20b304374303bc6b09..a6c14ff0c54f5f09f0bdc546b0ca48c536c56cae 100644 (file)
@@ -374,7 +374,28 @@ When implementing an irqchip inside a GPIO driver, these two functions should
 typically be called in the .startup() and .shutdown() callbacks from the
 irqchip.
 
-When using the gpiolib irqchip helpers, these callback are automatically
+When using the gpiolib irqchip helpers, these callbacks are automatically
+assigned.
+
+
+Disabling and enabling IRQs
+---------------------------
+When a GPIO is used as an IRQ signal, then gpiolib also needs to know if
+the IRQ is enabled or disabled. In order to inform gpiolib about this,
+a driver should call::
+
+       void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
+
+This allows drivers to drive the GPIO as an output while the IRQ is
+disabled. When the IRQ is enabled again, a driver should call::
+
+       void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
+
+When implementing an irqchip inside a GPIO driver, these two functions should
+typically be called in the .irq_disable() and .irq_enable() callbacks from the
+irqchip.
+
+When using the gpiolib irqchip helpers, these callbacks are automatically
 assigned.
 
 Real-Time compliance for GPIO IRQ chips
index 6a374ded1287d91a209607fcd82d559aadfecb5c..c5b8467f91043e288b7d5386c8f44da056ffb2c4 100644 (file)
@@ -38,7 +38,7 @@ Device tree support
 Device-managed API
 ==================
 
-.. kernel-doc:: drivers/gpio/devres.c
+.. kernel-doc:: drivers/gpio/gpiolib-devres.c
    :export:
 
 sysfs helpers
index 8c2cd7e03c963ae7bb6d7cf3b4986df298012baa..5b405190c0b4834f8dc5e0ba0324c426e84c88d8 100644 (file)
@@ -7396,6 +7396,12 @@ T:       git https://github.com/intel/gvt-linux.git
 S:     Supported
 F:     drivers/gpu/drm/i915/gvt/
 
+INTEL PMIC GPIO DRIVER
+R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+S:     Maintained
+F:     drivers/gpio/gpio-*cove.c
+F:     drivers/gpio/gpio-msic.c
+
 INTEL HID EVENT DRIVER
 M:     Alex Hung <alex.hung@canonical.com>
 L:     platform-driver-x86@vger.kernel.org
@@ -13352,6 +13358,7 @@ M:      Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
 R:     Pengutronix Kernel Team <kernel@pengutronix.de>
 S:     Supported
 F:     drivers/siox/*
+F:     drivers/gpio/gpio-siox.c
 F:     include/trace/events/siox.h
 
 SIS 190 ETHERNET DRIVER
@@ -14079,6 +14086,12 @@ S:     Supported
 F:     drivers/reset/reset-axs10x.c
 F:     Documentation/devicetree/bindings/reset/snps,axs10x-reset.txt
 
+SYNOPSYS CREG GPIO DRIVER
+M:     Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+S:     Maintained
+F:     drivers/gpio/gpio-creg-snps.c
+F:     Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt
+
 SYNOPSYS DESIGNWARE 8250 UART DRIVER
 R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:     Maintained
index 353f9e5a1454a67d674c90c663ccbabd6e0dcae1..efdaa27241c5eaee6bd6c231496bab51bf42d034 100644 (file)
@@ -130,10 +130,10 @@ static struct platform_device davinci_fb_device = {
 };
 
 static const struct gpio_led ntosd2_leds[] = {
-       { .name = "led1_green", .gpio = GPIO(10), },
-       { .name = "led1_red",   .gpio = GPIO(11), },
-       { .name = "led2_green", .gpio = GPIO(12), },
-       { .name = "led2_red",   .gpio = GPIO(13), },
+       { .name = "led1_green", .gpio = 10, },
+       { .name = "led1_red",   .gpio = 11, },
+       { .name = "led2_green", .gpio = 12, },
+       { .name = "led2_red",   .gpio = 13, },
 };
 
 static struct gpio_led_platform_data ntosd2_leds_data = {
index faf48a3b1fea913813681430bc55f3697a2c0028..706515faee066e71ae4b195869ee72297fe590aa 100644 (file)
@@ -141,6 +141,15 @@ EXPORT_SYMBOL_GPL(ep93xx_chip_revision);
  *************************************************************************/
 static struct resource ep93xx_gpio_resource[] = {
        DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO_AB),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO0MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO1MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO2MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO3MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO4MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO5MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO6MUX),
+       DEFINE_RES_IRQ(IRQ_EP93XX_GPIO7MUX),
 };
 
 static struct platform_device ep93xx_gpio_device = {
index 2a1a4180d5d0f5901e8fdbaab5d25339b581be01..1298b53ac2638ce72b223e7000b590c42f05c31b 100644 (file)
@@ -18,6 +18,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/cpu_pm.h>
 #include <linux/suspend.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -29,8 +30,6 @@
 #include <linux/clk-provider.h>
 #include <linux/irq.h>
 #include <linux/time.h>
-#include <linux/gpio.h>
-#include <linux/platform_data/gpio-omap.h>
 
 #include <asm/fncpy.h>
 
@@ -87,7 +86,7 @@ static int omap2_enter_full_retention(void)
        l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
        omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
 
-       omap2_gpio_prepare_for_idle(0);
+       cpu_cluster_pm_enter();
 
        /* One last check for pending IRQs to avoid extra latency due
         * to sleeping unnecessarily. */
@@ -100,7 +99,7 @@ static int omap2_enter_full_retention(void)
                           OMAP_SDRC_REGADDR(SDRC_POWER));
 
 no_sleep:
-       omap2_gpio_resume_after_idle();
+       cpu_cluster_pm_exit();
 
        clk_enable(osc_ck);
 
index 36c55547137cb08b9b1b662cb5477e591590598d..1a90050361f131f7675ccb16a1e20dde998a3486 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <linux/cpu_pm.h>
 #include <linux/pm.h>
 #include <linux/suspend.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/omap-dma.h>
 #include <linux/omap-gpmc.h>
-#include <linux/platform_data/gpio-omap.h>
 
 #include <trace/events/power.h>
 
@@ -197,7 +196,6 @@ void omap_sram_idle(void)
        int mpu_next_state = PWRDM_POWER_ON;
        int per_next_state = PWRDM_POWER_ON;
        int core_next_state = PWRDM_POWER_ON;
-       int per_going_off;
        u32 sdrc_pwr = 0;
 
        mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
@@ -227,10 +225,8 @@ void omap_sram_idle(void)
        pwrdm_pre_transition(NULL);
 
        /* PER */
-       if (per_next_state < PWRDM_POWER_ON) {
-               per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
-               omap2_gpio_prepare_for_idle(per_going_off);
-       }
+       if (per_next_state == PWRDM_POWER_OFF)
+               cpu_cluster_pm_enter();
 
        /* CORE */
        if (core_next_state < PWRDM_POWER_ON) {
@@ -295,8 +291,8 @@ void omap_sram_idle(void)
        pwrdm_post_transition(NULL);
 
        /* PER */
-       if (per_next_state < PWRDM_POWER_ON)
-               omap2_gpio_resume_after_idle();
+       if (per_next_state == PWRDM_POWER_OFF)
+               cpu_cluster_pm_exit();
 }
 
 static void omap3_pm_idle(void)
index 6a90bc1d916b4aa58ddc57ae6edd8ee40ae9b4ee..ecda4cf300dee5abb1b464e97291286d14c7c784 100644 (file)
@@ -51,12 +51,4 @@ typedef enum {
 
 extern void vr41xx_set_irq_level(unsigned int pin, irq_level_t level);
 
-typedef enum {
-       GPIO_PULL_DOWN,
-       GPIO_PULL_UP,
-       GPIO_PULL_DISABLE,
-} gpio_pull_t;
-
-extern int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull);
-
 #endif /* __NEC_VR41XX_GIU_H */
index fd39301f25ac325bcec1f7fcdf4cb839224c6cb8..7e56fc74093cf6d99b6ded61dc764579f43299d6 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/leds.h>
 #include <linux/init.h>
-#include <linux/platform_data/gpio-ts5500.h>
 #include <linux/platform_data/max197.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index f1a42f0f1ded658e196bcde56decfbd41d663267..9ad93ea42fdc73e81242ea358ffb357612833367 100644 (file)
@@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd)
 /* write to an LCD panel register in 8 bit GPIO mode */
 static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
 {
-       int values[10]; /* for DATA[0-7], RS, RW */
-       unsigned int i, n;
-
-       for (i = 0; i < 8; i++)
-               values[PIN_DATA0 + i] = !!(val & BIT(i));
-       values[PIN_CTRL_RS] = rs;
-       n = 9;
-       if (hd->pins[PIN_CTRL_RW]) {
-               values[PIN_CTRL_RW] = 0;
-               n++;
-       }
+       DECLARE_BITMAP(values, 10); /* for DATA[0-7], RS, RW */
+       unsigned int n;
+
+       values[0] = val;
+       __assign_bit(8, values, rs);
+       n = hd->pins[PIN_CTRL_RW] ? 10 : 9;
 
        /* Present the data to the port */
-       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values);
+       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, values);
 
        hd44780_strobe_gpio(hd);
 }
@@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs)
 /* write to an LCD panel register in 4 bit GPIO mode */
 static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs)
 {
-       int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
-       unsigned int i, n;
+       DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
+       unsigned int n;
 
        /* High nibble + RS, RW */
-       for (i = 4; i < 8; i++)
-               values[PIN_DATA0 + i] = !!(val & BIT(i));
-       values[PIN_CTRL_RS] = rs;
-       n = 5;
-       if (hd->pins[PIN_CTRL_RW]) {
-               values[PIN_CTRL_RW] = 0;
-               n++;
-       }
+       values[0] = val >> 4;
+       __assign_bit(4, values, rs);
+       n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
 
        /* Present the data to the port */
-       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-                                      &values[PIN_DATA4]);
+       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
 
        hd44780_strobe_gpio(hd);
 
        /* Low nibble */
-       for (i = 0; i < 4; i++)
-               values[PIN_DATA4 + i] = !!(val & BIT(i));
+       values[0] &= ~0x0fUL;
+       values[0] |= val & 0x0f;
 
        /* Present the data to the port */
-       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-                                      &values[PIN_DATA4]);
+       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
 
        hd44780_strobe_gpio(hd);
 }
@@ -155,23 +143,16 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd)
 /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */
 static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd)
 {
-       int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */
+       DECLARE_BITMAP(values, 6); /* for DATA[4-7], RS, RW */
        struct hd44780 *hd = lcd->drvdata;
-       unsigned int i, n;
+       unsigned int n;
 
        /* Command nibble + RS, RW */
-       for (i = 0; i < 4; i++)
-               values[PIN_DATA4 + i] = !!(cmd & BIT(i));
-       values[PIN_CTRL_RS] = 0;
-       n = 5;
-       if (hd->pins[PIN_CTRL_RW]) {
-               values[PIN_CTRL_RW] = 0;
-               n++;
-       }
+       values[0] = cmd & 0x0f;
+       n = hd->pins[PIN_CTRL_RW] ? 6 : 5;
 
        /* Present the data to the port */
-       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4],
-                                      &values[PIN_DATA4]);
+       gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, values);
 
        hd44780_strobe_gpio(hd);
 }
index 073fd9011154a907d8df33a3ca420e1c7a349637..9989ce904a372c899c1c366cfe55f0bd06bf346e 100644 (file)
@@ -110,13 +110,12 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
  */
 static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
 {
-       int i;
-       int values[8];
+       DECLARE_BITMAP(values, 8);
 
-       for (i = 0; i < 8; i++)
-               values[i] = 0;
+       values[0] = 0;
 
-       gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values);
+       gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
+                                      ts_nbus->data->info, values);
        gpiod_set_value_cansleep(ts_nbus->csn, 0);
        gpiod_set_value_cansleep(ts_nbus->strobe, 0);
        gpiod_set_value_cansleep(ts_nbus->ale, 0);
@@ -157,16 +156,11 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
 static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
 {
        struct gpio_descs *gpios = ts_nbus->data;
-       int i;
-       int values[8];
+       DECLARE_BITMAP(values, 8);
 
-       for (i = 0; i < 8; i++)
-               if (byte & BIT(i))
-                       values[i] = 1;
-               else
-                       values[i] = 0;
+       values[0] = byte;
 
-       gpiod_set_array_value_cansleep(8, gpios->desc, values);
+       gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
 }
 
 /*
index 052dd5960cec071b39c53822f5d45131fda3a585..833a1b51c9482c720d42c53421a41c3b8ba30668 100644 (file)
@@ -200,6 +200,7 @@ config GPIO_EP93XX
        def_bool y
        depends on ARCH_EP93XX
        select GPIO_GENERIC
+       select GPIOLIB_IRQCHIP
 
 config GPIO_EXAR
        tristate "Support for GPIO pins on XR17V352/354/358"
@@ -428,6 +429,24 @@ config GPIO_REG
          A 32-bit single register GPIO fixed in/out implementation.  This
          can be used to represent any register as a set of GPIO signals.
 
+config GPIO_SIOX
+       tristate "SIOX GPIO support"
+       depends on SIOX
+       select GPIOLIB_IRQCHIP
+       help
+         Say yes here to support SIOX I/O devices. These are units connected
+         via a SIOX bus and have a number of fixed-direction I/O lines.
+
+config GPIO_SNPS_CREG
+       bool "Synopsys GPIO via CREG (Control REGisters) driver"
+       depends on ARC || COMPILE_TEST
+       depends on OF_GPIO
+       help
+         This driver supports GPIOs via CREG on various Synopsys SoCs.
+         This is a single-register MMIO GPIO driver for complex cases
+         where only several fields in register belong to GPIO lines and
+         each GPIO line owns a field with different length and on/off value.
+
 config GPIO_SPEAR_SPICS
        bool "ST SPEAr13xx SPI Chip Select as GPIO support"
        depends on PLAT_SPEAR
@@ -469,6 +488,7 @@ config GPIO_SYSCON
 
 config GPIO_TB10X
        bool
+       select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
        select OF_GPIO
 
index 80d58c2de73070716ef67486df517a9a67c15900..671c4477c951aba6a9ae63ec0a9fa5d857bda933 100644 (file)
@@ -3,8 +3,8 @@
 
 ccflags-$(CONFIG_DEBUG_GPIO)   += -DDEBUG
 
-obj-$(CONFIG_GPIOLIB)          += devres.o
 obj-$(CONFIG_GPIOLIB)          += gpiolib.o
+obj-$(CONFIG_GPIOLIB)          += gpiolib-devres.o
 obj-$(CONFIG_GPIOLIB)          += gpiolib-legacy.o
 obj-$(CONFIG_GPIOLIB)          += gpiolib-devprop.o
 obj-$(CONFIG_OF_GPIO)          += gpiolib-of.o
@@ -110,6 +110,7 @@ obj-$(CONFIG_GPIO_REG)              += gpio-reg.o
 obj-$(CONFIG_ARCH_SA1100)      += gpio-sa1100.o
 obj-$(CONFIG_GPIO_SCH)         += gpio-sch.o
 obj-$(CONFIG_GPIO_SCH311X)     += gpio-sch311x.o
+obj-$(CONFIG_GPIO_SNPS_CREG)   += gpio-creg-snps.o
 obj-$(CONFIG_GPIO_SODAVILLE)   += gpio-sodaville.o
 obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
 obj-$(CONFIG_GPIO_SPRD)                += gpio-sprd.o
@@ -124,6 +125,7 @@ obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
 obj-$(CONFIG_GPIO_THUNDERX)    += gpio-thunderx.o
 obj-$(CONFIG_GPIO_TIMBERDALE)  += gpio-timberdale.o
 obj-$(CONFIG_GPIO_PALMAS)      += gpio-palmas.o
+obj-$(CONFIG_GPIO_SIOX)                += gpio-siox.o
 obj-$(CONFIG_GPIO_TPIC2810)    += gpio-tpic2810.o
 obj-$(CONFIG_GPIO_TPS65086)    += gpio-tps65086.o
 obj-$(CONFIG_GPIO_TPS65218)    += gpio-tps65218.o
index 21452622d954249e9b46423234bb14acbe535329..e321955782a138ec446246ad2fba4b39b1d7f647 100644 (file)
@@ -172,7 +172,7 @@ static struct platform_driver adp5520_gpio_driver = {
 
 module_platform_driver(adp5520_gpio_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("GPIO ADP5520 Driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:adp5520-gpio");
index da9781a2ef4adf230fc6704945fc02ac2bca3823..cc33d8986ad32e22f874fe2046a8f92587ba9cd9 100644 (file)
@@ -494,6 +494,6 @@ static struct i2c_driver adp5588_gpio_driver = {
 
 module_i2c_driver(adp5588_gpio_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("GPIO ADP5588 Driver");
 MODULE_LICENSE("GPL");
index d0707fc23afd12462969c25df1726a131310465c..c5536a509b598795e481057a020787ec2817fcdb 100644 (file)
@@ -373,6 +373,7 @@ static void bcm_kona_gpio_irq_mask(struct irq_data *d)
        val = readl(reg_base + GPIO_INT_MASK(bank_id));
        val |= BIT(bit);
        writel(val, reg_base + GPIO_INT_MASK(bank_id));
+       gpiochip_disable_irq(&kona_gpio->gpio_chip, gpio);
 
        raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
 }
@@ -394,6 +395,7 @@ static void bcm_kona_gpio_irq_unmask(struct irq_data *d)
        val = readl(reg_base + GPIO_INT_MSKCLR(bank_id));
        val |= BIT(bit);
        writel(val, reg_base + GPIO_INT_MSKCLR(bank_id));
+       gpiochip_enable_irq(&kona_gpio->gpio_chip, gpio);
 
        raw_spin_unlock_irqrestore(&kona_gpio->lock, flags);
 }
@@ -485,23 +487,15 @@ static void bcm_kona_gpio_irq_handler(struct irq_desc *desc)
 static int bcm_kona_gpio_irq_reqres(struct irq_data *d)
 {
        struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
-       int ret;
 
-       ret = gpiochip_lock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
-       if (ret) {
-               dev_err(kona_gpio->gpio_chip.parent,
-                       "unable to lock HW IRQ %lu for IRQ\n",
-                       d->hwirq);
-               return ret;
-       }
-       return 0;
+       return gpiochip_reqres_irq(&kona_gpio->gpio_chip, d->hwirq);
 }
 
 static void bcm_kona_gpio_irq_relres(struct irq_data *d)
 {
        struct bcm_kona_gpio *kona_gpio = irq_data_get_irq_chip_data(d);
 
-       gpiochip_unlock_as_irq(&kona_gpio->gpio_chip, d->hwirq);
+       gpiochip_relres_irq(&kona_gpio->gpio_chip, d->hwirq);
 }
 
 static struct irq_chip bcm_gpio_irq_chip = {
index 16c7f9f4941644b64c8fa71f4b0b2c7393e99b6a..af936dcca6596f2e60fb66f5615ff80210e1905d 100644 (file)
@@ -664,6 +664,18 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
                struct brcmstb_gpio_bank *bank;
                struct gpio_chip *gc;
 
+               /*
+                * If bank_width is 0, then there is an empty bank in the
+                * register block. Special handling for this case.
+                */
+               if (bank_width == 0) {
+                       dev_dbg(dev, "Width 0 found: Empty bank @ %d\n",
+                               num_banks);
+                       num_banks++;
+                       gpio_base += MAX_GPIO_PER_BANK;
+                       continue;
+               }
+
                bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
                if (!bank) {
                        err = -ENOMEM;
@@ -740,9 +752,6 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
                        goto fail;
        }
 
-       dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
-                       num_banks, priv->gpio_base, gpio_base - 1);
-
        if (priv->parent_wake_irq && need_wakeup_event)
                pm_wakeup_event(dev, 0);
 
diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c
new file mode 100644 (file)
index 0000000..8cbc94d
--- /dev/null
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Synopsys CREG (Control REGisters) GPIO driver
+//
+// Copyright (C) 2018 Synopsys
+// Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
+
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#define MAX_GPIO       32
+
+struct creg_layout {
+       u8 ngpio;
+       u8 shift[MAX_GPIO];
+       u8 on[MAX_GPIO];
+       u8 off[MAX_GPIO];
+       u8 bit_per_gpio[MAX_GPIO];
+};
+
+struct creg_gpio {
+       struct gpio_chip gc;
+       void __iomem *regs;
+       spinlock_t lock;
+       const struct creg_layout *layout;
+};
+
+static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct creg_gpio *hcg = gpiochip_get_data(gc);
+       const struct creg_layout *layout = hcg->layout;
+       u32 reg, reg_shift, value;
+       unsigned long flags;
+       int i;
+
+       value = val ? hcg->layout->on[offset] : hcg->layout->off[offset];
+
+       reg_shift = layout->shift[offset];
+       for (i = 0; i < offset; i++)
+               reg_shift += layout->bit_per_gpio[i] + layout->shift[i];
+
+       spin_lock_irqsave(&hcg->lock, flags);
+       reg = readl(hcg->regs);
+       reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift);
+       reg |=  (value << reg_shift);
+       writel(reg, hcg->regs);
+       spin_unlock_irqrestore(&hcg->lock, flags);
+}
+
+static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       creg_gpio_set(gc, offset, val);
+
+       return 0;
+}
+
+static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg,
+                                int i)
+{
+       const struct creg_layout *layout = hcg->layout;
+
+       if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8)
+               return -EINVAL;
+
+       /* Check that on valiue fits it's placeholder */
+       if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i])
+               return -EINVAL;
+
+       /* Check that off valiue fits it's placeholder */
+       if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i])
+               return -EINVAL;
+
+       if (layout->on[i] == layout->off[i])
+               return -EINVAL;
+
+       return 0;
+}
+
+static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg,
+                             u32 ngpios)
+{
+       u32 reg_len = 0;
+       int i;
+
+       if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO)
+               return -EINVAL;
+
+       if (ngpios < 1 || ngpios > hcg->layout->ngpio) {
+               dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < hcg->layout->ngpio; i++) {
+               if (creg_gpio_validate_pg(dev, hcg, i))
+                       return -EINVAL;
+
+               reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i];
+       }
+
+       /* Check that we fit in 32 bit register */
+       if (reg_len > 32)
+               return -EINVAL;
+
+       return 0;
+}
+
+static const struct creg_layout hsdk_cs_ctl = {
+       .ngpio          = 10,
+       .shift          = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+       .off            = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
+       .on             = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
+       .bit_per_gpio   = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
+};
+
+static const struct creg_layout axs10x_flsh_cs_ctl = {
+       .ngpio          = 1,
+       .shift          = { 0 },
+       .off            = { 1 },
+       .on             = { 3 },
+       .bit_per_gpio   = { 2 }
+};
+
+static const struct of_device_id creg_gpio_ids[] = {
+       {
+               .compatible = "snps,creg-gpio-axs10x",
+               .data = &axs10x_flsh_cs_ctl
+       }, {
+               .compatible = "snps,creg-gpio-hsdk",
+               .data = &hsdk_cs_ctl
+       }, { /* sentinel */ }
+};
+
+static int creg_gpio_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct device *dev = &pdev->dev;
+       struct creg_gpio *hcg;
+       struct resource *mem;
+       u32 ngpios;
+       int ret;
+
+       hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL);
+       if (!hcg)
+               return -ENOMEM;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hcg->regs = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(hcg->regs))
+               return PTR_ERR(hcg->regs);
+
+       match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
+       hcg->layout = match->data;
+       if (!hcg->layout)
+               return -EINVAL;
+
+       ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
+       if (ret)
+               return ret;
+
+       ret = creg_gpio_validate(dev, hcg, ngpios);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&hcg->lock);
+
+       hcg->gc.label = dev_name(dev);
+       hcg->gc.base = -1;
+       hcg->gc.ngpio = ngpios;
+       hcg->gc.set = creg_gpio_set;
+       hcg->gc.direction_output = creg_gpio_dir_out;
+       hcg->gc.of_node = dev->of_node;
+
+       ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg);
+       if (ret)
+               return ret;
+
+       dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios);
+
+       return 0;
+}
+
+static struct platform_driver creg_gpio_snps_driver = {
+       .driver = {
+               .name = "snps-creg-gpio",
+               .of_match_table = creg_gpio_ids,
+       },
+       .probe  = creg_gpio_probe,
+};
+builtin_platform_driver(creg_gpio_snps_driver);
index a5ece8ea79bc83837838760dd449e238e9570f3a..5c1564fcc24ea68808e8f553889b09ac6e5e2d9f 100644 (file)
@@ -9,6 +9,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
+
 #include <linux/gpio/driver.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/platform_data/gpio-davinci.h>
 #include <linux/irqchip/chained_irq.h>
+#include <linux/spinlock.h>
+
+#include <asm-generic/gpio.h>
+
+#define MAX_REGS_BANKS 5
+#define MAX_INT_PER_BANK 32
 
 struct davinci_gpio_regs {
        u32     dir;
@@ -41,11 +48,31 @@ struct davinci_gpio_regs {
 typedef struct irq_chip *(*gpio_get_irq_chip_cb_t)(unsigned int irq);
 
 #define BINTEN 0x8 /* GPIO Interrupt Per-Bank Enable Register */
-#define MAX_LABEL_SIZE 20
 
 static void __iomem *gpio_base;
 static unsigned int offset_array[5] = {0x10, 0x38, 0x60, 0x88, 0xb0};
 
+struct davinci_gpio_irq_data {
+       void __iomem                    *regs;
+       struct davinci_gpio_controller  *chip;
+       int                             bank_num;
+};
+
+struct davinci_gpio_controller {
+       struct gpio_chip        chip;
+       struct irq_domain       *irq_domain;
+       /* Serialize access to GPIO registers */
+       spinlock_t              lock;
+       void __iomem            *regs[MAX_REGS_BANKS];
+       int                     gpio_unbanked;
+       int                     irqs[MAX_INT_PER_BANK];
+};
+
+static inline u32 __gpio_mask(unsigned gpio)
+{
+       return 1 << (gpio % 32);
+}
+
 static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d)
 {
        struct davinci_gpio_regs __iomem *g;
@@ -166,14 +193,12 @@ of_err:
 
 static int davinci_gpio_probe(struct platform_device *pdev)
 {
-       static int ctrl_num, bank_base;
-       int gpio, bank, i, ret = 0;
+       int bank, i, ret = 0;
        unsigned int ngpio, nbank, nirq;
        struct davinci_gpio_controller *chips;
        struct davinci_gpio_platform_data *pdata;
        struct device *dev = &pdev->dev;
        struct resource *res;
-       char label[MAX_LABEL_SIZE];
 
        pdata = davinci_gpio_get_pdata(pdev);
        if (!pdata) {
@@ -207,10 +232,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
        else
                nirq = DIV_ROUND_UP(ngpio, 16);
 
-       nbank = DIV_ROUND_UP(ngpio, 32);
-       chips = devm_kcalloc(dev,
-                            nbank, sizeof(struct davinci_gpio_controller),
-                            GFP_KERNEL);
+       chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL);
        if (!chips)
                return -ENOMEM;
 
@@ -228,10 +250,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
                }
        }
 
-       snprintf(label, MAX_LABEL_SIZE, "davinci_gpio.%d", ctrl_num++);
-       chips->chip.label = devm_kstrdup(dev, label, GFP_KERNEL);
-               if (!chips->chip.label)
-                       return -ENOMEM;
+       chips->chip.label = dev_name(dev);
 
        chips->chip.direction_input = davinci_direction_in;
        chips->chip.get = davinci_gpio_get;
@@ -239,7 +258,7 @@ static int davinci_gpio_probe(struct platform_device *pdev)
        chips->chip.set = davinci_gpio_set;
 
        chips->chip.ngpio = ngpio;
-       chips->chip.base = bank_base;
+       chips->chip.base = -1;
 
 #ifdef CONFIG_OF_GPIO
        chips->chip.of_gpio_n_cells = 2;
@@ -252,28 +271,21 @@ static int davinci_gpio_probe(struct platform_device *pdev)
        }
 #endif
        spin_lock_init(&chips->lock);
-       bank_base += ngpio;
 
-       for (gpio = 0, bank = 0; gpio < ngpio; gpio += 32, bank++)
+       nbank = DIV_ROUND_UP(ngpio, 32);
+       for (bank = 0; bank < nbank; bank++)
                chips->regs[bank] = gpio_base + offset_array[bank];
 
        ret = devm_gpiochip_add_data(dev, &chips->chip, chips);
        if (ret)
-               goto err;
+               return ret;
 
        platform_set_drvdata(pdev, chips);
        ret = davinci_gpio_irq_setup(pdev);
        if (ret)
-               goto err;
+               return ret;
 
        return 0;
-
-err:
-       /* Revert the static variable increments */
-       ctrl_num--;
-       bank_base -= ngpio;
-
-       return ret;
 }
 
 /*--------------------------------------------------------------------------*/
index 45d384039e9b1ca13c410fbbcfc3091a51e6bfb0..71728d6e0bca441ec7ce82ef9853f4a00ff37b40 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Generic EP93xx GPIO handling
  *
@@ -6,10 +7,6 @@
  *
  * Based on code originally from:
  *  linux/arch/arm/mach-ep93xx/core.c
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
  */
 
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/gpio/driver.h>
-/* FIXME: this is here for gpio_to_irq() - get rid of this! */
-#include <linux/gpio.h>
+#include <linux/bitops.h>
+
+#define EP93XX_GPIO_F_INT_STATUS 0x5c
+#define EP93XX_GPIO_A_INT_STATUS 0xa0
+#define EP93XX_GPIO_B_INT_STATUS 0xbc
+
+/* Maximum value for gpio line identifiers */
+#define EP93XX_GPIO_LINE_MAX 63
 
-#include <mach/hardware.h>
-#include <mach/gpio-ep93xx.h>
+/* Maximum value for irq capable line identifiers */
+#define EP93XX_GPIO_LINE_MAX_IRQ 23
 
-#define irq_to_gpio(irq)       ((irq) - gpio_to_irq(0))
+/*
+ * Static mapping of GPIO bank F IRQS:
+ * F0..F7 (16..24) to irq 80..87.
+ */
+#define EP93XX_GPIO_F_IRQ_BASE 80
 
 struct ep93xx_gpio {
-       void __iomem            *mmio_base;
+       void __iomem            *base;
        struct gpio_chip        gc[8];
 };
 
@@ -48,27 +55,45 @@ static const u8 eoi_register_offset[3]              = { 0x98, 0xb4, 0x54 };
 static const u8 int_en_register_offset[3]      = { 0x9c, 0xb8, 0x58 };
 static const u8 int_debounce_register_offset[3]        = { 0xa8, 0xc4, 0x64 };
 
-static void ep93xx_gpio_update_int_params(unsigned port)
+static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg, unsigned port)
 {
        BUG_ON(port > 2);
 
-       writeb_relaxed(0, EP93XX_GPIO_REG(int_en_register_offset[port]));
+       writeb_relaxed(0, epg->base + int_en_register_offset[port]);
 
        writeb_relaxed(gpio_int_type2[port],
-               EP93XX_GPIO_REG(int_type2_register_offset[port]));
+                      epg->base + int_type2_register_offset[port]);
 
        writeb_relaxed(gpio_int_type1[port],
-               EP93XX_GPIO_REG(int_type1_register_offset[port]));
+                      epg->base + int_type1_register_offset[port]);
 
        writeb(gpio_int_unmasked[port] & gpio_int_enabled[port],
-               EP93XX_GPIO_REG(int_en_register_offset[port]));
+              epg->base + int_en_register_offset[port]);
+}
+
+static int ep93xx_gpio_port(struct gpio_chip *gc)
+{
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = 0;
+
+       while (port < ARRAY_SIZE(epg->gc) && gc != &epg->gc[port])
+               port++;
+
+       /* This should not happen but is there as a last safeguard */
+       if (port == ARRAY_SIZE(epg->gc)) {
+               pr_crit("can't find the GPIO port\n");
+               return 0;
+       }
+
+       return port;
 }
 
-static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
+static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
+                                    unsigned int offset, bool enable)
 {
-       int line = irq_to_gpio(irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
+       int port_mask = BIT(offset);
 
        if (enable)
                gpio_int_debounce[port] |= port_mask;
@@ -76,29 +101,36 @@ static void ep93xx_gpio_int_debounce(unsigned int irq, bool enable)
                gpio_int_debounce[port] &= ~port_mask;
 
        writeb(gpio_int_debounce[port],
-               EP93XX_GPIO_REG(int_debounce_register_offset[port]));
+              epg->base + int_debounce_register_offset[port]);
 }
 
 static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
 {
-       unsigned char status;
-       int i;
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       struct irq_chip *irqchip = irq_desc_get_chip(desc);
+       unsigned long stat;
+       int offset;
 
-       status = readb(EP93XX_GPIO_A_INT_STATUS);
-       for (i = 0; i < 8; i++) {
-               if (status & (1 << i)) {
-                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_A(0)) + i;
-                       generic_handle_irq(gpio_irq);
-               }
-       }
+       chained_irq_enter(irqchip, desc);
 
-       status = readb(EP93XX_GPIO_B_INT_STATUS);
-       for (i = 0; i < 8; i++) {
-               if (status & (1 << i)) {
-                       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_B(0)) + i;
-                       generic_handle_irq(gpio_irq);
-               }
-       }
+       /*
+        * Dispatch the IRQs to the irqdomain of each A and B
+        * gpiochip irqdomains depending on what has fired.
+        * The tricky part is that the IRQ line is shared
+        * between bank A and B and each has their own gpiochip.
+        */
+       stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
+       for_each_set_bit(offset, &stat, 8)
+               generic_handle_irq(irq_find_mapping(epg->gc[0].irq.domain,
+                                                   offset));
+
+       stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
+       for_each_set_bit(offset, &stat, 8)
+               generic_handle_irq(irq_find_mapping(epg->gc[1].irq.domain,
+                                                   offset));
+
+       chained_irq_exit(irqchip, desc);
 }
 
 static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
@@ -106,60 +138,67 @@ static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
        /*
         * map discontiguous hw irq range to continuous sw irq range:
         *
-        *  IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7})
+        *  IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7}
         */
+       struct irq_chip *irqchip = irq_desc_get_chip(desc);
        unsigned int irq = irq_desc_get_irq(desc);
        int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */
-       int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx;
+       int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
 
+       chained_irq_enter(irqchip, desc);
        generic_handle_irq(gpio_irq);
+       chained_irq_exit(irqchip, desc);
 }
 
 static void ep93xx_gpio_irq_ack(struct irq_data *d)
 {
-       int line = irq_to_gpio(d->irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
+       int port_mask = BIT(d->irq & 7);
 
        if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
                gpio_int_type2[port] ^= port_mask; /* switch edge direction */
-               ep93xx_gpio_update_int_params(port);
+               ep93xx_gpio_update_int_params(epg, port);
        }
 
-       writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+       writeb(port_mask, epg->base + eoi_register_offset[port]);
 }
 
 static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
 {
-       int line = irq_to_gpio(d->irq);
-       int port = line >> 3;
-       int port_mask = 1 << (line & 7);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
+       int port_mask = BIT(d->irq & 7);
 
        if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
                gpio_int_type2[port] ^= port_mask; /* switch edge direction */
 
        gpio_int_unmasked[port] &= ~port_mask;
-       ep93xx_gpio_update_int_params(port);
+       ep93xx_gpio_update_int_params(epg, port);
 
-       writeb(port_mask, EP93XX_GPIO_REG(eoi_register_offset[port]));
+       writeb(port_mask, epg->base + eoi_register_offset[port]);
 }
 
 static void ep93xx_gpio_irq_mask(struct irq_data *d)
 {
-       int line = irq_to_gpio(d->irq);
-       int port = line >> 3;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
 
-       gpio_int_unmasked[port] &= ~(1 << (line & 7));
-       ep93xx_gpio_update_int_params(port);
+       gpio_int_unmasked[port] &= ~BIT(d->irq & 7);
+       ep93xx_gpio_update_int_params(epg, port);
 }
 
 static void ep93xx_gpio_irq_unmask(struct irq_data *d)
 {
-       int line = irq_to_gpio(d->irq);
-       int port = line >> 3;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
 
-       gpio_int_unmasked[port] |= 1 << (line & 7);
-       ep93xx_gpio_update_int_params(port);
+       gpio_int_unmasked[port] |= BIT(d->irq & 7);
+       ep93xx_gpio_update_int_params(epg, port);
 }
 
 /*
@@ -169,12 +208,14 @@ static void ep93xx_gpio_irq_unmask(struct irq_data *d)
  */
 static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
 {
-       const int gpio = irq_to_gpio(d->irq);
-       const int port = gpio >> 3;
-       const int port_mask = 1 << (gpio & 7);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ep93xx_gpio *epg = gpiochip_get_data(gc);
+       int port = ep93xx_gpio_port(gc);
+       int offset = d->irq & 7;
+       int port_mask = BIT(offset);
        irq_flow_handler_t handler;
 
-       gpio_direction_input(gpio);
+       gc->direction_input(gc, offset);
 
        switch (type) {
        case IRQ_TYPE_EDGE_RISING:
@@ -200,7 +241,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
        case IRQ_TYPE_EDGE_BOTH:
                gpio_int_type1[port] |= port_mask;
                /* set initial polarity based on current input level */
-               if (gpio_get_value(gpio))
+               if (gc->get(gc, offset))
                        gpio_int_type2[port] &= ~port_mask; /* falling */
                else
                        gpio_int_type2[port] |= port_mask; /* rising */
@@ -214,7 +255,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
 
        gpio_int_enabled[port] |= port_mask;
 
-       ep93xx_gpio_update_int_params(port);
+       ep93xx_gpio_update_int_params(epg, port);
 
        return 0;
 }
@@ -228,35 +269,53 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
        .irq_set_type   = ep93xx_gpio_irq_type,
 };
 
-static void ep93xx_gpio_init_irq(void)
+static int ep93xx_gpio_init_irq(struct platform_device *pdev,
+                               struct ep93xx_gpio *epg)
 {
+       int ab_parent_irq = platform_get_irq(pdev, 0);
+       struct device *dev = &pdev->dev;
        int gpio_irq;
+       int ret;
+       int i;
 
-       for (gpio_irq = gpio_to_irq(0);
-            gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) {
+       /* The A bank */
+       ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
+                                   64, handle_level_irq,
+                                   IRQ_TYPE_NONE);
+       if (ret) {
+               dev_err(dev, "Could not add irqchip 0\n");
+               return ret;
+       }
+       gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
+                                    ab_parent_irq,
+                                    ep93xx_gpio_ab_irq_handler);
+
+       /* The B bank */
+       ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
+                                   72, handle_level_irq,
+                                   IRQ_TYPE_NONE);
+       if (ret) {
+               dev_err(dev, "Could not add irqchip 1\n");
+               return ret;
+       }
+       gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
+                                    ab_parent_irq,
+                                    ep93xx_gpio_ab_irq_handler);
+
+       /* The F bank */
+       for (i = 0; i < 8; i++) {
+               gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
+               irq_set_chip_data(gpio_irq, &epg->gc[5]);
                irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
                                         handle_level_irq);
                irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
        }
 
-       irq_set_chained_handler(IRQ_EP93XX_GPIO_AB,
-                               ep93xx_gpio_ab_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO0MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO1MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO2MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO3MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO4MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO5MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO6MUX,
-                               ep93xx_gpio_f_irq_handler);
-       irq_set_chained_handler(IRQ_EP93XX_GPIO7MUX,
-                               ep93xx_gpio_f_irq_handler);
+       for (i = 1; i <= 8; i++)
+               irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
+                                                ep93xx_gpio_f_irq_handler,
+                                                &epg->gc[i]);
+       return 0;
 }
 
 
@@ -268,68 +327,54 @@ struct ep93xx_gpio_bank {
        int             data;
        int             dir;
        int             base;
-       bool            has_debounce;
+       bool            has_irq;
 };
 
-#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _debounce)        \
+#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
        {                                                       \
                .label          = _label,                       \
                .data           = _data,                        \
                .dir            = _dir,                         \
                .base           = _base,                        \
-               .has_debounce   = _debounce,                    \
+               .has_irq        = _has_irq,                     \
        }
 
 static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
-       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true),
-       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true),
+       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
+       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
        EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
        EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
        EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
-       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true),
+       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
        EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
        EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
 };
 
-static int ep93xx_gpio_set_config(struct gpio_chip *chip, unsigned offset,
+static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
                                  unsigned long config)
 {
-       int gpio = chip->base + offset;
-       int irq = gpio_to_irq(gpio);
        u32 debounce;
 
        if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
                return -ENOTSUPP;
 
-       if (irq < 0)
-               return -EINVAL;
-
        debounce = pinconf_to_config_argument(config);
-       ep93xx_gpio_int_debounce(irq, debounce ? true : false);
+       ep93xx_gpio_int_debounce(gc, offset, debounce ? true : false);
 
        return 0;
 }
 
-/*
- * Map GPIO A0..A7  (0..7)  to irq 64..71,
- *          B0..B7  (7..15) to irq 72..79, and
- *          F0..F7 (16..24) to irq 80..87.
- */
-static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
 {
-       int gpio = chip->base + offset;
-
-       if (gpio > EP93XX_GPIO_LINE_MAX_IRQ)
-               return -EINVAL;
-
-       return 64 + gpio;
+       return EP93XX_GPIO_F_IRQ_BASE + offset;
 }
 
 static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
-       void __iomem *mmio_base, struct ep93xx_gpio_bank *bank)
+                               struct ep93xx_gpio *epg,
+                               struct ep93xx_gpio_bank *bank)
 {
-       void __iomem *data = mmio_base + bank->data;
-       void __iomem *dir =  mmio_base + bank->dir;
+       void __iomem *data = epg->base + bank->data;
+       void __iomem *dir = epg->base + bank->dir;
        int err;
 
        err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
@@ -339,41 +384,41 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
        gc->label = bank->label;
        gc->base = bank->base;
 
-       if (bank->has_debounce) {
+       if (bank->has_irq)
                gc->set_config = ep93xx_gpio_set_config;
-               gc->to_irq = ep93xx_gpio_to_irq;
-       }
 
-       return devm_gpiochip_add_data(dev, gc, NULL);
+       return devm_gpiochip_add_data(dev, gc, epg);
 }
 
 static int ep93xx_gpio_probe(struct platform_device *pdev)
 {
-       struct ep93xx_gpio *ep93xx_gpio;
+       struct ep93xx_gpio *epg;
        struct resource *res;
        int i;
        struct device *dev = &pdev->dev;
 
-       ep93xx_gpio = devm_kzalloc(dev, sizeof(struct ep93xx_gpio), GFP_KERNEL);
-       if (!ep93xx_gpio)
+       epg = devm_kzalloc(dev, sizeof(*epg), GFP_KERNEL);
+       if (!epg)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       ep93xx_gpio->mmio_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(ep93xx_gpio->mmio_base))
-               return PTR_ERR(ep93xx_gpio->mmio_base);
+       epg->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(epg->base))
+               return PTR_ERR(epg->base);
 
        for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
-               struct gpio_chip *gc = &ep93xx_gpio->gc[i];
+               struct gpio_chip *gc = &epg->gc[i];
                struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
 
-               if (ep93xx_gpio_add_bank(gc, &pdev->dev,
-                                        ep93xx_gpio->mmio_base, bank))
+               if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
                        dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
-                               bank->label);
+                                bank->label);
+               /* Only bank F has especially funky IRQ handling */
+               if (i == 5)
+                       gc->to_irq = ep93xx_gpio_f_to_irq;
        }
 
-       ep93xx_gpio_init_irq();
+       ep93xx_gpio_init_irq(pdev, epg);
 
        return 0;
 }
index 868bf8501560de42c863959886178a3baf74c138..95f578804b0eca205ba4fe8d9015363386e5cdaf 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/bitops.h>
+#include <linux/clk.h>
 
 /* GPIO registers definition */
 #define GPIO_DATA_OUT          0x00
  * struct ftgpio_gpio - Gemini GPIO state container
  * @dev: containing device for this instance
  * @gc: gpiochip for this instance
+ * @base: remapped I/O-memory base
+ * @clk: silicon clock
  */
 struct ftgpio_gpio {
        struct device *dev;
        struct gpio_chip gc;
        void __iomem *base;
+       struct clk *clk;
 };
 
 static void ftgpio_gpio_ack_irq(struct irq_data *d)
@@ -157,6 +161,73 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
        chained_irq_exit(irqchip, desc);
 }
 
+static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+                                 unsigned long config)
+{
+       enum pin_config_param param = pinconf_to_config_param(config);
+       u32 arg = pinconf_to_config_argument(config);
+       struct ftgpio_gpio *g = gpiochip_get_data(gc);
+       unsigned long pclk_freq;
+       u32 deb_div;
+       u32 val;
+
+       if (param != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       /*
+        * Debounce only works if interrupts are enabled. The manual
+        * states that if PCLK is 66 MHz, and this is set to 0x7D0, then
+        * PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is
+        * 2000 decimal, so what they mean is simply that the PCLK is
+        * divided by this value.
+        *
+        * As we get a debounce setting in microseconds, we calculate the
+        * desired period time and see if we can get a suitable debounce
+        * time.
+        */
+       pclk_freq = clk_get_rate(g->clk);
+       deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg);
+
+       /* This register is only 24 bits wide */
+       if (deb_div > (1 << 24))
+               return -ENOTSUPP;
+
+       dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n",
+               deb_div, (pclk_freq/deb_div));
+
+       val = readl(g->base + GPIO_DEBOUNCE_PRESCALE);
+       if (val == deb_div) {
+               /*
+                * The debounce timer happens to already be set to the
+                * desireable value, what a coincidence! We can just enable
+                * debounce on this GPIO line and return. This happens more
+                * often than you think, for example when all GPIO keys
+                * on a system are requesting the same debounce interval.
+                */
+               val = readl(g->base + GPIO_DEBOUNCE_EN);
+               val |= BIT(offset);
+               writel(val, g->base + GPIO_DEBOUNCE_EN);
+               return 0;
+       }
+
+       val = readl(g->base + GPIO_DEBOUNCE_EN);
+       if (val) {
+               /*
+                * Oh no! Someone is already using the debounce with
+                * another setting than what we need. Bummer.
+                */
+               return -ENOTSUPP;
+       }
+
+       /* First come, first serve */
+       writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE);
+       /* Enable debounce */
+       val |= BIT(offset);
+       writel(val, g->base + GPIO_DEBOUNCE_EN);
+
+       return 0;
+}
+
 static int ftgpio_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -180,6 +251,19 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        if (irq <= 0)
                return irq ? irq : -EINVAL;
 
+       g->clk = devm_clk_get(dev, NULL);
+       if (!IS_ERR(g->clk)) {
+               ret = clk_prepare_enable(g->clk);
+               if (ret)
+                       return ret;
+       } else if (PTR_ERR(g->clk) == -EPROBE_DEFER) {
+               /*
+                * Percolate deferrals, for anything else,
+                * just live without the clocking.
+                */
+               return PTR_ERR(g->clk);
+       }
+
        ret = bgpio_init(&g->gc, dev, 4,
                         g->base + GPIO_DATA_IN,
                         g->base + GPIO_DATA_SET,
@@ -189,7 +273,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
                         0);
        if (ret) {
                dev_err(dev, "unable to init generic GPIO\n");
-               return ret;
+               goto dis_clk;
        }
        g->gc.label = "FTGPIO010";
        g->gc.base = -1;
@@ -197,28 +281,50 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        g->gc.owner = THIS_MODULE;
        /* ngpio is set by bgpio_init() */
 
+       /* We need a silicon clock to do debounce */
+       if (!IS_ERR(g->clk))
+               g->gc.set_config = ftgpio_gpio_set_config;
+
        ret = devm_gpiochip_add_data(dev, &g->gc, g);
        if (ret)
-               return ret;
+               goto dis_clk;
 
        /* Disable, unmask and clear all interrupts */
        writel(0x0, g->base + GPIO_INT_EN);
        writel(0x0, g->base + GPIO_INT_MASK);
        writel(~0x0, g->base + GPIO_INT_CLR);
 
+       /* Clear any use of debounce */
+       writel(0x0, g->base + GPIO_DEBOUNCE_EN);
+
        ret = gpiochip_irqchip_add(&g->gc, &ftgpio_gpio_irqchip,
                                   0, handle_bad_irq,
                                   IRQ_TYPE_NONE);
        if (ret) {
                dev_info(dev, "could not add irqchip\n");
-               return ret;
+               goto dis_clk;
        }
        gpiochip_set_chained_irqchip(&g->gc, &ftgpio_gpio_irqchip,
                                     irq, ftgpio_gpio_irq_handler);
 
+       platform_set_drvdata(pdev, g);
        dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
 
        return 0;
+
+dis_clk:
+       if (!IS_ERR(g->clk))
+               clk_disable_unprepare(g->clk);
+       return ret;
+}
+
+static int ftgpio_gpio_remove(struct platform_device *pdev)
+{
+       struct ftgpio_gpio *g = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(g->clk))
+               clk_disable_unprepare(g->clk);
+       return 0;
 }
 
 static const struct of_device_id ftgpio_gpio_of_match[] = {
@@ -239,6 +345,7 @@ static struct platform_driver ftgpio_gpio_driver = {
                .name           = "ftgpio010-gpio",
                .of_match_table = of_match_ptr(ftgpio_gpio_of_match),
        },
-       .probe  = ftgpio_gpio_probe,
+       .probe = ftgpio_gpio_probe,
+       .remove = ftgpio_gpio_remove,
 };
 builtin_platform_driver(ftgpio_gpio_driver);
index ad6e5b5186691b01ed7cd301acc6a95985c41933..9d3ac51a765c1405b4fe0ec68e2beec9b2dd1dfd 100644 (file)
@@ -189,7 +189,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
        unsigned long     flag;
        struct egpio_chip *egpio;
        struct egpio_info *ei;
-       unsigned          bit;
        int               pos;
        int               reg;
        int               shift;
@@ -199,7 +198,6 @@ static void egpio_set(struct gpio_chip *chip, unsigned offset, int value)
 
        egpio = gpiochip_get_data(chip);
        ei    = dev_get_drvdata(egpio->dev);
-       bit   = egpio_bit(ei, offset);
        pos   = egpio_pos(ei, offset);
        reg   = egpio->reg_start + pos;
        shift = pos << ei->reg_shift;
@@ -334,7 +332,13 @@ static int __init egpio_probe(struct platform_device *pdev)
                ei->chip[i].is_out = pdata->chip[i].direction;
                ei->chip[i].dev = &(pdev->dev);
                chip = &(ei->chip[i].chip);
-               chip->label           = "htc-egpio";
+               chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                            "htc-egpio-%d",
+                                            i);
+               if (!chip->label) {
+                       ret = -ENOMEM;
+                       goto fail;
+               }
                chip->parent          = &pdev->dev;
                chip->owner           = THIS_MODULE;
                chip->get             = egpio_get;
index b5b9cb1fda5090780302a0a5074f8bc7972894c6..9a8876abeb572031d53f6503fe1fbf3c622eccbc 100644 (file)
@@ -313,18 +313,21 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset,
 
 static void gpiod_set_array_single_value_cansleep(unsigned int ndescs,
                                                  struct gpio_desc **desc,
+                                                 struct gpio_array *info,
                                                  int value)
 {
-       int i, *values;
+       unsigned long *values;
 
-       values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL);
+       values = bitmap_alloc(ndescs, GFP_KERNEL);
        if (!values)
                return;
 
-       for (i = 0; i < ndescs; i++)
-               values[i] = value;
+       if (value)
+               bitmap_fill(values, ndescs);
+       else
+               bitmap_zero(values, ndescs);
 
-       gpiod_set_array_value_cansleep(ndescs, desc, values);
+       gpiod_set_array_value_cansleep(ndescs, desc, info, values);
        kfree(values);
 }
 
@@ -397,7 +400,8 @@ static int max3191x_probe(struct spi_device *spi)
        if (max3191x->modesel_pins)
                gpiod_set_array_single_value_cansleep(
                                 max3191x->modesel_pins->ndescs,
-                                max3191x->modesel_pins->desc, max3191x->mode);
+                                max3191x->modesel_pins->desc,
+                                max3191x->modesel_pins->info, max3191x->mode);
 
        max3191x->ignore_uv = device_property_read_bool(dev,
                                                  "maxim,ignore-undervoltage");
index 935292a30c9979f4420d97437f9d875a32785ed1..50bdc29591c059612b0c5d58b0f3ce8cedfd32c6 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Generic driver for memory-mapped GPIO controllers.
  *
  * Copyright 2008 MontaVista Software, Inc.
  * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
  *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
  * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
  * ...``                                                         ```````..
  * ..The simplest form of a GPIO controller that the driver supports is``
index d66b7a768ecd264d5872997e6acf8715344640e8..8269cffc2967f772ba2da14e566fd136bb68da56 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/irq_sim.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
+#include <linux/property.h>
 
 #include "gpiolib.h"
 
@@ -28,6 +29,8 @@
  * of GPIO lines.
  */
 #define GPIO_MOCKUP_MAX_RANGES (GPIO_MOCKUP_MAX_GC * 2)
+/* Maximum of three properties + the sentinel. */
+#define GPIO_MOCKUP_MAX_PROP   4
 
 #define gpio_mockup_err(...)   pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
 
@@ -59,13 +62,6 @@ struct gpio_mockup_dbgfs_private {
        int offset;
 };
 
-struct gpio_mockup_platform_data {
-       int base;
-       int ngpio;
-       int index;
-       bool named_lines;
-};
-
 static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
 static int gpio_mockup_num_ranges;
 module_param_array(gpio_mockup_ranges, int, &gpio_mockup_num_ranges, 0400);
@@ -255,26 +251,37 @@ static int gpio_mockup_name_lines(struct device *dev,
 
 static int gpio_mockup_probe(struct platform_device *pdev)
 {
-       struct gpio_mockup_platform_data *pdata;
        struct gpio_mockup_chip *chip;
        struct gpio_chip *gc;
-       int rv, base, ngpio;
        struct device *dev;
-       char *name;
+       const char *name;
+       int rv, base;
+       u16 ngpio;
 
        dev = &pdev->dev;
-       pdata = dev_get_platdata(dev);
-       base = pdata->base;
-       ngpio = pdata->ngpio;
+
+       rv = device_property_read_u32(dev, "gpio-base", &base);
+       if (rv)
+               base = -1;
+
+       rv = device_property_read_u16(dev, "nr-gpios", &ngpio);
+       if (rv)
+               return rv;
+
+       rv = device_property_read_string(dev, "chip-name", &name);
+       if (rv)
+               name = NULL;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;
 
-       name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c",
-                             pdev->name, pdata->index);
-       if (!name)
-               return -ENOMEM;
+       if (!name) {
+               name = devm_kasprintf(dev, GFP_KERNEL,
+                                     "%s-%c", pdev->name, pdev->id + 'A');
+               if (!name)
+                       return -ENOMEM;
+       }
 
        gc = &chip->gc;
        gc->base = base;
@@ -295,7 +302,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
        if (!chip->lines)
                return -ENOMEM;
 
-       if (pdata->named_lines) {
+       if (device_property_read_bool(dev, "named-gpio-lines")) {
                rv = gpio_mockup_name_lines(dev, chip);
                if (rv)
                        return rv;
@@ -339,9 +346,11 @@ static void gpio_mockup_unregister_pdevs(void)
 
 static int __init gpio_mockup_init(void)
 {
-       int i, num_chips, err = 0, index = 'A';
-       struct gpio_mockup_platform_data pdata;
+       struct property_entry properties[GPIO_MOCKUP_MAX_PROP];
+       int i, prop, num_chips, err = 0, base;
+       struct platform_device_info pdevinfo;
        struct platform_device *pdev;
+       u16 ngpio;
 
        if ((gpio_mockup_num_ranges < 2) ||
            (gpio_mockup_num_ranges % 2) ||
@@ -371,17 +380,28 @@ static int __init gpio_mockup_init(void)
        }
 
        for (i = 0; i < num_chips; i++) {
-               pdata.index = index++;
-               pdata.base = gpio_mockup_range_base(i);
-               pdata.ngpio = pdata.base < 0
-                               ? gpio_mockup_range_ngpio(i)
-                               : gpio_mockup_range_ngpio(i) - pdata.base;
-               pdata.named_lines = gpio_mockup_named_lines;
-
-               pdev = platform_device_register_resndata(NULL,
-                                                        GPIO_MOCKUP_NAME,
-                                                        i, NULL, 0, &pdata,
-                                                        sizeof(pdata));
+               memset(properties, 0, sizeof(properties));
+               memset(&pdevinfo, 0, sizeof(pdevinfo));
+               prop = 0;
+
+               base = gpio_mockup_range_base(i);
+               if (base >= 0)
+                       properties[prop++] = PROPERTY_ENTRY_U32("gpio-base",
+                                                               base);
+
+               ngpio = base < 0 ? gpio_mockup_range_ngpio(i)
+                                : gpio_mockup_range_ngpio(i) - base;
+               properties[prop++] = PROPERTY_ENTRY_U16("nr-gpios", ngpio);
+
+               if (gpio_mockup_named_lines)
+                       properties[prop++] = PROPERTY_ENTRY_BOOL(
+                                               "named-gpio-lines");
+
+               pdevinfo.name = GPIO_MOCKUP_NAME;
+               pdevinfo.id = i;
+               pdevinfo.properties = properties;
+
+               pdev = platform_device_register_full(&pdevinfo);
                if (IS_ERR(pdev)) {
                        gpio_mockup_err("error registering device");
                        platform_driver_unregister(&gpio_mockup_driver);
index df30490da820da8f4c31fce7df386e2e0efb50a8..ea874fd033a5e2da19b4d3d8e6fb02afd598180d 100644 (file)
@@ -18,8 +18,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/gpio/driver.h>
-/* FIXME: for gpio_get_value(), replace this by direct register read */
-#include <linux/gpio.h>
 #include <linux/module.h>
 
 #define MXS_SET                0x4
@@ -86,7 +84,7 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
        port->both_edges &= ~pin_mask;
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
-               val = gpio_get_value(port->gc.base + d->hwirq);
+               val = port->gc.get(&port->gc, d->hwirq);
                if (val)
                        edge = GPIO_INT_FALL_EDGE;
                else
index e81008678a38f5c36987b37a83bac80ccaccae8a..9887c3db6e16ace91790fbb938452584512e45c5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/cpu_pm.h>
 #include <linux/device.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm.h>
 #include <linux/bitops.h>
 #include <linux/platform_data/gpio-omap.h>
 
-#define OFF_MODE       1
 #define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF
 
-static LIST_HEAD(omap_gpio_list);
+#define OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER    BIT(2)
+#define OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN       BIT(1)
 
 struct gpio_regs {
        u32 irqenable1;
@@ -48,6 +49,13 @@ struct gpio_regs {
        u32 debounce_en;
 };
 
+struct gpio_bank;
+
+struct gpio_omap_funcs {
+       void (*idle_enable_level_quirk)(struct gpio_bank *bank);
+       void (*idle_disable_level_quirk)(struct gpio_bank *bank);
+};
+
 struct gpio_bank {
        struct list_head node;
        void __iomem *base;
@@ -55,6 +63,7 @@ struct gpio_bank {
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
        struct gpio_regs context;
+       struct gpio_omap_funcs funcs;
        u32 saved_datain;
        u32 level_mask;
        u32 toggle_mask;
@@ -62,6 +71,8 @@ struct gpio_bank {
        raw_spinlock_t wa_lock;
        struct gpio_chip chip;
        struct clk *dbck;
+       struct notifier_block nb;
+       unsigned int is_suspended:1;
        u32 mod_usage;
        u32 irq_usage;
        u32 dbck_enable_mask;
@@ -73,8 +84,8 @@ struct gpio_bank {
        int stride;
        u32 width;
        int context_loss_count;
-       int power_mode;
        bool workaround_enabled;
+       u32 quirks;
 
        void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
        void (*set_dataout_multiple)(struct gpio_bank *bank,
@@ -368,9 +379,18 @@ static inline void omap_set_gpio_trigger(struct gpio_bank *bank, int gpio,
                        readl_relaxed(bank->base + bank->regs->fallingdetect);
 
        if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
-               omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit, trigger != 0);
-               bank->context.wake_en =
-                       readl_relaxed(bank->base + bank->regs->wkup_en);
+               /* Defer wkup_en register update until we idle? */
+               if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
+                       if (trigger)
+                               bank->context.wake_en |= gpio_bit;
+                       else
+                               bank->context.wake_en &= ~gpio_bit;
+               } else {
+                       omap_gpio_rmw(base, bank->regs->wkup_en, gpio_bit,
+                                     trigger != 0);
+                       bank->context.wake_en =
+                               readl_relaxed(bank->base + bank->regs->wkup_en);
+               }
        }
 
        /* This part needs to be executed always for OMAP{34xx, 44xx} */
@@ -682,12 +702,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
        struct gpio_bank *bank = gpiochip_get_data(chip);
        unsigned long flags;
 
-       /*
-        * If this is the first gpio_request for the bank,
-        * enable the bank module.
-        */
-       if (!BANK_USED(bank))
-               pm_runtime_get_sync(chip->parent);
+       pm_runtime_get_sync(chip->parent);
 
        raw_spin_lock_irqsave(&bank->lock, flags);
        omap_enable_gpio_module(bank, offset);
@@ -711,12 +726,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
        omap_disable_gpio_module(bank, offset);
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 
-       /*
-        * If this is the last gpio to be freed in the bank,
-        * disable the bank module.
-        */
-       if (!BANK_USED(bank))
-               pm_runtime_put(chip->parent);
+       pm_runtime_put(chip->parent);
 }
 
 /*
@@ -741,7 +751,9 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
        if (WARN_ON(!isr_reg))
                goto exit;
 
-       pm_runtime_get_sync(bank->chip.parent);
+       if (WARN_ONCE(!pm_runtime_active(bank->chip.parent),
+                     "gpio irq%i while runtime suspended?\n", irq))
+               return IRQ_NONE;
 
        while (1) {
                raw_spin_lock_irqsave(&bank->lock, lock_flags);
@@ -792,7 +804,6 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
                }
        }
 exit:
-       pm_runtime_put(bank->chip.parent);
        return IRQ_HANDLED;
 }
 
@@ -841,20 +852,14 @@ static void omap_gpio_irq_bus_lock(struct irq_data *data)
 {
        struct gpio_bank *bank = omap_irq_data_get_bank(data);
 
-       if (!BANK_USED(bank))
-               pm_runtime_get_sync(bank->chip.parent);
+       pm_runtime_get_sync(bank->chip.parent);
 }
 
 static void gpio_irq_bus_sync_unlock(struct irq_data *data)
 {
        struct gpio_bank *bank = omap_irq_data_get_bank(data);
 
-       /*
-        * If this is the last IRQ to be freed in the bank,
-        * disable the bank module.
-        */
-       if (!BANK_USED(bank))
-               pm_runtime_put(bank->chip.parent);
+       pm_runtime_put(bank->chip.parent);
 }
 
 static void omap_gpio_ack_irq(struct irq_data *d)
@@ -899,6 +904,82 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 }
 
+/*
+ * Only edges can generate a wakeup event to the PRCM.
+ *
+ * Therefore, ensure any wake-up capable GPIOs have
+ * edge-detection enabled before going idle to ensure a wakeup
+ * to the PRCM is generated on a GPIO transition. (c.f. 34xx
+ * NDA TRM 25.5.3.1)
+ *
+ * The normal values will be restored upon ->runtime_resume()
+ * by writing back the values saved in bank->context.
+ */
+static void __maybe_unused
+omap2_gpio_enable_level_quirk(struct gpio_bank *bank)
+{
+       u32 wake_low, wake_hi;
+
+       /* Enable additional edge detection for level gpios for idle */
+       wake_low = bank->context.leveldetect0 & bank->context.wake_en;
+       if (wake_low)
+               writel_relaxed(wake_low | bank->context.fallingdetect,
+                              bank->base + bank->regs->fallingdetect);
+
+       wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
+       if (wake_hi)
+               writel_relaxed(wake_hi | bank->context.risingdetect,
+                              bank->base + bank->regs->risingdetect);
+}
+
+static void __maybe_unused
+omap2_gpio_disable_level_quirk(struct gpio_bank *bank)
+{
+       /* Disable edge detection for level gpios after idle */
+       writel_relaxed(bank->context.fallingdetect,
+                      bank->base + bank->regs->fallingdetect);
+       writel_relaxed(bank->context.risingdetect,
+                      bank->base + bank->regs->risingdetect);
+}
+
+/*
+ * On omap4 and later SoC variants a level interrupt with wkup_en
+ * enabled blocks the GPIO functional clock from idling until the GPIO
+ * instance has been reset. To avoid that, we must set wkup_en only for
+ * idle for level interrupts, and clear level registers for the duration
+ * of idle. The level interrupts will be still there on wakeup by their
+ * nature.
+ */
+static void __maybe_unused
+omap4_gpio_enable_level_quirk(struct gpio_bank *bank)
+{
+       /* Update wake register for idle, edge bits might be already set */
+       writel_relaxed(bank->context.wake_en,
+                      bank->base + bank->regs->wkup_en);
+
+       /* Clear level registers for idle */
+       writel_relaxed(0, bank->base + bank->regs->leveldetect0);
+       writel_relaxed(0, bank->base + bank->regs->leveldetect1);
+}
+
+static void __maybe_unused
+omap4_gpio_disable_level_quirk(struct gpio_bank *bank)
+{
+       /* Restore level registers after idle */
+       writel_relaxed(bank->context.leveldetect0,
+                      bank->base + bank->regs->leveldetect0);
+       writel_relaxed(bank->context.leveldetect1,
+                      bank->base + bank->regs->leveldetect1);
+
+       /* Clear saved wkup_en for level, it will be set for next idle again */
+       bank->context.wake_en &= ~(bank->context.leveldetect0 |
+                                  bank->context.leveldetect1);
+
+       /* Update wake with only edge configuration */
+       writel_relaxed(bank->context.wake_en,
+                      bank->base + bank->regs->wkup_en);
+}
+
 /*---------------------------------------------------------------------*/
 
 static int omap_mpuio_suspend_noirq(struct device *dev)
@@ -1218,6 +1299,36 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        return ret;
 }
 
+static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context);
+static void omap_gpio_unidle(struct gpio_bank *bank);
+
+static int gpio_omap_cpu_notifier(struct notifier_block *nb,
+                                 unsigned long cmd, void *v)
+{
+       struct gpio_bank *bank;
+       unsigned long flags;
+
+       bank = container_of(nb, struct gpio_bank, nb);
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       switch (cmd) {
+       case CPU_CLUSTER_PM_ENTER:
+               if (bank->is_suspended)
+                       break;
+               omap_gpio_idle(bank, true);
+               break;
+       case CPU_CLUSTER_PM_ENTER_FAILED:
+       case CPU_CLUSTER_PM_EXIT:
+               if (bank->is_suspended)
+                       break;
+               omap_gpio_unidle(bank);
+               break;
+       }
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+       return NOTIFY_OK;
+}
+
 static const struct of_device_id omap_gpio_match[];
 
 static int omap_gpio_probe(struct platform_device *pdev)
@@ -1256,6 +1367,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
        irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
        irqc->name = dev_name(&pdev->dev);
        irqc->flags = IRQCHIP_MASK_ON_SUSPEND;
+       irqc->parent_device = dev;
 
        bank->irq = platform_get_irq(pdev, 0);
        if (bank->irq <= 0) {
@@ -1270,6 +1382,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
        bank->chip.parent = dev;
        bank->chip.owner = THIS_MODULE;
        bank->dbck_flag = pdata->dbck_flag;
+       bank->quirks = pdata->quirks;
        bank->stride = pdata->bank_stride;
        bank->width = pdata->bank_width;
        bank->is_mpuio = pdata->is_mpuio;
@@ -1278,6 +1391,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
 #ifdef CONFIG_OF_GPIO
        bank->chip.of_node = of_node_get(node);
 #endif
+
        if (node) {
                if (!of_property_read_bool(node, "ti,gpio-always-on"))
                        bank->loses_context = true;
@@ -1298,6 +1412,18 @@ static int omap_gpio_probe(struct platform_device *pdev)
                                omap_set_gpio_dataout_mask_multiple;
        }
 
+       if (bank->quirks & OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN) {
+               bank->funcs.idle_enable_level_quirk =
+                       omap4_gpio_enable_level_quirk;
+               bank->funcs.idle_disable_level_quirk =
+                       omap4_gpio_disable_level_quirk;
+       } else if (bank->quirks & OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER) {
+               bank->funcs.idle_enable_level_quirk =
+                       omap2_gpio_enable_level_quirk;
+               bank->funcs.idle_disable_level_quirk =
+                       omap2_gpio_disable_level_quirk;
+       }
+
        raw_spin_lock_init(&bank->lock);
        raw_spin_lock_init(&bank->wa_lock);
 
@@ -1322,7 +1448,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, bank);
 
        pm_runtime_enable(dev);
-       pm_runtime_irq_safe(dev);
        pm_runtime_get_sync(dev);
 
        if (bank->is_mpuio)
@@ -1341,9 +1466,13 @@ static int omap_gpio_probe(struct platform_device *pdev)
 
        omap_gpio_show_rev(bank);
 
-       pm_runtime_put(dev);
+       if (bank->funcs.idle_enable_level_quirk &&
+           bank->funcs.idle_disable_level_quirk) {
+               bank->nb.notifier_call = gpio_omap_cpu_notifier;
+               cpu_pm_register_notifier(&bank->nb);
+       }
 
-       list_add_tail(&bank->node, &omap_gpio_list);
+       pm_runtime_put(dev);
 
        return 0;
 }
@@ -1352,6 +1481,8 @@ static int omap_gpio_remove(struct platform_device *pdev)
 {
        struct gpio_bank *bank = platform_get_drvdata(pdev);
 
+       if (bank->nb.notifier_call)
+               cpu_pm_unregister_notifier(&bank->nb);
        list_del(&bank->node);
        gpiochip_remove(&bank->chip);
        pm_runtime_disable(&pdev->dev);
@@ -1361,48 +1492,22 @@ static int omap_gpio_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_ARCH_OMAP2PLUS
-
-#if defined(CONFIG_PM)
 static void omap_gpio_restore_context(struct gpio_bank *bank);
 
-static int omap_gpio_runtime_suspend(struct device *dev)
+static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       struct device *dev = bank->chip.parent;
        u32 l1 = 0, l2 = 0;
-       unsigned long flags;
-       u32 wake_low, wake_hi;
 
-       raw_spin_lock_irqsave(&bank->lock, flags);
-
-       /*
-        * Only edges can generate a wakeup event to the PRCM.
-        *
-        * Therefore, ensure any wake-up capable GPIOs have
-        * edge-detection enabled before going idle to ensure a wakeup
-        * to the PRCM is generated on a GPIO transition. (c.f. 34xx
-        * NDA TRM 25.5.3.1)
-        *
-        * The normal values will be restored upon ->runtime_resume()
-        * by writing back the values saved in bank->context.
-        */
-       wake_low = bank->context.leveldetect0 & bank->context.wake_en;
-       if (wake_low)
-               writel_relaxed(wake_low | bank->context.fallingdetect,
-                            bank->base + bank->regs->fallingdetect);
-       wake_hi = bank->context.leveldetect1 & bank->context.wake_en;
-       if (wake_hi)
-               writel_relaxed(wake_hi | bank->context.risingdetect,
-                            bank->base + bank->regs->risingdetect);
+       if (bank->funcs.idle_enable_level_quirk)
+               bank->funcs.idle_enable_level_quirk(bank);
 
        if (!bank->enabled_non_wakeup_gpios)
                goto update_gpio_context_count;
 
-       if (bank->power_mode != OFF_MODE) {
-               bank->power_mode = 0;
+       if (!may_lose_context)
                goto update_gpio_context_count;
-       }
+
        /*
         * If going to OFF, remove triggering for all
         * non-wakeup GPIOs.  Otherwise spurious IRQs will be
@@ -1427,23 +1532,16 @@ update_gpio_context_count:
                                bank->get_context_loss_count(dev);
 
        omap_gpio_dbck_disable(bank);
-       raw_spin_unlock_irqrestore(&bank->lock, flags);
-
-       return 0;
 }
 
 static void omap_gpio_init_context(struct gpio_bank *p);
 
-static int omap_gpio_runtime_resume(struct device *dev)
+static void omap_gpio_unidle(struct gpio_bank *bank)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       struct device *dev = bank->chip.parent;
        u32 l = 0, gen, gen0, gen1;
-       unsigned long flags;
        int c;
 
-       raw_spin_lock_irqsave(&bank->lock, flags);
-
        /*
         * On the first resume during the probe, the context has not
         * been initialised and so initialise it now. Also initialise
@@ -1459,16 +1557,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
 
        omap_gpio_dbck_enable(bank);
 
-       /*
-        * In ->runtime_suspend(), level-triggered, wakeup-enabled
-        * GPIOs were set to edge trigger also in order to be able to
-        * generate a PRCM wakeup.  Here we restore the
-        * pre-runtime_suspend() values for edge triggering.
-        */
-       writel_relaxed(bank->context.fallingdetect,
-                    bank->base + bank->regs->fallingdetect);
-       writel_relaxed(bank->context.risingdetect,
-                    bank->base + bank->regs->risingdetect);
+       if (bank->funcs.idle_disable_level_quirk)
+               bank->funcs.idle_disable_level_quirk(bank);
 
        if (bank->loses_context) {
                if (!bank->get_context_loss_count) {
@@ -1478,16 +1568,13 @@ static int omap_gpio_runtime_resume(struct device *dev)
                        if (c != bank->context_loss_count) {
                                omap_gpio_restore_context(bank);
                        } else {
-                               raw_spin_unlock_irqrestore(&bank->lock, flags);
-                               return 0;
+                               return;
                        }
                }
        }
 
-       if (!bank->workaround_enabled) {
-               raw_spin_unlock_irqrestore(&bank->lock, flags);
-               return 0;
-       }
+       if (!bank->workaround_enabled)
+               return;
 
        l = readl_relaxed(bank->base + bank->regs->datain);
 
@@ -1540,41 +1627,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
        }
 
        bank->workaround_enabled = false;
-       raw_spin_unlock_irqrestore(&bank->lock, flags);
-
-       return 0;
-}
-#endif /* CONFIG_PM */
-
-#if IS_BUILTIN(CONFIG_GPIO_OMAP)
-void omap2_gpio_prepare_for_idle(int pwr_mode)
-{
-       struct gpio_bank *bank;
-
-       list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!BANK_USED(bank) || !bank->loses_context)
-                       continue;
-
-               bank->power_mode = pwr_mode;
-
-               pm_runtime_put_sync_suspend(bank->chip.parent);
-       }
-}
-
-void omap2_gpio_resume_after_idle(void)
-{
-       struct gpio_bank *bank;
-
-       list_for_each_entry(bank, &omap_gpio_list, node) {
-               if (!BANK_USED(bank) || !bank->loses_context)
-                       continue;
-
-               pm_runtime_get_sync(bank->chip.parent);
-       }
 }
-#endif
 
-#if defined(CONFIG_PM)
 static void omap_gpio_init_context(struct gpio_bank *p)
 {
        struct omap_gpio_reg_offs *regs = p->regs;
@@ -1631,17 +1685,57 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
        writel_relaxed(bank->context.irqenable2,
                                bank->base + bank->regs->irqenable2);
 }
-#endif /* CONFIG_PM */
-#else
-#define omap_gpio_runtime_suspend NULL
-#define omap_gpio_runtime_resume NULL
-static inline void omap_gpio_init_context(struct gpio_bank *p) {}
-#endif
 
+static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       unsigned long flags;
+       int error = 0;
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       /* Must be idled only by CPU_CLUSTER_PM_ENTER? */
+       if (bank->irq_usage) {
+               error = -EBUSY;
+               goto unlock;
+       }
+       omap_gpio_idle(bank, true);
+       bank->is_suspended = true;
+unlock:
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+       return error;
+}
+
+static int __maybe_unused omap_gpio_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct gpio_bank *bank = platform_get_drvdata(pdev);
+       unsigned long flags;
+       int error = 0;
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       /* Must be unidled only by CPU_CLUSTER_PM_ENTER? */
+       if (bank->irq_usage) {
+               error = -EBUSY;
+               goto unlock;
+       }
+       omap_gpio_unidle(bank);
+       bank->is_suspended = false;
+unlock:
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+
+       return error;
+}
+
+#ifdef CONFIG_ARCH_OMAP2PLUS
 static const struct dev_pm_ops gpio_pm_ops = {
        SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
                                                                        NULL)
 };
+#else
+static const struct dev_pm_ops gpio_pm_ops;
+#endif /* CONFIG_ARCH_OMAP2PLUS */
 
 #if defined(CONFIG_OF)
 static struct omap_gpio_reg_offs omap2_gpio_regs = {
@@ -1690,6 +1784,11 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
        .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
 };
 
+/*
+ * Note that omap2 does not currently support idle modes with context loss so
+ * no need to add OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER quirk flag to save
+ * and restore context.
+ */
 static const struct omap_gpio_platform_data omap2_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
@@ -1700,12 +1799,15 @@ static const struct omap_gpio_platform_data omap3_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
+       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER,
 };
 
 static const struct omap_gpio_platform_data omap4_pdata = {
        .regs = &omap4_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
+       .quirks = OMAP_GPIO_QUIRK_IDLE_REMOVE_TRIGGER |
+                 OMAP_GPIO_QUIRK_DEFERRED_WKUP_EN,
 };
 
 static const struct of_device_id omap_gpio_match[] = {
index c18712dabf93d359a9fc34ed4431d1791dc36aef..bfe4c5c9f41cef3a9c3a483e5283e015d840bc91 100644 (file)
@@ -776,6 +776,9 @@ static int pxa_gpio_suspend(void)
        struct pxa_gpio_bank *c;
        int gpio;
 
+       if (!pchip)
+               return 0;
+
        for_each_gpio_bank(gpio, c, pchip) {
                c->saved_gplr = readl_relaxed(c->regbase + GPLR_OFFSET);
                c->saved_gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
@@ -794,6 +797,9 @@ static void pxa_gpio_resume(void)
        struct pxa_gpio_bank *c;
        int gpio;
 
+       if (!pchip)
+               return;
+
        for_each_gpio_bank(gpio, c, pchip) {
                /* restore level with set/clear */
                writel_relaxed(c->saved_gplr, c->regbase + GPSR_OFFSET);
index 55cc61086d99d10c8921320abe3e3e9c69bdacd7..3c82bb3c20304982ca68692028bf82861d2e95ee 100644 (file)
@@ -321,6 +321,9 @@ static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,
        u32 val, bankmask;
 
        bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
+       if (chip->valid_mask)
+               bankmask &= chip->valid_mask[0];
+
        if (!bankmask)
                return;
 
@@ -558,6 +561,9 @@ static int gpio_rcar_resume(struct device *dev)
        u32 mask;
 
        for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {
+               if (!gpiochip_line_is_valid(&p->gpio_chip, offset))
+                       continue;
+
                mask = BIT(offset);
                /* I/O pin */
                if (!(p->bank_info.iointsel & mask)) {
diff --git a/drivers/gpio/gpio-siox.c b/drivers/gpio/gpio-siox.c
new file mode 100644 (file)
index 0000000..571b2a8
--- /dev/null
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015-2018 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
+ */
+
+#include <linux/module.h>
+#include <linux/siox.h>
+#include <linux/gpio/driver.h>
+#include <linux/of.h>
+
+struct gpio_siox_ddata {
+       struct gpio_chip gchip;
+       struct irq_chip ichip;
+       struct mutex lock;
+       u8 setdata[1];
+       u8 getdata[3];
+
+       spinlock_t irqlock;
+       u32 irq_enable;
+       u32 irq_status;
+       u32 irq_type[20];
+};
+
+/*
+ * Note that this callback only sets the value that is clocked out in the next
+ * cycle.
+ */
+static int gpio_siox_set_data(struct siox_device *sdevice, u8 status, u8 buf[])
+{
+       struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+
+       mutex_lock(&ddata->lock);
+       buf[0] = ddata->setdata[0];
+       mutex_unlock(&ddata->lock);
+
+       return 0;
+}
+
+static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
+{
+       struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+       size_t offset;
+       u32 trigger;
+
+       mutex_lock(&ddata->lock);
+
+       spin_lock_irq(&ddata->irqlock);
+
+       for (offset = 0; offset < 12; ++offset) {
+               unsigned int bitpos = 11 - offset;
+               unsigned int gpiolevel = buf[bitpos / 8] & (1 << bitpos % 8);
+               unsigned int prev_level =
+                       ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
+               u32 irq_type = ddata->irq_type[offset];
+
+               if (gpiolevel) {
+                       if ((irq_type & IRQ_TYPE_LEVEL_HIGH) ||
+                           ((irq_type & IRQ_TYPE_EDGE_RISING) && !prev_level))
+                               ddata->irq_status |= 1 << offset;
+               } else {
+                       if ((irq_type & IRQ_TYPE_LEVEL_LOW) ||
+                           ((irq_type & IRQ_TYPE_EDGE_FALLING) && prev_level))
+                               ddata->irq_status |= 1 << offset;
+               }
+       }
+
+       trigger = ddata->irq_status & ddata->irq_enable;
+
+       spin_unlock_irq(&ddata->irqlock);
+
+       ddata->getdata[0] = buf[0];
+       ddata->getdata[1] = buf[1];
+       ddata->getdata[2] = buf[2];
+
+       mutex_unlock(&ddata->lock);
+
+       for (offset = 0; offset < 12; ++offset) {
+               if (trigger & (1 << offset)) {
+                       struct irq_domain *irqdomain = ddata->gchip.irq.domain;
+                       unsigned int irq = irq_find_mapping(irqdomain, offset);
+
+                       /*
+                        * Conceptually handle_nested_irq should call the flow
+                        * handler of the irq chip. But it doesn't, so we have
+                        * to clean the irq_status here.
+                        */
+                       spin_lock_irq(&ddata->irqlock);
+                       ddata->irq_status &= ~(1 << offset);
+                       spin_unlock_irq(&ddata->irqlock);
+
+                       handle_nested_irq(irq);
+               }
+       }
+
+       return 0;
+}
+
+static void gpio_siox_irq_ack(struct irq_data *d)
+{
+       struct irq_chip *ic = irq_data_get_irq_chip(d);
+       struct gpio_siox_ddata *ddata =
+               container_of(ic, struct gpio_siox_ddata, ichip);
+
+       spin_lock_irq(&ddata->irqlock);
+       ddata->irq_status &= ~(1 << d->hwirq);
+       spin_unlock_irq(&ddata->irqlock);
+}
+
+static void gpio_siox_irq_mask(struct irq_data *d)
+{
+       struct irq_chip *ic = irq_data_get_irq_chip(d);
+       struct gpio_siox_ddata *ddata =
+               container_of(ic, struct gpio_siox_ddata, ichip);
+
+       spin_lock_irq(&ddata->irqlock);
+       ddata->irq_enable &= ~(1 << d->hwirq);
+       spin_unlock_irq(&ddata->irqlock);
+}
+
+static void gpio_siox_irq_unmask(struct irq_data *d)
+{
+       struct irq_chip *ic = irq_data_get_irq_chip(d);
+       struct gpio_siox_ddata *ddata =
+               container_of(ic, struct gpio_siox_ddata, ichip);
+
+       spin_lock_irq(&ddata->irqlock);
+       ddata->irq_enable |= 1 << d->hwirq;
+       spin_unlock_irq(&ddata->irqlock);
+}
+
+static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
+{
+       struct irq_chip *ic = irq_data_get_irq_chip(d);
+       struct gpio_siox_ddata *ddata =
+               container_of(ic, struct gpio_siox_ddata, ichip);
+
+       spin_lock_irq(&ddata->irqlock);
+       ddata->irq_type[d->hwirq] = type;
+       spin_unlock_irq(&ddata->irqlock);
+
+       return 0;
+}
+
+static int gpio_siox_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct gpio_siox_ddata *ddata =
+               container_of(chip, struct gpio_siox_ddata, gchip);
+       int ret;
+
+       mutex_lock(&ddata->lock);
+
+       if (offset >= 12) {
+               unsigned int bitpos = 19 - offset;
+
+               ret = ddata->setdata[0] & (1 << bitpos);
+       } else {
+               unsigned int bitpos = 11 - offset;
+
+               ret = ddata->getdata[bitpos / 8] & (1 << (bitpos % 8));
+       }
+
+       mutex_unlock(&ddata->lock);
+
+       return ret;
+}
+
+static void gpio_siox_set(struct gpio_chip *chip,
+                         unsigned int offset, int value)
+{
+       struct gpio_siox_ddata *ddata =
+               container_of(chip, struct gpio_siox_ddata, gchip);
+       u8 mask = 1 << (19 - offset);
+
+       mutex_lock(&ddata->lock);
+
+       if (value)
+               ddata->setdata[0] |= mask;
+       else
+               ddata->setdata[0] &= ~mask;
+
+       mutex_unlock(&ddata->lock);
+}
+
+static int gpio_siox_direction_input(struct gpio_chip *chip,
+                                    unsigned int offset)
+{
+       if (offset >= 12)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int gpio_siox_direction_output(struct gpio_chip *chip,
+                                     unsigned int offset, int value)
+{
+       if (offset < 12)
+               return -EINVAL;
+
+       gpio_siox_set(chip, offset, value);
+       return 0;
+}
+
+static int gpio_siox_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+       if (offset < 12)
+               return 1; /* input */
+       else
+               return 0; /* output */
+}
+
+static int gpio_siox_probe(struct siox_device *sdevice)
+{
+       struct gpio_siox_ddata *ddata;
+       int ret;
+
+       ddata = devm_kzalloc(&sdevice->dev, sizeof(*ddata), GFP_KERNEL);
+       if (!ddata)
+               return -ENOMEM;
+
+       dev_set_drvdata(&sdevice->dev, ddata);
+
+       mutex_init(&ddata->lock);
+       spin_lock_init(&ddata->irqlock);
+
+       ddata->gchip.base = -1;
+       ddata->gchip.can_sleep = 1;
+       ddata->gchip.parent = &sdevice->dev;
+       ddata->gchip.owner = THIS_MODULE;
+       ddata->gchip.get = gpio_siox_get;
+       ddata->gchip.set = gpio_siox_set;
+       ddata->gchip.direction_input = gpio_siox_direction_input;
+       ddata->gchip.direction_output = gpio_siox_direction_output;
+       ddata->gchip.get_direction = gpio_siox_get_direction;
+       ddata->gchip.ngpio = 20;
+
+       ddata->ichip.name = "siox-gpio";
+       ddata->ichip.irq_ack = gpio_siox_irq_ack;
+       ddata->ichip.irq_mask = gpio_siox_irq_mask;
+       ddata->ichip.irq_unmask = gpio_siox_irq_unmask;
+       ddata->ichip.irq_set_type = gpio_siox_irq_set_type;
+
+       ret = gpiochip_add(&ddata->gchip);
+       if (ret) {
+               dev_err(&sdevice->dev,
+                       "Failed to register gpio chip (%d)\n", ret);
+               goto err_gpiochip;
+       }
+
+       ret = gpiochip_irqchip_add(&ddata->gchip, &ddata->ichip,
+                                  0, handle_level_irq, IRQ_TYPE_EDGE_RISING);
+       if (ret) {
+               dev_err(&sdevice->dev,
+                       "Failed to register irq chip (%d)\n", ret);
+err_gpiochip:
+               gpiochip_remove(&ddata->gchip);
+       }
+
+       return ret;
+}
+
+static int gpio_siox_remove(struct siox_device *sdevice)
+{
+       struct gpio_siox_ddata *ddata = dev_get_drvdata(&sdevice->dev);
+
+       gpiochip_remove(&ddata->gchip);
+       return 0;
+}
+
+static struct siox_driver gpio_siox_driver = {
+       .probe = gpio_siox_probe,
+       .remove = gpio_siox_remove,
+       .set_data = gpio_siox_set_data,
+       .get_data = gpio_siox_get_data,
+       .driver = {
+               .name = "gpio-siox",
+       },
+};
+
+static int __init gpio_siox_init(void)
+{
+       return siox_driver_register(&gpio_siox_driver);
+}
+module_init(gpio_siox_init);
+
+static void __exit gpio_siox_exit(void)
+{
+       siox_driver_unregister(&gpio_siox_driver);
+}
+module_exit(gpio_siox_exit);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("SIOX gpio driver");
+MODULE_LICENSE("GPL v2");
index 87c18a544513768ce03aa38464a77125e6b1c867..7f3da34c78746b7549d8d394337e408e1c2a9768 100644 (file)
@@ -122,7 +122,7 @@ static int syscon_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int val)
                                   BIT(offs % SYSCON_REG_BITS));
        }
 
-       priv->data->set(chip, offset, val);
+       chip->set(chip, offset, val);
 
        return 0;
 }
index a12cd0b5c9721d487583c09b58fddebeaa8ab136..d5e5d19f4c0ad3a051802d3f2c832812b0834eaf 100644 (file)
 
 
 /**
- * @spinlock: used for atomic read/modify/write of registers
  * @base: register base address
  * @domain: IRQ domain of GPIO generated interrupts managed by this controller
  * @irq: Interrupt line of parent interrupt controller
  * @gc: gpio_chip structure associated to this GPIO controller
  */
 struct tb10x_gpio {
-       spinlock_t spinlock;
        void __iomem *base;
        struct irq_domain *domain;
        int irq;
@@ -76,60 +74,14 @@ static inline void tb10x_set_bits(struct tb10x_gpio *gpio, unsigned int offs,
        u32 r;
        unsigned long flags;
 
-       spin_lock_irqsave(&gpio->spinlock, flags);
+       spin_lock_irqsave(&gpio->gc.bgpio_lock, flags);
 
        r = tb10x_reg_read(gpio, offs);
        r = (r & ~mask) | (val & mask);
 
        tb10x_reg_write(gpio, offs, r);
 
-       spin_unlock_irqrestore(&gpio->spinlock, flags);
-}
-
-static int tb10x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-       struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
-       int mask = BIT(offset);
-       int val = TB10X_GPIO_DIR_IN << offset;
-
-       tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
-
-       return 0;
-}
-
-static int tb10x_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
-       int val;
-
-       val = tb10x_reg_read(tb10x_gpio, OFFSET_TO_REG_DATA);
-
-       if (val & BIT(offset))
-               return 1;
-       else
-               return 0;
-}
-
-static void tb10x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
-       int mask = BIT(offset);
-       int val = value << offset;
-
-       tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DATA, mask, val);
-}
-
-static int tb10x_gpio_direction_out(struct gpio_chip *chip,
-                                       unsigned offset, int value)
-{
-       struct tb10x_gpio *tb10x_gpio = gpiochip_get_data(chip);
-       int mask = BIT(offset);
-       int val = TB10X_GPIO_DIR_OUT << offset;
-
-       tb10x_gpio_set(chip, offset, value);
-       tb10x_set_bits(tb10x_gpio, OFFSET_TO_REG_DDR, mask, val);
-
-       return 0;
+       spin_unlock_irqrestore(&gpio->gc.bgpio_lock, flags);
 }
 
 static int tb10x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@@ -169,72 +121,85 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
 {
        struct tb10x_gpio *tb10x_gpio;
        struct resource *mem;
-       struct device_node *dn = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
        int ret = -EBUSY;
        u32 ngpio;
 
-       if (!dn)
+       if (!np)
                return -EINVAL;
 
-       if (of_property_read_u32(dn, "abilis,ngpio", &ngpio))
+       if (of_property_read_u32(np, "abilis,ngpio", &ngpio))
                return -EINVAL;
 
-       tb10x_gpio = devm_kzalloc(&pdev->dev, sizeof(*tb10x_gpio), GFP_KERNEL);
+       tb10x_gpio = devm_kzalloc(dev, sizeof(*tb10x_gpio), GFP_KERNEL);
        if (tb10x_gpio == NULL)
                return -ENOMEM;
 
-       spin_lock_init(&tb10x_gpio->spinlock);
-
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       tb10x_gpio->base = devm_ioremap_resource(&pdev->dev, mem);
+       tb10x_gpio->base = devm_ioremap_resource(dev, mem);
        if (IS_ERR(tb10x_gpio->base))
                return PTR_ERR(tb10x_gpio->base);
 
-       tb10x_gpio->gc.label            =
-               devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
+       tb10x_gpio->gc.label =
+               devm_kasprintf(dev, GFP_KERNEL, "%pOF", pdev->dev.of_node);
        if (!tb10x_gpio->gc.label)
                return -ENOMEM;
 
-       tb10x_gpio->gc.parent           = &pdev->dev;
-       tb10x_gpio->gc.owner            = THIS_MODULE;
-       tb10x_gpio->gc.direction_input  = tb10x_gpio_direction_in;
-       tb10x_gpio->gc.get              = tb10x_gpio_get;
-       tb10x_gpio->gc.direction_output = tb10x_gpio_direction_out;
-       tb10x_gpio->gc.set              = tb10x_gpio_set;
-       tb10x_gpio->gc.request          = gpiochip_generic_request;
-       tb10x_gpio->gc.free             = gpiochip_generic_free;
-       tb10x_gpio->gc.base             = -1;
-       tb10x_gpio->gc.ngpio            = ngpio;
-       tb10x_gpio->gc.can_sleep        = false;
-
-
-       ret = devm_gpiochip_add_data(&pdev->dev, &tb10x_gpio->gc, tb10x_gpio);
+       /*
+        * Initialize generic GPIO with one single register for reading and setting
+        * the lines, no special set or clear registers and a data direction register
+        * wher 1 means "output".
+        */
+       ret = bgpio_init(&tb10x_gpio->gc, dev, 4,
+                        tb10x_gpio->base + OFFSET_TO_REG_DATA,
+                        NULL,
+                        NULL,
+                        tb10x_gpio->base + OFFSET_TO_REG_DDR,
+                        NULL,
+                        0);
+       if (ret) {
+               dev_err(dev, "unable to init generic GPIO\n");
+               return ret;
+       }
+       tb10x_gpio->gc.base = -1;
+       tb10x_gpio->gc.parent = dev;
+       tb10x_gpio->gc.owner = THIS_MODULE;
+       /*
+        * ngpio is set by bgpio_init() but we override it, this .request()
+        * callback also overrides the one set up by generic GPIO.
+        */
+       tb10x_gpio->gc.ngpio = ngpio;
+       tb10x_gpio->gc.request = gpiochip_generic_request;
+       tb10x_gpio->gc.free = gpiochip_generic_free;
+
+       ret = devm_gpiochip_add_data(dev, &tb10x_gpio->gc, tb10x_gpio);
        if (ret < 0) {
-               dev_err(&pdev->dev, "Could not add gpiochip.\n");
+               dev_err(dev, "Could not add gpiochip.\n");
                return ret;
        }
 
        platform_set_drvdata(pdev, tb10x_gpio);
 
-       if (of_find_property(dn, "interrupt-controller", NULL)) {
+       if (of_find_property(np, "interrupt-controller", NULL)) {
                struct irq_chip_generic *gc;
 
                ret = platform_get_irq(pdev, 0);
                if (ret < 0) {
-                       dev_err(&pdev->dev, "No interrupt specified.\n");
+                       dev_err(dev, "No interrupt specified.\n");
                        return ret;
                }
 
                tb10x_gpio->gc.to_irq   = tb10x_gpio_to_irq;
                tb10x_gpio->irq         = ret;
 
-               ret = devm_request_irq(&pdev->dev, ret, tb10x_gpio_irq_cascade,
+               ret = devm_request_irq(dev, ret, tb10x_gpio_irq_cascade,
                                IRQF_TRIGGER_NONE | IRQF_SHARED,
-                               dev_name(&pdev->dev), tb10x_gpio);
+                               dev_name(dev), tb10x_gpio);
                if (ret != 0)
                        return ret;
 
-               tb10x_gpio->domain = irq_domain_add_linear(dn,
+               tb10x_gpio->domain = irq_domain_add_linear(np,
                                                tb10x_gpio->gc.ngpio,
                                                &irq_generic_chip_ops, NULL);
                if (!tb10x_gpio->domain) {
index b23c4d2429be51f47035f1920554e3bf77e122ae..2eea98ff4ea32460de049f655e82f5a5039f8350 100644 (file)
@@ -1,20 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
  *     Andrew F. Davis <afd@ti.com>
  *
- * 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.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License version 2 for more details.
- *
  * Based on the TPS65912 driver
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
index 042b9a20781af42fcda8d5b5a6832afbdcfc31b5..9b6cc74f47c818eff0a1984d057f59ec9c1dcb1b 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * TI TPS6586x GPIO driver
  *
@@ -7,22 +8,10 @@
  * Based on tps6586x.c
  * Copyright (c) 2010 CompuLab Ltd.
  * Mike Rapoport <mike@compulab.co.il>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mfd/tps6586x.h>
index e63d7dabf78b1e61482cc5716b69640efa5d9c9c..0c785b0fd1617aac8a6e9793e0311eadb551e101 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * TI TPS6591x GPIO driver
  *
@@ -5,18 +6,12 @@
  *
  * Author: Graeme Gregory <gg@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
- *  Free Software Foundation;  either version 2 of the License, or (at your
- *  option) any later version.
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/tps65910.h>
index abc0798ef843a485a88b4a520cb529e1b6b99780..3ad68bd78282590103a735c49430b6348276b803 100644 (file)
@@ -1,23 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * GPIO driver for TI TPS65912x PMICs
  *
  * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
  *     Andrew F. Davis <afd@ti.com>
  *
- * 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.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether expressed or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License version 2 for more details.
- *
  * Based on the Arizona GPIO driver and the previous TPS65912 driver by
  * Margarita Olaya Cabrera <magi@slimlogic.co.uk>
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
@@ -40,9 +32,9 @@ static int tps65912_gpio_get_direction(struct gpio_chip *gc,
                return ret;
 
        if (val & GPIO_CFG_MASK)
-               return GPIOF_DIR_OUT;
+               return 0;
        else
-               return GPIOF_DIR_IN;
+               return 1;
 }
 
 static int tps65912_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
index 6cfeba07f8820aa858c637e947f5508af2aef05d..c91890488402539ddff45ffb8d540be1d629bb2d 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Digital I/O driver for Technologic Systems TS-5500
  *
  * TS-5600:
  *   Documentation: http://wiki.embeddedarm.com/wiki/TS-5600
  *   Blocks: LCD port (identical to TS-5500 LCD).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/bitops.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/io.h>
 #include <linux/module.h>
-#include <linux/platform_data/gpio-ts5500.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
@@ -318,7 +314,6 @@ static void ts5500_disable_irq(struct ts5500_priv *priv)
 static int ts5500_dio_probe(struct platform_device *pdev)
 {
        enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data;
-       struct ts5500_dio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        const char *name = dev_name(dev);
        struct ts5500_priv *priv;
@@ -349,10 +344,6 @@ static int ts5500_dio_probe(struct platform_device *pdev)
        priv->gpio_chip.set = ts5500_gpio_set;
        priv->gpio_chip.to_irq = ts5500_gpio_to_irq;
        priv->gpio_chip.base = -1;
-       if (pdata) {
-               priv->gpio_chip.base = pdata->base;
-               priv->strap = pdata->strap;
-       }
 
        switch (block) {
        case TS5500_DIO1:
index 9b511df5450eb6cb0bda513adce296b6ce9287cb..fbfb648d350263426d0d5e00cc888d4e4baadb87 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Access to GPIOs on TWL4030/TPS659x0 chips
  *
@@ -9,20 +10,6 @@
  *
  * Initial Code:
  *     Andy Lowe / Nishanth Menon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
 #include <linux/module.h>
@@ -30,7 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/kthread.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/irqdomain.h>
@@ -167,6 +154,23 @@ static int twl4030_set_gpio_direction(int gpio, int is_input)
        return ret;
 }
 
+static int twl4030_get_gpio_direction(int gpio)
+{
+       u8 d_bnk = gpio >> 3;
+       u8 d_msk = BIT(gpio & 0x7);
+       u8 base = REG_GPIODATADIR1 + d_bnk;
+       int ret = 0;
+
+       ret = gpio_twl4030_read(base);
+       if (ret < 0)
+               return ret;
+
+       /* 1 = output, but gpiolib semantics are inverse so invert */
+       ret = !(ret & d_msk);
+
+       return ret;
+}
+
 static int twl4030_set_gpio_dataout(int gpio, int enable)
 {
        u8 d_bnk = gpio >> 3;
@@ -372,6 +376,28 @@ static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
        return ret;
 }
 
+static int twl_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
+       /*
+        * Default 0 = output
+        * LED GPIOs >= TWL4030_GPIO_MAX are always output
+        */
+       int ret = 0;
+
+       mutex_lock(&priv->mutex);
+       if (offset < TWL4030_GPIO_MAX) {
+               ret = twl4030_get_gpio_direction(offset);
+               if (ret) {
+                       mutex_unlock(&priv->mutex);
+                       return ret;
+               }
+       }
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+
 static int twl_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct gpio_twl4030_priv *priv = gpiochip_get_data(chip);
@@ -387,8 +413,9 @@ static const struct gpio_chip template_chip = {
        .request                = twl_request,
        .free                   = twl_free,
        .direction_input        = twl_direction_in,
-       .get                    = twl_get,
        .direction_output       = twl_direction_out,
+       .get_direction          = twl_get_direction,
+       .get                    = twl_get,
        .set                    = twl_set,
        .to_irq                 = twl_to_irq,
        .can_sleep              = true,
index dadeacf43e0ce492f57447b5b0060163c2bd1081..c845b2ff1f4376082cab35232ed00c09dcf8c4f3 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Access to GPOs on TWL6040 chip
  *
@@ -6,28 +7,15 @@
  * Authors:
  *     Sergio Aguirre <saaguirre@ti.com>
  *     Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kthread.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
+#include <linux/bitops.h>
 #include <linux/of.h>
 
 #include <linux/mfd/twl6040.h>
@@ -41,7 +29,13 @@ static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset)
        if (ret < 0)
                return ret;
 
-       return (ret >> offset) & 1;
+       return !!(ret & BIT(offset));
+}
+
+static int twl6040gpo_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+       /* This means "out" */
+       return 0;
 }
 
 static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset,
@@ -62,9 +56,9 @@ static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value)
                return;
 
        if (value)
-               gpoctl = ret | (1 << offset);
+               gpoctl = ret | BIT(offset);
        else
-               gpoctl = ret & ~(1 << offset);
+               gpoctl = ret & ~BIT(offset);
 
        twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl);
 }
@@ -74,6 +68,7 @@ static struct gpio_chip twl6040gpo_chip = {
        .owner                  = THIS_MODULE,
        .get                    = twl6040gpo_get,
        .direction_output       = twl6040gpo_direction_out,
+       .get_direction          = twl6040gpo_get_direction,
        .set                    = twl6040gpo_set,
        .can_sleep              = true,
 };
index d4ad6d0e02a25be60755b39b600c16cbbcd43981..5960396c8d9a263d835f764b4e0f0de95fe06b30 100644 (file)
@@ -1,23 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Freescale vf610 GPIO support through PORT and GPIO
  *
  * Copyright (c) 2014 Toradex AG.
  *
  * Author: Stefan Agner <stefan@agner.ch>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 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.
  */
-
 #include <linux/bitops.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index e6d1328dddfaf4a4ed161d9545f9e754607707c8..9b604f13e3029d9411c9cba18c90bdac4c2d89f7 100644 (file)
@@ -1,15 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *  Nano River Technologies viperboard GPIO lib driver
  *
  *  (C) 2012 by Lemonage GmbH
  *  Author: Lars Poeschel <poeschel@lemonage.de>
  *  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 as published by the
- *  Free Software Foundation;  either version 2 of the License, or (at your
- *  option) any later version.
- *
  */
 
 #include <linux/kernel.h>
@@ -19,9 +14,8 @@
 #include <linux/types.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
-
 #include <linux/usb.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 
 #include <linux/mfd/viperboard.h>
 
index 027699cec911b5df7d963d61479e80da17f58b39..b13a49c89cc1526bfcf93df686704b78ecdfdc3c 100644 (file)
@@ -1,27 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  *  Driver for NEC VR4100 series General-purpose I/O Unit.
  *
  *  Copyright (C) 2002 MontaVista Software Inc.
  *     Author: Yoichi Yuasa <source@mvista.com>
  *  Copyright (C) 2003-2009  Yoichi Yuasa <yuasa@linux-mips.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -384,44 +371,6 @@ static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
        return 0;
 }
 
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
-       u16 reg, mask;
-       unsigned long flags;
-
-       if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
-               return -EPERM;
-
-       if (pin >= 15)
-               return -EINVAL;
-
-       mask = 1 << pin;
-
-       spin_lock_irqsave(&giu_lock, flags);
-
-       if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
-               reg = giu_read(GIUTERMUPDN);
-               if (pull == GPIO_PULL_UP)
-                       reg |= mask;
-               else
-                       reg &= ~mask;
-               giu_write(GIUTERMUPDN, reg);
-
-               reg = giu_read(GIUUSEUPDN);
-               reg |= mask;
-               giu_write(GIUUSEUPDN, reg);
-       } else {
-               reg = giu_read(GIUUSEUPDN);
-               reg &= ~mask;
-               giu_write(GIUUSEUPDN, reg);
-       }
-
-       spin_unlock_irqrestore(&giu_lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
 static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
 {
        u16 reg, mask;
index 98a6f1fcc561a89f07f6cc396584fdd131a9dc79..4ff146ca32fecad74be7c13e35fec281e424ccfa 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Linux GPIOlib driver for the VIA VX855 integrated southbridge GPIO
  *
@@ -5,27 +6,10 @@
  * Copyright (C) 2010 One Laptop per Child
  * Author: Harald Welte <HaraldWelte@viatech.com>
  * 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 as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
  */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
index 324813e8304e586bf02786ef16d9dcb41e9ba52c..a3a32a77041f98e3b30e590c59a9873247fced32 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * gpiolib support for Wolfson WM831x PMICs
  *
@@ -5,17 +6,12 @@
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/mfd/core.h>
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
index e46752e73dd9066e91d9c9edb55bc15ef0ae02ec..460f0a4b04bd22da631b78f0272fff53589e7777 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * gpiolib support for Wolfson WM835x PMICs
  *
@@ -5,17 +6,12 @@
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/mfd/core.h>
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
index 1e35756ac55b74bd2d53e0575210a9fded1b705a..9af89cf7f6bc9859aa13b1d6b2baebf00c50ac57 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * gpiolib support for Wolfson WM8994
  *
@@ -5,17 +6,12 @@
  *
  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/mfd/core.h>
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
index 8e4275eaa7d73c10194e778835c7fc8f5c10d556..0a3607fd21af76c2a97cbd367a7f71b3f7a46c0f 100644 (file)
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2003-2015 Broadcom Corporation
  * 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 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.
  */
 
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
 #include <linux/module.h>
index f16c0427952e16e435af4734fa7f3f7d8063cd5c..43d3fa5f511aafde5d568e42c6239efcca03bf13 100644 (file)
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2013 TangoTec 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.
- *
  * Driver for the Xtensa LX4 GPIO32 Option
  *
  * Documentation: Xtensa LX4 Microprocessor Data Book, Section 2.22
@@ -30,7 +27,7 @@
 
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/bitops.h>
 #include <linux/platform_device.h>
 
index 3926ce9c28405beb4fed2d94b3baecd0f2490c11..57432397e5e53c7a9310dda924f582e9d242fc22 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/of_device.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 
 /*
  * Memory layout:
index 8b9d7e42c600b60d26bad7f26c32ed938be6e7a2..2b1a7b455aa83303410a34818ece422af6487392 100644 (file)
@@ -1,17 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * ACPI helpers for GPIO API
  *
  * Copyright (C) 2012, Intel Corporation
  * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
  *          Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/errno.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/machine.h>
index f748aa3e77f72000b357718d5c955abba38c5c07..dd517098ab9529df69ed4d5c7ca6af5b299ee813 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Device property helpers for GPIO chips.
  *
  * Copyright (C) 2016, Intel Corporation
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/property.h>
@@ -32,32 +29,29 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip,
        struct gpio_device *gdev = chip->gpiodev;
        const char **names;
        int ret, i;
+       int count;
 
-       ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
-                                               NULL, 0);
-       if (ret < 0)
+       count = fwnode_property_read_string_array(fwnode, "gpio-line-names",
+                                                 NULL, 0);
+       if (count < 0)
                return;
 
-       if (ret != gdev->ngpio) {
-               dev_warn(&gdev->dev,
-                        "names %d do not match number of GPIOs %d\n", ret,
-                        gdev->ngpio);
-               return;
-       }
+       if (count > gdev->ngpio)
+               count = gdev->ngpio;
 
-       names = kcalloc(gdev->ngpio, sizeof(*names), GFP_KERNEL);
+       names = kcalloc(count, sizeof(*names), GFP_KERNEL);
        if (!names)
                return;
 
        ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
-                                               names, gdev->ngpio);
+                                               names, count);
        if (ret < 0) {
                dev_warn(&gdev->dev, "failed to read GPIO line names\n");
                kfree(names);
                return;
        }
 
-       for (i = 0; i < gdev->ngpio; i++)
+       for (i = 0; i < count; i++)
                gdev->descs[i].name = names[i];
 
        kfree(names);
similarity index 96%
rename from drivers/gpio/devres.c
rename to drivers/gpio/gpiolib-devres.c
index e82cc763633cac5de63f7c1b77ddfe14daf39b9a..01959369360bd761cdb6a30c06980363e78ef40d 100644 (file)
@@ -1,14 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * drivers/gpio/devres.c - managed gpio resources
- *
- * 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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * devres.c - managed gpio resources
  * This file is based on kernel/irq/devres.c
  *
  * Copyright (c) 2011 John Crispin <john@phrozen.org>
index 8b830996fe0212d3ae0153ae5b708a84fa53976e..30e2476a6dc4e0a2342e7c4bbe0aa88cc948523d 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 
index d4e7a09598faedbecb1ccdee24e6138b70e4e7d8..7f1260c78270b57ebd60daee22bbbec939125234 100644 (file)
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * OF helpers for the GPIO API
  *
  * Copyright (c) 2007-2008  MontaVista Software, Inc.
  *
  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  */
 
 #include <linux/device.h>
@@ -58,7 +54,8 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
 }
 
 static void of_gpio_flags_quirks(struct device_node *np,
-                                enum of_gpio_flags *flags)
+                                enum of_gpio_flags *flags,
+                                int index)
 {
        /*
         * Some GPIO fixed regulator quirks.
@@ -92,6 +89,51 @@ static void of_gpio_flags_quirks(struct device_node *np,
                pr_info("%s uses legacy open drain flag - update the DTS if you can\n",
                        of_node_full_name(np));
        }
+
+       /*
+        * Legacy handling of SPI active high chip select. If we have a
+        * property named "cs-gpios" we need to inspect the child node
+        * to determine if the flags should have inverted semantics.
+        */
+       if (IS_ENABLED(CONFIG_SPI_MASTER) &&
+           of_property_read_bool(np, "cs-gpios")) {
+               struct device_node *child;
+               u32 cs;
+               int ret;
+
+               for_each_child_of_node(np, child) {
+                       ret = of_property_read_u32(child, "reg", &cs);
+                       if (!ret)
+                               continue;
+                       if (cs == index) {
+                               /*
+                                * SPI children have active low chip selects
+                                * by default. This can be specified negatively
+                                * by just omitting "spi-cs-high" in the
+                                * device node, or actively by tagging on
+                                * GPIO_ACTIVE_LOW as flag in the device
+                                * tree. If the line is simultaneously
+                                * tagged as active low in the device tree
+                                * and has the "spi-cs-high" set, we get a
+                                * conflict and the "spi-cs-high" flag will
+                                * take precedence.
+                                */
+                               if (of_property_read_bool(np, "spi-cs-high")) {
+                                       if (*flags & OF_GPIO_ACTIVE_LOW) {
+                                               pr_warn("%s GPIO handle specifies active low - ignored\n",
+                                                       of_node_full_name(np));
+                                               *flags &= ~OF_GPIO_ACTIVE_LOW;
+                                       }
+                               } else {
+                                       if (!(*flags & OF_GPIO_ACTIVE_LOW))
+                                               pr_info("%s enforce active low on chipselect handle\n",
+                                                       of_node_full_name(np));
+                                       *flags |= OF_GPIO_ACTIVE_LOW;
+                               }
+                               break;
+                       }
+               }
+       }
 }
 
 /**
@@ -132,7 +174,7 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
                goto out;
 
        if (flags)
-               of_gpio_flags_quirks(np, flags);
+               of_gpio_flags_quirks(np, flags, index);
 
        pr_debug("%s: parsed '%s' property of node '%pOF[%d]' - status (%d)\n",
                 __func__, propname, np, index,
@@ -349,8 +391,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
        else if (of_property_read_bool(np, "output-high"))
                *dflags |= GPIOD_OUT_HIGH;
        else {
-               pr_warn("GPIO line %d (%s): no hogging state specified, bailing out\n",
-                       desc_to_gpio(desc), np->name);
+               pr_warn("GPIO line %d (%pOFn): no hogging state specified, bailing out\n",
+                       desc_to_gpio(desc), np);
                return ERR_PTR(-EINVAL);
        }
 
index 3dbaf489a8a52146aacdf2dbec23af18f5bb3b0a..fbf6b1a0a4fae6ce395fcb9f7a514551ae79258e 100644 (file)
@@ -1,8 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 #include <linux/idr.h>
 #include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/sysfs.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio/driver.h>
 #include <linux/interrupt.h>
@@ -444,11 +444,6 @@ static struct attribute *gpiochip_attrs[] = {
 };
 ATTRIBUTE_GROUPS(gpiochip);
 
-static struct gpio_desc *gpio_to_valid_desc(int gpio)
-{
-       return gpio_is_valid(gpio) ? gpio_to_desc(gpio) : NULL;
-}
-
 /*
  * /sys/class/gpio/export ... write-only
  *     integer N ... number of GPIO to export (full access)
@@ -467,7 +462,7 @@ static ssize_t export_store(struct class *class,
        if (status < 0)
                goto done;
 
-       desc = gpio_to_valid_desc(gpio);
+       desc = gpio_to_desc(gpio);
        /* reject invalid GPIOs */
        if (!desc) {
                pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
@@ -514,7 +509,7 @@ static ssize_t unexport_store(struct class *class,
        if (status < 0)
                goto done;
 
-       desc = gpio_to_valid_desc(gpio);
+       desc = gpio_to_desc(gpio);
        /* reject bogus commands (gpio_unexport ignores them) */
        if (!desc) {
                pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
index db1f4b2b092dccae1919d9791444b76b4b9dfdec..230e41562462b27fdf5d11874b3de8c34c107707 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 #include <linux/bitmap.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -210,15 +211,15 @@ static int gpiochip_find_base(int ngpio)
  */
 int gpiod_get_direction(struct gpio_desc *desc)
 {
-       struct gpio_chip        *chip;
-       unsigned                offset;
-       int                     status = -EINVAL;
+       struct gpio_chip *chip;
+       unsigned offset;
+       int status;
 
        chip = gpiod_to_chip(desc);
        offset = gpio_chip_hwgpio(desc);
 
        if (!chip->get_direction)
-               return status;
+               return -ENOTSUPP;
 
        status = chip->get_direction(chip, offset);
        if (status > 0) {
@@ -359,7 +360,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
        return p;
 }
 
-static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip)
 {
 #ifdef CONFIG_OF_GPIO
        int size;
@@ -380,6 +381,14 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
        return 0;
 }
 
+static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+       if (gpiochip->init_valid_mask)
+               return gpiochip->init_valid_mask(gpiochip);
+
+       return 0;
+}
+
 static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
 {
        kfree(gpiochip->valid_mask);
@@ -427,7 +436,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
        struct linehandle_state *lh = filep->private_data;
        void __user *ip = (void __user *)arg;
        struct gpiohandle_data ghd;
-       int vals[GPIOHANDLES_MAX];
+       DECLARE_BITMAP(vals, GPIOHANDLES_MAX);
        int i;
 
        if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
@@ -436,13 +445,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
                                                        true,
                                                        lh->numdescs,
                                                        lh->descs,
+                                                       NULL,
                                                        vals);
                if (ret)
                        return ret;
 
                memset(&ghd, 0, sizeof(ghd));
                for (i = 0; i < lh->numdescs; i++)
-                       ghd.values[i] = vals[i];
+                       ghd.values[i] = test_bit(i, vals);
 
                if (copy_to_user(ip, &ghd, sizeof(ghd)))
                        return -EFAULT;
@@ -461,13 +471,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
 
                /* Clamp all values to [0,1] */
                for (i = 0; i < lh->numdescs; i++)
-                       vals[i] = !!ghd.values[i];
+                       __assign_bit(i, vals, ghd.values[i]);
 
                /* Reuse the array setting function */
                return gpiod_set_array_value_complex(false,
                                              true,
                                              lh->numdescs,
                                              lh->descs,
+                                             NULL,
                                              vals);
        }
        return -EINVAL;
@@ -812,26 +823,26 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
 {
        struct lineevent_state *le = p;
        struct gpioevent_data ge;
-       int ret, level;
+       int ret;
 
        /* Do not leak kernel stack to userspace */
        memset(&ge, 0, sizeof(ge));
 
        ge.timestamp = le->timestamp;
-       level = gpiod_get_value_cansleep(le->desc);
 
        if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE
            && le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
+               int level = gpiod_get_value_cansleep(le->desc);
                if (level)
                        /* Emit low-to-high event */
                        ge.id = GPIOEVENT_EVENT_RISING_EDGE;
                else
                        /* Emit high-to-low event */
                        ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
-       } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE && level) {
+       } else if (le->eflags & GPIOEVENT_REQUEST_RISING_EDGE) {
                /* Emit low-to-high event */
                ge.id = GPIOEVENT_EVENT_RISING_EDGE;
-       } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE && !level) {
+       } else if (le->eflags & GPIOEVENT_REQUEST_FALLING_EDGE) {
                /* Emit high-to-low event */
                ge.id = GPIOEVENT_EVENT_FALLING_EDGE;
        } else {
@@ -942,7 +953,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
                irqflags |= IRQF_TRIGGER_FALLING;
        irqflags |= IRQF_ONESHOT;
-       irqflags |= IRQF_SHARED;
 
        INIT_KFIFO(le->events);
        init_waitqueue_head(&le->wait);
@@ -1341,19 +1351,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       for (i = 0; i < chip->ngpio; i++) {
-               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.
-                */
-               desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
-       }
+       for (i = 0; i < chip->ngpio; i++)
+               gdev->descs[i].gdev = gdev;
 
 #ifdef CONFIG_PINCTRL
        INIT_LIST_HEAD(&gdev->pin_ranges);
@@ -1367,7 +1366,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (status)
                goto err_remove_from_list;
 
-       status = gpiochip_init_valid_mask(chip);
+       status = gpiochip_alloc_valid_mask(chip);
        if (status)
                goto err_remove_irqchip_mask;
 
@@ -1379,6 +1378,21 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (status)
                goto err_remove_chip;
 
+       status = gpiochip_init_valid_mask(chip);
+       if (status)
+               goto err_remove_chip;
+
+       for (i = 0; i < chip->ngpio; i++) {
+               struct gpio_desc *desc = &gdev->descs[i];
+
+               if (chip->get_direction && gpiochip_line_is_valid(chip, i))
+                       desc->flags = !chip->get_direction(chip, i) ?
+                                       (1 << FLAG_IS_OUT) : 0;
+               else
+                       desc->flags = !chip->direction_input ?
+                                       (1 << FLAG_IS_OUT) : 0;
+       }
+
        acpi_gpiochip_add(chip);
 
        machine_gpiochip_add(chip);
@@ -1512,7 +1526,7 @@ static int devm_gpio_chip_match(struct device *dev, void *res, void *data)
 
 /**
  * devm_gpiochip_add_data() - Resource manager gpiochip_add_data()
- * @dev: the device pointer on which irq_chip belongs to.
+ * @dev: pointer to the device that gpio_chip belongs to.
  * @chip: the chip to register, with chip->base initialized
  * @data: driver-private data associated with this chip
  *
@@ -1649,7 +1663,6 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
 /**
  * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
  * @gpiochip: the gpiochip to set the irqchip chain to
- * @irqchip: the irqchip to chain to the gpiochip
  * @parent_irq: the irq number corresponding to the parent IRQ for this
  * chained irqchip
  * @parent_handler: the parent interrupt handler for the accumulated IRQ
@@ -1657,12 +1670,9 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
  * cascaded, pass NULL in this handler argument
  */
 static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
-                                         struct irq_chip *irqchip,
                                          unsigned int parent_irq,
                                          irq_flow_handler_t parent_handler)
 {
-       unsigned int offset;
-
        if (!gpiochip->irq.domain) {
                chip_err(gpiochip, "called %s before setting up irqchip\n",
                         __func__);
@@ -1686,14 +1696,6 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
                gpiochip->irq.parents = &gpiochip->irq.parent_irq;
                gpiochip->irq.num_parents = 1;
        }
-
-       /* Set the parent IRQ for all affected IRQs */
-       for (offset = 0; offset < gpiochip->ngpio; offset++) {
-               if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
-                       continue;
-               irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
-                              parent_irq);
-       }
 }
 
 /**
@@ -1703,8 +1705,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
  * @parent_irq: the irq number corresponding to the parent IRQ for this
  * chained irqchip
  * @parent_handler: the parent interrupt handler for the accumulated IRQ
- * coming out of the gpiochip. If the interrupt is nested rather than
- * cascaded, pass NULL in this handler argument
+ * coming out of the gpiochip.
  */
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
                                  struct irq_chip *irqchip,
@@ -1716,8 +1717,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
                return;
        }
 
-       gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
-                                     parent_handler);
+       gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, parent_handler);
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 
@@ -1732,8 +1732,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
                                 struct irq_chip *irqchip,
                                 unsigned int parent_irq)
 {
-       gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
-                                     NULL);
+       gpiochip_set_cascaded_irqchip(gpiochip, parent_irq, NULL);
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
 
@@ -1805,39 +1804,75 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
+static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       if (!gpiochip_irqchip_irq_valid(chip, offset))
+               return -ENXIO;
+
+       return irq_create_mapping(chip->irq.domain, offset);
+}
+
 static int gpiochip_irq_reqres(struct irq_data *d)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
-       int ret;
-
-       if (!try_module_get(chip->gpiodev->owner))
-               return -ENODEV;
 
-       ret = gpiochip_lock_as_irq(chip, d->hwirq);
-       if (ret) {
-               chip_err(chip,
-                       "unable to lock HW IRQ %lu for IRQ\n",
-                       d->hwirq);
-               module_put(chip->gpiodev->owner);
-               return ret;
-       }
-       return 0;
+       return gpiochip_reqres_irq(chip, d->hwirq);
 }
 
 static void gpiochip_irq_relres(struct irq_data *d)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
-       gpiochip_unlock_as_irq(chip, d->hwirq);
-       module_put(chip->gpiodev->owner);
+       gpiochip_relres_irq(chip, d->hwirq);
 }
 
-static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
+static void gpiochip_irq_enable(struct irq_data *d)
 {
-       if (!gpiochip_irqchip_irq_valid(chip, offset))
-               return -ENXIO;
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
-       return irq_create_mapping(chip->irq.domain, offset);
+       gpiochip_enable_irq(chip, d->hwirq);
+       if (chip->irq.irq_enable)
+               chip->irq.irq_enable(d);
+       else
+               chip->irq.chip->irq_unmask(d);
+}
+
+static void gpiochip_irq_disable(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       if (chip->irq.irq_disable)
+               chip->irq.irq_disable(d);
+       else
+               chip->irq.chip->irq_mask(d);
+       gpiochip_disable_irq(chip, d->hwirq);
+}
+
+static void gpiochip_set_irq_hooks(struct gpio_chip *gpiochip)
+{
+       struct irq_chip *irqchip = gpiochip->irq.chip;
+
+       if (!irqchip->irq_request_resources &&
+           !irqchip->irq_release_resources) {
+               irqchip->irq_request_resources = gpiochip_irq_reqres;
+               irqchip->irq_release_resources = gpiochip_irq_relres;
+       }
+       if (WARN_ON(gpiochip->irq.irq_enable))
+               return;
+       /* Check if the irqchip already has this hook... */
+       if (irqchip->irq_enable == gpiochip_irq_enable) {
+               /*
+                * ...and if so, give a gentle warning that this is bad
+                * practice.
+                */
+               chip_info(gpiochip,
+                         "detected irqchip that is shared with multiple gpiochips: please fix the driver.\n");
+               return;
+       }
+       gpiochip->irq.irq_enable = irqchip->irq_enable;
+       gpiochip->irq.irq_disable = irqchip->irq_disable;
+       irqchip->irq_enable = gpiochip_irq_enable;
+       irqchip->irq_disable = gpiochip_irq_disable;
 }
 
 /**
@@ -1898,16 +1933,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
        if (!gpiochip->irq.domain)
                return -EINVAL;
 
-       /*
-        * It is possible for a driver to override this, but only if the
-        * alternative functions are both implemented.
-        */
-       if (!irqchip->irq_request_resources &&
-           !irqchip->irq_release_resources) {
-               irqchip->irq_request_resources = gpiochip_irq_reqres;
-               irqchip->irq_release_resources = gpiochip_irq_relres;
-       }
-
        if (gpiochip->irq.parent_handler) {
                void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
 
@@ -1923,6 +1948,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
                }
        }
 
+       gpiochip_set_irq_hooks(gpiochip);
+
        acpi_gpiochip_request_interrupts(gpiochip);
 
        return 0;
@@ -1936,11 +1963,12 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
  */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
+       struct irq_chip *irqchip = gpiochip->irq.chip;
        unsigned int offset;
 
        acpi_gpiochip_free_interrupts(gpiochip);
 
-       if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
+       if (irqchip && gpiochip->irq.parent_handler) {
                struct gpio_irq_chip *irq = &gpiochip->irq;
                unsigned int i;
 
@@ -1964,11 +1992,19 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
                irq_domain_remove(gpiochip->irq.domain);
        }
 
-       if (gpiochip->irq.chip) {
-               gpiochip->irq.chip->irq_request_resources = NULL;
-               gpiochip->irq.chip->irq_release_resources = NULL;
-               gpiochip->irq.chip = NULL;
+       if (irqchip) {
+               if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
+                       irqchip->irq_request_resources = NULL;
+                       irqchip->irq_release_resources = NULL;
+               }
+               if (irqchip->irq_enable == gpiochip_irq_enable) {
+                       irqchip->irq_enable = gpiochip->irq.irq_enable;
+                       irqchip->irq_disable = gpiochip->irq.irq_disable;
+               }
        }
+       gpiochip->irq.irq_enable = NULL;
+       gpiochip->irq.irq_disable = NULL;
+       gpiochip->irq.chip = NULL;
 
        gpiochip_irqchip_free_valid_mask(gpiochip);
 }
@@ -2057,15 +2093,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
                return -EINVAL;
        }
 
-       /*
-        * It is possible for a driver to override this, but only if the
-        * alternative functions are both implemented.
-        */
-       if (!irqchip->irq_request_resources &&
-           !irqchip->irq_release_resources) {
-               irqchip->irq_request_resources = gpiochip_irq_reqres;
-               irqchip->irq_release_resources = gpiochip_irq_relres;
-       }
+       gpiochip_set_irq_hooks(gpiochip);
 
        acpi_gpiochip_request_interrupts(gpiochip);
 
@@ -2513,19 +2541,38 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
 int gpiod_direction_input(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
-       int                     status = -EINVAL;
+       int                     status = 0;
 
        VALIDATE_DESC(desc);
        chip = desc->gdev->chip;
 
-       if (!chip->get || !chip->direction_input) {
+       /*
+        * It is legal to have no .get() and .direction_input() specified if
+        * the chip is output-only, but you can't specify .direction_input()
+        * and not support the .get() operation, that doesn't make sense.
+        */
+       if (!chip->get && chip->direction_input) {
                gpiod_warn(desc,
-                       "%s: missing get() or direction_input() operations\n",
-                       __func__);
+                          "%s: missing get() but have direction_input()\n",
+                          __func__);
                return -EIO;
        }
 
-       status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+       /*
+        * If we have a .direction_input() callback, things are simple,
+        * just call it. Else we are some input-only chip so try to check the
+        * direction (if .get_direction() is supported) else we silently
+        * assume we are in input mode after this.
+        */
+       if (chip->direction_input) {
+               status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+       } else if (chip->get_direction &&
+                 (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
+               gpiod_warn(desc,
+                          "%s: missing direction_input() operation and line is output\n",
+                          __func__);
+               return -EIO;
+       }
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
@@ -2547,16 +2594,38 @@ static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
 {
        struct gpio_chip *gc = desc->gdev->chip;
        int val = !!value;
-       int ret;
+       int ret = 0;
 
-       if (!gc->set || !gc->direction_output) {
+       /*
+        * It's OK not to specify .direction_output() if the gpiochip is
+        * output-only, but if there is then not even a .set() operation it
+        * is pretty tricky to drive the output line.
+        */
+       if (!gc->set && !gc->direction_output) {
                gpiod_warn(desc,
-                      "%s: missing set() or direction_output() operations\n",
-                      __func__);
+                          "%s: missing set() and direction_output() operations\n",
+                          __func__);
                return -EIO;
        }
 
-       ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
+       if (gc->direction_output) {
+               ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), val);
+       } else {
+               /* Check that we are in output mode if we can */
+               if (gc->get_direction &&
+                   gc->get_direction(gc, gpio_chip_hwgpio(desc))) {
+                       gpiod_warn(desc,
+                               "%s: missing direction_output() operation\n",
+                               __func__);
+                       return -EIO;
+               }
+               /*
+                * If we can't actively set the direction, we are some
+                * output-only chip, so just drive the output as desired.
+                */
+               gc->set(gc, gpio_chip_hwgpio(desc), val);
+       }
+
        if (!ret)
                set_bit(FLAG_IS_OUT, &desc->flags);
        trace_gpio_value(desc_to_gpio(desc), 0, val);
@@ -2605,8 +2674,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
        else
                value = !!value;
 
-       /* GPIOs used for IRQs shall not be set as output */
-       if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
+       /* GPIOs used for enabled IRQs shall not be set as output */
+       if (test_bit(FLAG_USED_AS_IRQ, &desc->flags) &&
+           test_bit(FLAG_IRQ_IS_ENABLED, &desc->flags)) {
                gpiod_err(desc,
                          "%s: tried to set a GPIO tied to an IRQ as output\n",
                          __func__);
@@ -2785,9 +2855,39 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip,
 int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                                  unsigned int array_size,
                                  struct gpio_desc **desc_array,
-                                 int *value_array)
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap)
 {
-       int i = 0;
+       int err, i = 0;
+
+       /*
+        * Validate array_info against desc_array and its size.
+        * It should immediately follow desc_array if both
+        * have been obtained from the same gpiod_get_array() call.
+        */
+       if (array_info && array_info->desc == desc_array &&
+           array_size <= array_info->size &&
+           (void *)array_info == desc_array + array_info->size) {
+               if (!can_sleep)
+                       WARN_ON(array_info->chip->can_sleep);
+
+               err = gpio_chip_get_multiple(array_info->chip,
+                                            array_info->get_mask,
+                                            value_bitmap);
+               if (err)
+                       return err;
+
+               if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
+                       bitmap_xor(value_bitmap, value_bitmap,
+                                  array_info->invert_mask, array_size);
+
+               if (bitmap_full(array_info->get_mask, array_size))
+                       return 0;
+
+               i = find_first_zero_bit(array_info->get_mask, array_size);
+       } else {
+               array_info = NULL;
+       }
 
        while (i < array_size) {
                struct gpio_chip *chip = desc_array[i]->gdev->chip;
@@ -2819,6 +2919,10 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
 
                        __set_bit(hwgpio, mask);
                        i++;
+
+                       if (array_info)
+                               i = find_next_zero_bit(array_info->get_mask,
+                                                      array_size, i);
                } while ((i < array_size) &&
                         (desc_array[i]->gdev->chip == chip));
 
@@ -2829,15 +2933,20 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                        return ret;
                }
 
-               for (j = first; j < i; j++) {
+               for (j = first; j < i; ) {
                        const struct gpio_desc *desc = desc_array[j];
                        int hwgpio = gpio_chip_hwgpio(desc);
                        int value = test_bit(hwgpio, bits);
 
                        if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                                value = !value;
-                       value_array[j] = value;
+                       __assign_bit(j, value_bitmap, value);
                        trace_gpio_value(desc_to_gpio(desc), 1, value);
+                       j++;
+
+                       if (array_info)
+                               j = find_next_zero_bit(array_info->get_mask, i,
+                                                      j);
                }
 
                if (mask != fastpath)
@@ -2896,9 +3005,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
 
 /**
  * gpiod_get_raw_array_value() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
@@ -2908,20 +3018,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value);
  * and it will complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_get_raw_array_value(unsigned int array_size,
-                             struct gpio_desc **desc_array, int *value_array)
+                             struct gpio_desc **desc_array,
+                             struct gpio_array *array_info,
+                             unsigned long *value_bitmap)
 {
        if (!desc_array)
                return -EINVAL;
        return gpiod_get_array_value_complex(true, false, array_size,
-                                            desc_array, value_array);
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
 
 /**
  * gpiod_get_array_value() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.  Return 0 in case of success, else an error code.
@@ -2930,12 +3044,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value);
  * and it will complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_get_array_value(unsigned int array_size,
-                         struct gpio_desc **desc_array, int *value_array)
+                         struct gpio_desc **desc_array,
+                         struct gpio_array *array_info,
+                         unsigned long *value_bitmap)
 {
        if (!desc_array)
                return -EINVAL;
        return gpiod_get_array_value_complex(false, false, array_size,
-                                            desc_array, value_array);
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_array_value);
 
@@ -3026,12 +3143,39 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
 }
 
 int gpiod_set_array_value_complex(bool raw, bool can_sleep,
-                                  unsigned int array_size,
-                                  struct gpio_desc **desc_array,
-                                  int *value_array)
+                                 unsigned int array_size,
+                                 struct gpio_desc **desc_array,
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap)
 {
        int i = 0;
 
+       /*
+        * Validate array_info against desc_array and its size.
+        * It should immediately follow desc_array if both
+        * have been obtained from the same gpiod_get_array() call.
+        */
+       if (array_info && array_info->desc == desc_array &&
+           array_size <= array_info->size &&
+           (void *)array_info == desc_array + array_info->size) {
+               if (!can_sleep)
+                       WARN_ON(array_info->chip->can_sleep);
+
+               if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
+                       bitmap_xor(value_bitmap, value_bitmap,
+                                  array_info->invert_mask, array_size);
+
+               gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
+                                      value_bitmap);
+
+               if (bitmap_full(array_info->set_mask, array_size))
+                       return 0;
+
+               i = find_first_zero_bit(array_info->set_mask, array_size);
+       } else {
+               array_info = NULL;
+       }
+
        while (i < array_size) {
                struct gpio_chip *chip = desc_array[i]->gdev->chip;
                unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
@@ -3057,9 +3201,16 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
                do {
                        struct gpio_desc *desc = desc_array[i];
                        int hwgpio = gpio_chip_hwgpio(desc);
-                       int value = value_array[i];
+                       int value = test_bit(i, value_bitmap);
 
-                       if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+                       /*
+                        * Pins applicable for fast input but not for
+                        * fast output processing may have been already
+                        * inverted inside the fast path, skip them.
+                        */
+                       if (!raw && !(array_info &&
+                           test_bit(i, array_info->invert_mask)) &&
+                           test_bit(FLAG_ACTIVE_LOW, &desc->flags))
                                value = !value;
                        trace_gpio_value(desc_to_gpio(desc), 0, value);
                        /*
@@ -3079,6 +3230,10 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
                                count++;
                        }
                        i++;
+
+                       if (array_info)
+                               i = find_next_zero_bit(array_info->set_mask,
+                                                      array_size, i);
                } while ((i < array_size) &&
                         (desc_array[i]->gdev->chip == chip));
                /* push collected bits to outputs */
@@ -3153,9 +3308,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
 
 /**
  * gpiod_set_raw_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.
@@ -3164,20 +3320,23 @@ EXPORT_SYMBOL_GPL(gpiod_set_value);
  * complain if the GPIO chip functions potentially sleep.
  */
 int gpiod_set_raw_array_value(unsigned int array_size,
-                        struct gpio_desc **desc_array, int *value_array)
+                             struct gpio_desc **desc_array,
+                             struct gpio_array *array_info,
+                             unsigned long *value_bitmap)
 {
        if (!desc_array)
                return -EINVAL;
        return gpiod_set_array_value_complex(true, false, array_size,
-                                       desc_array, value_array);
+                                       desc_array, array_info, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
 
 /**
  * gpiod_set_array_value() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.
@@ -3185,13 +3344,16 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
  * This function should be called from contexts where we cannot sleep, and will
  * complain if the GPIO chip functions potentially sleep.
  */
-void gpiod_set_array_value(unsigned int array_size,
-                          struct gpio_desc **desc_array, int *value_array)
+int gpiod_set_array_value(unsigned int array_size,
+                         struct gpio_desc **desc_array,
+                         struct gpio_array *array_info,
+                         unsigned long *value_bitmap)
 {
        if (!desc_array)
-               return;
-       gpiod_set_array_value_complex(false, false, array_size, desc_array,
-                                     value_array);
+               return -EINVAL;
+       return gpiod_set_array_value_complex(false, false, array_size,
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value);
 
@@ -3293,6 +3455,7 @@ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
        }
 
        set_bit(FLAG_USED_AS_IRQ, &desc->flags);
+       set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
 
        /*
         * If the consumer has not set up a label (such as when the
@@ -3323,6 +3486,7 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
                return;
 
        clear_bit(FLAG_USED_AS_IRQ, &desc->flags);
+       clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
 
        /* If we only had this marking, erase it */
        if (desc->label && !strcmp(desc->label, "interrupt"))
@@ -3330,6 +3494,28 @@ void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset)
 }
 EXPORT_SYMBOL_GPL(gpiochip_unlock_as_irq);
 
+void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
+
+       if (!IS_ERR(desc) &&
+           !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags)))
+               clear_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
+}
+EXPORT_SYMBOL_GPL(gpiochip_disable_irq);
+
+void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       struct gpio_desc *desc = gpiochip_get_desc(chip, offset);
+
+       if (!IS_ERR(desc) &&
+           !WARN_ON(!test_bit(FLAG_USED_AS_IRQ, &desc->flags))) {
+               WARN_ON(test_bit(FLAG_IS_OUT, &desc->flags));
+               set_bit(FLAG_IRQ_IS_ENABLED, &desc->flags);
+       }
+}
+EXPORT_SYMBOL_GPL(gpiochip_enable_irq);
+
 bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
 {
        if (offset >= chip->ngpio)
@@ -3339,6 +3525,30 @@ bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset)
 }
 EXPORT_SYMBOL_GPL(gpiochip_line_is_irq);
 
+int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       int ret;
+
+       if (!try_module_get(chip->gpiodev->owner))
+               return -ENODEV;
+
+       ret = gpiochip_lock_as_irq(chip, offset);
+       if (ret) {
+               chip_err(chip, "unable to lock HW IRQ %u for IRQ\n", offset);
+               module_put(chip->gpiodev->owner);
+               return ret;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_reqres_irq);
+
+void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       gpiochip_unlock_as_irq(chip, offset);
+       module_put(chip->gpiodev->owner);
+}
+EXPORT_SYMBOL_GPL(gpiochip_relres_irq);
+
 bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset)
 {
        if (offset >= chip->ngpio)
@@ -3411,9 +3621,10 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
 
 /**
  * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.  Return 0 in case of success,
@@ -3423,21 +3634,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep);
  */
 int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
                                       struct gpio_desc **desc_array,
-                                      int *value_array)
+                                      struct gpio_array *array_info,
+                                      unsigned long *value_bitmap)
 {
        might_sleep_if(extra_checks);
        if (!desc_array)
                return -EINVAL;
        return gpiod_get_array_value_complex(true, true, array_size,
-                                            desc_array, value_array);
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
 
 /**
  * gpiod_get_array_value_cansleep() - read values from an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be read
- * @value_array: array to store the read values
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap to store the read values
  *
  * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.  Return 0 in case of success, else an error code.
@@ -3446,13 +3660,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep);
  */
 int gpiod_get_array_value_cansleep(unsigned int array_size,
                                   struct gpio_desc **desc_array,
-                                  int *value_array)
+                                  struct gpio_array *array_info,
+                                  unsigned long *value_bitmap)
 {
        might_sleep_if(extra_checks);
        if (!desc_array)
                return -EINVAL;
        return gpiod_get_array_value_complex(false, true, array_size,
-                                            desc_array, value_array);
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep);
 
@@ -3494,9 +3710,10 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
 
 /**
  * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the raw values of the GPIOs, i.e. the values of the physical lines
  * without regard for their ACTIVE_LOW status.
@@ -3504,14 +3721,15 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep);
  * This function is to be called from contexts that can sleep.
  */
 int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
-                                       struct gpio_desc **desc_array,
-                                       int *value_array)
+                                      struct gpio_desc **desc_array,
+                                      struct gpio_array *array_info,
+                                      unsigned long *value_bitmap)
 {
        might_sleep_if(extra_checks);
        if (!desc_array)
                return -EINVAL;
        return gpiod_set_array_value_complex(true, true, array_size, desc_array,
-                                     value_array);
+                                     array_info, value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
 
@@ -3534,24 +3752,27 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n)
 
 /**
  * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs
- * @array_size: number of elements in the descriptor / value arrays
+ * @array_size: number of elements in the descriptor array / value bitmap
  * @desc_array: array of GPIO descriptors whose values will be assigned
- * @value_array: array of values to assign
+ * @array_info: information on applicability of fast bitmap processing path
+ * @value_bitmap: bitmap of values to assign
  *
  * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status
  * into account.
  *
  * This function is to be called from contexts that can sleep.
  */
-void gpiod_set_array_value_cansleep(unsigned int array_size,
-                                   struct gpio_desc **desc_array,
-                                   int *value_array)
+int gpiod_set_array_value_cansleep(unsigned int array_size,
+                                  struct gpio_desc **desc_array,
+                                  struct gpio_array *array_info,
+                                  unsigned long *value_bitmap)
 {
        might_sleep_if(extra_checks);
        if (!desc_array)
-               return;
-       gpiod_set_array_value_complex(false, true, array_size, desc_array,
-                                     value_array);
+               return -EINVAL;
+       return gpiod_set_array_value_complex(false, true, array_size,
+                                            desc_array, array_info,
+                                            value_bitmap);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
 
@@ -4186,7 +4407,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
 {
        struct gpio_desc *desc;
        struct gpio_descs *descs;
-       int count;
+       struct gpio_array *array_info = NULL;
+       struct gpio_chip *chip;
+       int count, bitmap_size;
 
        count = gpiod_count(dev, con_id);
        if (count < 0)
@@ -4202,9 +4425,92 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
                        gpiod_put_array(descs);
                        return ERR_CAST(desc);
                }
+
                descs->desc[descs->ndescs] = desc;
+
+               chip = gpiod_to_chip(desc);
+               /*
+                * If pin hardware number of array member 0 is also 0, select
+                * its chip as a candidate for fast bitmap processing path.
+                */
+               if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
+                       struct gpio_descs *array;
+
+                       bitmap_size = BITS_TO_LONGS(chip->ngpio > count ?
+                                                   chip->ngpio : count);
+
+                       array = kzalloc(struct_size(descs, desc, count) +
+                                       struct_size(array_info, invert_mask,
+                                       3 * bitmap_size), GFP_KERNEL);
+                       if (!array) {
+                               gpiod_put_array(descs);
+                               return ERR_PTR(-ENOMEM);
+                       }
+
+                       memcpy(array, descs,
+                              struct_size(descs, desc, descs->ndescs + 1));
+                       kfree(descs);
+
+                       descs = array;
+                       array_info = (void *)(descs->desc + count);
+                       array_info->get_mask = array_info->invert_mask +
+                                                 bitmap_size;
+                       array_info->set_mask = array_info->get_mask +
+                                                 bitmap_size;
+
+                       array_info->desc = descs->desc;
+                       array_info->size = count;
+                       array_info->chip = chip;
+                       bitmap_set(array_info->get_mask, descs->ndescs,
+                                  count - descs->ndescs);
+                       bitmap_set(array_info->set_mask, descs->ndescs,
+                                  count - descs->ndescs);
+                       descs->info = array_info;
+               }
+               /* Unmark array members which don't belong to the 'fast' chip */
+               if (array_info && array_info->chip != chip) {
+                       __clear_bit(descs->ndescs, array_info->get_mask);
+                       __clear_bit(descs->ndescs, array_info->set_mask);
+               }
+               /*
+                * Detect array members which belong to the 'fast' chip
+                * but their pins are not in hardware order.
+                */
+               else if (array_info &&
+                          gpio_chip_hwgpio(desc) != descs->ndescs) {
+                       /*
+                        * Don't use fast path if all array members processed so
+                        * far belong to the same chip as this one but its pin
+                        * hardware number is different from its array index.
+                        */
+                       if (bitmap_full(array_info->get_mask, descs->ndescs)) {
+                               array_info = NULL;
+                       } else {
+                               __clear_bit(descs->ndescs,
+                                           array_info->get_mask);
+                               __clear_bit(descs->ndescs,
+                                           array_info->set_mask);
+                       }
+               } else if (array_info) {
+                       /* Exclude open drain or open source from fast output */
+                       if (gpiochip_line_is_open_drain(chip, descs->ndescs) ||
+                           gpiochip_line_is_open_source(chip, descs->ndescs))
+                               __clear_bit(descs->ndescs,
+                                           array_info->set_mask);
+                       /* Identify 'fast' pins which require invertion */
+                       if (gpiod_is_active_low(desc))
+                               __set_bit(descs->ndescs,
+                                         array_info->invert_mask);
+               }
+
                descs->ndescs++;
        }
+       if (array_info)
+               dev_dbg(dev,
+                       "GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n",
+                       array_info->chip->label, array_info->size,
+                       *array_info->get_mask, *array_info->set_mask,
+                       *array_info->invert_mask);
        return descs;
 }
 EXPORT_SYMBOL_GPL(gpiod_get_array);
@@ -4291,8 +4597,9 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
        struct gpio_chip        *chip = gdev->chip;
        unsigned                gpio = gdev->base;
        struct gpio_desc        *gdesc = &gdev->descs[0];
-       int                     is_out;
-       int                     is_irq;
+       bool                    is_out;
+       bool                    is_irq;
+       bool                    active_low;
 
        for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
                if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
@@ -4306,11 +4613,13 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
                gpiod_get_direction(gdesc);
                is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
                is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
-               seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s",
+               active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags);
+               seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
                        gpio, gdesc->name ? gdesc->name : "", gdesc->label,
                        is_out ? "out" : "in ",
                        chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "?  ",
-                       is_irq ? "IRQ" : "   ");
+                       is_irq ? "IRQ " : "",
+                       active_low ? "ACTIVE LOW" : "");
                seq_printf(s, "\n");
        }
 }
index a7e49fef73d41de2327d32fdb202fac7ed5b33d5..087d865286a0c8ffe620c5abf33a14778a3f5e36 100644 (file)
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Internal GPIO functions.
  *
  * Copyright (C) 2013, Intel Corporation
  * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
- *
- * 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.
  */
 
 #ifndef GPIOLIB_H
@@ -183,15 +180,26 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
 }
 #endif
 
+struct gpio_array {
+       struct gpio_desc        **desc;
+       unsigned int            size;
+       struct gpio_chip        *chip;
+       unsigned long           *get_mask;
+       unsigned long           *set_mask;
+       unsigned long           invert_mask[];
+};
+
 struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
 int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                                  unsigned int array_size,
                                  struct gpio_desc **desc_array,
-                                 int *value_array);
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap);
 int gpiod_set_array_value_complex(bool raw, bool can_sleep,
-                                  unsigned int array_size,
-                                  struct gpio_desc **desc_array,
-                                  int *value_array);
+                                 unsigned int array_size,
+                                 struct gpio_desc **desc_array,
+                                 struct gpio_array *array_info,
+                                 unsigned long *value_bitmap);
 
 /* This is just passed between gpiolib and devres */
 struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
@@ -214,6 +222,7 @@ struct gpio_desc {
 #define FLAG_OPEN_DRAIN        7       /* Gpio is open drain type */
 #define FLAG_OPEN_SOURCE 8     /* Gpio is open source type */
 #define FLAG_USED_AS_IRQ 9     /* GPIO is connected to an IRQ */
+#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
 #define FLAG_IS_HOGGED 11      /* GPIO is hogged */
 #define FLAG_TRANSITORY 12     /* GPIO may lose value in sleep or reset */
 
index 401308e3d036fe54ad172690d9ba5ac0ee54b7e3..13882a2a4f6020ed294c36c198d54c4dab1d7693 100644 (file)
@@ -22,18 +22,16 @@ struct gpiomux {
        struct i2c_mux_gpio_platform_data data;
        unsigned gpio_base;
        struct gpio_desc **gpios;
-       int *values;
 };
 
 static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val)
 {
-       int i;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(val));
 
-       for (i = 0; i < mux->data.n_gpios; i++)
-               mux->values[i] = (val >> i) & 1;
+       values[0] = val;
 
-       gpiod_set_array_value_cansleep(mux->data.n_gpios,
-                                      mux->gpios, mux->values);
+       gpiod_set_array_value_cansleep(mux->data.n_gpios, mux->gpios, NULL,
+                                      values);
 }
 
 static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan)
@@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
                return -EPROBE_DEFER;
 
        muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values,
-                            mux->data.n_gpios * sizeof(*mux->gpios) +
-                            mux->data.n_gpios * sizeof(*mux->values), 0,
+                            mux->data.n_gpios * sizeof(*mux->gpios), 0,
                             i2c_mux_gpio_select, NULL);
        if (!muxc) {
                ret = -ENOMEM;
                goto alloc_failed;
        }
        mux->gpios = muxc->priv;
-       mux->values = (int *)(mux->gpios + mux->data.n_gpios);
        muxc->priv = mux;
 
        platform_set_drvdata(pdev, muxc);
index a8b9fee4d62a1e2c16a463cc02c0a8802c186a29..ece34c7346933599912b30a914bebb0fc5000f02 100644 (file)
@@ -40,17 +40,21 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
        struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
 
        if (!IS_ERR(reset_gpios)) {
-               int i, *values;
+               unsigned long *values;
                int nvalues = reset_gpios->ndescs;
 
-               values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
+               values = bitmap_alloc(nvalues, GFP_KERNEL);
                if (!values)
                        return;
 
-               for (i = 0; i < nvalues; i++)
-                       values[i] = value;
+               if (value)
+                       bitmap_fill(values, nvalues);
+               else
+                       bitmap_zero(values, nvalues);
+
+               gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc,
+                                              reset_gpios->info, values);
 
-               gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
                kfree(values);
        }
 }
index 6fdd9316db8b9f96a6cb163c064862428d434b74..02c1f2c014e8bf9116df68b26fc08cca612669c1 100644 (file)
 
 struct mux_gpio {
        struct gpio_descs *gpios;
-       int *val;
 };
 
 static int mux_gpio_set(struct mux_control *mux, int state)
 {
        struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
-       int i;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(state));
 
-       for (i = 0; i < mux_gpio->gpios->ndescs; i++)
-               mux_gpio->val[i] = (state >> i) & 1;
+       values[0] = state;
 
        gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs,
                                       mux_gpio->gpios->desc,
-                                      mux_gpio->val);
+                                      mux_gpio->gpios->info, values);
 
        return 0;
 }
@@ -58,13 +56,11 @@ static int mux_gpio_probe(struct platform_device *pdev)
        if (pins < 0)
                return pins;
 
-       mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) +
-                                      pins * sizeof(*mux_gpio->val));
+       mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio));
        if (IS_ERR(mux_chip))
                return PTR_ERR(mux_chip);
 
        mux_gpio = mux_chip_priv(mux_chip);
-       mux_gpio->val = (int *)(mux_gpio + 1);
        mux_chip->ops = &mux_gpio_ops;
 
        mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
index bc90764a8b8dcd7dd7140c20f39e8538d47de23e..fe34576262bda2890963517284a152673994db12 100644 (file)
 struct mdio_mux_gpio_state {
        struct gpio_descs *gpios;
        void *mux_handle;
-       int values[];
 };
 
 static int mdio_mux_gpio_switch_fn(int current_child, int desired_child,
                                   void *data)
 {
        struct mdio_mux_gpio_state *s = data;
-       unsigned int n;
+       DECLARE_BITMAP(values, BITS_PER_TYPE(desired_child));
 
        if (current_child == desired_child)
                return 0;
 
-       for (n = 0; n < s->gpios->ndescs; n++)
-               s->values[n] = (desired_child >> n) & 1;
+       values[0] = desired_child;
 
        gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc,
-                                      s->values);
+                                      s->gpios->info, values);
 
        return 0;
 }
@@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev)
        if (IS_ERR(gpios))
                return PTR_ERR(gpios);
 
-       s = devm_kzalloc(&pdev->dev, struct_size(s, values, gpios->ndescs),
-                        GFP_KERNEL);
+       s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
        if (!s) {
                gpiod_put_array(gpios);
                return -ENOMEM;
index c5f2344c189badcea4f92dbbf4bf497dd2d64796..3a8c84bb174d73992570cd89a0f8ea4c3fce1983 100644 (file)
@@ -351,19 +351,20 @@ static int soc_common_pcmcia_config_skt(
 
        if (ret == 0) {
                struct gpio_desc *descs[2];
-               int values[2], n = 0;
+               DECLARE_BITMAP(values, 2);
+               int n = 0;
 
                if (skt->gpio_reset) {
                        descs[n] = skt->gpio_reset;
-                       values[n++] = !!(state->flags & SS_RESET);
+                       __assign_bit(n++, values, state->flags & SS_RESET);
                }
                if (skt->gpio_bus_enable) {
                        descs[n] = skt->gpio_bus_enable;
-                       values[n++] = !!(state->flags & SS_OUTPUT_ENA);
+                       __assign_bit(n++, values, state->flags & SS_OUTPUT_ENA);
                }
 
                if (n)
-                       gpiod_set_array_value_cansleep(n, descs, values);
+                       gpiod_set_array_value_cansleep(n, descs, NULL, values);
 
                /*
                 * This really needs a better solution.  The IRQ
index 0075fb0bef8c55eab8d66804f9c6310003e8ec17..25d456a323c2ba96d78ad23689d10c8ed7e89ded 100644 (file)
@@ -157,15 +157,13 @@ static const struct phy_ops gpio_usb_ops = {
  */
 static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
 {
-       int values[PHY_MDM6600_NR_CMD_LINES];
-       int i;
+       DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
 
-       val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1;
-       for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++)
-               values[i] = (val & BIT(i)) >> i;
+       values[0] = val;
 
        gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
-                                      ddata->cmd_gpios->desc, values);
+                                      ddata->cmd_gpios->desc,
+                                      ddata->cmd_gpios->info, values);
 }
 
 /**
@@ -176,7 +174,7 @@ static void phy_mdm6600_status(struct work_struct *work)
 {
        struct phy_mdm6600 *ddata;
        struct device *dev;
-       int values[PHY_MDM6600_NR_STATUS_LINES];
+       DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
        int error, i, val = 0;
 
        ddata = container_of(work, struct phy_mdm6600, status_work.work);
@@ -184,16 +182,17 @@ static void phy_mdm6600_status(struct work_struct *work)
 
        error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
                                               ddata->status_gpios->desc,
+                                              ddata->status_gpios->info,
                                               values);
        if (error)
                return;
 
        for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) {
-               val |= values[i] << i;
+               val |= test_bit(i, values) << i;
                dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
-                       __func__, i, values[i], val);
+                       __func__, i, test_bit(i, values), val);
        }
-       ddata->status = val;
+       ddata->status = values[0];
 
        dev_info(dev, "modem status: %i %s\n",
                 ddata->status,
index d12bed7bb5416bf6af62d86e2e2b4705aa031151..7c7d083e2c0dcd6859f1e5ff3170be1d6bc3a130 100644 (file)
@@ -601,6 +601,42 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #define msm_gpio_dbg_show NULL
 #endif
 
+static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
+{
+       struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+       int ret;
+       unsigned int len, i;
+       unsigned int max_gpios = pctrl->soc->ngpios;
+       u16 *tmp;
+
+       /* The number of GPIOs in the ACPI tables */
+       len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL,
+                                                  0);
+       if (ret < 0)
+               return 0;
+
+       if (ret > max_gpios)
+               return -EINVAL;
+
+       tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
+       if (ret < 0) {
+               dev_err(pctrl->dev, "could not read list of GPIOs\n");
+               goto out;
+       }
+
+       bitmap_zero(chip->valid_mask, max_gpios);
+       for (i = 0; i < len; i++)
+               set_bit(tmp[i], chip->valid_mask);
+
+out:
+       kfree(tmp);
+       return ret;
+}
+
 static const struct gpio_chip msm_gpio_template = {
        .direction_input  = msm_gpio_direction_input,
        .direction_output = msm_gpio_direction_output,
@@ -610,6 +646,7 @@ static const struct gpio_chip msm_gpio_template = {
        .request          = gpiochip_generic_request,
        .free             = gpiochip_generic_free,
        .dbg_show         = msm_gpio_dbg_show,
+       .init_valid_mask  = msm_gpio_init_valid_mask,
 };
 
 /* For dual-edge interrupts in software, since some hardware has no
@@ -925,41 +962,6 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
-static int msm_gpio_init_valid_mask(struct gpio_chip *chip,
-                                   struct msm_pinctrl *pctrl)
-{
-       int ret;
-       unsigned int len, i;
-       unsigned int max_gpios = pctrl->soc->ngpios;
-       u16 *tmp;
-
-       /* The number of GPIOs in the ACPI tables */
-       len = ret = device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0);
-       if (ret < 0)
-               return 0;
-
-       if (ret > max_gpios)
-               return -EINVAL;
-
-       tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       ret = device_property_read_u16_array(pctrl->dev, "gpios", tmp, len);
-       if (ret < 0) {
-               dev_err(pctrl->dev, "could not read list of GPIOs\n");
-               goto out;
-       }
-
-       bitmap_zero(chip->valid_mask, max_gpios);
-       for (i = 0; i < len; i++)
-               set_bit(tmp[i], chip->valid_mask);
-
-out:
-       kfree(tmp);
-       return ret;
-}
-
 static bool msm_gpio_needs_valid_mask(struct msm_pinctrl *pctrl)
 {
        return device_property_read_u16_array(pctrl->dev, "gpios", NULL, 0) > 0;
@@ -998,13 +1000,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
                return ret;
        }
 
-       ret = msm_gpio_init_valid_mask(chip, pctrl);
-       if (ret) {
-               dev_err(pctrl->dev, "Failed to setup irq valid bits\n");
-               gpiochip_remove(&pctrl->chip);
-               return ret;
-       }
-
        /*
         * For DeviceTree-supported systems, the gpio core checks the
         * pinctrl's device node for the "gpio-ranges" property.
index 25b9fcd5e3a4bcedd8b4a5288cf6ff2e3e6605eb..b7810b1aad0716171331f104d3844ac4f959c4a4 100644 (file)
@@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
                            long mask)
 {
        struct ad7606_state *st = iio_priv(indio_dev);
-       int values[3];
+       DECLARE_BITMAP(values, 3);
        int ret, i;
 
        switch (mask) {
@@ -227,12 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
                if (ret < 0)
                        return ret;
 
-               values[0] = (ret >> 0) & 1;
-               values[1] = (ret >> 1) & 1;
-               values[2] = (ret >> 2) & 1;
+               values[0] = ret;
 
                mutex_lock(&st->lock);
-               gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
+               gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info,
                                      values);
                st->oversampling = val;
                mutex_unlock(&st->lock);
index 1c06325beacaeb3a6e19011385fcc379ef16ce8e..39ed56214cd32c32447ef30baf1997dc27d2a003 100644 (file)
@@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
 {
        enum mctrl_gpio_idx i;
        struct gpio_desc *desc_array[UART_GPIO_MAX];
-       int value_array[UART_GPIO_MAX];
+       DECLARE_BITMAP(values, UART_GPIO_MAX);
        unsigned int count = 0;
 
        if (gpios == NULL)
@@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
        for (i = 0; i < UART_GPIO_MAX; i++)
                if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) {
                        desc_array[count] = gpios->gpio[i];
-                       value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl);
+                       __assign_bit(count, values,
+                                    mctrl & mctrl_gpios_desc[i].mctrl);
                        count++;
                }
-       gpiod_set_array_value(count, desc_array, value_array);
+       gpiod_set_array_value(count, desc_array, NULL, values);
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_set);
 
index 33695a1d8b35bf32b2eb3566513b3a16236fc151..f2f887795d43e9ae2cbe8b15be896547dbebbb43 100644 (file)
@@ -17,11 +17,20 @@ struct device;
  */
 struct gpio_desc;
 
+/**
+ * Opaque descriptor for a structure of GPIO array attributes.  This structure
+ * is attached to struct gpiod_descs obtained from gpiod_get_array() and can be
+ * passed back to get/set array functions in order to activate fast processing
+ * path if applicable.
+ */
+struct gpio_array;
+
 /**
  * Struct containing an array of descriptors that can be obtained using
  * gpiod_get_array().
  */
 struct gpio_descs {
+       struct gpio_array *info;
        unsigned int ndescs;
        struct gpio_desc *desc[];
 };
@@ -105,36 +114,46 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
 /* Value get/set from non-sleeping context */
 int gpiod_get_value(const struct gpio_desc *desc);
 int gpiod_get_array_value(unsigned int array_size,
-                         struct gpio_desc **desc_array, int *value_array);
+                         struct gpio_desc **desc_array,
+                         struct gpio_array *array_info,
+                         unsigned long *value_bitmap);
 void gpiod_set_value(struct gpio_desc *desc, int value);
-void gpiod_set_array_value(unsigned int array_size,
-                          struct gpio_desc **desc_array, int *value_array);
+int gpiod_set_array_value(unsigned int array_size,
+                         struct gpio_desc **desc_array,
+                         struct gpio_array *array_info,
+                         unsigned long *value_bitmap);
 int gpiod_get_raw_value(const struct gpio_desc *desc);
 int gpiod_get_raw_array_value(unsigned int array_size,
                              struct gpio_desc **desc_array,
-                             int *value_array);
+                             struct gpio_array *array_info,
+                             unsigned long *value_bitmap);
 void gpiod_set_raw_value(struct gpio_desc *desc, int value);
 int gpiod_set_raw_array_value(unsigned int array_size,
-                              struct gpio_desc **desc_array,
-                              int *value_array);
+                             struct gpio_desc **desc_array,
+                             struct gpio_array *array_info,
+                             unsigned long *value_bitmap);
 
 /* Value get/set from sleeping context */
 int gpiod_get_value_cansleep(const struct gpio_desc *desc);
 int gpiod_get_array_value_cansleep(unsigned int array_size,
                                   struct gpio_desc **desc_array,
-                                  int *value_array);
+                                  struct gpio_array *array_info,
+                                  unsigned long *value_bitmap);
 void gpiod_set_value_cansleep(struct gpio_desc *desc, int value);
-void gpiod_set_array_value_cansleep(unsigned int array_size,
-                                   struct gpio_desc **desc_array,
-                                   int *value_array);
+int gpiod_set_array_value_cansleep(unsigned int array_size,
+                                  struct gpio_desc **desc_array,
+                                  struct gpio_array *array_info,
+                                  unsigned long *value_bitmap);
 int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc);
 int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
                                       struct gpio_desc **desc_array,
-                                      int *value_array);
+                                      struct gpio_array *array_info,
+                                      unsigned long *value_bitmap);
 void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value);
 int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
-                                       struct gpio_desc **desc_array,
-                                       int *value_array);
+                                      struct gpio_desc **desc_array,
+                                      struct gpio_array *array_info,
+                                      unsigned long *value_bitmap);
 
 int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
@@ -331,7 +350,8 @@ static inline int gpiod_get_value(const struct gpio_desc *desc)
 }
 static inline int gpiod_get_array_value(unsigned int array_size,
                                        struct gpio_desc **desc_array,
-                                       int *value_array)
+                                       struct gpio_array *array_info,
+                                       unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
@@ -342,12 +362,14 @@ static inline void gpiod_set_value(struct gpio_desc *desc, int value)
        /* GPIO can never have been requested */
        WARN_ON(1);
 }
-static inline void gpiod_set_array_value(unsigned int array_size,
-                                        struct gpio_desc **desc_array,
-                                        int *value_array)
+static inline int gpiod_set_array_value(unsigned int array_size,
+                                       struct gpio_desc **desc_array,
+                                       struct gpio_array *array_info,
+                                       unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
+       return 0;
 }
 static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
 {
@@ -357,7 +379,8 @@ static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
 }
 static inline int gpiod_get_raw_array_value(unsigned int array_size,
                                            struct gpio_desc **desc_array,
-                                           int *value_array)
+                                           struct gpio_array *array_info,
+                                           unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
@@ -369,8 +392,9 @@ static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
        WARN_ON(1);
 }
 static inline int gpiod_set_raw_array_value(unsigned int array_size,
-                                            struct gpio_desc **desc_array,
-                                            int *value_array)
+                                           struct gpio_desc **desc_array,
+                                           struct gpio_array *array_info,
+                                           unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
@@ -385,7 +409,8 @@ static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
 }
 static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
                                     struct gpio_desc **desc_array,
-                                    int *value_array)
+                                    struct gpio_array *array_info,
+                                    unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
@@ -396,12 +421,14 @@ static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
        /* GPIO can never have been requested */
        WARN_ON(1);
 }
-static inline void gpiod_set_array_value_cansleep(unsigned int array_size,
+static inline int gpiod_set_array_value_cansleep(unsigned int array_size,
                                            struct gpio_desc **desc_array,
-                                           int *value_array)
+                                           struct gpio_array *array_info,
+                                           unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
+       return 0;
 }
 static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
 {
@@ -411,7 +438,8 @@ static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
 }
 static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
                                               struct gpio_desc **desc_array,
-                                              int *value_array)
+                                              struct gpio_array *array_info,
+                                              unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
@@ -425,7 +453,8 @@ static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
 }
 static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
                                                struct gpio_desc **desc_array,
-                                               int *value_array)
+                                               struct gpio_array *array_info,
+                                               unsigned long *value_bitmap)
 {
        /* GPIO can never have been requested */
        WARN_ON(1);
index a4d5eb37744ad0ca3e6000814c8a713801e267b9..2db62b550b95a5045b9d386757b173addeb2f3cb 100644 (file)
@@ -66,9 +66,15 @@ struct gpio_irq_chip {
        /**
         * @lock_key:
         *
-        * Per GPIO IRQ chip lockdep classes.
+        * Per GPIO IRQ chip lockdep class for IRQ lock.
         */
        struct lock_class_key *lock_key;
+
+       /**
+        * @request_key:
+        *
+        * Per GPIO IRQ chip lockdep class for IRQ request.
+        */
        struct lock_class_key *request_key;
 
        /**
@@ -145,6 +151,20 @@ struct gpio_irq_chip {
         * will allocate and map all IRQs during initialization.
         */
        unsigned int first;
+
+       /**
+        * @irq_enable:
+        *
+        * Store old irq_chip irq_enable callback
+        */
+       void            (*irq_enable)(struct irq_data *data);
+
+       /**
+        * @irq_disable:
+        *
+        * Store old irq_chip irq_disable callback
+        */
+       void            (*irq_disable)(struct irq_data *data);
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -165,9 +185,13 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  * @free: optional hook for chip-specific deactivation, such as
  *     disabling module power and clock; may sleep
  * @get_direction: returns direction for signal "offset", 0=out, 1=in,
- *     (same as GPIOF_DIR_XXX), or negative error
+ *     (same as GPIOF_DIR_XXX), or negative error.
+ *     It is recommended to always implement this function, even on
+ *     input-only or output-only gpio chips.
  * @direction_input: configures signal "offset" as input, or returns error
+ *     This can be omitted on input-only or output-only gpio chips.
  * @direction_output: configures signal "offset" as output, or returns error
+ *     This can be omitted on input-only or output-only gpio chips.
  * @get: returns value for signal "offset", 0=low, 1=high, or negative error
  * @get_multiple: reads values for multiple signals defined by "mask" and
  *     stores them in "bits", returns 0 on success or negative error
@@ -263,6 +287,9 @@ struct gpio_chip {
 
        void                    (*dbg_show)(struct seq_file *s,
                                                struct gpio_chip *chip);
+
+       int                     (*init_valid_mask)(struct gpio_chip *chip);
+
        int                     base;
        u16                     ngpio;
        const char              *const *names;
@@ -301,7 +328,9 @@ struct gpio_chip {
        /**
         * @need_valid_mask:
         *
-        * If set core allocates @valid_mask with all bits set to one.
+        * If set core allocates @valid_mask with all its values initialized
+        * with init_valid_mask() or set to one if init_valid_mask() is not
+        * defined
         */
        bool need_valid_mask;
 
@@ -402,6 +431,10 @@ extern struct gpio_chip *gpiochip_find(void *data,
 int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
 void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
 bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
+int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset);
+void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset);
+void gpiochip_disable_irq(struct gpio_chip *chip, unsigned int offset);
+void gpiochip_enable_irq(struct gpio_chip *chip, unsigned int offset);
 
 /* Line status inquiry for drivers */
 bool gpiochip_line_is_open_drain(struct gpio_chip *chip, unsigned int offset);
index 57a5a35e0073aedf560a53f7581996b21e652835..f92a47e180341c2f6e138ae576e6581cdbda52dd 100644 (file)
 #ifndef __DAVINCI_GPIO_PLATFORM_H
 #define __DAVINCI_GPIO_PLATFORM_H
 
-#include <linux/io.h>
-#include <linux/spinlock.h>
-
-#include <asm-generic/gpio.h>
-
-#define MAX_REGS_BANKS         5
-#define MAX_INT_PER_BANK 32
-
 struct davinci_gpio_platform_data {
        u32     ngpio;
        u32     gpio_unbanked;
 };
 
-struct davinci_gpio_irq_data {
-       void __iomem                    *regs;
-       struct davinci_gpio_controller  *chip;
-       int                             bank_num;
-};
-
-struct davinci_gpio_controller {
-       struct gpio_chip        chip;
-       struct irq_domain       *irq_domain;
-       /* Serialize access to GPIO registers */
-       spinlock_t              lock;
-       void __iomem            *regs[MAX_REGS_BANKS];
-       int                     gpio_unbanked;
-       int                     irqs[MAX_INT_PER_BANK];
-       unsigned int            base;
-};
-
-/*
- * basic gpio routines
- */
-#define        GPIO(X)         (X)     /* 0 <= X <= (DAVINCI_N_GPIO - 1) */
-
 /* Convert GPIO signal to GPIO pin number */
 #define GPIO_TO_PIN(bank, gpio)        (16 * (bank) + (gpio))
 
-static inline u32 __gpio_mask(unsigned gpio)
-{
-       return 1 << (gpio % 32);
-}
 #endif
index 8612855691b2d62e36d17e82f62d9f6b31d47342..8485c6a9a383203be7517fc39cbed734d1648927 100644 (file)
@@ -197,23 +197,12 @@ struct omap_gpio_platform_data {
        bool is_mpuio;          /* whether the bank is of type MPUIO */
        u32 non_wakeup_gpios;
 
+       u32 quirks;             /* Version specific quirks mask */
+
        struct omap_gpio_reg_offs *regs;
 
        /* Return context loss count due to PM states changing */
        int (*get_context_loss_count)(struct device *dev);
 };
 
-#if IS_BUILTIN(CONFIG_GPIO_OMAP)
-extern void omap2_gpio_prepare_for_idle(int off_mode);
-extern void omap2_gpio_resume_after_idle(void);
-#else
-static inline void omap2_gpio_prepare_for_idle(int off_mode)
-{
-}
-
-static inline void omap2_gpio_resume_after_idle(void)
-{
-}
-#endif
-
 #endif
diff --git a/include/linux/platform_data/gpio-ts5500.h b/include/linux/platform_data/gpio-ts5500.h
deleted file mode 100644 (file)
index b10d11c..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * GPIO (DIO) header for Technologic Systems TS-5500
- *
- * Copyright (c) 2012 Savoir-faire Linux Inc.
- *     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
- *
- * 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.
- */
-
-#ifndef _PDATA_GPIO_TS5500_H
-#define _PDATA_GPIO_TS5500_H
-
-/**
- * struct ts5500_dio_platform_data - TS-5500 pin block configuration
- * @base:      The GPIO base number to use.
- * @strap:     The only pin connected to an interrupt in a block is input-only.
- *             If you need a bidirectional line which can trigger an IRQ, you
- *             may strap it with an in/out pin. This flag indicates this case.
- */
-struct ts5500_dio_platform_data {
-       int base;
-       bool strap;
-};
-
-#endif /* _PDATA_GPIO_TS5500_H */
index 1bf6e6df084b8a18f9df34e54ed3be82056ffaf4..4ebfe0ac6c5b942e6078945b3a2fc9446db846bc 100644 (file)
@@ -65,7 +65,7 @@ struct gpioline_info {
 
 /**
  * struct gpiohandle_request - Information about a GPIO handle request
- * @lineoffsets: an array desired lines, specified by offset index for the
+ * @lineoffsets: an array of desired lines, specified by offset index for the
  * associated GPIO device
  * @flags: desired flags for the desired GPIO lines, such as
  * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed