Merge tag 'gpio-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Dec 2020 02:07:20 +0000 (18:07 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Dec 2020 02:07:20 +0000 (18:07 -0800)
Pull GPIO updates from Linus Walleij:
 "This is the bulk of the GPIO changes for the v5.11 kernel cycle:

  Core changes:

   - Retired the old set-up function for GPIO IRQ chips. All chips now
     use the template struct gpio_irq_chip and pass that to the core to
     be set up alongside the gpio_chip. We can finally get rid of the
     old cruft.

   - Some refactoring and clean up of the core code.

   - Support edge event timestamps to be stamped using REALTIME (wall
     clock) timestamps. We have found solid use cases for this, so we
     support it.

  New drivers:

   - MStar MSC313 GPIO driver.

   - HiSilicon GPIO driver.

  Driver improvements:

   - The PCA953x driver now also supports the NXP PCAL9554B/C chips.

   - The mockup driver can now be probed from the device tree which is
     pretty useful for virtual prototyping of devices.

   - The Rcar driver now supports .get_multiple()

   - The MXC driver dropped some legacy and became a pure device tree
     client.

   - The Exar driver was moved over to the IDA interface for
     enumerating, and also switched over to using regmap for register
     access"

* tag 'gpio-v5.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: (87 commits)
  MAINTAINERS: Remove reference to non-existing file
  gpio: hisi: Do not require ACPI for COMPILE_TEST
  MAINTAINERS: Add maintainer for HiSilicon GPIO driver
  gpio: gpio-hisi: Add HiSilicon GPIO support
  gpio: cs5535: Simplify the return expression of cs5535_gpio_probe()
  gpiolib: irq hooks: fix recursion in gpiochip_irq_unmask
  dt-bindings: mt7621-gpio: convert bindings to YAML format
  gpiolib: cdev: Flag invalid GPIOs as used
  gpio: put virtual gpio device into their own submenu
  drivers: gpio: amd8111: use SPDX-License-Identifier
  drivers: gpio: amd8111: prefer dev_err()/dev_info() over raw printk
  drivers: gpio: bt8xx: prefer dev_err()/dev_warn() over of raw printk
  gpio: Add TODO item for debugfs interface
  gpio: just plain warning when nonexisting gpio requested
  tools: gpio: add option to report wall-clock time to gpio-event-mon
  tools: gpio: add support for reporting realtime event clock to lsgpio
  gpiolib: cdev: allow edge event timestamps to be configured as REALTIME
  gpio: msc313: MStar MSC313 GPIO driver
  dt-bindings: gpio: Binding for MStar MSC313 GPIO controller
  dt-bindings: gpio: Add a binding header for the MSC313 GPIO driver
  ...

46 files changed:
Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml
Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt [deleted file]
Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml [new file with mode: 0644]
Documentation/driver-api/gpio/consumer.rst
Documentation/driver-api/gpio/driver.rst
MAINTAINERS
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/TODO
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-amd8111.c
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-bt8xx.c
drivers/gpio/gpio-cs5535.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-exar.c
drivers/gpio/gpio-hisi.c [new file with mode: 0644]
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-msc313.c [new file with mode: 0644]
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-mxs.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-sifive.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-xilinx.c
drivers/gpio/gpio-xra1403.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-acpi.h
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib-devres.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
include/dt-bindings/gpio/tegra186-gpio.h
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
include/uapi/linux/gpio.h
tools/gpio/gpio-event-mon.c
tools/gpio/lsgpio.c

index 183ec23..f5ee23c 100644 (file)
@@ -48,6 +48,7 @@ properties:
       - nxp,pcal6416
       - nxp,pcal6524
       - nxp,pcal9535
+      - nxp,pcal9554b
       - nxp,pcal9555a
       - onnn,cat9554
       - onnn,pca9654
index 08eed23..e506f30 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
 - gpio-controller : Marks the device node as a GPIO controller.
 
 Optional properties:
+- clocks : Input clock specifier. Refer to common clock bindings.
 - interrupts : Interrupt mapping for GPIO IRQ.
 - xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
 - xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
@@ -29,6 +30,7 @@ Example:
 gpio: gpio@40000000 {
        #gpio-cells = <2>;
        compatible = "xlnx,xps-gpio-1.00.a";
+       clocks = <&clkc25>;
        gpio-controller ;
        interrupt-parent = <&microblaze_0_intc>;
        interrupts = < 6 2 >;
diff --git a/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt b/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.txt
deleted file mode 100644 (file)
index e1c49b6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-Mediatek MT7621 SoC GPIO controller bindings
-
-The IP core used inside these SoCs has 3 banks of 32 GPIOs each.
-The registers of all the banks are interwoven inside one single IO range.
-We load one GPIO controller instance per bank. Also the GPIO controller can receive
-interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU
-using GIC INT12.
-
-Required properties for the top level node:
-- #gpio-cells : Should be two. The first cell is the GPIO pin 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.
-- #interrupt-cells : Specifies the number of cells needed to encode an
-   interrupt. Should be 2. The first cell defines the interrupt number,
-   the second encodes the trigger flags encoded as described in
-   Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
-- compatible:
-  - "mediatek,mt7621-gpio" for Mediatek controllers
-- reg : Physical base address and length of the controller's registers
-- interrupt-parent : phandle of the parent interrupt controller.
-- interrupts : Interrupt specifier for the controllers interrupt.
-- interrupt-controller : Mark the device node as an interrupt controller.
-- gpio-controller : Marks the device node as a GPIO controller.
-
-Example:
-       gpio@600 {
-               #gpio-cells = <2>;
-               #interrupt-cells = <2>;
-               compatible = "mediatek,mt7621-gpio";
-               gpio-controller;
-               interrupt-controller;
-               reg = <0x600 0x100>;
-               interrupt-parent = <&gic>;
-               interrupts = <GIC_SHARED 12 IRQ_TYPE_LEVEL_HIGH>;
-       };
diff --git a/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.yaml b/Documentation/devicetree/bindings/gpio/mediatek,mt7621-gpio.yaml
new file mode 100644 (file)
index 0000000..5bbb2a3
--- /dev/null
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/mediatek,mt7621-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT7621 SoC GPIO controller
+
+maintainers:
+  - Sergio Paracuellos <sergio.paracuellos@gmail.com>
+
+description: |
+  The IP core used inside these SoCs has 3 banks of 32 GPIOs each.
+  The registers of all the banks are interwoven inside one single IO range.
+  We load one GPIO controller instance per bank. Also the GPIO controller can receive
+  interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU
+  using GIC INT12.
+
+properties:
+  $nodename:
+    pattern: "^gpio@[0-9a-f]+$"
+
+  compatible:
+    const: mediatek,mt7621-gpio
+
+  reg:
+    maxItems: 1
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-controller: true
+  gpio-ranges: true
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - "#gpio-cells"
+  - gpio-controller
+  - gpio-ranges
+  - interrupt-controller
+  - "#interrupt-cells"
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/mips-gic.h>
+
+    gpio@600 {
+      compatible = "mediatek,mt7621-gpio";
+      reg = <0x600 0x100>;
+      #gpio-cells = <2>;
+      gpio-controller;
+      gpio-ranges = <&pinctrl 0 0 95>;
+      interrupt-controller;
+      #interrupt-cells = <2>;
+      interrupt-parent = <&gic>;
+      interrupts = <GIC_SHARED 12 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml b/Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
new file mode 100644 (file)
index 0000000..1f2ef40
--- /dev/null
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/mstar,msc313-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MStar/SigmaStar GPIO controller
+
+maintainers:
+  - Daniel Palmer <daniel@thingy.jp>
+
+properties:
+  $nodename:
+    pattern: "^gpio@[0-9a-f]+$"
+
+  compatible:
+    const: mstar,msc313-gpio
+
+  reg:
+    maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-ranges: true
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - gpio-controller
+  - "#gpio-cells"
+  - interrupt-controller
+  - "#interrupt-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/msc313-gpio.h>
+
+    gpio: gpio@207800 {
+      compatible = "mstar,msc313e-gpio";
+      #gpio-cells = <2>;
+      reg = <0x207800 0x200>;
+      gpio-controller;
+      gpio-ranges = <&pinctrl 0 36 22>,
+                    <&pinctrl 22 63 4>,
+                    <&pinctrl 26 68 6>;
+      #interrupt-cells = <2>;
+      interrupt-controller;
+      interrupt-parent = <&intc_fiq>;
+    };
index 423492d..173e4c7 100644 (file)
@@ -440,18 +440,20 @@ For details refer to Documentation/firmware-guide/acpi/gpio-properties.rst
 
 Interacting With the Legacy GPIO Subsystem
 ==========================================
-Many kernel subsystems still handle GPIOs using the legacy integer-based
-interface. Although it is strongly encouraged to upgrade them to the safer
-descriptor-based API, the following two functions allow you to convert a GPIO
-descriptor into the GPIO integer namespace and vice-versa::
+Many kernel subsystems and drivers still handle GPIOs using the legacy
+integer-based interface. It is strongly recommended to update these to the new
+gpiod interface. For cases where both interfaces need to be used, the following
+two functions allow to convert a GPIO descriptor into the GPIO integer namespace
+and vice-versa::
 
        int desc_to_gpio(const struct gpio_desc *desc)
        struct gpio_desc *gpio_to_desc(unsigned gpio)
 
-The GPIO number returned by desc_to_gpio() can be safely used as long as the
-GPIO descriptor has not been freed. All the same, a GPIO number passed to
-gpio_to_desc() must have been properly acquired, and usage of the returned GPIO
-descriptor is only possible after the GPIO number has been released.
+The GPIO number returned by desc_to_gpio() can safely be used as a parameter of
+the gpio\_*() functions for as long as the GPIO descriptor `desc` is not freed.
+All the same, a GPIO number passed to gpio_to_desc() must first be properly
+acquired using e.g. gpio_request_one(), and the returned GPIO descriptor is only
+considered valid until that GPIO number is released using gpio_free().
 
 Freeing a GPIO obtained by one API with the other API is forbidden and an
 unchecked error.
index 072a745..0fb57e2 100644 (file)
@@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the
 struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
 If you do this, the additional irq_chip will be set up by gpiolib at the
 same time as setting up the rest of the GPIO functionality. The following
-is a typical example of a cascaded interrupt handler using gpio_irq_chip:
+is a typical example of a chained cascaded interrupt handler using
+the gpio_irq_chip:
 
 .. code-block:: c
 
@@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:
 
   return devm_gpiochip_add_data(dev, &g->gc, g);
 
-The helper support using hierarchical interrupt controllers as well.
+The helper supports using threaded interrupts as well. Then you just request
+the interrupt separately and go with it:
+
+.. code-block:: c
+
+  /* Typical state container with dynamic irqchip */
+  struct my_gpio {
+      struct gpio_chip gc;
+      struct irq_chip irq;
+  };
+
+  int irq; /* from platform etc */
+  struct my_gpio *g;
+  struct gpio_irq_chip *girq;
+
+  /* Set up the irqchip dynamically */
+  g->irq.name = "my_gpio_irq";
+  g->irq.irq_ack = my_gpio_ack_irq;
+  g->irq.irq_mask = my_gpio_mask_irq;
+  g->irq.irq_unmask = my_gpio_unmask_irq;
+  g->irq.irq_set_type = my_gpio_set_irq_type;
+
+  ret = devm_request_threaded_irq(dev, irq, NULL,
+               irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
+  if (ret < 0)
+       return ret;
+
+  /* Get a pointer to the gpio_irq_chip */
+  girq = &g->gc.irq;
+  girq->chip = &g->irq;
+  /* This will let us handle the parent IRQ in the driver */
+  girq->parent_handler = NULL;
+  girq->num_parents = 0;
+  girq->parents = NULL;
+  girq->default_type = IRQ_TYPE_NONE;
+  girq->handler = handle_bad_irq;
+
+  return devm_gpiochip_add_data(dev, &g->gc, g);
+
+The helper supports using hierarchical interrupt controllers as well.
 In this case the typical set-up will look like this:
 
 .. code-block:: c
@@ -493,32 +533,13 @@ the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
 As always it is good to look at examples in the kernel tree for advice
 on how to find the required pieces.
 
-The old way of adding irqchips to gpiochips after registration is also still
-available but we try to move away from this:
-
-- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
-  gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ
-  callbacks, so the callbacks need to embed the gpio_chip in its state
-  container and obtain a pointer to the container using container_of().
-  (See Documentation/driver-api/driver-model/design-patterns.rst)
-
-- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
-  as discussed above regarding different types of cascaded irqchips. The
-  cascaded irq has to be handled by a threaded interrupt handler.
-  Apart from that it works exactly like the chained irqchip.
-
-- gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
-  gpio_chip from a parent IRQ. As the parent IRQ has usually been
-  explicitly requested by the driver, this does very little more than
-  mark all the child IRQs as having the other IRQ as parent.
-
 If there is a need to exclude certain GPIO lines from the IRQ domain handled by
 these helpers, we can set .irq.need_valid_mask of the gpiochip before
 devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an
 .irq.valid_mask with as many bits set as there are GPIO lines in the chip, each
 bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits
-from this mask. The mask must be filled in before gpiochip_irqchip_add() or
-gpiochip_irqchip_add_nested() is called.
+from this mask. The mask can be filled in the init_valid_mask() callback
+that is part of the struct gpio_irq_chip.
 
 To use the helpers please keep the following in mind:
 
index 28d7acd..9d7784a 100644 (file)
@@ -2146,8 +2146,10 @@ L:       linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 W:     http://linux-chenxing.org/
 F:     Documentation/devicetree/bindings/arm/mstar/*
+F:     Documentation/devicetree/bindings/gpio/mstar,msc313-gpio.yaml
 F:     arch/arm/boot/dts/mstar-*
 F:     arch/arm/mach-mstar/
+F:     drivers/gpio/gpio-msc313.c
 F:     include/dt-bindings/gpio/msc313-gpio.h
 
 ARM/NEC MOBILEPRO 900/c MACHINE SUPPORT
@@ -7548,6 +7550,7 @@ M:        Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 L:     linux-gpio@vger.kernel.org
 L:     linux-acpi@vger.kernel.org
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git
 F:     Documentation/firmware-guide/acpi/gpio-properties.rst
 F:     drivers/gpio/gpiolib-acpi.c
 F:     drivers/gpio/gpiolib-acpi.h
@@ -7981,6 +7984,12 @@ L:       dmaengine@vger.kernel.org
 S:     Maintained
 F:     drivers/dma/hisi_dma.c
 
+HISILICON GPIO DRIVER
+M:     Luo Jiaxing <luojiaxing@huawei.com>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/gpio/gpio-hisi.c
+
 HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE)
 M:     Zaibo Xu <xuzaibo@huawei.com>
 L:     linux-crypto@vger.kernel.org
@@ -19500,6 +19509,16 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/net/can/xilinx_can.txt
 F:     drivers/net/can/xilinx_can.c
 
+XILINX GPIO DRIVER
+M:     Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
+R:     Srinivas Neeli <srinivas.neeli@xilinx.com>
+R:     Michal Simek <michal.simek@xilinx.com>
+S:     Maintained
+F:     Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
+F:     Documentation/devicetree/bindings/gpio/gpio-zynq.txt
+F:     drivers/gpio/gpio-xilinx.c
+F:     drivers/gpio/gpio-zynq.c
+
 XILINX SD-FEC IP CORES
 M:     Derek Kiernan <derek.kiernan@xilinx.com>
 M:     Dragan Cvetic <dragan.cvetic@xilinx.com>
index 5d4de5c..c70f46e 100644 (file)
@@ -59,8 +59,9 @@ config DEBUG_GPIO
          that are most common when setting up new platforms or boards.
 
 config GPIO_SYSFS
-       bool "/sys/class/gpio/... (sysfs interface)"
+       bool "/sys/class/gpio/... (sysfs interface)" if EXPERT
        depends on SYSFS
+       select GPIO_CDEV # We need to encourage the new ABI
        help
          Say Y here to add the legacy sysfs interface for GPIOs.
 
@@ -255,6 +256,7 @@ config GPIO_EP93XX
 config GPIO_EXAR
        tristate "Support for GPIO pins on XR17V352/354/358"
        depends on SERIAL_8250_EXAR
+       select REGMAP_MMIO
        help
          Selecting this option will enable handling of GPIO pins present
          on Exar XR17V352/354/358 chips.
@@ -296,6 +298,17 @@ config GPIO_GRGPIO
          Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB
          VHDL IP core library.
 
+config GPIO_HISI
+       tristate "HiSilicon GPIO controller driver"
+       depends on (ARM64 && ACPI) || COMPILE_TEST
+       select GPIO_GENERIC
+       select GPIOLIB_IRQCHIP
+       help
+         Say Y or M here to build support for the HiSilicon GPIO controller
+         driver GPIO block.
+         This GPIO controller support double-edge interrupt and multi-core
+         concurrent access.
+
 config GPIO_HLWD
        tristate "Nintendo Wii (Hollywood) GPIO"
        depends on OF_GPIO
@@ -737,6 +750,17 @@ config GPIO_AMD_FCH
          Note: This driver doesn't registers itself automatically, as it
          needs to be provided with platform specific configuration.
          (See eg. CONFIG_PCENGINES_APU2.)
+
+config GPIO_MSC313
+       bool "MStar MSC313 GPIO support"
+       depends on ARCH_MSTARV7
+       default ARCH_MSTARV7
+       select GPIOLIB_IRQCHIP
+       select IRQ_DOMAIN_HIERARCHY
+       help
+         Say Y here to support the main GPIO block on MStar/SigmaStar
+         ARMv7 based SoCs.
+
 endmenu
 
 menu "Port-mapped I/O GPIO drivers"
@@ -1590,6 +1614,8 @@ config GPIO_VIPERBOARD
 
 endmenu
 
+menu "Virtual GPIO drivers"
+
 config GPIO_AGGREGATOR
        tristate "GPIO Aggregator"
        help
@@ -1613,4 +1639,6 @@ config GPIO_MOCKUP
          tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
          it.
 
+endmenu
+
 endif
index 09dada8..35e3b60 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_GPIO_GE_FPGA)            += gpio-ge.o
 obj-$(CONFIG_GPIO_GPIO_MM)             += gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)              += gpio-grgpio.o
 obj-$(CONFIG_GPIO_GW_PLD)              += gpio-gw-pld.o
+obj-$(CONFIG_GPIO_HISI)                 += gpio-hisi.o
 obj-$(CONFIG_GPIO_HLWD)                        += gpio-hlwd.o
 obj-$(CONFIG_HTC_EGPIO)                        += gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)                 += gpio-ich.o
@@ -101,6 +102,7 @@ obj-$(CONFIG_GPIO_MOCKUP)           += gpio-mockup.o
 obj-$(CONFIG_GPIO_MOXTET)              += gpio-moxtet.o
 obj-$(CONFIG_GPIO_MPC5200)             += gpio-mpc5200.o
 obj-$(CONFIG_GPIO_MPC8XXX)             += gpio-mpc8xxx.o
+obj-$(CONFIG_GPIO_MSC313)              += gpio-msc313.o
 obj-$(CONFIG_GPIO_MSIC)                        += gpio-msic.o
 obj-$(CONFIG_GPIO_MT7621)              += gpio-mt7621.o
 obj-$(CONFIG_GPIO_MVEBU)               += gpio-mvebu.o
index e560e45..0229fa7 100644 (file)
@@ -129,58 +129,9 @@ GPIOLIB irqchip
 The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
 try to cover any generic kind of irqchip cascaded from a GPIO.
 
-- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template,
-  parent and flags before calling [devm_]gpiochip_add[_data]().
-  Currently we set up the irqchip after setting up the gpiochip
-  using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip().
-  This is too complex, so convert all users over to just set up
-  the irqchip before registering the gpio_chip, typical example:
-
-  /* Typical state container with dynamic irqchip */
-  struct my_gpio {
-      struct gpio_chip gc;
-      struct irq_chip irq;
-  };
-
-  int irq; /* from platform etc */
-  struct my_gpio *g;
-  struct gpio_irq_chip *girq;
-
-  /* Set up the irqchip dynamically */
-  g->irq.name = "my_gpio_irq";
-  g->irq.irq_ack = my_gpio_ack_irq;
-  g->irq.irq_mask = my_gpio_mask_irq;
-  g->irq.irq_unmask = my_gpio_unmask_irq;
-  g->irq.irq_set_type = my_gpio_set_irq_type;
-
-  /* Get a pointer to the gpio_irq_chip */
-  girq = &g->gc.irq;
-  girq->chip = &g->irq;
-  girq->parent_handler = ftgpio_gpio_irq_handler;
-  girq->num_parents = 1;
-  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
-                               GFP_KERNEL);
-  if (!girq->parents)
-      return -ENOMEM;
-  girq->default_type = IRQ_TYPE_NONE;
-  girq->handler = handle_bad_irq;
-  girq->parents[0] = irq;
-
-  When this is done, we will delete the old APIs for instatiating
-  GPIOLIB_IRQCHIP and simplify the code.
-
 - Look over and identify any remaining easily converted drivers and
   dry-code conversions to gpiolib irqchip for maintainers to test
 
-- Drop gpiochip_set_chained_irqchip() when all the chained irqchips
-  have been converted to the above infrastructure.
-
-- Add more infrastructure to make it possible to also pass a threaded
-  irqchip in struct gpio_irq_chip.
-
-- Drop gpiochip_irqchip_add_nested() when all the chained irqchips
-  have been converted to the above infrastructure.
-
 
 Increase integration with pin control
 
@@ -191,3 +142,39 @@ use of the global GPIO numbers. Once the above is complete, it may
 make sense to simply join the subsystems into one and make pin
 multiplexing, pin configuration, GPIO, etc selectable options in one
 and the same pin control and GPIO subsystem.
+
+
+Debugfs in place of sysfs
+
+The old sysfs code that enables simple uses of GPIOs from the
+command line is still popular despite the existance of the proper
+character device. The reason is that it is simple to use on
+root filesystems where you only have a minimal set of tools such
+as "cat", "echo" etc.
+
+The old sysfs still need to be strongly deprecated and removed
+as it relies on the global GPIO numberspace that assume a strict
+order of global GPIO numbers that do not change between boots
+and is independent of probe order.
+
+To solve this and provide an ABI that people can use for hacks
+and development, implement a debugfs interface to manipulate
+GPIO lines that can do everything that sysfs can do today: one
+directory per gpiochip and one file entry per line:
+
+/sys/kernel/debug/gpiochip/gpiochip0
+/sys/kernel/debug/gpiochip/gpiochip0/gpio0
+/sys/kernel/debug/gpiochip/gpiochip0/gpio1
+/sys/kernel/debug/gpiochip/gpiochip0/gpio2
+/sys/kernel/debug/gpiochip/gpiochip0/gpio3
+...
+/sys/kernel/debug/gpiochip/gpiochip1
+/sys/kernel/debug/gpiochip/gpiochip1/gpio0
+/sys/kernel/debug/gpiochip/gpiochip1/gpio1
+...
+
+The exact files and design of the debugfs interface can be
+discussed but the idea is to provide a low-level access point
+for debugging and hacking and to expose all lines without the
+need of any exporting. Also provide ample ammunition to shoot
+oneself in the foot, because this is debugfs after all.
index 94c3a9b..b132afa 100644 (file)
@@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data)
 
                                outb(idi48gpio->cos_enb, idi48gpio->base + 7);
 
-                               raw_spin_unlock_irqrestore(&idi48gpio->lock,
-                                                          flags);
+                               raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
                        }
 
                        return;
@@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
 
                                outb(idi48gpio->cos_enb, idi48gpio->base + 7);
 
-                               raw_spin_unlock_irqrestore(&idi48gpio->lock,
-                                                          flags);
+                               raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
                        }
 
                        return;
index fdcebe5..14e6b3e 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * GPIO driver for AMD 8111 south bridges
  *
  * Hardware driver for Intel i810 Random Number Generator (RNG)
  * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
  * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 #include <linux/ioport.h>
 #include <linux/module.h>
@@ -179,7 +176,6 @@ static int __init amd_gpio_init(void)
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *ent;
 
-
        /* We look for our device - AMD South Bridge
         * I don't know about a system with two such bridges,
         * so we can assume that there is max. one device.
@@ -223,11 +219,10 @@ found:
 
        spin_lock_init(&gp.lock);
 
-       printk(KERN_INFO "AMD-8111 GPIO detected\n");
+       dev_info(&pdev->dev, "AMD-8111 GPIO detected\n");
        err = gpiochip_add_data(&gp.chip, &gp);
        if (err) {
-               printk(KERN_ERR "GPIO registering failed (%d)\n",
-                      err);
+               dev_err(&pdev->dev, "GPIO registering failed (%d)\n", err);
                ioport_unmap(gp.pm);
                goto out;
        }
index d535934..678ddd3 100644 (file)
@@ -123,6 +123,7 @@ static int ath79_gpio_irq_set_type(struct irq_data *data,
        switch (flow_type) {
        case IRQ_TYPE_EDGE_RISING:
                polarity |= mask;
+               fallthrough;
        case IRQ_TYPE_EDGE_FALLING:
        case IRQ_TYPE_EDGE_BOTH:
                break;
index a6f30ad..7920cf2 100644 (file)
@@ -175,13 +175,13 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
 
        err = pci_enable_device(dev);
        if (err) {
-               printk(KERN_ERR "bt8xxgpio: Can't enable device.\n");
+               dev_err(&dev->dev, "can't enable device.\n");
                return err;
        }
        if (!devm_request_mem_region(&dev->dev, pci_resource_start(dev, 0),
                                pci_resource_len(dev, 0),
                                "bt8xxgpio")) {
-               printk(KERN_WARNING "bt8xxgpio: Can't request iomem (0x%llx).\n",
+               dev_warn(&dev->dev, "can't request iomem (0x%llx).\n",
                       (unsigned long long)pci_resource_start(dev, 0));
                err = -EBUSY;
                goto err_disable;
@@ -191,7 +191,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
 
        bg->mmio = devm_ioremap(&dev->dev, pci_resource_start(dev, 0), 0x1000);
        if (!bg->mmio) {
-               printk(KERN_ERR "bt8xxgpio: ioremap() failed\n");
+               dev_err(&dev->dev, "ioremap() failed\n");
                err = -EIO;
                goto err_disable;
        }
@@ -207,7 +207,7 @@ static int bt8xxgpio_probe(struct pci_dev *dev,
        bt8xxgpio_gpio_setup(bg);
        err = gpiochip_add_data(&bg->gpio, bg);
        if (err) {
-               printk(KERN_ERR "bt8xxgpio: Failed to register GPIOs\n");
+               dev_err(&dev->dev, "failed to register GPIOs\n");
                goto err_disable;
        }
 
index 53b24e3..6da3a24 100644 (file)
@@ -345,12 +345,8 @@ static int cs5535_gpio_probe(struct platform_device *pdev)
                                mask_orig, mask);
 
        /* finally, register with the generic GPIO API */
-       err = devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip,
-                                    &cs5535_gpio_chip);
-       if (err)
-               return err;
-
-       return 0;
+       return devm_gpiochip_add_data(&pdev->dev, &cs5535_gpio_chip.chip,
+                                     &cs5535_gpio_chip);
 }
 
 static struct platform_driver cs5535_gpio_driver = {
index 4275c18..d3233cc 100644 (file)
@@ -616,10 +616,9 @@ static int dwapb_get_reset(struct dwapb_gpio *gpio)
        int err;
 
        gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL);
-       if (IS_ERR(gpio->rst)) {
-               dev_err(gpio->dev, "Cannot get reset descriptor\n");
-               return PTR_ERR(gpio->rst);
-       }
+       if (IS_ERR(gpio->rst))
+               return dev_err_probe(gpio->dev, PTR_ERR(gpio->rst),
+                                    "Cannot get reset descriptor\n");
 
        err = reset_control_deassert(gpio->rst);
        if (err) {
index b1accfb..d37de78 100644 (file)
@@ -4,14 +4,17 @@
  *
  * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
  */
+
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/gpio/driver.h>
+#include <linux/idr.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 
 #define EXAR_OFFSET_MPIOLVL_LO 0x90
 #define EXAR_OFFSET_MPIOSEL_LO 0x93
@@ -24,60 +27,39 @@ static DEFINE_IDA(ida_index);
 
 struct exar_gpio_chip {
        struct gpio_chip gpio_chip;
-       struct mutex lock;
+       struct regmap *regmap;
        int index;
-       void __iomem *regs;
        char name[20];
        unsigned int first_pin;
 };
 
-static void exar_update(struct gpio_chip *chip, unsigned int reg, int val,
-                       unsigned int offset)
+static unsigned int
+exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
 {
-       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       int temp;
-
-       mutex_lock(&exar_gpio->lock);
-       temp = readb(exar_gpio->regs + reg);
-       temp &= ~BIT(offset);
-       if (val)
-               temp |= BIT(offset);
-       writeb(temp, exar_gpio->regs + reg);
-       mutex_unlock(&exar_gpio->lock);
+       return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
+                                                  : EXAR_OFFSET_MPIOSEL_LO;
 }
 
-static int exar_set_direction(struct gpio_chip *chip, int direction,
-                             unsigned int offset)
+static unsigned int
+exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
 {
-       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
-               EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
-       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
-
-       exar_update(chip, addr, direction, bit);
-       return 0;
+       return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
+                                                  : EXAR_OFFSET_MPIOLVL_LO;
 }
 
-static int exar_get(struct gpio_chip *chip, unsigned int reg)
+static unsigned int
+exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
 {
-       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       int value;
-
-       mutex_lock(&exar_gpio->lock);
-       value = readb(exar_gpio->regs + reg);
-       mutex_unlock(&exar_gpio->lock);
-
-       return value;
+       return (offset + exar_gpio->first_pin) % 8;
 }
 
 static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
 {
        struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
-               EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
-       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
+       unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
+       unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-       if (exar_get(chip, addr) & BIT(bit))
+       if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)))
                return GPIO_LINE_DIRECTION_IN;
 
        return GPIO_LINE_DIRECTION_OUT;
@@ -86,39 +68,66 @@ static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
 static int exar_get_value(struct gpio_chip *chip, unsigned int offset)
 {
        struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
-               EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
-       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
+       unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
+       unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-       return !!(exar_get(chip, addr) & BIT(bit));
+       return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit)));
 }
 
 static void exar_set_value(struct gpio_chip *chip, unsigned int offset,
                           int value)
 {
        struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
-       unsigned int addr = (offset + exar_gpio->first_pin) / 8 ?
-               EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
-       unsigned int bit  = (offset + exar_gpio->first_pin) % 8;
+       unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset);
+       unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
 
-       exar_update(chip, addr, value, bit);
+       if (value)
+               regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
+       else
+               regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
 }
 
 static int exar_direction_output(struct gpio_chip *chip, unsigned int offset,
                                 int value)
 {
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
+       unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
+
        exar_set_value(chip, offset, value);
-       return exar_set_direction(chip, 0, offset);
+       regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit));
+
+       return 0;
 }
 
 static int exar_direction_input(struct gpio_chip *chip, unsigned int offset)
 {
-       return exar_set_direction(chip, 1, offset);
+       struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip);
+       unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset);
+       unsigned int bit = exar_offset_to_bit(exar_gpio, offset);
+
+       regmap_set_bits(exar_gpio->regmap, addr, BIT(bit));
+
+       return 0;
 }
 
+static void exar_devm_ida_free(void *data)
+{
+       struct exar_gpio_chip *exar_gpio = data;
+
+       ida_free(&ida_index, exar_gpio->index);
+}
+
+static const struct regmap_config exar_regmap_config = {
+       .name           = "exar-gpio",
+       .reg_bits       = 16,
+       .val_bits       = 8,
+};
+
 static int gpio_exar_probe(struct platform_device *pdev)
 {
-       struct pci_dev *pcidev = to_pci_dev(pdev->dev.parent);
+       struct device *dev = &pdev->dev;
+       struct pci_dev *pcidev = to_pci_dev(dev->parent);
        struct exar_gpio_chip *exar_gpio;
        u32 first_pin, ngpios;
        void __iomem *p;
@@ -132,30 +141,37 @@ static int gpio_exar_probe(struct platform_device *pdev)
        if (!p)
                return -ENOMEM;
 
-       ret = device_property_read_u32(&pdev->dev, "exar,first-pin",
-                                      &first_pin);
+       ret = device_property_read_u32(dev, "exar,first-pin", &first_pin);
        if (ret)
                return ret;
 
-       ret = device_property_read_u32(&pdev->dev, "ngpios", &ngpios);
+       ret = device_property_read_u32(dev, "ngpios", &ngpios);
        if (ret)
                return ret;
 
-       exar_gpio = devm_kzalloc(&pdev->dev, sizeof(*exar_gpio), GFP_KERNEL);
+       exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL);
        if (!exar_gpio)
                return -ENOMEM;
 
-       mutex_init(&exar_gpio->lock);
+       /*
+        * We don't need to check the return values of mmio regmap operations (unless
+        * the regmap has a clock attached which is not the case here).
+        */
+       exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config);
+       if (IS_ERR(exar_gpio->regmap))
+               return PTR_ERR(exar_gpio->regmap);
+
+       index = ida_alloc(&ida_index, GFP_KERNEL);
+       if (index < 0)
+               return index;
 
-       index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
-       if (index < 0) {
-               ret = index;
-               goto err_mutex_destroy;
-       }
+       ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio);
+       if (ret)
+               return ret;
 
        sprintf(exar_gpio->name, "exar_gpio%d", index);
        exar_gpio->gpio_chip.label = exar_gpio->name;
-       exar_gpio->gpio_chip.parent = &pdev->dev;
+       exar_gpio->gpio_chip.parent = dev;
        exar_gpio->gpio_chip.direction_output = exar_direction_output;
        exar_gpio->gpio_chip.direction_input = exar_direction_input;
        exar_gpio->gpio_chip.get_direction = exar_get_direction;
@@ -163,39 +179,20 @@ static int gpio_exar_probe(struct platform_device *pdev)
        exar_gpio->gpio_chip.set = exar_set_value;
        exar_gpio->gpio_chip.base = -1;
        exar_gpio->gpio_chip.ngpio = ngpios;
-       exar_gpio->regs = p;
        exar_gpio->index = index;
        exar_gpio->first_pin = first_pin;
 
-       ret = devm_gpiochip_add_data(&pdev->dev,
-                                    &exar_gpio->gpio_chip, exar_gpio);
+       ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio);
        if (ret)
-               goto err_destroy;
+               return ret;
 
        platform_set_drvdata(pdev, exar_gpio);
 
-       return 0;
-
-err_destroy:
-       ida_simple_remove(&ida_index, index);
-err_mutex_destroy:
-       mutex_destroy(&exar_gpio->lock);
-       return ret;
-}
-
-static int gpio_exar_remove(struct platform_device *pdev)
-{
-       struct exar_gpio_chip *exar_gpio = platform_get_drvdata(pdev);
-
-       ida_simple_remove(&ida_index, exar_gpio->index);
-       mutex_destroy(&exar_gpio->lock);
-
        return 0;
 }
 
 static struct platform_driver gpio_exar_driver = {
        .probe  = gpio_exar_probe,
-       .remove = gpio_exar_remove,
        .driver = {
                .name = DRIVER_NAME,
        },
diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c
new file mode 100644 (file)
index 0000000..ad3d4da
--- /dev/null
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2020 HiSilicon Limited. */
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define HISI_GPIO_SWPORT_DR_SET_WX     0x000
+#define HISI_GPIO_SWPORT_DR_CLR_WX     0x004
+#define HISI_GPIO_SWPORT_DDR_SET_WX    0x010
+#define HISI_GPIO_SWPORT_DDR_CLR_WX    0x014
+#define HISI_GPIO_SWPORT_DDR_ST_WX     0x018
+#define HISI_GPIO_INTEN_SET_WX         0x020
+#define HISI_GPIO_INTEN_CLR_WX         0x024
+#define HISI_GPIO_INTMASK_SET_WX       0x030
+#define HISI_GPIO_INTMASK_CLR_WX       0x034
+#define HISI_GPIO_INTTYPE_EDGE_SET_WX  0x040
+#define HISI_GPIO_INTTYPE_EDGE_CLR_WX  0x044
+#define HISI_GPIO_INT_POLARITY_SET_WX  0x050
+#define HISI_GPIO_INT_POLARITY_CLR_WX  0x054
+#define HISI_GPIO_DEBOUNCE_SET_WX      0x060
+#define HISI_GPIO_DEBOUNCE_CLR_WX      0x064
+#define HISI_GPIO_INTSTATUS_WX         0x070
+#define HISI_GPIO_PORTA_EOI_WX         0x078
+#define HISI_GPIO_EXT_PORT_WX          0x080
+#define HISI_GPIO_INTCOMB_MASK_WX      0x0a0
+#define HISI_GPIO_INT_DEDGE_SET                0x0b0
+#define HISI_GPIO_INT_DEDGE_CLR                0x0b4
+#define HISI_GPIO_INT_DEDGE_ST         0x0b8
+
+#define HISI_GPIO_LINE_NUM_MAX 32
+#define HISI_GPIO_DRIVER_NAME  "gpio-hisi"
+
+struct hisi_gpio {
+       struct gpio_chip        chip;
+       struct device           *dev;
+       void __iomem            *reg_base;
+       unsigned int            line_num;
+       struct irq_chip         irq_chip;
+       int                     irq;
+};
+
+static inline u32 hisi_gpio_read_reg(struct gpio_chip *chip,
+                                    unsigned int off)
+{
+       struct hisi_gpio *hisi_gpio =
+                       container_of(chip, struct hisi_gpio, chip);
+       void __iomem *reg = hisi_gpio->reg_base + off;
+
+       return readl(reg);
+}
+
+static inline void hisi_gpio_write_reg(struct gpio_chip *chip,
+                                      unsigned int off, u32 val)
+{
+       struct hisi_gpio *hisi_gpio =
+                       container_of(chip, struct hisi_gpio, chip);
+       void __iomem *reg = hisi_gpio->reg_base + off;
+
+       writel(val, reg);
+}
+
+static void hisi_gpio_set_debounce(struct gpio_chip *chip, unsigned int off,
+                                  u32 debounce)
+{
+       if (debounce)
+               hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_SET_WX, BIT(off));
+       else
+               hisi_gpio_write_reg(chip, HISI_GPIO_DEBOUNCE_CLR_WX, BIT(off));
+}
+
+static int hisi_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                               unsigned long config)
+{
+       u32 config_para = pinconf_to_config_param(config);
+       u32 config_arg;
+
+       switch (config_para) {
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               config_arg = pinconf_to_config_argument(config);
+               hisi_gpio_set_debounce(chip, offset, config_arg);
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static void hisi_gpio_set_ack(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       hisi_gpio_write_reg(chip, HISI_GPIO_PORTA_EOI_WX, BIT(irqd_to_hwirq(d)));
+}
+
+static void hisi_gpio_irq_set_mask(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_SET_WX, BIT(irqd_to_hwirq(d)));
+}
+
+static void hisi_gpio_irq_clr_mask(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       hisi_gpio_write_reg(chip, HISI_GPIO_INTMASK_CLR_WX, BIT(irqd_to_hwirq(d)));
+}
+
+static int hisi_gpio_irq_set_type(struct irq_data *d, u32 type)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int mask = BIT(irqd_to_hwirq(d));
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_SET, mask);
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, mask);
+               hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, mask);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_SET_WX, mask);
+               hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, mask);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, mask);
+               hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_SET_WX, mask);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               hisi_gpio_write_reg(chip, HISI_GPIO_INTTYPE_EDGE_CLR_WX, mask);
+               hisi_gpio_write_reg(chip, HISI_GPIO_INT_POLARITY_CLR_WX, mask);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * The dual-edge interrupt and other interrupt's registers do not
+        * take effect at the same time. The registers of the two-edge
+        * interrupts have higher priorities, the configuration of
+        * the dual-edge interrupts must be disabled before the configuration
+        * of other kind of interrupts.
+        */
+       if (type != IRQ_TYPE_EDGE_BOTH) {
+               unsigned int both = hisi_gpio_read_reg(chip, HISI_GPIO_INT_DEDGE_ST);
+
+               if (both & mask)
+                       hisi_gpio_write_reg(chip, HISI_GPIO_INT_DEDGE_CLR, mask);
+       }
+
+       if (type & IRQ_TYPE_LEVEL_MASK)
+               irq_set_handler_locked(d, handle_level_irq);
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
+
+       return 0;
+}
+
+static void hisi_gpio_irq_enable(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       hisi_gpio_irq_clr_mask(d);
+       hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_SET_WX, BIT(irqd_to_hwirq(d)));
+}
+
+static void hisi_gpio_irq_disable(struct irq_data *d)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+
+       hisi_gpio_irq_set_mask(d);
+       hisi_gpio_write_reg(chip, HISI_GPIO_INTEN_CLR_WX, BIT(irqd_to_hwirq(d)));
+}
+
+static void hisi_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct hisi_gpio *hisi_gpio = irq_desc_get_handler_data(desc);
+       unsigned long irq_msk = hisi_gpio_read_reg(&hisi_gpio->chip,
+                                                  HISI_GPIO_INTSTATUS_WX);
+       struct irq_chip *irq_c = irq_desc_get_chip(desc);
+       int hwirq;
+
+       chained_irq_enter(irq_c, desc);
+       for_each_set_bit(hwirq, &irq_msk, HISI_GPIO_LINE_NUM_MAX)
+               generic_handle_irq(irq_find_mapping(hisi_gpio->chip.irq.domain,
+                                                   hwirq));
+       chained_irq_exit(irq_c, desc);
+}
+
+static void hisi_gpio_init_irq(struct hisi_gpio *hisi_gpio)
+{
+       struct gpio_chip *chip = &hisi_gpio->chip;
+       struct gpio_irq_chip *girq_chip = &chip->irq;
+
+       /* Set hooks for irq_chip */
+       hisi_gpio->irq_chip.irq_ack = hisi_gpio_set_ack;
+       hisi_gpio->irq_chip.irq_mask = hisi_gpio_irq_set_mask;
+       hisi_gpio->irq_chip.irq_unmask = hisi_gpio_irq_clr_mask;
+       hisi_gpio->irq_chip.irq_set_type = hisi_gpio_irq_set_type;
+       hisi_gpio->irq_chip.irq_enable = hisi_gpio_irq_enable;
+       hisi_gpio->irq_chip.irq_disable = hisi_gpio_irq_disable;
+
+       girq_chip->chip = &hisi_gpio->irq_chip;
+       girq_chip->default_type = IRQ_TYPE_NONE;
+       girq_chip->num_parents = 1;
+       girq_chip->parents = &hisi_gpio->irq;
+       girq_chip->parent_handler = hisi_gpio_irq_handler;
+       girq_chip->parent_handler_data = hisi_gpio;
+
+       /* Clear Mask of GPIO controller combine IRQ */
+       hisi_gpio_write_reg(chip, HISI_GPIO_INTCOMB_MASK_WX, 1);
+}
+
+static const struct acpi_device_id hisi_gpio_acpi_match[] = {
+       {"HISI0184", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, hisi_gpio_acpi_match);
+
+static void hisi_gpio_get_pdata(struct device *dev,
+                               struct hisi_gpio *hisi_gpio)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct fwnode_handle *fwnode;
+       int idx = 0;
+
+       device_for_each_child_node(dev, fwnode)  {
+               /* Cycle for once, no need for an array to save line_num */
+               if (fwnode_property_read_u32(fwnode, "ngpios",
+                                            &hisi_gpio->line_num)) {
+                       dev_err(dev,
+                               "failed to get number of lines for port%d and use default value instead\n",
+                               idx);
+                       hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX;
+               }
+
+               if (WARN_ON(hisi_gpio->line_num > HISI_GPIO_LINE_NUM_MAX))
+                       hisi_gpio->line_num = HISI_GPIO_LINE_NUM_MAX;
+
+               hisi_gpio->irq = platform_get_irq(pdev, idx);
+
+               dev_info(dev,
+                        "get hisi_gpio[%d] with %d lines\n", idx,
+                        hisi_gpio->line_num);
+
+               idx++;
+       }
+}
+
+static int hisi_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct hisi_gpio *hisi_gpio;
+       int port_num;
+       int ret;
+
+       /*
+        * One GPIO controller own one port currently,
+        * if we get more from ACPI table, return error.
+        */
+       port_num = device_get_child_node_count(dev);
+       if (WARN_ON(port_num != 1))
+               return -ENODEV;
+
+       hisi_gpio = devm_kzalloc(dev, sizeof(*hisi_gpio), GFP_KERNEL);
+       if (!hisi_gpio)
+               return -ENOMEM;
+
+       hisi_gpio->reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(hisi_gpio->reg_base))
+               return PTR_ERR(hisi_gpio->reg_base);
+
+       hisi_gpio_get_pdata(dev, hisi_gpio);
+
+       hisi_gpio->dev = dev;
+
+       ret = bgpio_init(&hisi_gpio->chip, hisi_gpio->dev, 0x4,
+                        hisi_gpio->reg_base + HISI_GPIO_EXT_PORT_WX,
+                        hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_SET_WX,
+                        hisi_gpio->reg_base + HISI_GPIO_SWPORT_DR_CLR_WX,
+                        hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_SET_WX,
+                        hisi_gpio->reg_base + HISI_GPIO_SWPORT_DDR_CLR_WX,
+                        BGPIOF_NO_SET_ON_INPUT);
+       if (ret) {
+               dev_err(dev, "failed to init, ret = %d\n", ret);
+               return ret;
+       }
+
+       hisi_gpio->chip.set_config = hisi_gpio_set_config;
+       hisi_gpio->chip.ngpio = hisi_gpio->line_num;
+       hisi_gpio->chip.bgpio_dir_unreadable = 1;
+       hisi_gpio->chip.base = -1;
+
+       if (hisi_gpio->irq > 0)
+               hisi_gpio_init_irq(hisi_gpio);
+
+       ret = devm_gpiochip_add_data(dev, &hisi_gpio->chip, hisi_gpio);
+       if (ret) {
+               dev_err(dev, "failed to register gpiochip, ret = %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct platform_driver hisi_gpio_driver = {
+       .driver         = {
+               .name   = HISI_GPIO_DRIVER_NAME,
+               .acpi_match_table = hisi_gpio_acpi_match,
+       },
+       .probe          = hisi_gpio_probe,
+};
+
+module_platform_driver(hisi_gpio_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luo Jiaxing <luojiaxing@huawei.com>");
+MODULE_DESCRIPTION("HiSilicon GPIO controller driver");
+MODULE_ALIAS("platform:" HISI_GPIO_DRIVER_NAME);
index 67ed4f2..28b757d 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/irq_sim.h>
 #include <linux/irqdomain.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
@@ -460,9 +461,16 @@ static int gpio_mockup_probe(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id gpio_mockup_of_match[] = {
+       { .compatible = "gpio-mockup", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, gpio_mockup_of_match);
+
 static struct platform_driver gpio_mockup_driver = {
        .driver = {
                .name = "gpio-mockup",
+               .of_match_table = gpio_mockup_of_match,
        },
        .probe = gpio_mockup_probe,
 };
@@ -556,8 +564,7 @@ static int __init gpio_mockup_init(void)
 {
        int i, num_chips, err;
 
-       if ((gpio_mockup_num_ranges < 2) ||
-           (gpio_mockup_num_ranges % 2) ||
+       if ((gpio_mockup_num_ranges % 2) ||
            (gpio_mockup_num_ranges > GPIO_MOCKUP_MAX_RANGES))
                return -EINVAL;
 
diff --git a/drivers/gpio/gpio-msc313.c b/drivers/gpio/gpio-msc313.c
new file mode 100644 (file)
index 0000000..da31a5f
--- /dev/null
@@ -0,0 +1,460 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020 Daniel Palmer<daniel@thingy.jp> */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/gpio/msc313-gpio.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#define DRIVER_NAME "gpio-msc313"
+
+#define MSC313_GPIO_IN  BIT(0)
+#define MSC313_GPIO_OUT BIT(4)
+#define MSC313_GPIO_OEN BIT(5)
+
+/*
+ * These bits need to be saved to correctly restore the
+ * gpio state when resuming from suspend to memory.
+ */
+#define MSC313_GPIO_BITSTOSAVE (MSC313_GPIO_OUT | MSC313_GPIO_OEN)
+
+/* pad names for fuart, same for all SoCs so far */
+#define MSC313_PINNAME_FUART_RX                "fuart_rx"
+#define MSC313_PINNAME_FUART_TX                "fuart_tx"
+#define MSC313_PINNAME_FUART_CTS       "fuart_cts"
+#define MSC313_PINNAME_FUART_RTS       "fuart_rts"
+
+/* pad names for sr, mercury5 is different */
+#define MSC313_PINNAME_SR_IO2          "sr_io2"
+#define MSC313_PINNAME_SR_IO3          "sr_io3"
+#define MSC313_PINNAME_SR_IO4          "sr_io4"
+#define MSC313_PINNAME_SR_IO5          "sr_io5"
+#define MSC313_PINNAME_SR_IO6          "sr_io6"
+#define MSC313_PINNAME_SR_IO7          "sr_io7"
+#define MSC313_PINNAME_SR_IO8          "sr_io8"
+#define MSC313_PINNAME_SR_IO9          "sr_io9"
+#define MSC313_PINNAME_SR_IO10         "sr_io10"
+#define MSC313_PINNAME_SR_IO11         "sr_io11"
+#define MSC313_PINNAME_SR_IO12         "sr_io12"
+#define MSC313_PINNAME_SR_IO13         "sr_io13"
+#define MSC313_PINNAME_SR_IO14         "sr_io14"
+#define MSC313_PINNAME_SR_IO15         "sr_io15"
+#define MSC313_PINNAME_SR_IO16         "sr_io16"
+#define MSC313_PINNAME_SR_IO17         "sr_io17"
+
+/* pad names for sd, same for all SoCs so far */
+#define MSC313_PINNAME_SD_CLK          "sd_clk"
+#define MSC313_PINNAME_SD_CMD          "sd_cmd"
+#define MSC313_PINNAME_SD_D0           "sd_d0"
+#define MSC313_PINNAME_SD_D1           "sd_d1"
+#define MSC313_PINNAME_SD_D2           "sd_d2"
+#define MSC313_PINNAME_SD_D3           "sd_d3"
+
+/* pad names for i2c1, same for all SoCs so for */
+#define MSC313_PINNAME_I2C1_SCL                "i2c1_scl"
+#define MSC313_PINNAME_I2C1_SCA                "i2c1_sda"
+
+/* pad names for spi0, same for all SoCs so far */
+#define MSC313_PINNAME_SPI0_CZ         "spi0_cz"
+#define MSC313_PINNAME_SPI0_CK         "spi0_ck"
+#define MSC313_PINNAME_SPI0_DI         "spi0_di"
+#define MSC313_PINNAME_SPI0_DO         "spi0_do"
+
+#define FUART_NAMES                    \
+       MSC313_PINNAME_FUART_RX,        \
+       MSC313_PINNAME_FUART_TX,        \
+       MSC313_PINNAME_FUART_CTS,       \
+       MSC313_PINNAME_FUART_RTS
+
+#define OFF_FUART_RX   0x50
+#define OFF_FUART_TX   0x54
+#define OFF_FUART_CTS  0x58
+#define OFF_FUART_RTS  0x5c
+
+#define FUART_OFFSETS  \
+       OFF_FUART_RX,   \
+       OFF_FUART_TX,   \
+       OFF_FUART_CTS,  \
+       OFF_FUART_RTS
+
+#define SR_NAMES               \
+       MSC313_PINNAME_SR_IO2,  \
+       MSC313_PINNAME_SR_IO3,  \
+       MSC313_PINNAME_SR_IO4,  \
+       MSC313_PINNAME_SR_IO5,  \
+       MSC313_PINNAME_SR_IO6,  \
+       MSC313_PINNAME_SR_IO7,  \
+       MSC313_PINNAME_SR_IO8,  \
+       MSC313_PINNAME_SR_IO9,  \
+       MSC313_PINNAME_SR_IO10, \
+       MSC313_PINNAME_SR_IO11, \
+       MSC313_PINNAME_SR_IO12, \
+       MSC313_PINNAME_SR_IO13, \
+       MSC313_PINNAME_SR_IO14, \
+       MSC313_PINNAME_SR_IO15, \
+       MSC313_PINNAME_SR_IO16, \
+       MSC313_PINNAME_SR_IO17
+
+#define OFF_SR_IO2     0x88
+#define OFF_SR_IO3     0x8c
+#define OFF_SR_IO4     0x90
+#define OFF_SR_IO5     0x94
+#define OFF_SR_IO6     0x98
+#define OFF_SR_IO7     0x9c
+#define OFF_SR_IO8     0xa0
+#define OFF_SR_IO9     0xa4
+#define OFF_SR_IO10    0xa8
+#define OFF_SR_IO11    0xac
+#define OFF_SR_IO12    0xb0
+#define OFF_SR_IO13    0xb4
+#define OFF_SR_IO14    0xb8
+#define OFF_SR_IO15    0xbc
+#define OFF_SR_IO16    0xc0
+#define OFF_SR_IO17    0xc4
+
+#define SR_OFFSETS     \
+       OFF_SR_IO2,     \
+       OFF_SR_IO3,     \
+       OFF_SR_IO4,     \
+       OFF_SR_IO5,     \
+       OFF_SR_IO6,     \
+       OFF_SR_IO7,     \
+       OFF_SR_IO8,     \
+       OFF_SR_IO9,     \
+       OFF_SR_IO10,    \
+       OFF_SR_IO11,    \
+       OFF_SR_IO12,    \
+       OFF_SR_IO13,    \
+       OFF_SR_IO14,    \
+       OFF_SR_IO15,    \
+       OFF_SR_IO16,    \
+       OFF_SR_IO17
+
+#define SD_NAMES               \
+       MSC313_PINNAME_SD_CLK,  \
+       MSC313_PINNAME_SD_CMD,  \
+       MSC313_PINNAME_SD_D0,   \
+       MSC313_PINNAME_SD_D1,   \
+       MSC313_PINNAME_SD_D2,   \
+       MSC313_PINNAME_SD_D3
+
+#define OFF_SD_CLK     0x140
+#define OFF_SD_CMD     0x144
+#define OFF_SD_D0      0x148
+#define OFF_SD_D1      0x14c
+#define OFF_SD_D2      0x150
+#define OFF_SD_D3      0x154
+
+#define SD_OFFSETS     \
+       OFF_SD_CLK,     \
+       OFF_SD_CMD,     \
+       OFF_SD_D0,      \
+       OFF_SD_D1,      \
+       OFF_SD_D2,      \
+       OFF_SD_D3
+
+#define I2C1_NAMES                     \
+       MSC313_PINNAME_I2C1_SCL,        \
+       MSC313_PINNAME_I2C1_SCA
+
+#define OFF_I2C1_SCL   0x188
+#define OFF_I2C1_SCA   0x18c
+
+#define I2C1_OFFSETS   \
+       OFF_I2C1_SCL,   \
+       OFF_I2C1_SCA
+
+#define SPI0_NAMES             \
+       MSC313_PINNAME_SPI0_CZ, \
+       MSC313_PINNAME_SPI0_CK, \
+       MSC313_PINNAME_SPI0_DI, \
+       MSC313_PINNAME_SPI0_DO
+
+#define OFF_SPI0_CZ    0x1c0
+#define OFF_SPI0_CK    0x1c4
+#define OFF_SPI0_DI    0x1c8
+#define OFF_SPI0_DO    0x1cc
+
+#define SPI0_OFFSETS   \
+       OFF_SPI0_CZ,    \
+       OFF_SPI0_CK,    \
+       OFF_SPI0_DI,    \
+       OFF_SPI0_DO
+
+struct msc313_gpio_data {
+       const char * const *names;
+       const unsigned int *offsets;
+       const unsigned int num;
+};
+
+#define MSC313_GPIO_CHIPDATA(_chip) \
+static const struct msc313_gpio_data _chip##_data = { \
+       .names = _chip##_names, \
+       .offsets = _chip##_offsets, \
+       .num = ARRAY_SIZE(_chip##_offsets), \
+}
+
+#ifdef CONFIG_MACH_INFINITY
+static const char * const msc313_names[] = {
+       FUART_NAMES,
+       SR_NAMES,
+       SD_NAMES,
+       I2C1_NAMES,
+       SPI0_NAMES,
+};
+
+static const unsigned int msc313_offsets[] = {
+       FUART_OFFSETS,
+       SR_OFFSETS,
+       SD_OFFSETS,
+       I2C1_OFFSETS,
+       SPI0_OFFSETS,
+};
+
+MSC313_GPIO_CHIPDATA(msc313);
+#endif
+
+struct msc313_gpio {
+       void __iomem *base;
+       const struct msc313_gpio_data *gpio_data;
+       u8 *saved;
+};
+
+static void msc313_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+       struct msc313_gpio *gpio = gpiochip_get_data(chip);
+       u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
+
+       if (value)
+               gpioreg |= MSC313_GPIO_OUT;
+       else
+               gpioreg &= ~MSC313_GPIO_OUT;
+
+       writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
+}
+
+static int msc313_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct msc313_gpio *gpio = gpiochip_get_data(chip);
+
+       return readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]) & MSC313_GPIO_IN;
+}
+
+static int msc313_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+       struct msc313_gpio *gpio = gpiochip_get_data(chip);
+       u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
+
+       gpioreg |= MSC313_GPIO_OEN;
+       writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
+
+       return 0;
+}
+
+static int msc313_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value)
+{
+       struct msc313_gpio *gpio = gpiochip_get_data(chip);
+       u8 gpioreg = readb_relaxed(gpio->base + gpio->gpio_data->offsets[offset]);
+
+       gpioreg &= ~MSC313_GPIO_OEN;
+       if (value)
+               gpioreg |= MSC313_GPIO_OUT;
+       else
+               gpioreg &= ~MSC313_GPIO_OUT;
+       writeb_relaxed(gpioreg, gpio->base + gpio->gpio_data->offsets[offset]);
+
+       return 0;
+}
+
+/*
+ * The interrupt handling happens in the parent interrupt controller,
+ * we don't do anything here.
+ */
+static struct irq_chip msc313_gpio_irqchip = {
+       .name = "GPIO",
+       .irq_eoi = irq_chip_eoi_parent,
+       .irq_mask = irq_chip_mask_parent,
+       .irq_unmask = irq_chip_unmask_parent,
+       .irq_set_type = irq_chip_set_type_parent,
+       .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+/*
+ * The parent interrupt controller needs the GIC interrupt type set to GIC_SPI
+ * so we need to provide the fwspec. Essentially gpiochip_populate_parent_fwspec_twocell
+ * that puts GIC_SPI into the first cell.
+ */
+static void *msc313_gpio_populate_parent_fwspec(struct gpio_chip *gc,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
+{
+       struct irq_fwspec *fwspec;
+
+       fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
+       if (!fwspec)
+               return NULL;
+
+       fwspec->fwnode = gc->irq.parent_domain->fwnode;
+       fwspec->param_count = 3;
+       fwspec->param[0] = GIC_SPI;
+       fwspec->param[1] = parent_hwirq;
+       fwspec->param[2] = parent_type;
+
+       return fwspec;
+}
+
+static int msc313e_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
+                                            unsigned int child,
+                                            unsigned int child_type,
+                                            unsigned int *parent,
+                                            unsigned int *parent_type)
+{
+       struct msc313_gpio *priv = gpiochip_get_data(chip);
+       unsigned int offset = priv->gpio_data->offsets[child];
+
+       /*
+        * only the spi0 pins have interrupts on the parent
+        * on all of the known chips and so far they are all
+        * mapped to the same place
+        */
+       if (offset >= OFF_SPI0_CZ && offset <= OFF_SPI0_DO) {
+               *parent_type = child_type;
+               *parent = ((offset - OFF_SPI0_CZ) >> 2) + 28;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int msc313_gpio_probe(struct platform_device *pdev)
+{
+       const struct msc313_gpio_data *match_data;
+       struct msc313_gpio *gpio;
+       struct gpio_chip *gpiochip;
+       struct gpio_irq_chip *gpioirqchip;
+       struct irq_domain *parent_domain;
+       struct device_node *parent_node;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       match_data = of_device_get_match_data(dev);
+       if (!match_data)
+               return -EINVAL;
+
+       parent_node = of_irq_find_parent(dev->of_node);
+       if (!parent_node)
+               return -ENODEV;
+
+       parent_domain = irq_find_host(parent_node);
+       if (!parent_domain)
+               return -ENODEV;
+
+       gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       gpio->gpio_data = match_data;
+
+       gpio->saved = devm_kcalloc(dev, gpio->gpio_data->num, sizeof(*gpio->saved), GFP_KERNEL);
+       if (!gpio->saved)
+               return -ENOMEM;
+
+       gpio->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gpio->base))
+               return PTR_ERR(gpio->base);
+
+       platform_set_drvdata(pdev, gpio);
+
+       gpiochip = devm_kzalloc(dev, sizeof(*gpiochip), GFP_KERNEL);
+       if (!gpiochip)
+               return -ENOMEM;
+
+       gpiochip->label = DRIVER_NAME;
+       gpiochip->parent = dev;
+       gpiochip->request = gpiochip_generic_request;
+       gpiochip->free = gpiochip_generic_free;
+       gpiochip->direction_input = msc313_gpio_direction_input;
+       gpiochip->direction_output = msc313_gpio_direction_output;
+       gpiochip->get = msc313_gpio_get;
+       gpiochip->set = msc313_gpio_set;
+       gpiochip->base = -1;
+       gpiochip->ngpio = gpio->gpio_data->num;
+       gpiochip->names = gpio->gpio_data->names;
+
+       gpioirqchip = &gpiochip->irq;
+       gpioirqchip->chip = &msc313_gpio_irqchip;
+       gpioirqchip->fwnode = of_node_to_fwnode(dev->of_node);
+       gpioirqchip->parent_domain = parent_domain;
+       gpioirqchip->child_to_parent_hwirq = msc313e_gpio_child_to_parent_hwirq;
+       gpioirqchip->populate_parent_alloc_arg = msc313_gpio_populate_parent_fwspec;
+       gpioirqchip->handler = handle_bad_irq;
+       gpioirqchip->default_type = IRQ_TYPE_NONE;
+
+       ret = devm_gpiochip_add_data(dev, gpiochip, gpio);
+       return ret;
+}
+
+static int msc313_gpio_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id msc313_gpio_of_match[] = {
+#ifdef CONFIG_MACH_INFINITY
+       {
+               .compatible = "mstar,msc313-gpio",
+               .data = &msc313_data,
+       },
+#endif
+       { }
+};
+
+/*
+ * The GPIO controller loses the state of the registers when the
+ * SoC goes into suspend to memory mode so we need to save some
+ * of the register bits before suspending and put it back when resuming
+ */
+static int __maybe_unused msc313_gpio_suspend(struct device *dev)
+{
+       struct msc313_gpio *gpio = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < gpio->gpio_data->num; i++)
+               gpio->saved[i] = readb_relaxed(gpio->base + gpio->gpio_data->offsets[i]) & MSC313_GPIO_BITSTOSAVE;
+
+       return 0;
+}
+
+static int __maybe_unused msc313_gpio_resume(struct device *dev)
+{
+       struct msc313_gpio *gpio = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < gpio->gpio_data->num; i++)
+               writeb_relaxed(gpio->saved[i], gpio->base + gpio->gpio_data->offsets[i]);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(msc313_gpio_ops, msc313_gpio_suspend, msc313_gpio_resume);
+
+static struct platform_driver msc313_gpio_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = msc313_gpio_of_match,
+               .pm = &msc313_gpio_ops,
+       },
+       .probe = msc313_gpio_probe,
+       .remove = msc313_gpio_remove,
+};
+
+builtin_platform_driver(msc313_gpio_driver);
index 2f24559..672681a 100644 (file)
@@ -78,8 +78,7 @@
 
 /*
  * The Armada XP has per-CPU registers for interrupt cause, interrupt
- * mask and interrupt level mask. Those are relative to the
- * percpu_membase.
+ * mask and interrupt level mask. Those are in percpu_regs range.
  */
 #define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
 #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu)  (0x10 + (cpu) * 0x4)
@@ -93,7 +92,7 @@
 #define MVEBU_MAX_GPIO_PER_BANK                32
 
 struct mvebu_pwm {
-       void __iomem            *membase;
+       struct regmap           *regs;
        unsigned long            clk_rate;
        struct gpio_desc        *gpiod;
        struct pwm_chip          chip;
@@ -279,17 +278,17 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
 }
 
 /*
- * Functions returning addresses of individual registers for a given
+ * Functions returning offsets of individual registers for a given
  * PWM controller.
  */
-static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
+static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
 {
-       return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
+       return PWM_BLINK_ON_DURATION_OFF;
 }
 
-static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
+static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
 {
-       return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
+       return PWM_BLINK_OFF_DURATION_OFF;
 }
 
 /*
@@ -600,6 +599,13 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc)
        chained_irq_exit(chip, desc);
 }
 
+static const struct regmap_config mvebu_gpio_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .fast_io = true,
+};
+
 /*
  * Functions implementing the pwm_chip methods
  */
@@ -660,9 +666,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
 
        spin_lock_irqsave(&mvpwm->lock, flags);
 
-       val = (unsigned long long)
-               readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
-       val *= NSEC_PER_SEC;
+       regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
+       val = (unsigned long long) u * NSEC_PER_SEC;
        do_div(val, mvpwm->clk_rate);
        if (val > UINT_MAX)
                state->duty_cycle = UINT_MAX;
@@ -671,9 +676,8 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
        else
                state->duty_cycle = 1;
 
-       val = (unsigned long long)
-               readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
-       val *= NSEC_PER_SEC;
+       regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
+       val = (unsigned long long) u * NSEC_PER_SEC;
        do_div(val, mvpwm->clk_rate);
        if (val < state->duty_cycle) {
                state->period = 1;
@@ -726,8 +730,8 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 
        spin_lock_irqsave(&mvpwm->lock, flags);
 
-       writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
-       writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
+       regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on);
+       regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off);
        if (state->enabled)
                mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
        else
@@ -752,10 +756,10 @@ static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
 
        regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
                    &mvpwm->blink_select);
-       mvpwm->blink_on_duration =
-               readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
-       mvpwm->blink_off_duration =
-               readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
+       regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
+                   &mvpwm->blink_on_duration);
+       regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
+                   &mvpwm->blink_off_duration);
 }
 
 static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
@@ -764,10 +768,10 @@ static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
 
        regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
                     mvpwm->blink_select);
-       writel_relaxed(mvpwm->blink_on_duration,
-                      mvebu_pwmreg_blink_on_duration(mvpwm));
-       writel_relaxed(mvpwm->blink_off_duration,
-                      mvebu_pwmreg_blink_off_duration(mvpwm));
+       regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
+                    mvpwm->blink_on_duration);
+       regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
+                    mvpwm->blink_off_duration);
 }
 
 static int mvebu_pwm_probe(struct platform_device *pdev,
@@ -776,6 +780,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 {
        struct device *dev = &pdev->dev;
        struct mvebu_pwm *mvpwm;
+       void __iomem *base;
        u32 set;
 
        if (!of_device_is_compatible(mvchip->chip.of_node,
@@ -813,9 +818,14 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
        mvchip->mvpwm = mvpwm;
        mvpwm->mvchip = mvchip;
 
-       mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
-       if (IS_ERR(mvpwm->membase))
-               return PTR_ERR(mvpwm->membase);
+       base = devm_platform_ioremap_resource_byname(pdev, "pwm");
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
+                                           &mvebu_gpio_regmap_config);
+       if (IS_ERR(mvpwm->regs))
+               return PTR_ERR(mvpwm->regs);
 
        mvpwm->clk_rate = clk_get_rate(mvchip->clk);
        if (!mvpwm->clk_rate) {
@@ -1022,13 +1032,6 @@ static int mvebu_gpio_resume(struct platform_device *pdev)
        return 0;
 }
 
-static const struct regmap_config mvebu_gpio_regmap_config = {
-       .reg_bits = 32,
-       .reg_stride = 4,
-       .val_bits = 32,
-       .fast_io = true,
-};
-
 static int mvebu_gpio_probe_raw(struct platform_device *pdev,
                                struct mvebu_gpio_chip *mvchip)
 {
index 643f4c5..157106e 100644 (file)
 #include <linux/of_device.h>
 #include <linux/bug.h>
 
-enum mxc_gpio_hwtype {
-       IMX1_GPIO,      /* runs on i.mx1 */
-       IMX21_GPIO,     /* runs on i.mx21 and i.mx27 */
-       IMX31_GPIO,     /* runs on i.mx31 */
-       IMX35_GPIO,     /* runs on all other i.mx */
-};
-
 /* device type dependent stuff */
 struct mxc_gpio_hwdata {
        unsigned dr_reg;
@@ -68,6 +61,7 @@ struct mxc_gpio_port {
        u32 both_edges;
        struct mxc_gpio_reg_saved gpio_saved_reg;
        bool power_off;
+       const struct mxc_gpio_hwdata *hwdata;
 };
 
 static struct mxc_gpio_hwdata imx1_imx21_gpio_hwdata = {
@@ -115,48 +109,27 @@ static struct mxc_gpio_hwdata imx35_gpio_hwdata = {
        .fall_edge      = 0x03,
 };
 
-static enum mxc_gpio_hwtype mxc_gpio_hwtype;
-static struct mxc_gpio_hwdata *mxc_gpio_hwdata;
-
-#define GPIO_DR                        (mxc_gpio_hwdata->dr_reg)
-#define GPIO_GDIR              (mxc_gpio_hwdata->gdir_reg)
-#define GPIO_PSR               (mxc_gpio_hwdata->psr_reg)
-#define GPIO_ICR1              (mxc_gpio_hwdata->icr1_reg)
-#define GPIO_ICR2              (mxc_gpio_hwdata->icr2_reg)
-#define GPIO_IMR               (mxc_gpio_hwdata->imr_reg)
-#define GPIO_ISR               (mxc_gpio_hwdata->isr_reg)
-#define GPIO_EDGE_SEL          (mxc_gpio_hwdata->edge_sel_reg)
-
-#define GPIO_INT_LOW_LEV       (mxc_gpio_hwdata->low_level)
-#define GPIO_INT_HIGH_LEV      (mxc_gpio_hwdata->high_level)
-#define GPIO_INT_RISE_EDGE     (mxc_gpio_hwdata->rise_edge)
-#define GPIO_INT_FALL_EDGE     (mxc_gpio_hwdata->fall_edge)
+#define GPIO_DR                        (port->hwdata->dr_reg)
+#define GPIO_GDIR              (port->hwdata->gdir_reg)
+#define GPIO_PSR               (port->hwdata->psr_reg)
+#define GPIO_ICR1              (port->hwdata->icr1_reg)
+#define GPIO_ICR2              (port->hwdata->icr2_reg)
+#define GPIO_IMR               (port->hwdata->imr_reg)
+#define GPIO_ISR               (port->hwdata->isr_reg)
+#define GPIO_EDGE_SEL          (port->hwdata->edge_sel_reg)
+
+#define GPIO_INT_LOW_LEV       (port->hwdata->low_level)
+#define GPIO_INT_HIGH_LEV      (port->hwdata->high_level)
+#define GPIO_INT_RISE_EDGE     (port->hwdata->rise_edge)
+#define GPIO_INT_FALL_EDGE     (port->hwdata->fall_edge)
 #define GPIO_INT_BOTH_EDGES    0x4
 
-static const struct platform_device_id mxc_gpio_devtype[] = {
-       {
-               .name = "imx1-gpio",
-               .driver_data = IMX1_GPIO,
-       }, {
-               .name = "imx21-gpio",
-               .driver_data = IMX21_GPIO,
-       }, {
-               .name = "imx31-gpio",
-               .driver_data = IMX31_GPIO,
-       }, {
-               .name = "imx35-gpio",
-               .driver_data = IMX35_GPIO,
-       }, {
-               /* sentinel */
-       }
-};
-
 static const struct of_device_id mxc_gpio_dt_ids[] = {
-       { .compatible = "fsl,imx1-gpio", .data = &mxc_gpio_devtype[IMX1_GPIO], },
-       { .compatible = "fsl,imx21-gpio", .data = &mxc_gpio_devtype[IMX21_GPIO], },
-       { .compatible = "fsl,imx31-gpio", .data = &mxc_gpio_devtype[IMX31_GPIO], },
-       { .compatible = "fsl,imx35-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
-       { .compatible = "fsl,imx7d-gpio", .data = &mxc_gpio_devtype[IMX35_GPIO], },
+       { .compatible = "fsl,imx1-gpio", .data =  &imx1_imx21_gpio_hwdata },
+       { .compatible = "fsl,imx21-gpio", .data = &imx1_imx21_gpio_hwdata },
+       { .compatible = "fsl,imx31-gpio", .data = &imx31_gpio_hwdata },
+       { .compatible = "fsl,imx35-gpio", .data = &imx35_gpio_hwdata },
+       { .compatible = "fsl,imx7d-gpio", .data = &imx35_gpio_hwdata },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, mxc_gpio_dt_ids);
@@ -372,36 +345,6 @@ static int mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base)
        return rv;
 }
 
-static void mxc_gpio_get_hw(struct platform_device *pdev)
-{
-       const struct of_device_id *of_id =
-                       of_match_device(mxc_gpio_dt_ids, &pdev->dev);
-       enum mxc_gpio_hwtype hwtype;
-
-       if (of_id)
-               pdev->id_entry = of_id->data;
-       hwtype = pdev->id_entry->driver_data;
-
-       if (mxc_gpio_hwtype) {
-               /*
-                * The driver works with a reasonable presupposition,
-                * that is all gpio ports must be the same type when
-                * running on one soc.
-                */
-               BUG_ON(mxc_gpio_hwtype != hwtype);
-               return;
-       }
-
-       if (hwtype == IMX35_GPIO)
-               mxc_gpio_hwdata = &imx35_gpio_hwdata;
-       else if (hwtype == IMX31_GPIO)
-               mxc_gpio_hwdata = &imx31_gpio_hwdata;
-       else
-               mxc_gpio_hwdata = &imx1_imx21_gpio_hwdata;
-
-       mxc_gpio_hwtype = hwtype;
-}
-
 static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
 {
        struct mxc_gpio_port *port = gpiochip_get_data(gc);
@@ -417,14 +360,14 @@ static int mxc_gpio_probe(struct platform_device *pdev)
        int irq_base;
        int err;
 
-       mxc_gpio_get_hw(pdev);
-
        port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
        if (!port)
                return -ENOMEM;
 
        port->dev = &pdev->dev;
 
+       port->hwdata = device_get_match_data(&pdev->dev);
+
        port->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(port->base))
                return PTR_ERR(port->base);
@@ -461,7 +404,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
        writel(0, port->base + GPIO_IMR);
        writel(~0, port->base + GPIO_ISR);
 
-       if (mxc_gpio_hwtype == IMX21_GPIO) {
+       if (of_device_is_compatible(np, "fsl,imx21-gpio")) {
                /*
                 * Setup one handler for all GPIO interrupts. Actually setting
                 * the handler is needed only once, but doing it for every port
@@ -596,7 +539,6 @@ static struct platform_driver mxc_gpio_driver = {
                .suppress_bind_attrs = true,
        },
        .probe          = mxc_gpio_probe,
-       .id_table       = mxc_gpio_devtype,
 };
 
 static int __init gpio_mxc_init(void)
index c4a314c..dfc0c1e 100644 (file)
@@ -254,19 +254,6 @@ static int mxs_gpio_get_direction(struct gpio_chip *gc, unsigned offset)
        return GPIO_LINE_DIRECTION_IN;
 }
 
-static const struct platform_device_id mxs_gpio_ids[] = {
-       {
-               .name = "imx23-gpio",
-               .driver_data = IMX23_GPIO,
-       }, {
-               .name = "imx28-gpio",
-               .driver_data = IMX28_GPIO,
-       }, {
-               /* sentinel */
-       }
-};
-MODULE_DEVICE_TABLE(platform, mxs_gpio_ids);
-
 static const struct of_device_id mxs_gpio_dt_ids[] = {
        { .compatible = "fsl,imx23-gpio", .data = (void *) IMX23_GPIO, },
        { .compatible = "fsl,imx28-gpio", .data = (void *) IMX28_GPIO, },
@@ -370,7 +357,6 @@ static struct platform_driver mxs_gpio_driver = {
                .suppress_bind_attrs = true,
        },
        .probe          = mxs_gpio_probe,
-       .id_table       = mxs_gpio_ids,
 };
 
 static int __init mxs_gpio_init(void)
index f7ceb2b..41952bb 100644 (file)
@@ -1049,11 +1049,8 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        irq->first = irq_base;
 
        ret = gpiochip_add_data(&bank->chip, bank);
-       if (ret) {
-               dev_err(bank->chip.parent,
-                       "Could not register gpio chip %d\n", ret);
-               return ret;
-       }
+       if (ret)
+               return dev_err_probe(bank->chip.parent, ret, "Could not register gpio chip\n");
 
        ret = devm_request_irq(bank->chip.parent, bank->irq,
                               omap_gpio_irq_handler,
index 3ef19ce..0b572db 100644 (file)
@@ -32,6 +32,11 @@ struct gpio_rcar_bank_info {
        u32 intmsk;
 };
 
+struct gpio_rcar_info {
+       bool has_outdtsel;
+       bool has_both_edge_trigger;
+};
+
 struct gpio_rcar_priv {
        void __iomem *base;
        spinlock_t lock;
@@ -40,24 +45,23 @@ struct gpio_rcar_priv {
        struct irq_chip irq_chip;
        unsigned int irq_parent;
        atomic_t wakeup_path;
-       bool has_outdtsel;
-       bool has_both_edge_trigger;
+       struct gpio_rcar_info info;
        struct gpio_rcar_bank_info bank_info;
 };
 
-#define IOINTSEL 0x00  /* General IO/Interrupt Switching Register */
-#define INOUTSEL 0x04  /* General Input/Output Switching Register */
-#define OUTDT 0x08     /* General Output Register */
-#define INDT 0x0c      /* General Input Register */
-#define INTDT 0x10     /* Interrupt Display Register */
-#define INTCLR 0x14    /* Interrupt Clear Register */
-#define INTMSK 0x18    /* Interrupt Mask Register */
-#define MSKCLR 0x1c    /* Interrupt Mask Clear Register */
-#define POSNEG 0x20    /* Positive/Negative Logic Select Register */
-#define EDGLEVEL 0x24  /* Edge/level Select Register */
-#define FILONOFF 0x28  /* Chattering Prevention On/Off Register */
-#define OUTDTSEL 0x40  /* Output Data Select Register */
-#define BOTHEDGE 0x4c  /* One Edge/Both Edge Select Register */
+#define IOINTSEL       0x00    /* General IO/Interrupt Switching Register */
+#define INOUTSEL       0x04    /* General Input/Output Switching Register */
+#define OUTDT          0x08    /* General Output Register */
+#define INDT           0x0c    /* General Input Register */
+#define INTDT          0x10    /* Interrupt Display Register */
+#define INTCLR         0x14    /* Interrupt Clear Register */
+#define INTMSK         0x18    /* Interrupt Mask Register */
+#define MSKCLR         0x1c    /* Interrupt Mask Clear Register */
+#define POSNEG         0x20    /* Positive/Negative Logic Select Register */
+#define EDGLEVEL       0x24    /* Edge/level Select Register */
+#define FILONOFF       0x28    /* Chattering Prevention On/Off Register */
+#define OUTDTSEL       0x40    /* Output Data Select Register */
+#define BOTHEDGE       0x4c    /* One Edge/Both Edge Select Register */
 
 #define RCAR_MAX_GPIO_PER_BANK         32
 
@@ -123,7 +127,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
        gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);
 
        /* Select one edge or both edges in BOTHEDGE */
-       if (p->has_both_edge_trigger)
+       if (p->info.has_both_edge_trigger)
                gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);
 
        /* Select "Interrupt Input Mode" in IOINTSEL */
@@ -162,7 +166,7 @@ static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
                                                      false);
                break;
        case IRQ_TYPE_EDGE_BOTH:
-               if (!p->has_both_edge_trigger)
+               if (!p->info.has_both_edge_trigger)
                        return -EINVAL;
                gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,
                                                      true);
@@ -238,7 +242,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
        gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);
 
        /* Select General Output Register to output data in OUTDTSEL */
-       if (p->has_outdtsel && output)
+       if (p->info.has_outdtsel && output)
                gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);
 
        spin_unlock_irqrestore(&p->lock, flags);
@@ -295,14 +299,44 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
 
 static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
 {
+       struct gpio_rcar_priv *p = gpiochip_get_data(chip);
        u32 bit = BIT(offset);
 
        /* testing on r8a7790 shows that INDT does not show correct pin state
         * when configured as output, so use OUTDT in case of output pins */
-       if (gpio_rcar_read(gpiochip_get_data(chip), INOUTSEL) & bit)
-               return !!(gpio_rcar_read(gpiochip_get_data(chip), OUTDT) & bit);
+       if (gpio_rcar_read(p, INOUTSEL) & bit)
+               return !!(gpio_rcar_read(p, OUTDT) & bit);
        else
-               return !!(gpio_rcar_read(gpiochip_get_data(chip), INDT) & bit);
+               return !!(gpio_rcar_read(p, INDT) & bit);
+}
+
+static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                 unsigned long *bits)
+{
+       struct gpio_rcar_priv *p = gpiochip_get_data(chip);
+       u32 bankmask, outputs, m, val = 0;
+       unsigned long flags;
+
+       bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);
+       if (chip->valid_mask)
+               bankmask &= chip->valid_mask[0];
+
+       if (!bankmask)
+               return 0;
+
+       spin_lock_irqsave(&p->lock, flags);
+       outputs = gpio_rcar_read(p, INOUTSEL);
+       m = outputs & bankmask;
+       if (m)
+               val |= gpio_rcar_read(p, OUTDT) & m;
+
+       m = ~outputs & bankmask;
+       if (m)
+               val |= gpio_rcar_read(p, INDT) & m;
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       bits[0] = val;
+       return 0;
 }
 
 static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -346,11 +380,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
        return 0;
 }
 
-struct gpio_rcar_info {
-       bool has_outdtsel;
-       bool has_both_edge_trigger;
-};
-
 static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
        .has_outdtsel = false,
        .has_both_edge_trigger = false,
@@ -417,8 +446,7 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
        int ret;
 
        info = of_device_get_match_data(p->dev);
-       p->has_outdtsel = info->has_outdtsel;
-       p->has_both_edge_trigger = info->has_both_edge_trigger;
+       p->info = *info;
 
        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
        *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
@@ -479,6 +507,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
        gpio_chip->get_direction = gpio_rcar_get_direction;
        gpio_chip->direction_input = gpio_rcar_direction_input;
        gpio_chip->get = gpio_rcar_get;
+       gpio_chip->get_multiple = gpio_rcar_get_multiple;
        gpio_chip->direction_output = gpio_rcar_direction_output;
        gpio_chip->set = gpio_rcar_set;
        gpio_chip->set_multiple = gpio_rcar_set_multiple;
@@ -552,7 +581,7 @@ static int gpio_rcar_suspend(struct device *dev)
        p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);
        p->bank_info.posneg = gpio_rcar_read(p, POSNEG);
        p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);
-       if (p->has_both_edge_trigger)
+       if (p->info.has_both_edge_trigger)
                p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);
 
        if (atomic_read(&p->wakeup_path))
index d5eb9ca..403f9e8 100644 (file)
@@ -29,7 +29,6 @@
 #define SIFIVE_GPIO_OUTPUT_XOR 0x40
 
 #define SIFIVE_GPIO_MAX                32
-#define SIFIVE_GPIO_IRQ_OFFSET 7
 
 struct sifive_gpio {
        void __iomem            *base;
@@ -37,7 +36,7 @@ struct sifive_gpio {
        struct regmap           *regs;
        unsigned long           irq_state;
        unsigned int            trigger[SIFIVE_GPIO_MAX];
-       unsigned int            irq_parent[SIFIVE_GPIO_MAX];
+       unsigned int            irq_number[SIFIVE_GPIO_MAX];
 };
 
 static void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
@@ -128,6 +127,16 @@ static void sifive_gpio_irq_eoi(struct irq_data *d)
        irq_chip_eoi_parent(d);
 }
 
+static int sifive_gpio_irq_set_affinity(struct irq_data *data,
+                                       const struct cpumask *dest,
+                                       bool force)
+{
+       if (data->parent_data)
+               return irq_chip_set_affinity_parent(data, dest, force);
+
+       return -EINVAL;
+}
+
 static struct irq_chip sifive_gpio_irqchip = {
        .name           = "sifive-gpio",
        .irq_set_type   = sifive_gpio_irq_set_type,
@@ -136,6 +145,7 @@ static struct irq_chip sifive_gpio_irqchip = {
        .irq_enable     = sifive_gpio_irq_enable,
        .irq_disable    = sifive_gpio_irq_disable,
        .irq_eoi        = sifive_gpio_irq_eoi,
+       .irq_set_affinity = sifive_gpio_irq_set_affinity,
 };
 
 static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
@@ -144,8 +154,12 @@ static int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
                                             unsigned int *parent,
                                             unsigned int *parent_type)
 {
+       struct sifive_gpio *chip = gpiochip_get_data(gc);
+       struct irq_data *d = irq_get_irq_data(chip->irq_number[child]);
+
        *parent_type = IRQ_TYPE_NONE;
-       *parent = child + SIFIVE_GPIO_IRQ_OFFSET;
+       *parent = irqd_to_hwirq(d);
+
        return 0;
 }
 
@@ -165,7 +179,7 @@ static int sifive_gpio_probe(struct platform_device *pdev)
        struct irq_domain *parent;
        struct gpio_irq_chip *girq;
        struct sifive_gpio *chip;
-       int ret, ngpio;
+       int ret, ngpio, i;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
@@ -200,6 +214,9 @@ static int sifive_gpio_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       for (i = 0; i < ngpio; i++)
+               chip->irq_number[i] = platform_get_irq(pdev, i);
+
        ret = bgpio_init(&chip->gc, dev, 4,
                         chip->base + SIFIVE_GPIO_INPUT_VAL,
                         chip->base + SIFIVE_GPIO_OUTPUT_VAL,
index b0155d6..b94ef81 100644 (file)
@@ -474,15 +474,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
        stmpe_gpio->chip.parent = &pdev->dev;
        stmpe_gpio->chip.of_node = np;
        stmpe_gpio->chip.base = -1;
-       /*
-        * REVISIT: this makes sure the valid mask gets allocated and
-        * filled in when adding the gpio_chip, but the rest of the
-        * gpio_irqchip is still filled in using the old method
-        * in gpiochip_irqchip_add_nested() so clean this up once we
-        * get the gpio_irqchip to initialize while adding the
-        * gpio_chip also for threaded irqchips.
-        */
-       stmpe_gpio->chip.irq.init_valid_mask = stmpe_init_irq_valid_mask;
 
        if (IS_ENABLED(CONFIG_DEBUG_FS))
                 stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
@@ -520,6 +511,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
                girq->default_type = IRQ_TYPE_NONE;
                girq->handler = handle_simple_irq;
                girq->threaded = true;
+               girq->init_valid_mask = stmpe_init_irq_valid_mask;
        }
 
        ret = gpiochip_add_data(&stmpe_gpio->chip, stmpe_gpio);
index 8656815..e19ebff 100644 (file)
@@ -61,8 +61,16 @@ struct tegra_gpio_info;
 struct tegra_gpio_bank {
        unsigned int bank;
        unsigned int irq;
-       spinlock_t lvl_lock[4];
-       spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */
+
+       /*
+        * IRQ-core code uses raw locking, and thus, nested locking also
+        * should be raw in order not to trip spinlock debug warnings.
+        */
+       raw_spinlock_t lvl_lock[4];
+
+       /* Lock for updating debounce count register */
+       spinlock_t dbc_lock[4];
+
 #ifdef CONFIG_PM_SLEEP
        u32 cnf[4];
        u32 out[4];
@@ -334,14 +342,14 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
                return -EINVAL;
        }
 
-       spin_lock_irqsave(&bank->lvl_lock[port], flags);
+       raw_spin_lock_irqsave(&bank->lvl_lock[port], flags);
 
        val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
        val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
        val |= lvl_type << GPIO_BIT(gpio);
        tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio));
 
-       spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
+       raw_spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
 
        tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0);
        tegra_gpio_enable(tgi, gpio);
@@ -560,6 +568,9 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
 };
 
+static struct lock_class_key gpio_lock_class;
+static struct lock_class_key gpio_request_class;
+
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
        struct tegra_gpio_info *tgi;
@@ -661,6 +672,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
                bank = &tgi->bank_info[GPIO_BANK(gpio)];
 
                irq_set_chip_data(irq, bank);
+               irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class);
                irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
        }
 
@@ -671,7 +683,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
                                                 tegra_gpio_irq_handler, bank);
 
                for (j = 0; j < 4; j++) {
-                       spin_lock_init(&bank->lvl_lock[j]);
+                       raw_spin_lock_init(&bank->lvl_lock[j]);
                        spin_lock_init(&bank->dbc_lock[j]);
                }
        }
index 9500074..286e0b1 100644 (file)
@@ -444,6 +444,16 @@ static int tegra186_irq_set_wake(struct irq_data *data, unsigned int on)
        return 0;
 }
 
+static int tegra186_irq_set_affinity(struct irq_data *data,
+                                    const struct cpumask *dest,
+                                    bool force)
+{
+       if (data->parent_data)
+               return irq_chip_set_affinity_parent(data, dest, force);
+
+       return -EINVAL;
+}
+
 static void tegra186_gpio_irq(struct irq_desc *desc)
 {
        struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
@@ -690,6 +700,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->intc.irq_unmask = tegra186_irq_unmask;
        gpio->intc.irq_set_type = tegra186_irq_set_type;
        gpio->intc.irq_set_wake = tegra186_irq_set_wake;
+       gpio->intc.irq_set_affinity = tegra186_irq_set_affinity;
 
        irq = &gpio->gpio.irq;
        irq->chip = &gpio->intc;
index 67f9f82..be53938 100644 (file)
@@ -6,13 +6,14 @@
  */
 
 #include <linux/bitops.h>
-#include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/errno.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
 #include <linux/slab.h>
 
 /* Register Offset Definitions */
@@ -38,6 +39,7 @@
  * @gpio_state: GPIO state shadow register
  * @gpio_dir: GPIO direction shadow register
  * @gpio_lock: Lock used for synchronization
+ * @clk: clock resource for this driver
  */
 struct xgpio_instance {
        struct gpio_chip gc;
@@ -46,6 +48,7 @@ struct xgpio_instance {
        u32 gpio_state[2];
        u32 gpio_dir[2];
        spinlock_t gpio_lock[2];
+       struct clk *clk;
 };
 
 static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
@@ -256,6 +259,23 @@ static void xgpio_save_regs(struct xgpio_instance *chip)
                       chip->gpio_dir[1]);
 }
 
+/**
+ * xgpio_remove - Remove method for the GPIO device.
+ * @pdev: pointer to the platform device
+ *
+ * This function remove gpiochips and frees all the allocated resources.
+ *
+ * Return: 0 always
+ */
+static int xgpio_remove(struct platform_device *pdev)
+{
+       struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(gpio->clk);
+
+       return 0;
+}
+
 /**
  * xgpio_of_probe - Probe method for the GPIO device.
  * @pdev: pointer to the platform device
@@ -278,7 +298,8 @@ static int xgpio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, chip);
 
        /* Update GPIO state shadow register with default value */
-       of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
+       if (of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]))
+               chip->gpio_state[0] = 0x0;
 
        /* Update GPIO direction shadow register with default value */
        if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
@@ -298,8 +319,9 @@ static int xgpio_probe(struct platform_device *pdev)
 
        if (is_dual) {
                /* Update GPIO state shadow register with default value */
-               of_property_read_u32(np, "xlnx,dout-default-2",
-                                    &chip->gpio_state[1]);
+               if (of_property_read_u32(np, "xlnx,dout-default-2",
+                                        &chip->gpio_state[1]))
+                       chip->gpio_state[1] = 0x0;
 
                /* Update GPIO direction shadow register with default value */
                if (of_property_read_u32(np, "xlnx,tri-default-2",
@@ -334,11 +356,25 @@ static int xgpio_probe(struct platform_device *pdev)
                return PTR_ERR(chip->regs);
        }
 
+       chip->clk = devm_clk_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(chip->clk)) {
+               if (PTR_ERR(chip->clk) != -EPROBE_DEFER)
+                       dev_dbg(&pdev->dev, "Input clock not found\n");
+               return PTR_ERR(chip->clk);
+       }
+
+       status = clk_prepare_enable(chip->clk);
+       if (status < 0) {
+               dev_err(&pdev->dev, "Failed to prepare clk\n");
+               return status;
+       }
+
        xgpio_save_regs(chip);
 
        status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
        if (status) {
                dev_err(&pdev->dev, "failed to add GPIO chip\n");
+               clk_disable_unprepare(chip->clk);
                return status;
        }
 
@@ -354,6 +390,7 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
 
 static struct platform_driver xgpio_plat_driver = {
        .probe          = xgpio_probe,
+       .remove         = xgpio_remove,
        .driver         = {
                        .name = "gpio-xilinx",
                        .of_match_table = xgpio_of_match,
index e2cac12..49c878c 100644 (file)
@@ -186,15 +186,7 @@ static int xra1403_probe(struct spi_device *spi)
                return ret;
        }
 
-       ret = devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
-       if (ret < 0) {
-               dev_err(&spi->dev, "Unable to register gpiochip\n");
-               return ret;
-       }
-
-       spi_set_drvdata(spi, xra);
-
-       return 0;
+       return devm_gpiochip_add_data(&spi->dev, &xra->chip, xra);
 }
 
 static const struct spi_device_id xra1403_ids[] = {
index 834a12f..e37a57d 100644 (file)
@@ -205,6 +205,68 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
                acpi_gpiochip_request_irq(acpi_gpio, event);
 }
 
+static enum gpiod_flags
+acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
+{
+       /* GpioInt() implies input configuration */
+       if (agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
+               return GPIOD_IN;
+
+       switch (agpio->io_restriction) {
+       case ACPI_IO_RESTRICT_INPUT:
+               return GPIOD_IN;
+       case ACPI_IO_RESTRICT_OUTPUT:
+               /*
+                * ACPI GPIO resources don't contain an initial value for the
+                * GPIO. Therefore we deduce that value from the pull field
+                * and the polarity instead. If the pin is pulled up we assume
+                * default to be high, if it is pulled down we assume default
+                * to be low, otherwise we leave pin untouched. For active low
+                * polarity values will be switched. See also
+                * Documentation/firmware-guide/acpi/gpio-properties.rst.
+                */
+               switch (agpio->pin_config) {
+               case ACPI_PIN_CONFIG_PULLUP:
+                       return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH;
+               case ACPI_PIN_CONFIG_PULLDOWN:
+                       return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * Assume that the BIOS has configured the direction and pull
+        * accordingly.
+        */
+       return GPIOD_ASIS;
+}
+
+static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
+                                               struct acpi_resource_gpio *agpio,
+                                               unsigned int index,
+                                               const char *label)
+{
+       int polarity = GPIO_ACTIVE_HIGH;
+       enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
+       unsigned int pin = agpio->pin_table[index];
+       struct gpio_desc *desc;
+       int ret;
+
+       desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
+       if (IS_ERR(desc))
+               return desc;
+
+       ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout);
+       if (ret)
+               gpiochip_free_own_desc(desc);
+
+       return ret ? ERR_PTR(ret) : desc;
+}
+
 static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
 {
        const char *controller, *pin_str;
@@ -290,8 +352,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
        if (!handler)
                return AE_OK;
 
-       desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event",
-                                        GPIO_ACTIVE_HIGH, GPIOD_IN);
+       desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
        if (IS_ERR(desc)) {
                dev_err(chip->parent,
                        "Failed to request GPIO for pin 0x%04X, err %ld\n",
@@ -526,39 +587,6 @@ static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
        return false;
 }
 
-static enum gpiod_flags
-acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio)
-{
-       switch (agpio->io_restriction) {
-       case ACPI_IO_RESTRICT_INPUT:
-               return GPIOD_IN;
-       case ACPI_IO_RESTRICT_OUTPUT:
-               /*
-                * ACPI GPIO resources don't contain an initial value for the
-                * GPIO. Therefore we deduce that value from the pull field
-                * instead. If the pin is pulled up we assume default to be
-                * high, if it is pulled down we assume default to be low,
-                * otherwise we leave pin untouched.
-                */
-               switch (agpio->pin_config) {
-               case ACPI_PIN_CONFIG_PULLUP:
-                       return GPIOD_OUT_HIGH;
-               case ACPI_PIN_CONFIG_PULLDOWN:
-                       return GPIOD_OUT_LOW;
-               default:
-                       break;
-               }
-       default:
-               break;
-       }
-
-       /*
-        * Assume that the BIOS has configured the direction and pull
-        * accordingly.
-        */
-       return GPIOD_ASIS;
-}
-
 static int
 __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
 {
@@ -633,7 +661,7 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
 struct acpi_gpio_lookup {
        struct acpi_gpio_info info;
        int index;
-       int pin_index;
+       u16 pin_index;
        bool active_low;
        struct gpio_desc *desc;
        int n;
@@ -649,7 +677,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
        if (!lookup->desc) {
                const struct acpi_resource_gpio *agpio = &ares->data.gpio;
                bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
-               int pin_index;
+               u16 pin_index;
 
                if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
                        lookup->index++;
@@ -664,6 +692,7 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
                lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
                                              agpio->pin_table[pin_index]);
                lookup->info.pin_config = agpio->pin_config;
+               lookup->info.debounce = agpio->debounce_timeout;
                lookup->info.gpioint = gpioint;
 
                /*
@@ -674,13 +703,13 @@ static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
                 * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
                 */
                if (lookup->info.gpioint) {
-                       lookup->info.flags = GPIOD_IN;
                        lookup->info.polarity = agpio->polarity;
                        lookup->info.triggering = agpio->triggering;
                } else {
-                       lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio);
                        lookup->info.polarity = lookup->active_low;
                }
+
+               lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio, lookup->info.polarity);
        }
 
        return 1;
@@ -794,7 +823,7 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
                if (ret)
                        return ERR_PTR(ret);
 
-               dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %d %u\n",
+               dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %u %u\n",
                        dev_name(&lookup.info.adev->dev), lookup.index,
                        lookup.pin_index, lookup.active_low);
        } else {
@@ -942,6 +971,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
 
                if (info.gpioint && idx++ == index) {
                        unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
+                       enum gpiod_flags dflags = GPIOD_ASIS;
                        char label[32];
                        int irq;
 
@@ -952,11 +982,18 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
                        if (irq < 0)
                                return irq;
 
+                       acpi_gpio_update_gpiod_flags(&dflags, &info);
+                       acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
+
                        snprintf(label, sizeof(label), "GpioInt() %d", index);
-                       ret = gpiod_configure_flags(desc, label, lflags, info.flags);
+                       ret = gpiod_configure_flags(desc, label, lflags, dflags);
                        if (ret < 0)
                                return ret;
 
+                       ret = gpio_set_debounce_timeout(desc, info.debounce);
+                       if (ret)
+                               return ret;
+
                        irq_flags = acpi_dev_get_irq_type(info.triggering,
                                                          info.polarity);
 
@@ -982,7 +1019,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
        struct gpio_chip *chip = achip->chip;
        struct acpi_resource_gpio *agpio;
        struct acpi_resource *ares;
-       int pin_index = (int)address;
+       u16 pin_index = address;
        acpi_status status;
        int length;
        int i;
@@ -1005,7 +1042,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                return AE_BAD_PARAMETER;
        }
 
-       length = min(agpio->pin_table_length, (u16)(pin_index + bits));
+       length = min_t(u16, agpio->pin_table_length, pin_index + bits);
        for (i = pin_index; i < length; ++i) {
                int pin = agpio->pin_table[i];
                struct acpi_gpio_connection *conn;
@@ -1042,23 +1079,18 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                }
 
                if (!found) {
-                       enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio);
-                       const char *label = "ACPI:OpRegion";
-
-                       desc = gpiochip_request_own_desc(chip, pin, label,
-                                                        GPIO_ACTIVE_HIGH,
-                                                        flags);
+                       desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
                        if (IS_ERR(desc)) {
-                               status = AE_ERROR;
                                mutex_unlock(&achip->conn_lock);
+                               status = AE_ERROR;
                                goto out;
                        }
 
                        conn = kzalloc(sizeof(*conn), GFP_KERNEL);
                        if (!conn) {
-                               status = AE_NO_MEMORY;
                                gpiochip_free_own_desc(desc);
                                mutex_unlock(&achip->conn_lock);
+                               status = AE_NO_MEMORY;
                                goto out;
                        }
 
@@ -1070,8 +1102,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
                mutex_unlock(&achip->conn_lock);
 
                if (function == ACPI_WRITE)
-                       gpiod_set_raw_value_cansleep(desc,
-                                                    !!((1 << i) & *value));
+                       gpiod_set_raw_value_cansleep(desc, !!(*value & BIT(i)));
                else
                        *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
        }
@@ -1132,7 +1163,7 @@ acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip,
        int ret;
 
        *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       *dflags = 0;
+       *dflags = GPIOD_ASIS;
        *name = NULL;
 
        ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios,
index 1c6d65c..e2edb63 100644 (file)
@@ -18,6 +18,7 @@ struct acpi_device;
  * @pin_config: pin bias as provided by ACPI
  * @polarity: interrupt polarity as provided by ACPI
  * @triggering: triggering type as provided by ACPI
+ * @debounce: debounce timeout as provided by ACPI
  * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
  */
 struct acpi_gpio_info {
@@ -27,6 +28,7 @@ struct acpi_gpio_info {
        int pin_config;
        int polarity;
        int triggering;
+       unsigned int debounce;
        unsigned int quirks;
 };
 
index e9faeaf..12b679c 100644 (file)
@@ -428,6 +428,12 @@ struct line {
         */
        struct linereq *req;
        unsigned int irq;
+       /*
+        * eflags is set by edge_detector_setup(), edge_detector_stop() and
+        * edge_detector_update(), which are themselves mutually exclusive,
+        * and is accessed by edge_irq_thread() and debounce_work_func(),
+        * which can both live with a slightly stale value.
+        */
        u64 eflags;
        /*
         * timestamp_ns and req_seqno are accessed only by
@@ -504,11 +510,14 @@ struct linereq {
        (GPIO_V2_LINE_FLAG_EDGE_RISING | \
         GPIO_V2_LINE_FLAG_EDGE_FALLING)
 
+#define GPIO_V2_LINE_FLAG_EDGE_BOTH GPIO_V2_LINE_EDGE_FLAGS
+
 #define GPIO_V2_LINE_VALID_FLAGS \
        (GPIO_V2_LINE_FLAG_ACTIVE_LOW | \
         GPIO_V2_LINE_DIRECTION_FLAGS | \
         GPIO_V2_LINE_DRIVE_FLAGS | \
         GPIO_V2_LINE_EDGE_FLAGS | \
+        GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME | \
         GPIO_V2_LINE_BIAS_FLAGS)
 
 static void linereq_put_event(struct linereq *lr,
@@ -529,11 +538,20 @@ static void linereq_put_event(struct linereq *lr,
                pr_debug_ratelimited("event FIFO is full - event dropped\n");
 }
 
+static u64 line_event_timestamp(struct line *line)
+{
+       if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags))
+               return ktime_get_real_ns();
+
+       return ktime_get_ns();
+}
+
 static irqreturn_t edge_irq_thread(int irq, void *p)
 {
        struct line *line = p;
        struct linereq *lr = line->req;
        struct gpio_v2_line_event le;
+       u64 eflags;
 
        /* Do not leak kernel stack to userspace */
        memset(&le, 0, sizeof(le));
@@ -546,14 +564,14 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
                 * which case we didn't get the timestamp from
                 * edge_irq_handler().
                 */
-               le.timestamp_ns = ktime_get_ns();
+               le.timestamp_ns = line_event_timestamp(line);
                if (lr->num_lines != 1)
                        line->req_seqno = atomic_inc_return(&lr->seqno);
        }
        line->timestamp_ns = 0;
 
-       if (line->eflags == (GPIO_V2_LINE_FLAG_EDGE_RISING |
-                            GPIO_V2_LINE_FLAG_EDGE_FALLING)) {
+       eflags = READ_ONCE(line->eflags);
+       if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) {
                int level = gpiod_get_value_cansleep(line->desc);
 
                if (level)
@@ -562,10 +580,10 @@ static irqreturn_t edge_irq_thread(int irq, void *p)
                else
                        /* Emit high-to-low event */
                        le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
-       } else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
+       } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) {
                /* Emit low-to-high event */
                le.id = GPIO_V2_LINE_EVENT_RISING_EDGE;
-       } else if (line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
+       } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) {
                /* Emit high-to-low event */
                le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE;
        } else {
@@ -590,7 +608,7 @@ static irqreturn_t edge_irq_handler(int irq, void *p)
         * Just store the timestamp in hardirq context so we get it as
         * close in time as possible to the actual event.
         */
-       line->timestamp_ns = ktime_get_ns();
+       line->timestamp_ns = line_event_timestamp(line);
 
        if (lr->num_lines != 1)
                line->req_seqno = atomic_inc_return(&lr->seqno);
@@ -634,6 +652,7 @@ static void debounce_work_func(struct work_struct *work)
        struct line *line = container_of(work, struct line, work.work);
        struct linereq *lr;
        int level;
+       u64 eflags;
 
        level = gpiod_get_raw_value_cansleep(line->desc);
        if (level < 0) {
@@ -647,7 +666,8 @@ static void debounce_work_func(struct work_struct *work)
        WRITE_ONCE(line->level, level);
 
        /* -- edge detection -- */
-       if (!line->eflags)
+       eflags = READ_ONCE(line->eflags);
+       if (!eflags)
                return;
 
        /* switch from physical level to logical - if they differ */
@@ -655,15 +675,15 @@ static void debounce_work_func(struct work_struct *work)
                level = !level;
 
        /* ignore edges that are not being monitored */
-       if (((line->eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
-           ((line->eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
+       if (((eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) && !level) ||
+           ((eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) && level))
                return;
 
        /* Do not leak kernel stack to userspace */
        memset(&le, 0, sizeof(le));
 
        lr = line->req;
-       le.timestamp_ns = ktime_get_ns();
+       le.timestamp_ns = line_event_timestamp(line);
        le.offset = gpio_chip_hwgpio(line->desc);
        line->line_seqno++;
        le.line_seqno = line->line_seqno;
@@ -755,7 +775,7 @@ static void edge_detector_stop(struct line *line)
 
        cancel_delayed_work_sync(&line->work);
        WRITE_ONCE(line->sw_debounced, 0);
-       line->eflags = 0;
+       WRITE_ONCE(line->eflags, 0);
        /* do not change line->level - see comment in debounced_value() */
 }
 
@@ -774,7 +794,7 @@ static int edge_detector_setup(struct line *line,
                if (ret)
                        return ret;
        }
-       line->eflags = eflags;
+       WRITE_ONCE(line->eflags, eflags);
        if (gpio_v2_line_config_debounced(lc, line_idx)) {
                debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx);
                ret = debounce_setup(line, debounce_period_us);
@@ -817,13 +837,13 @@ static int edge_detector_update(struct line *line,
        unsigned int debounce_period_us =
                gpio_v2_line_config_debounce_period(lc, line_idx);
 
-       if ((line->eflags == eflags) && !polarity_change &&
+       if ((READ_ONCE(line->eflags) == eflags) && !polarity_change &&
            (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us))
                return 0;
 
        /* sw debounced and still will be...*/
        if (debounce_period_us && READ_ONCE(line->sw_debounced)) {
-               line->eflags = eflags;
+               WRITE_ONCE(line->eflags, eflags);
                WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us);
                return 0;
        }
@@ -967,6 +987,9 @@ static void gpio_v2_line_config_flags_to_desc_flags(u64 flags,
                   flags & GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN);
        assign_bit(FLAG_BIAS_DISABLE, flagsp,
                   flags & GPIO_V2_LINE_FLAG_BIAS_DISABLED);
+
+       assign_bit(FLAG_EVENT_CLOCK_REALTIME, flagsp,
+                  flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME);
 }
 
 static long linereq_get_values(struct linereq *lr, void __user *ip)
@@ -1479,21 +1502,10 @@ static __poll_t lineevent_poll(struct file *file,
        return events;
 }
 
-static ssize_t lineevent_get_size(void)
-{
-#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
-       /* i386 has no padding after 'id' */
-       if (in_ia32_syscall()) {
-               struct compat_gpioeevent_data {
-                       compat_u64      timestamp;
-                       u32             id;
-               };
-
-               return sizeof(struct compat_gpioeevent_data);
-       }
-#endif
-       return sizeof(struct gpioevent_data);
-}
+struct compat_gpioeevent_data {
+       compat_u64      timestamp;
+       u32             id;
+};
 
 static ssize_t lineevent_read(struct file *file,
                              char __user *buf,
@@ -1515,7 +1527,10 @@ static ssize_t lineevent_read(struct file *file,
         * actual sizeof() and pass this as an argument to copy_to_user() to
         * drop unneeded bytes from the output.
         */
-       ge_size = lineevent_get_size();
+       if (compat_need_64bit_alignment_fixup())
+               ge_size = sizeof(struct compat_gpioeevent_data);
+       else
+               ge_size = sizeof(struct gpioevent_data);
        if (count < ge_size)
                return -EINVAL;
 
@@ -1910,6 +1925,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
            test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
            test_bit(FLAG_EXPORT, &desc->flags) ||
            test_bit(FLAG_SYSFS, &desc->flags) ||
+           !gpiochip_line_is_valid(gc, info->offset) ||
            !ok_for_pinctrl)
                info->flags |= GPIO_V2_LINE_FLAG_USED;
 
@@ -1938,6 +1954,9 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
        if (test_bit(FLAG_EDGE_FALLING, &desc->flags))
                info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
 
+       if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags))
+               info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
+
        debounce_period_us = READ_ONCE(desc->debounce_period_us);
        if (debounce_period_us) {
                info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
index 7dbce4c..4a517e5 100644 (file)
@@ -246,10 +246,8 @@ struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev,
        struct gpio_desc *desc;
 
        desc = devm_gpiod_get_index(dev, con_id, index, flags);
-       if (IS_ERR(desc)) {
-               if (PTR_ERR(desc) == -ENOENT)
-                       return NULL;
-       }
+       if (gpiod_not_found(desc))
+               return NULL;
 
        return desc;
 }
@@ -308,7 +306,7 @@ devm_gpiod_get_array_optional(struct device *dev, const char *con_id,
        struct gpio_descs *descs;
 
        descs = devm_gpiod_get_array(dev, con_id, flags);
-       if (PTR_ERR(descs) == -ENOENT)
+       if (gpiod_not_found(descs))
                return NULL;
 
        return descs;
@@ -479,9 +477,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
 }
 EXPORT_SYMBOL_GPL(devm_gpio_free);
 
-static void devm_gpio_chip_release(struct device *dev, void *res)
+static void devm_gpio_chip_release(void *data)
 {
-       struct gpio_chip *gc = *(struct gpio_chip **)res;
+       struct gpio_chip *gc = data;
 
        gpiochip_remove(gc);
 }
@@ -507,23 +505,12 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, vo
                                    struct lock_class_key *lock_key,
                                    struct lock_class_key *request_key)
 {
-       struct gpio_chip **ptr;
        int ret;
 
-       ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
-                            GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
        ret = gpiochip_add_data_with_key(gc, data, lock_key, request_key);
-       if (ret < 0) {
-               devres_free(ptr);
+       if (ret < 0)
                return ret;
-       }
 
-       *ptr = gc;
-       devres_add(dev, ptr);
-
-       return 0;
+       return devm_add_action_or_reset(dev, devm_gpio_chip_release, gc);
 }
 EXPORT_SYMBOL_GPL(devm_gpiochip_add_data_with_key);
index 2f895a2..b4a7111 100644 (file)
@@ -509,31 +509,31 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
 
-               if (!IS_ERR(desc) || PTR_ERR(desc) != -ENOENT)
+               if (!gpiod_not_found(desc))
                        break;
        }
 
-       if (PTR_ERR(desc) == -ENOENT) {
+       if (gpiod_not_found(desc)) {
                /* Special handling for SPI GPIOs if used */
                desc = of_find_spi_gpio(dev, con_id, &of_flags);
        }
 
-       if (PTR_ERR(desc) == -ENOENT) {
+       if (gpiod_not_found(desc)) {
                /* This quirk looks up flags and all */
                desc = of_find_spi_cs_gpio(dev, con_id, idx, flags);
                if (!IS_ERR(desc))
                        return desc;
        }
 
-       if (PTR_ERR(desc) == -ENOENT) {
+       if (gpiod_not_found(desc)) {
                /* Special handling for regulator GPIOs if used */
                desc = of_find_regulator_gpio(dev, con_id, &of_flags);
        }
 
-       if (PTR_ERR(desc) == -ENOENT)
+       if (gpiod_not_found(desc))
                desc = of_find_arizona_gpio(dev, con_id, &of_flags);
 
-       if (PTR_ERR(desc) == -ENOENT)
+       if (gpiod_not_found(desc))
                desc = of_find_usb_gpio(dev, con_id, &of_flags);
 
        if (IS_ERR(desc))
@@ -593,7 +593,7 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
 
        xlate_flags = 0;
        *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       *dflags = 0;
+       *dflags = GPIOD_ASIS;
 
        ret = of_property_read_u32(chip_np, "#gpio-cells", &tmp);
        if (ret)
index 728f6c6..26c5466 100644 (file)
@@ -476,7 +476,7 @@ static ssize_t export_store(struct class *class,
         */
 
        status = gpiod_request(desc, "sysfs");
-       if (status < 0) {
+       if (status) {
                if (status == -EPROBE_DEFER)
                        status = -ENODEV;
                goto done;
index 6e3c4d7..b02cc2a 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+
 #include <linux/bitmap.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -119,7 +120,7 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
        spin_unlock_irqrestore(&gpio_lock, flags);
 
        if (!gpio_is_valid(gpio))
-               WARN(1, "invalid GPIO %d\n", gpio);
+               pr_warn("invalid GPIO %d\n", gpio);
 
        return NULL;
 }
@@ -211,7 +212,7 @@ static int gpiochip_find_base(int ngpio)
 int gpiod_get_direction(struct gpio_desc *desc)
 {
        struct gpio_chip *gc;
-       unsigned offset;
+       unsigned int offset;
        int ret;
 
        gc = gpiod_to_chip(desc);
@@ -771,9 +772,11 @@ err_free_ida:
        ida_free(&gpio_ida, gdev->id);
 err_free_gdev:
        /* failures here can mean systems won't boot... */
-       pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
-              gdev->base, gdev->base + gdev->ngpio - 1,
-              gc->label ? : "generic", ret);
+       if (ret != -EPROBE_DEFER) {
+               pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
+                      gdev->base, gdev->base + gdev->ngpio - 1,
+                      gc->label ? : "generic", ret);
+       }
        kfree(gdev);
        return ret;
 }
@@ -936,67 +939,6 @@ bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_irq_valid);
 
-/**
- * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
- * @gc: the gpiochip to set the irqchip chain to
- * @parent_irq: the irq number corresponding to the parent IRQ for this
- * cascaded 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
- */
-static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gc,
-                                         unsigned int parent_irq,
-                                         irq_flow_handler_t parent_handler)
-{
-       struct gpio_irq_chip *girq = &gc->irq;
-       struct device *dev = &gc->gpiodev->dev;
-
-       if (!girq->domain) {
-               chip_err(gc, "called %s before setting up irqchip\n",
-                        __func__);
-               return;
-       }
-
-       if (parent_handler) {
-               if (gc->can_sleep) {
-                       chip_err(gc,
-                                "you cannot have chained interrupts on a chip that may sleep\n");
-                       return;
-               }
-               girq->parents = devm_kcalloc(dev, 1,
-                                            sizeof(*girq->parents),
-                                            GFP_KERNEL);
-               if (!girq->parents) {
-                       chip_err(gc, "out of memory allocating parent IRQ\n");
-                       return;
-               }
-               girq->parents[0] = parent_irq;
-               girq->num_parents = 1;
-               /*
-                * The parent irqchip is already using the chip_data for this
-                * irqchip, so our callbacks simply use the handler_data.
-                */
-               irq_set_chained_handler_and_data(parent_irq, parent_handler,
-                                                gc);
-       }
-}
-
-/**
- * gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
- * @gc: the gpiochip to set the irqchip nested handler to
- * @irqchip: the irqchip to nest to the gpiochip
- * @parent_irq: the irq number corresponding to the parent IRQ for this
- * nested irqchip
- */
-void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
-                                struct irq_chip *irqchip,
-                                unsigned int parent_irq)
-{
-       gpiochip_set_cascaded_irqchip(gc, parent_irq, NULL);
-}
-EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
-
 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
 
 /**
@@ -1394,7 +1336,7 @@ void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
 
-static int gpiochip_to_irq(struct gpio_chip *gc, unsigned offset)
+static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
 {
        struct irq_domain *domain = gc->irq.domain;
 
@@ -1477,7 +1419,8 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
        if (WARN_ON(gc->irq.irq_enable))
                return;
        /* Check if the irqchip already has this hook... */
-       if (irqchip->irq_enable == gpiochip_irq_enable) {
+       if (irqchip->irq_enable == gpiochip_irq_enable ||
+               irqchip->irq_mask == gpiochip_irq_mask) {
                /*
                 * ...and if so, give a gentle warning that this is bad
                 * practice.
@@ -1647,98 +1590,6 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
        gpiochip_irqchip_free_valid_mask(gc);
 }
 
-/**
- * gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip
- * @gc: the gpiochip to add the irqchip to
- * @irqchip: the irqchip to add to the gpiochip
- * @first_irq: if not dynamically assigned, the base (first) IRQ to
- * allocate gpiochip irqs from
- * @handler: the irq handler to use (often a predefined irq core function)
- * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
- * to have the core avoid setting up any default type in the hardware.
- * @threaded: whether this irqchip uses a nested thread handler
- * @lock_key: lockdep class for IRQ lock
- * @request_key: lockdep class for IRQ request
- *
- * This function closely associates a certain irqchip with a certain
- * gpiochip, providing an irq domain to translate the local IRQs to
- * global irqs in the gpiolib core, and making sure that the gpiochip
- * is passed as chip data to all related functions. Driver callbacks
- * need to use gpiochip_get_data() to get their local state containers back
- * from the gpiochip passed as chip data. An irqdomain will be stored
- * in the gpiochip that shall be used by the driver to handle IRQ number
- * translation. The gpiochip will need to be initialized and registered
- * before calling this function.
- *
- * This function will handle two cell:ed simple IRQs and assumes all
- * the pins on the gpiochip can generate a unique IRQ. Everything else
- * need to be open coded.
- */
-int gpiochip_irqchip_add_key(struct gpio_chip *gc,
-                            struct irq_chip *irqchip,
-                            unsigned int first_irq,
-                            irq_flow_handler_t handler,
-                            unsigned int type,
-                            bool threaded,
-                            struct lock_class_key *lock_key,
-                            struct lock_class_key *request_key)
-{
-       struct device_node *of_node;
-
-       if (!gc || !irqchip)
-               return -EINVAL;
-
-       if (!gc->parent) {
-               chip_err(gc, "missing gpiochip .dev parent pointer\n");
-               return -EINVAL;
-       }
-       gc->irq.threaded = threaded;
-       of_node = gc->parent->of_node;
-#ifdef CONFIG_OF_GPIO
-       /*
-        * If the gpiochip has an assigned OF node this takes precedence
-        * FIXME: get rid of this and use gc->parent->of_node
-        * everywhere
-        */
-       if (gc->of_node)
-               of_node = gc->of_node;
-#endif
-       /*
-        * Specifying a default trigger is a terrible idea if DT or ACPI is
-        * used to configure the interrupts, as you may end-up with
-        * conflicting triggers. Tell the user, and reset to NONE.
-        */
-       if (WARN(of_node && type != IRQ_TYPE_NONE,
-                "%pOF: Ignoring %d default trigger\n", of_node, type))
-               type = IRQ_TYPE_NONE;
-       if (has_acpi_companion(gc->parent) && type != IRQ_TYPE_NONE) {
-               acpi_handle_warn(ACPI_HANDLE(gc->parent),
-                                "Ignoring %d default trigger\n", type);
-               type = IRQ_TYPE_NONE;
-       }
-
-       gc->irq.chip = irqchip;
-       gc->irq.handler = handler;
-       gc->irq.default_type = type;
-       gc->to_irq = gpiochip_to_irq;
-       gc->irq.lock_key = lock_key;
-       gc->irq.request_key = request_key;
-       gc->irq.domain = irq_domain_add_simple(of_node,
-                                       gc->ngpio, first_irq,
-                                       &gpiochip_domain_ops, gc);
-       if (!gc->irq.domain) {
-               gc->irq.chip = NULL;
-               return -EINVAL;
-       }
-
-       gpiochip_set_irq_hooks(gc);
-
-       acpi_gpiochip_request_interrupts(gc);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
-
 /**
  * gpiochip_irqchip_add_domain() - adds an irqdomain to a gpiochip
  * @gc: the gpiochip to add the irqchip to
@@ -1788,7 +1639,7 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
  * @gc: the gpiochip owning the GPIO
  * @offset: the offset of the GPIO to request for GPIO function
  */
-int gpiochip_generic_request(struct gpio_chip *gc, unsigned offset)
+int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset)
 {
 #ifdef CONFIG_PINCTRL
        if (list_empty(&gc->gpiodev->pin_ranges))
@@ -1804,7 +1655,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request);
  * @gc: the gpiochip to request the gpio function for
  * @offset: the offset of the GPIO to free from GPIO function
  */
-void gpiochip_generic_free(struct gpio_chip *gc, unsigned offset)
+void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset)
 {
 #ifdef CONFIG_PINCTRL
        if (list_empty(&gc->gpiodev->pin_ranges))
@@ -1821,7 +1672,7 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_free);
  * @offset: the offset of the GPIO to apply the configuration
  * @config: the configuration to be applied
  */
-int gpiochip_generic_config(struct gpio_chip *gc, unsigned offset,
+int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset,
                            unsigned long config)
 {
        return pinctrl_gpio_set_config(gc->gpiodev->base + offset, config);
@@ -1985,11 +1836,9 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 
        if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
                desc_set_label(desc, label ? : "?");
-               ret = 0;
        } else {
-               kfree_const(label);
                ret = -EBUSY;
-               goto done;
+               goto out_free_unlock;
        }
 
        if (gc->request) {
@@ -2002,11 +1851,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
                        ret = -EINVAL;
                spin_lock_irqsave(&gpio_lock, flags);
 
-               if (ret < 0) {
+               if (ret) {
                        desc_set_label(desc, NULL);
-                       kfree_const(label);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
-                       goto done;
+                       goto out_free_unlock;
                }
        }
        if (gc->get_direction) {
@@ -2015,8 +1863,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
                gpiod_get_direction(desc);
                spin_lock_irqsave(&gpio_lock, flags);
        }
-done:
        spin_unlock_irqrestore(&gpio_lock, flags);
+       return 0;
+
+out_free_unlock:
+       spin_unlock_irqrestore(&gpio_lock, flags);
+       kfree_const(label);
        return ret;
 }
 
@@ -2068,7 +1920,7 @@ int gpiod_request(struct gpio_desc *desc, const char *label)
 
        if (try_module_get(gdev->owner)) {
                ret = gpiod_request_commit(desc, label);
-               if (ret < 0)
+               if (ret)
                        module_put(gdev->owner);
                else
                        get_device(&gdev->dev);
@@ -2151,7 +2003,7 @@ void gpiod_free(struct gpio_desc *desc)
  * help with diagnostics, and knowing that the signal is used as a GPIO
  * can help avoid accidentally multiplexing it to another controller.
  */
-const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned offset)
+const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset)
 {
        struct gpio_desc *desc;
 
@@ -2251,30 +2103,49 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset,
        return gc->set_config(gc, offset, config);
 }
 
-static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
+static int gpio_set_config_with_argument(struct gpio_desc *desc,
+                                        enum pin_config_param mode,
+                                        u32 argument)
 {
        struct gpio_chip *gc = desc->gdev->chip;
        unsigned long config;
-       unsigned arg;
+
+       config = pinconf_to_config_packed(mode, argument);
+       return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
+}
+
+static int gpio_set_config_with_argument_optional(struct gpio_desc *desc,
+                                                 enum pin_config_param mode,
+                                                 u32 argument)
+{
+       struct device *dev = &desc->gdev->dev;
+       int gpio = gpio_chip_hwgpio(desc);
+       int ret;
+
+       ret = gpio_set_config_with_argument(desc, mode, argument);
+       if (ret != -ENOTSUPP)
+               return ret;
 
        switch (mode) {
-       case PIN_CONFIG_BIAS_PULL_DOWN:
-       case PIN_CONFIG_BIAS_PULL_UP:
-               arg = 1;
+       case PIN_CONFIG_PERSIST_STATE:
+               dev_dbg(dev, "Persistence not supported for GPIO %d\n", gpio);
                break;
-
        default:
-               arg = 0;
+               break;
        }
 
-       config = PIN_CONF_PACKED(mode, arg);
-       return gpio_do_set_config(gc, gpio_chip_hwgpio(desc), config);
+       return 0;
+}
+
+static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
+{
+       return gpio_set_config_with_argument(desc, mode, 0);
 }
 
 static int gpio_set_bias(struct gpio_desc *desc)
 {
-       int bias = 0;
-       int ret = 0;
+       enum pin_config_param bias;
+       unsigned int arg;
 
        if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
                bias = PIN_CONFIG_BIAS_DISABLE;
@@ -2282,13 +2153,28 @@ static int gpio_set_bias(struct gpio_desc *desc)
                bias = PIN_CONFIG_BIAS_PULL_UP;
        else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
                bias = PIN_CONFIG_BIAS_PULL_DOWN;
+       else
+               return 0;
 
-       if (bias) {
-               ret = gpio_set_config(desc, bias);
-               if (ret != -ENOTSUPP)
-                       return ret;
+       switch (bias) {
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_UP:
+               arg = 1;
+               break;
+
+       default:
+               arg = 0;
+               break;
        }
-       return 0;
+
+       return gpio_set_config_with_argument_optional(desc, bias, arg);
+}
+
+int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce)
+{
+       return gpio_set_config_with_argument_optional(desc,
+                                                     PIN_CONFIG_INPUT_DEBOUNCE,
+                                                     debounce);
 }
 
 /**
@@ -2510,7 +2396,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_config);
  * 0 on success, %-ENOTSUPP if the controller doesn't support setting the
  * debounce time.
  */
-int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
+int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce)
 {
        unsigned long config;
 
@@ -2529,11 +2415,6 @@ EXPORT_SYMBOL_GPL(gpiod_set_debounce);
  */
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
 {
-       struct gpio_chip *gc;
-       unsigned long packed;
-       int gpio;
-       int rc;
-
        VALIDATE_DESC(desc);
        /*
         * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for
@@ -2542,21 +2423,9 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
        assign_bit(FLAG_TRANSITORY, &desc->flags, transitory);
 
        /* If the driver supports it, set the persistence state now */
-       gc = desc->gdev->chip;
-       if (!gc->set_config)
-               return 0;
-
-       packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
-                                         !transitory);
-       gpio = gpio_chip_hwgpio(desc);
-       rc = gpio_do_set_config(gc, gpio, packed);
-       if (rc == -ENOTSUPP) {
-               dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
-                               gpio);
-               return 0;
-       }
-
-       return rc;
+       return gpio_set_config_with_argument_optional(desc,
+                                                     PIN_CONFIG_PERSIST_STATE,
+                                                     !transitory);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_transitory);
 
@@ -3784,7 +3653,7 @@ struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
 
                desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
                                              label);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+               if (!gpiod_not_found(desc))
                        break;
        }
 
@@ -3960,7 +3829,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
         * Either we are not using DT or ACPI, or their lookup did not return
         * a result. In that case, use platform lookup as a fallback.
         */
-       if (!desc || desc == ERR_PTR(-ENOENT)) {
+       if (!desc || gpiod_not_found(desc)) {
                dev_dbg(dev, "using lookup tables for GPIO lookup\n");
                desc = gpiod_find(dev, con_id, idx, &lookupflags);
        }
@@ -3975,7 +3844,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
         * the device name as label
         */
        ret = gpiod_request(desc, con_id ? con_id : devname);
-       if (ret < 0) {
+       if (ret) {
                if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
                        /*
                         * This happens when there are several consumers for
@@ -4095,10 +3964,8 @@ struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
        struct gpio_desc *desc;
 
        desc = gpiod_get_index(dev, con_id, index, flags);
-       if (IS_ERR(desc)) {
-               if (PTR_ERR(desc) == -ENOENT)
-                       return NULL;
-       }
+       if (gpiod_not_found(desc))
+               return NULL;
 
        return desc;
 }
@@ -4300,7 +4167,7 @@ struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev,
        struct gpio_descs *descs;
 
        descs = gpiod_get_array(dev, con_id, flags);
-       if (PTR_ERR(descs) == -ENOENT)
+       if (gpiod_not_found(descs))
                return NULL;
 
        return descs;
index b674b5b..30bc3f8 100644 (file)
@@ -116,6 +116,7 @@ struct gpio_desc {
 #define FLAG_BIAS_DISABLE    15        /* GPIO has pull disabled */
 #define FLAG_EDGE_RISING     16        /* GPIO CDEV detects rising edge events */
 #define FLAG_EDGE_FALLING    17        /* GPIO CDEV detects falling edge events */
+#define FLAG_EVENT_CLOCK_REALTIME      18 /* GPIO CDEV reports REALTIME timestamps in events */
 
        /* Connection label */
        const char              *label;
@@ -130,10 +131,13 @@ struct gpio_desc {
 #endif
 };
 
+#define gpiod_not_found(desc)          (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
+
 int gpiod_request(struct gpio_desc *desc, const char *label);
 void gpiod_free(struct gpio_desc *desc);
 int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags);
+int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce);
 int gpiod_hog(struct gpio_desc *desc, const char *name,
                unsigned long lflags, enum gpiod_flags dflags);
 
index 0782b05..af0d958 100644 (file)
@@ -8,8 +8,8 @@
  * The second cell contains standard flag values specified in gpio.h.
  */
 
-#ifndef _DT_BINDINGS_GPIO_TEGRA_GPIO_H
-#define _DT_BINDINGS_GPIO_TEGRA_GPIO_H
+#ifndef _DT_BINDINGS_GPIO_TEGRA186_GPIO_H
+#define _DT_BINDINGS_GPIO_TEGRA186_GPIO_H
 
 #include <dt-bindings/gpio/gpio.h>
 
index 901aab8..ef49307 100644 (file)
@@ -158,7 +158,7 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
                                       unsigned long *value_bitmap);
 
 int gpiod_set_config(struct gpio_desc *desc, unsigned long config);
-int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce);
+int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce);
 int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
 void gpiod_toggle_active_low(struct gpio_desc *desc);
 
@@ -481,7 +481,7 @@ static inline int gpiod_set_config(struct gpio_desc *desc, unsigned long config)
        return -ENOSYS;
 }
 
-static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
+static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce)
 {
        /* GPIO can never have been requested */
        WARN_ON(desc);
index 4a7e295..286de05 100644 (file)
@@ -621,83 +621,12 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
 void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
                                    struct irq_data *data);
 
-void gpiochip_set_nested_irqchip(struct gpio_chip *gc,
-               struct irq_chip *irqchip,
-               unsigned int parent_irq);
-
-int gpiochip_irqchip_add_key(struct gpio_chip *gc,
-                            struct irq_chip *irqchip,
-                            unsigned int first_irq,
-                            irq_flow_handler_t handler,
-                            unsigned int type,
-                            bool threaded,
-                            struct lock_class_key *lock_key,
-                            struct lock_class_key *request_key);
-
 bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
                                unsigned int offset);
 
 int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
                                struct irq_domain *domain);
 
-#ifdef CONFIG_LOCKDEP
-
-/*
- * Lockdep requires that each irqchip instance be created with a
- * unique key so as to avoid unnecessary warnings. This upfront
- * boilerplate static inlines provides such a key for each
- * unique instance.
- */
-static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
-                                      struct irq_chip *irqchip,
-                                      unsigned int first_irq,
-                                      irq_flow_handler_t handler,
-                                      unsigned int type)
-{
-       static struct lock_class_key lock_key;
-       static struct lock_class_key request_key;
-
-       return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
-                                       handler, type, false,
-                                       &lock_key, &request_key);
-}
-
-static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
-                         struct irq_chip *irqchip,
-                         unsigned int first_irq,
-                         irq_flow_handler_t handler,
-                         unsigned int type)
-{
-
-       static struct lock_class_key lock_key;
-       static struct lock_class_key request_key;
-
-       return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
-                                       handler, type, true,
-                                       &lock_key, &request_key);
-}
-#else /* ! CONFIG_LOCKDEP */
-static inline int gpiochip_irqchip_add(struct gpio_chip *gc,
-                                      struct irq_chip *irqchip,
-                                      unsigned int first_irq,
-                                      irq_flow_handler_t handler,
-                                      unsigned int type)
-{
-       return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
-                                       handler, type, false, NULL, NULL);
-}
-
-static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gc,
-                         struct irq_chip *irqchip,
-                         unsigned int first_irq,
-                         irq_flow_handler_t handler,
-                         unsigned int type)
-{
-       return gpiochip_irqchip_add_key(gc, irqchip, first_irq,
-                                       handler, type, true, NULL, NULL);
-}
-#endif /* CONFIG_LOCKDEP */
-
 int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset);
 void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset);
 int gpiochip_generic_config(struct gpio_chip *gc, unsigned int offset,
index 2072c26..e4eb0b8 100644 (file)
@@ -65,6 +65,7 @@ struct gpiochip_info {
  * @GPIO_V2_LINE_FLAG_BIAS_PULL_UP: line has pull-up bias enabled
  * @GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN: line has pull-down bias enabled
  * @GPIO_V2_LINE_FLAG_BIAS_DISABLED: line has bias disabled
+ * @GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME: line events contain REALTIME timestamps
  */
 enum gpio_v2_line_flag {
        GPIO_V2_LINE_FLAG_USED                  = _BITULL(0),
@@ -78,6 +79,7 @@ enum gpio_v2_line_flag {
        GPIO_V2_LINE_FLAG_BIAS_PULL_UP          = _BITULL(8),
        GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN        = _BITULL(9),
        GPIO_V2_LINE_FLAG_BIAS_DISABLED         = _BITULL(10),
+       GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME  = _BITULL(11),
 };
 
 /**
@@ -270,9 +272,6 @@ enum gpio_v2_line_event_id {
 /**
  * struct gpio_v2_line_event - The actual event being pushed to userspace
  * @timestamp_ns: best estimate of time of event occurrence, in nanoseconds.
- * The @timestamp_ns is read from %CLOCK_MONOTONIC and is intended to allow
- * the accurate measurement of the time between events. It does not provide
- * the wall-clock time.
  * @id: event identifier with value from &enum gpio_v2_line_event_id
  * @offset: the offset of the line that triggered the event
  * @seqno: the sequence number for this event in the sequence of events for
@@ -280,6 +279,13 @@ enum gpio_v2_line_event_id {
  * @line_seqno: the sequence number for this event in the sequence of
  * events on this particular line
  * @padding: reserved for future use
+ *
+ * By default the @timestamp_ns is read from %CLOCK_MONOTONIC and is
+ * intended to allow the accurate measurement of the time between events.
+ * It does not provide the wall-clock time.
+ *
+ * If the %GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME flag is set then the
+ * @timestamp_ns is read from %CLOCK_REALTIME.
  */
 struct gpio_v2_line_event {
        __aligned_u64 timestamp_ns;
index 90c3155..cacd66a 100644 (file)
@@ -148,6 +148,7 @@ void print_usage(void)
                "  -s         Set line as open source\n"
                "  -r         Listen for rising edges\n"
                "  -f         Listen for falling edges\n"
+               "  -w         Report the wall-clock time for events\n"
                "  -b <n>     Debounce the line with period n microseconds\n"
                " [-c <n>]    Do <n> loops (optional, infinite loop if not stated)\n"
                "  -?         This helptext\n"
@@ -173,7 +174,7 @@ int main(int argc, char **argv)
 
        memset(&config, 0, sizeof(config));
        config.flags = GPIO_V2_LINE_FLAG_INPUT;
-       while ((c = getopt(argc, argv, "c:n:o:b:dsrf?")) != -1) {
+       while ((c = getopt(argc, argv, "c:n:o:b:dsrfw?")) != -1) {
                switch (c) {
                case 'c':
                        loops = strtoul(optarg, NULL, 10);
@@ -204,6 +205,9 @@ int main(int argc, char **argv)
                case 'f':
                        config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
                        break;
+               case 'w':
+                       config.flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
+                       break;
                case '?':
                        print_usage();
                        return -1;
index 5a05a45..c61d061 100644 (file)
@@ -65,6 +65,10 @@ struct gpio_flag flagnames[] = {
                .name = "bias-disabled",
                .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
        },
+       {
+               .name = "clock-realtime",
+               .mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,
+       },
 };
 
 static void print_attributes(struct gpio_v2_line_info *info)