Merge tag 'v5.4-rc6' into devel
authorLinus Walleij <linus.walleij@linaro.org>
Tue, 5 Nov 2019 10:00:40 +0000 (11:00 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 5 Nov 2019 10:00:40 +0000 (11:00 +0100)
Linux 5.4-rc6

30 files changed:
Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio-rda.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
Documentation/driver-api/bt8xxgpio.rst [deleted file]
Documentation/driver-api/gpio/bt8xxgpio.rst [new file with mode: 0644]
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/gpio/index.rst
Documentation/driver-api/index.rst
MAINTAINERS
drivers/ata/ahci_imx.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-aspeed-sgpio.c [new file with mode: 0644]
drivers/gpio/gpio-ath79.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-htc-egpio.c
drivers/gpio/gpio-max77620.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-rda.c [new file with mode: 0644]
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-xgene.c
drivers/gpio/gpio-xgs-iproc.c [new file with mode: 0644]
drivers/gpio/gpiolib-devres.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpio/sgpio-aspeed.c [deleted file]
include/linux/gpio/consumer.h
include/uapi/linux/gpio.h

diff --git a/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml b/Documentation/devicetree/bindings/gpio/brcm,xgs-iproc-gpio.yaml
new file mode 100644 (file)
index 0000000..64e279a
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/brcm,xgs-iproc-gpio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom XGS iProc GPIO controller
+
+maintainers:
+  - Chris Packham <chris.packham@alliedtelesis.co.nz>
+
+description: |
+  This controller is the Chip Common A GPIO present on a number of Broadcom
+  switch ASICs with integrated SoCs.
+
+properties:
+  compatible:
+    const: brcm,iproc-gpio-cca
+
+  reg:
+    items:
+      - description: the I/O address containing the GPIO controller
+                     registers.
+      - description: the I/O address containing the Chip Common A interrupt
+                     registers.
+
+  gpio-controller: true
+
+  '#gpio-cells':
+      const: 2
+
+  ngpios:
+    minimum: 0
+    maximum: 32
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - "#gpio-cells"
+  - gpio-controller
+
+dependencies:
+  interrupt-controller: [ interrupts ]
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    gpio@18000060 {
+        compatible = "brcm,iproc-gpio-cca";
+        #gpio-cells = <2>;
+        reg = <0x18000060 0x50>,
+              <0x18000000 0x50>;
+        ngpios = <12>;
+        gpio-controller;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+        interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+    };
+
+
+...
diff --git a/Documentation/devicetree/bindings/gpio/gpio-rda.yaml b/Documentation/devicetree/bindings/gpio/gpio-rda.yaml
new file mode 100644 (file)
index 0000000..6ece555
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/gpio/gpio-rda.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RDA Micro GPIO controller
+
+maintainers:
+  - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+
+properties:
+  compatible:
+    const: rda,8810pl-gpio
+
+  reg:
+    maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+    const: 2
+
+  ngpios:
+    description:
+      Number of available gpios in a bank.
+    minimum: 1
+    maximum: 32
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - gpio-controller
+  - "#gpio-cells"
+  - ngpios
+  - interrupt-controller
+  - "#interrupt-cells"
+  - interrupts
+
+additionalProperties: false
+
+...
index f3f2c46..41e5fed 100644 (file)
@@ -8,6 +8,7 @@ Required Properties:
     - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller.
     - "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller.
     - "renesas,gpio-r8a774a1": for R8A774A1 (RZ/G2M) compatible GPIO controller.
+    - "renesas,gpio-r8a774b1": for R8A774B1 (RZ/G2N) compatible GPIO controller.
     - "renesas,gpio-r8a774c0": for R8A774C0 (RZ/G2E) compatible GPIO controller.
     - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller.
     - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller.
diff --git a/Documentation/driver-api/bt8xxgpio.rst b/Documentation/driver-api/bt8xxgpio.rst
deleted file mode 100644 (file)
index a845feb..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-===================================================================
-A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio)
-===================================================================
-
-For advanced documentation, see http://www.bu3sch.de/btgpio.php
-
-A generic digital 24-port PCI GPIO card can be built out of an ordinary
-Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The
-Brooktree chip is used in old analog Hauppauge WinTV PCI cards. You can easily
-find them used for low prices on the net.
-
-The bt8xx chip does have 24 digital GPIO ports.
-These ports are accessible via 24 pins on the SMD chip package.
-
-
-How to physically access the GPIO pins
-======================================
-
-The are several ways to access these pins. One might unsolder the whole chip
-and put it on a custom PCI board, or one might only unsolder each individual
-GPIO pin and solder that to some tiny wire. As the chip package really is tiny
-there are some advanced soldering skills needed in any case.
-
-The physical pinouts are drawn in the following ASCII art.
-The GPIO pins are marked with G00-G23::
-
-                                           G G G G G G G G G G G G     G G G G G G
-                                           0 0 0 0 0 0 0 0 0 0 1 1     1 1 1 1 1 1
-                                           0 1 2 3 4 5 6 7 8 9 0 1     2 3 4 5 6 7
-           | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
-           ---------------------------------------------------------------------------
-         --|                               ^                                     ^   |--
-         --|                               pin 86                           pin 67   |--
-         --|                                                                         |--
-         --|                                                               pin 61 >  |-- G18
-         --|                                                                         |-- G19
-         --|                                                                         |-- G20
-         --|                                                                         |-- G21
-         --|                                                                         |-- G22
-         --|                                                               pin 56 >  |-- G23
-         --|                                                                         |--
-         --|                           Brooktree 878/879                             |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|                                                                         |--
-         --|   O                                                                     |--
-         --|                                                                         |--
-           ---------------------------------------------------------------------------
-           | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
-           ^
-           This is pin 1
-
diff --git a/Documentation/driver-api/gpio/bt8xxgpio.rst b/Documentation/driver-api/gpio/bt8xxgpio.rst
new file mode 100644 (file)
index 0000000..d7e75f1
--- /dev/null
@@ -0,0 +1,62 @@
+===================================================================
+A driver for a selfmade cheap BT8xx based PCI GPIO-card (bt8xxgpio)
+===================================================================
+
+For advanced documentation, see https://bues.ch/cms/unmaintained/btgpio.html
+
+A generic digital 24-port PCI GPIO card can be built out of an ordinary
+Brooktree bt848, bt849, bt878 or bt879 based analog TV tuner card. The
+Brooktree chip is used in old analog Hauppauge WinTV PCI cards. You can easily
+find them used for low prices on the net.
+
+The bt8xx chip does have 24 digital GPIO ports.
+These ports are accessible via 24 pins on the SMD chip package.
+
+
+How to physically access the GPIO pins
+======================================
+
+The are several ways to access these pins. One might unsolder the whole chip
+and put it on a custom PCI board, or one might only unsolder each individual
+GPIO pin and solder that to some tiny wire. As the chip package really is tiny
+there are some advanced soldering skills needed in any case.
+
+The physical pinouts are drawn in the following ASCII art.
+The GPIO pins are marked with G00-G23::
+
+                                           G G G G G G G G G G G G     G G G G G G
+                                           0 0 0 0 0 0 0 0 0 0 1 1     1 1 1 1 1 1
+                                           0 1 2 3 4 5 6 7 8 9 0 1     2 3 4 5 6 7
+           | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+           ---------------------------------------------------------------------------
+         --|                               ^                                     ^   |--
+         --|                               pin 86                           pin 67   |--
+         --|                                                                         |--
+         --|                                                               pin 61 >  |-- G18
+         --|                                                                         |-- G19
+         --|                                                                         |-- G20
+         --|                                                                         |-- G21
+         --|                                                                         |-- G22
+         --|                                                               pin 56 >  |-- G23
+         --|                                                                         |--
+         --|                           Brooktree 878/879                             |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|                                                                         |--
+         --|   O                                                                     |--
+         --|                                                                         |--
+           ---------------------------------------------------------------------------
+           | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
+           ^
+           This is pin 1
+
index 3fdb324..18dca55 100644 (file)
@@ -415,6 +415,8 @@ 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:
 
+.. code-block:: c
+
   /* Typical state container with dynamic irqchip */
   struct my_gpio {
       struct gpio_chip gc;
@@ -450,6 +452,8 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:
 The helper support using hierarchical interrupt controllers as well.
 In this case the typical set-up will look like this:
 
+.. code-block:: c
+
   /* Typical state container with dynamic irqchip */
   struct my_gpio {
       struct gpio_chip gc;
index c5b8467..5b61032 100644 (file)
@@ -13,6 +13,7 @@ Contents:
    board
    drivers-on-gpio
    legacy
+   bt8xxgpio
 
 Core
 ====
index 38e638a..2b3b694 100644 (file)
@@ -69,7 +69,6 @@ available subsections can be seen below.
    fpga/index
    acpi/index
    backlight/lp855x-driver.rst
-   bt8xxgpio
    connector
    console
    dcdbas
index cba1095..5db06cb 100644 (file)
@@ -2150,9 +2150,11 @@ L:       linux-unisoc@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/boot/dts/rda8810pl-*
 F:     drivers/clocksource/timer-rda.c
+F:     drivers/gpio/gpio-rda.c
 F:     drivers/irqchip/irq-rda-intc.c
 F:     drivers/tty/serial/rda-uart.c
 F:     Documentation/devicetree/bindings/arm/rda.yaml
+F:     Documentation/devicetree/bindings/gpio/gpio-rda.yaml
 F:     Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
 F:     Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
 F:     Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
index bfc617c..948d2c6 100644 (file)
@@ -11,8 +11,8 @@
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/ahci_platform.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 #include <linux/libata.h>
@@ -100,7 +100,7 @@ struct imx_ahci_priv {
        struct clk *phy_pclk0;
        struct clk *phy_pclk1;
        void __iomem *phy_base;
-       int clkreq_gpio;
+       struct gpio_desc *clkreq_gpiod;
        struct regmap *gpr;
        bool no_device;
        bool first_time;
@@ -980,7 +980,6 @@ static struct scsi_host_template ahci_platform_sht = {
 
 static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
 {
-       int ret;
        struct resource *phy_res;
        struct platform_device *pdev = imxpriv->ahci_pdev;
        struct device_node *np = dev->of_node;
@@ -1033,20 +1032,12 @@ static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
        }
 
        /* Fetch GPIO, then enable the external OSC */
-       imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0);
-       if (gpio_is_valid(imxpriv->clkreq_gpio)) {
-               ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio,
-                                           GPIOF_OUT_INIT_LOW,
-                                           "SATA CLKREQ");
-               if (ret == -EBUSY) {
-                       dev_info(dev, "clkreq had been initialized.\n");
-               } else if (ret) {
-                       dev_err(dev, "%d unable to get clkreq.\n", ret);
-                       return ret;
-               }
-       } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) {
-               return imxpriv->clkreq_gpio;
-       }
+       imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq",
+                               GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+       if (IS_ERR(imxpriv->clkreq_gpiod))
+               return PTR_ERR(imxpriv->clkreq_gpiod);
+       if (imxpriv->clkreq_gpiod)
+               gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ");
 
        return 0;
 }
index 38e096e..e951639 100644 (file)
@@ -120,6 +120,14 @@ config GPIO_ASPEED
        help
          Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers.
 
+config GPIO_ASPEED_SGPIO
+       bool "Aspeed SGPIO support"
+       depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO
+       select GPIO_GENERIC
+       select GPIOLIB_IRQCHIP
+       help
+         Say Y here to support Aspeed AST2500 SGPIO functionality.
+
 config GPIO_ATH79
        tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
        default y if ATH79
@@ -147,6 +155,15 @@ config GPIO_BCM_KONA
        help
          Turn on GPIO support for Broadcom "Kona" chips.
 
+config GPIO_BCM_XGS_IPROC
+       tristate "BRCM XGS iProc GPIO support"
+       depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST)
+       select GPIO_GENERIC
+       select GPIOLIB_IRQCHIP
+       default ARCH_BCM_IPROC
+       help
+         Say yes here to enable GPIO support for Broadcom XGS iProc SoCs.
+
 config GPIO_BRCMSTB
        tristate "BRCMSTB GPIO support"
        default y if (ARCH_BRCMSTB || BMIPS_GENERIC)
@@ -435,6 +452,15 @@ config GPIO_RCAR
        help
          Say yes here to support GPIO on Renesas R-Car SoCs.
 
+config GPIO_RDA
+       bool "RDA Micro GPIO controller support"
+       depends on ARCH_RDA || COMPILE_TEST
+       depends on OF_GPIO
+       select GPIO_GENERIC
+       select GPIOLIB_IRQCHIP
+       help
+         Say Y here to support RDA Micro GPIO controller.
+
 config GPIO_REG
        bool
        help
@@ -531,6 +557,7 @@ config GPIO_TEGRA186
        depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
        depends on OF_GPIO
        select GPIOLIB_IRQCHIP
+       select IRQ_DOMAIN_HIERARCHY
        help
          Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs.
 
@@ -1320,7 +1347,7 @@ config GPIO_BT8XX
          The card needs to be physically altered for using it as a
          GPIO card. For more information on how to build a GPIO card
          from a BT8xx TV card, see the documentation file at
-         Documentation/driver-api/bt8xxgpio.rst
+         Documentation/driver-api/gpio/bt8xxgpio.rst
 
          If unsure, say N.
 
index d2fd19c..34eb8b2 100644 (file)
@@ -32,8 +32,10 @@ obj-$(CONFIG_GPIO_AMD_FCH)           += gpio-amd-fch.o
 obj-$(CONFIG_GPIO_AMDPT)               += gpio-amdpt.o
 obj-$(CONFIG_GPIO_ARIZONA)             += gpio-arizona.o
 obj-$(CONFIG_GPIO_ASPEED)              += gpio-aspeed.o
+obj-$(CONFIG_GPIO_ASPEED_SGPIO)                += gpio-aspeed-sgpio.o
 obj-$(CONFIG_GPIO_ATH79)               += gpio-ath79.o
 obj-$(CONFIG_GPIO_BCM_KONA)            += gpio-bcm-kona.o
+obj-$(CONFIG_GPIO_BCM_XGS_IPROC)       += gpio-xgs-iproc.o
 obj-$(CONFIG_GPIO_BD70528)             += gpio-bd70528.o
 obj-$(CONFIG_GPIO_BD9571MWV)           += gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BRCMSTB)             += gpio-brcmstb.o
@@ -115,6 +117,7 @@ obj-$(CONFIG_GPIO_PXA)                      += gpio-pxa.o
 obj-$(CONFIG_GPIO_RASPBERRYPI_EXP)     += gpio-raspberrypi-exp.o
 obj-$(CONFIG_GPIO_RC5T583)             += gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RCAR)                        += gpio-rcar.o
+obj-$(CONFIG_GPIO_RDA)                 += gpio-rda.o
 obj-$(CONFIG_GPIO_RDC321X)             += gpio-rdc321x.o
 obj-$(CONFIG_GPIO_REG)                 += gpio-reg.o
 obj-$(CONFIG_ARCH_SA1100)              += gpio-sa1100.o
index ff53887..79dead6 100644 (file)
@@ -65,7 +65,7 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
        unsigned i;
-       const unsigned register_offset[6] = { 0, 1, 2, 4, 5, 6 };
+       static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
        unsigned base_offset;
        unsigned mask;
 
diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c
new file mode 100644 (file)
index 0000000..7e99860
--- /dev/null
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2019 American Megatrends International LLC.
+ *
+ * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#define MAX_NR_SGPIO                   80
+
+#define ASPEED_SGPIO_CTRL              0x54
+
+#define ASPEED_SGPIO_PINS_MASK         GENMASK(9, 6)
+#define ASPEED_SGPIO_CLK_DIV_MASK      GENMASK(31, 16)
+#define ASPEED_SGPIO_ENABLE            BIT(0)
+
+struct aspeed_sgpio {
+       struct gpio_chip chip;
+       struct clk *pclk;
+       spinlock_t lock;
+       void __iomem *base;
+       uint32_t dir_in[3];
+       int irq;
+};
+
+struct aspeed_sgpio_bank {
+       uint16_t    val_regs;
+       uint16_t    rdata_reg;
+       uint16_t    irq_regs;
+       const char  names[4][3];
+};
+
+/*
+ * Note: The "value" register returns the input value when the GPIO is
+ *      configured as an input.
+ *
+ *      The "rdata" register returns the output value when the GPIO is
+ *      configured as an output.
+ */
+static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
+       {
+               .val_regs = 0x0000,
+               .rdata_reg = 0x0070,
+               .irq_regs = 0x0004,
+               .names = { "A", "B", "C", "D" },
+       },
+       {
+               .val_regs = 0x001C,
+               .rdata_reg = 0x0074,
+               .irq_regs = 0x0020,
+               .names = { "E", "F", "G", "H" },
+       },
+       {
+               .val_regs = 0x0038,
+               .rdata_reg = 0x0078,
+               .irq_regs = 0x003C,
+               .names = { "I", "J" },
+       },
+};
+
+enum aspeed_sgpio_reg {
+       reg_val,
+       reg_rdata,
+       reg_irq_enable,
+       reg_irq_type0,
+       reg_irq_type1,
+       reg_irq_type2,
+       reg_irq_status,
+};
+
+#define GPIO_VAL_VALUE      0x00
+#define GPIO_IRQ_ENABLE     0x00
+#define GPIO_IRQ_TYPE0      0x04
+#define GPIO_IRQ_TYPE1      0x08
+#define GPIO_IRQ_TYPE2      0x0C
+#define GPIO_IRQ_STATUS     0x10
+
+static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
+                                    const struct aspeed_sgpio_bank *bank,
+                                    const enum aspeed_sgpio_reg reg)
+{
+       switch (reg) {
+       case reg_val:
+               return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
+       case reg_rdata:
+               return gpio->base + bank->rdata_reg;
+       case reg_irq_enable:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
+       case reg_irq_type0:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
+       case reg_irq_type1:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
+       case reg_irq_type2:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
+       case reg_irq_status:
+               return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
+       default:
+               /* acturally if code runs to here, it's an error case */
+               BUG_ON(1);
+       }
+}
+
+#define GPIO_BANK(x)    ((x) >> 5)
+#define GPIO_OFFSET(x)  ((x) & 0x1f)
+#define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
+
+static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
+{
+       unsigned int bank = GPIO_BANK(offset);
+
+       WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
+       return &aspeed_sgpio_banks[bank];
+}
+
+static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_sgpio_bank *bank = to_bank(offset);
+       unsigned long flags;
+       enum aspeed_sgpio_reg reg;
+       bool is_input;
+       int rc = 0;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+       reg = is_input ? reg_val : reg_rdata;
+       rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return rc;
+}
+
+static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       const struct aspeed_sgpio_bank *bank = to_bank(offset);
+       void __iomem *addr;
+       u32 reg = 0;
+
+       addr = bank_reg(gpio, bank, reg_val);
+       reg = ioread32(addr);
+
+       if (val)
+               reg |= GPIO_BIT(offset);
+       else
+               reg &= ~GPIO_BIT(offset);
+
+       iowrite32(reg, addr);
+}
+
+static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       sgpio_set_value(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+       gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
+{
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
+       sgpio_set_value(gc, offset, val);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return 0;
+}
+
+static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       int dir_status;
+       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio->lock, flags);
+       dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       return dir_status;
+
+}
+
+static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
+                                       struct aspeed_sgpio **gpio,
+                                       const struct aspeed_sgpio_bank **bank,
+                                       u32 *bit, int *offset)
+{
+       struct aspeed_sgpio *internal;
+
+       *offset = irqd_to_hwirq(d);
+       internal = irq_data_get_irq_chip_data(d);
+       WARN_ON(!internal);
+
+       *gpio = internal;
+       *bank = to_bank(*offset);
+       *bit = GPIO_BIT(*offset);
+}
+
+static void aspeed_sgpio_irq_ack(struct irq_data *d)
+{
+       const struct aspeed_sgpio_bank *bank;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       void __iomem *status_addr;
+       int offset;
+       u32 bit;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+       status_addr = bank_reg(gpio, bank, reg_irq_status);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       iowrite32(bit, status_addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
+{
+       const struct aspeed_sgpio_bank *bank;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       u32 reg, bit;
+       void __iomem *addr;
+       int offset;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+       addr = bank_reg(gpio, bank, reg_irq_enable);
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       reg = ioread32(addr);
+       if (set)
+               reg |= bit;
+       else
+               reg &= ~bit;
+
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
+static void aspeed_sgpio_irq_mask(struct irq_data *d)
+{
+       aspeed_sgpio_irq_set_mask(d, false);
+}
+
+static void aspeed_sgpio_irq_unmask(struct irq_data *d)
+{
+       aspeed_sgpio_irq_set_mask(d, true);
+}
+
+static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
+{
+       u32 type0 = 0;
+       u32 type1 = 0;
+       u32 type2 = 0;
+       u32 bit, reg;
+       const struct aspeed_sgpio_bank *bank;
+       irq_flow_handler_t handler;
+       struct aspeed_sgpio *gpio;
+       unsigned long flags;
+       void __iomem *addr;
+       int offset;
+
+       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
+
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_BOTH:
+               type2 |= bit;
+               /* fall through */
+       case IRQ_TYPE_EDGE_RISING:
+               type0 |= bit;
+               /* fall through */
+       case IRQ_TYPE_EDGE_FALLING:
+               handler = handle_edge_irq;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               type0 |= bit;
+               /* fall through */
+       case IRQ_TYPE_LEVEL_LOW:
+               type1 |= bit;
+               handler = handle_level_irq;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&gpio->lock, flags);
+
+       addr = bank_reg(gpio, bank, reg_irq_type0);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type0;
+       iowrite32(reg, addr);
+
+       addr = bank_reg(gpio, bank, reg_irq_type1);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type1;
+       iowrite32(reg, addr);
+
+       addr = bank_reg(gpio, bank, reg_irq_type2);
+       reg = ioread32(addr);
+       reg = (reg & ~bit) | type2;
+       iowrite32(reg, addr);
+
+       spin_unlock_irqrestore(&gpio->lock, flags);
+
+       irq_set_handler_locked(d, handler);
+
+       return 0;
+}
+
+static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+       struct irq_chip *ic = irq_desc_get_chip(desc);
+       struct aspeed_sgpio *data = gpiochip_get_data(gc);
+       unsigned int i, p, girq;
+       unsigned long reg;
+
+       chained_irq_enter(ic, desc);
+
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
+
+               reg = ioread32(bank_reg(data, bank, reg_irq_status));
+
+               for_each_set_bit(p, &reg, 32) {
+                       girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
+                       generic_handle_irq(girq);
+               }
+
+       }
+
+       chained_irq_exit(ic, desc);
+}
+
+static struct irq_chip aspeed_sgpio_irqchip = {
+       .name       = "aspeed-sgpio",
+       .irq_ack    = aspeed_sgpio_irq_ack,
+       .irq_mask   = aspeed_sgpio_irq_mask,
+       .irq_unmask = aspeed_sgpio_irq_unmask,
+       .irq_set_type   = aspeed_sgpio_set_type,
+};
+
+static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
+                                  struct platform_device *pdev)
+{
+       int rc, i;
+       const struct aspeed_sgpio_bank *bank;
+       struct gpio_irq_chip *irq;
+
+       rc = platform_get_irq(pdev, 0);
+       if (rc < 0)
+               return rc;
+
+       gpio->irq = rc;
+
+       /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               bank =  &aspeed_sgpio_banks[i];
+               /* disable irq enable bits */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
+               /* clear status bits */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
+       }
+
+       irq = &gpio->chip.irq;
+       irq->chip = &aspeed_sgpio_irqchip;
+       irq->handler = handle_bad_irq;
+       irq->default_type = IRQ_TYPE_NONE;
+       irq->parent_handler = aspeed_sgpio_irq_handler;
+       irq->parent_handler_data = gpio;
+       irq->parents = &gpio->irq;
+       irq->num_parents = 1;
+
+       /* set IRQ settings and Enable Interrupt */
+       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
+               bank = &aspeed_sgpio_banks[i];
+               /* set falling or level-low irq */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
+               /* trigger type is edge */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
+               /* dual edge trigger mode. */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
+               /* enable irq */
+               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+       }
+
+       return 0;
+}
+
+static const struct of_device_id aspeed_sgpio_of_table[] = {
+       { .compatible = "aspeed,ast2400-sgpio" },
+       { .compatible = "aspeed,ast2500-sgpio" },
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
+
+static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+{
+       struct aspeed_sgpio *gpio;
+       u32 nr_gpios, sgpio_freq, sgpio_clk_div;
+       int rc;
+       unsigned long apb_freq;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+
+       gpio->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gpio->base))
+               return PTR_ERR(gpio->base);
+
+       rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Could not read ngpios property\n");
+               return -EINVAL;
+       } else if (nr_gpios > MAX_NR_SGPIO) {
+               dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
+                       MAX_NR_SGPIO, nr_gpios);
+               return -EINVAL;
+       }
+
+       rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Could not read bus-frequency property\n");
+               return -EINVAL;
+       }
+
+       gpio->pclk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(gpio->pclk)) {
+               dev_err(&pdev->dev, "devm_clk_get failed\n");
+               return PTR_ERR(gpio->pclk);
+       }
+
+       apb_freq = clk_get_rate(gpio->pclk);
+
+       /*
+        * From the datasheet,
+        *      SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
+        *      period = 2 * (GPIO254[31:16] + 1) / PCLK
+        *      frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
+        *      frequency = PCLK / (2 * (GPIO254[31:16] + 1))
+        *      frequency * 2 * (GPIO254[31:16] + 1) = PCLK
+        *      GPIO254[31:16] = PCLK / (frequency * 2) - 1
+        */
+       if (sgpio_freq == 0)
+               return -EINVAL;
+
+       sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
+
+       if (sgpio_clk_div > (1 << 16) - 1)
+               return -EINVAL;
+
+       iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
+                 FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
+                 ASPEED_SGPIO_ENABLE,
+                 gpio->base + ASPEED_SGPIO_CTRL);
+
+       spin_lock_init(&gpio->lock);
+
+       gpio->chip.parent = &pdev->dev;
+       gpio->chip.ngpio = nr_gpios;
+       gpio->chip.direction_input = aspeed_sgpio_dir_in;
+       gpio->chip.direction_output = aspeed_sgpio_dir_out;
+       gpio->chip.get_direction = aspeed_sgpio_get_direction;
+       gpio->chip.request = NULL;
+       gpio->chip.free = NULL;
+       gpio->chip.get = aspeed_sgpio_get;
+       gpio->chip.set = aspeed_sgpio_set;
+       gpio->chip.set_config = NULL;
+       gpio->chip.label = dev_name(&pdev->dev);
+       gpio->chip.base = -1;
+
+       /* set all SGPIO pins as input (1). */
+       memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
+
+       aspeed_sgpio_setup_irqs(gpio, pdev);
+
+       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static struct platform_driver aspeed_sgpio_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = aspeed_sgpio_of_table,
+       },
+};
+
+module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
+MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
+MODULE_LICENSE("GPL");
index f1a5ea9..53fae02 100644 (file)
@@ -226,7 +226,6 @@ static int ath79_gpio_probe(struct platform_device *pdev)
        struct device_node *np = dev->of_node;
        struct ath79_gpio_ctrl *ctrl;
        struct gpio_irq_chip *girq;
-       struct resource *res;
        u32 ath79_gpio_count;
        bool oe_inverted;
        int err;
@@ -256,12 +255,9 @@ static int ath79_gpio_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-       ctrl->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!ctrl->base)
-               return -ENOMEM;
+       ctrl->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(ctrl->base))
+               return PTR_ERR(ctrl->base);
 
        raw_spin_lock_init(&ctrl->lock);
        err = bgpio_init(&ctrl->gc, dev, 4,
index 620f25b..674ebeb 100644 (file)
@@ -269,7 +269,7 @@ static void em_gio_irq_domain_remove(void *data)
 static int em_gio_probe(struct platform_device *pdev)
 {
        struct em_gio_priv *p;
-       struct resource *io[2], *irq[2];
+       struct resource *irq[2];
        struct gpio_chip *gpio_chip;
        struct irq_chip *irq_chip;
        struct device *dev = &pdev->dev;
@@ -285,25 +285,21 @@ static int em_gio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, p);
        spin_lock_init(&p->sense_lock);
 
-       io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
 
-       if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
+       if (!irq[0] || !irq[1]) {
                dev_err(dev, "missing IRQ or IOMEM\n");
                return -EINVAL;
        }
 
-       p->base0 = devm_ioremap_nocache(dev, io[0]->start,
-                                       resource_size(io[0]));
-       if (!p->base0)
-               return -ENOMEM;
+       p->base0 = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(p->base0))
+               return PTR_ERR(p->base0);
 
-       p->base1 = devm_ioremap_nocache(dev, io[1]->start,
-                                  resource_size(io[1]));
-       if (!p->base1)
-               return -ENOMEM;
+       p->base1 = devm_platform_ioremap_resource(pdev, 1);
+       if (IS_ERR(p->base1))
+               return PTR_ERR(p->base1);
 
        if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
                dev_err(dev, "Missing ngpios OF property\n");
index 6eb56f7..8aa23d7 100644 (file)
@@ -265,7 +265,6 @@ static int __init egpio_probe(struct platform_device *pdev)
        struct gpio_chip  *chip;
        unsigned int      irq, irq_end;
        int               i;
-       int               ret;
 
        /* Initialize ei data structure. */
        ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
@@ -275,28 +274,24 @@ static int __init egpio_probe(struct platform_device *pdev)
        spin_lock_init(&ei->lock);
 
        /* Find chained irq */
-       ret = -EINVAL;
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (res)
                ei->chained_irq = res->start;
 
        /* Map egpio chip into virtual address space. */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               goto fail;
-       ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
-                                            resource_size(res));
-       if (!ei->base_addr)
-               goto fail;
-       pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
+       ei->base_addr = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(ei->base_addr))
+               return PTR_ERR(ei->base_addr);
 
        if ((pdata->bus_width != 16) && (pdata->bus_width != 32))
-               goto fail;
+               return -EINVAL;
+
        ei->bus_shift = fls(pdata->bus_width - 1) - 3;
        pr_debug("bus_shift = %d\n", ei->bus_shift);
 
        if ((pdata->reg_width != 8) && (pdata->reg_width != 16))
-               goto fail;
+               return -EINVAL;
+
        ei->reg_shift = fls(pdata->reg_width - 1);
        pr_debug("reg_shift = %d\n", ei->reg_shift);
 
@@ -308,10 +303,9 @@ static int __init egpio_probe(struct platform_device *pdev)
        ei->chip = devm_kcalloc(&pdev->dev,
                                ei->nchips, sizeof(struct egpio_chip),
                                GFP_KERNEL);
-       if (!ei->chip) {
-               ret = -ENOMEM;
-               goto fail;
-       }
+       if (!ei->chip)
+               return -ENOMEM;
+
        for (i = 0; i < ei->nchips; i++) {
                ei->chip[i].reg_start = pdata->chip[i].reg_start;
                ei->chip[i].cached_values = pdata->chip[i].initial_values;
@@ -321,10 +315,9 @@ static int __init egpio_probe(struct platform_device *pdev)
                chip->label = devm_kasprintf(&pdev->dev, GFP_KERNEL,
                                             "htc-egpio-%d",
                                             i);
-               if (!chip->label) {
-                       ret = -ENOMEM;
-                       goto fail;
-               }
+               if (!chip->label)
+                       return -ENOMEM;
+
                chip->parent          = &pdev->dev;
                chip->owner           = THIS_MODULE;
                chip->get             = egpio_get;
@@ -366,10 +359,6 @@ static int __init egpio_probe(struct platform_device *pdev)
        }
 
        return 0;
-
-fail:
-       printk(KERN_ERR "EGPIO failed to setup\n");
-       return ret;
 }
 
 #ifdef CONFIG_PM
index faf86ea..c5b64a4 100644 (file)
@@ -18,109 +18,115 @@ struct max77620_gpio {
        struct gpio_chip        gpio_chip;
        struct regmap           *rmap;
        struct device           *dev;
+       struct mutex            buslock; /* irq_bus_lock */
+       unsigned int            irq_type[8];
+       bool                    irq_enabled[8];
 };
 
-static const struct regmap_irq max77620_gpio_irqs[] = {
-       [0] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 0,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [1] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 1,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [2] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 2,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [3] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 3,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [4] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 4,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [5] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 5,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [6] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 6,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-       [7] = {
-               .reg_offset = 0,
-               .mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
-               .type = {
-                       .type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
-                       .type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
-                       .type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
-                       .type_reg_offset = 7,
-                       .types_supported = IRQ_TYPE_EDGE_BOTH,
-               },
-       },
-};
+static irqreturn_t max77620_gpio_irqhandler(int irq, void *data)
+{
+       struct max77620_gpio *gpio = data;
+       unsigned int value, offset;
+       unsigned long pending;
+       int err;
+
+       err = regmap_read(gpio->rmap, MAX77620_REG_IRQ_LVL2_GPIO, &value);
+       if (err < 0) {
+               dev_err(gpio->dev, "REG_IRQ_LVL2_GPIO read failed: %d\n", err);
+               return IRQ_NONE;
+       }
+
+       pending = value;
+
+       for_each_set_bit(offset, &pending, 8) {
+               unsigned int virq;
+
+               virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset);
+               handle_nested_irq(virq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void max77620_gpio_irq_mask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct max77620_gpio *gpio = gpiochip_get_data(chip);
+
+       gpio->irq_enabled[data->hwirq] = false;
+}
 
-static const struct regmap_irq_chip max77620_gpio_irq_chip = {
-       .name = "max77620-gpio",
-       .irqs = max77620_gpio_irqs,
-       .num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
-       .num_regs = 1,
-       .num_type_reg = 8,
-       .irq_reg_stride = 1,
-       .type_reg_stride = 1,
-       .status_base = MAX77620_REG_IRQ_LVL2_GPIO,
-       .type_base = MAX77620_REG_GPIO0,
+static void max77620_gpio_irq_unmask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct max77620_gpio *gpio = gpiochip_get_data(chip);
+
+       gpio->irq_enabled[data->hwirq] = true;
+}
+
+static int max77620_gpio_set_irq_type(struct irq_data *data, unsigned int type)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct max77620_gpio *gpio = gpiochip_get_data(chip);
+       unsigned int irq_type;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               irq_type = MAX77620_CNFG_GPIO_INT_RISING;
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               irq_type = MAX77620_CNFG_GPIO_INT_FALLING;
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               irq_type = MAX77620_CNFG_GPIO_INT_RISING |
+                          MAX77620_CNFG_GPIO_INT_FALLING;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       gpio->irq_type[data->hwirq] = irq_type;
+
+       return 0;
+}
+
+static void max77620_gpio_bus_lock(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct max77620_gpio *gpio = gpiochip_get_data(chip);
+
+       mutex_lock(&gpio->buslock);
+}
+
+static void max77620_gpio_bus_sync_unlock(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct max77620_gpio *gpio = gpiochip_get_data(chip);
+       unsigned int value, offset = data->hwirq;
+       int err;
+
+       value = gpio->irq_enabled[offset] ? gpio->irq_type[offset] : 0;
+
+       err = regmap_update_bits(gpio->rmap, GPIO_REG_ADDR(offset),
+                                MAX77620_CNFG_GPIO_INT_MASK, value);
+       if (err < 0)
+               dev_err(chip->parent, "failed to update interrupt mask: %d\n",
+                       err);
+
+       mutex_unlock(&gpio->buslock);
+}
+
+static struct irq_chip max77620_gpio_irqchip = {
+       .name           = "max77620-gpio",
+       .irq_mask       = max77620_gpio_irq_mask,
+       .irq_unmask     = max77620_gpio_irq_unmask,
+       .irq_set_type   = max77620_gpio_set_irq_type,
+       .irq_bus_lock   = max77620_gpio_bus_lock,
+       .irq_bus_sync_unlock = max77620_gpio_bus_sync_unlock,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND,
 };
 
 static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
@@ -254,14 +260,6 @@ static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
        return -ENOTSUPP;
 }
 
-static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
-{
-       struct max77620_gpio *mgpio = gpiochip_get_data(gc);
-       struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent);
-
-       return regmap_irq_get_virq(chip->gpio_irq_data, offset);
-}
-
 static int max77620_gpio_probe(struct platform_device *pdev)
 {
        struct max77620_chip *chip =  dev_get_drvdata(pdev->dev.parent);
@@ -287,7 +285,6 @@ static int max77620_gpio_probe(struct platform_device *pdev)
        mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
        mgpio->gpio_chip.set = max77620_gpio_set;
        mgpio->gpio_chip.set_config = max77620_gpio_set_config;
-       mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
        mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
        mgpio->gpio_chip.can_sleep = 1;
        mgpio->gpio_chip.base = -1;
@@ -303,15 +300,21 @@ static int max77620_gpio_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq,
-                                      IRQF_ONESHOT, -1,
-                                      &max77620_gpio_irq_chip,
-                                      &chip->gpio_irq_data);
+       mutex_init(&mgpio->buslock);
+
+       gpiochip_irqchip_add_nested(&mgpio->gpio_chip, &max77620_gpio_irqchip,
+                                   0, handle_edge_irq, IRQ_TYPE_NONE);
+
+       ret = request_threaded_irq(gpio_irq, NULL, max77620_gpio_irqhandler,
+                                  IRQF_ONESHOT, "max77620-gpio", mgpio);
        if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to add gpio irq_chip %d\n", ret);
+               dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret);
                return ret;
        }
 
+       gpiochip_set_nested_irqchip(&mgpio->gpio_chip, &max77620_gpio_irqchip,
+                                   gpio_irq);
+
        return 0;
 }
 
index 16a47de..58ff372 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/gpio/driver.h>
 #include <linux/bitops.h>
+#include <linux/interrupt.h>
 
 #define MPC8XXX_GPIO_PINS      32
 
@@ -127,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
                return -ENXIO;
 }
 
-static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc)
+static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
 {
-       struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
-       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
        struct gpio_chip *gc = &mpc8xxx_gc->gc;
-       unsigned int mask;
+       unsigned long mask;
+       int i;
 
        mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
                & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
-       if (mask)
-               generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
-                                                    32 - ffs(mask)));
-       if (chip->irq_eoi)
-               chip->irq_eoi(&desc->irq_data);
+       for_each_set_bit(i, &mask, 32)
+               generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i));
+
+       return IRQ_HANDLED;
 }
 
 static void mpc8xxx_irq_unmask(struct irq_data *d)
@@ -409,8 +409,16 @@ static int mpc8xxx_probe(struct platform_device *pdev)
        if (devtype->gpio_dir_in_init)
                devtype->gpio_dir_in_init(gc);
 
-       irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
-                                        mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);
+       ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
+                              mpc8xxx_gpio_irq_cascade,
+                              IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
+                              mpc8xxx_gc);
+       if (ret) {
+               dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
+                       np->full_name, mpc8xxx_gc->irqn, ret);
+               goto err;
+       }
+
        return 0;
 err:
        iounmap(mpc8xxx_gc->regs);
index 7907a87..c77d474 100644 (file)
@@ -411,6 +411,7 @@ static int mxc_gpio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct mxc_gpio_port *port;
+       int irq_count;
        int irq_base;
        int err;
 
@@ -426,9 +427,15 @@ static int mxc_gpio_probe(struct platform_device *pdev)
        if (IS_ERR(port->base))
                return PTR_ERR(port->base);
 
-       port->irq_high = platform_get_irq(pdev, 1);
-       if (port->irq_high < 0)
-               port->irq_high = 0;
+       irq_count = platform_irq_count(pdev);
+       if (irq_count < 0)
+               return irq_count;
+
+       if (irq_count > 1) {
+               port->irq_high = platform_get_irq(pdev, 1);
+               if (port->irq_high < 0)
+                       port->irq_high = 0;
+       }
 
        port->irq = platform_get_irq(pdev, 0);
        if (port->irq < 0)
diff --git a/drivers/gpio/gpio-rda.c b/drivers/gpio/gpio-rda.c
new file mode 100644 (file)
index 0000000..28dcbb5
--- /dev/null
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RDA Micro GPIO driver
+ *
+ * Copyright (C) 2012 RDA Micro Inc.
+ * Copyright (C) 2019 Manivannan Sadhasivam
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define RDA_GPIO_OEN_VAL               0x00
+#define RDA_GPIO_OEN_SET_OUT           0x04
+#define RDA_GPIO_OEN_SET_IN            0x08
+#define RDA_GPIO_VAL                   0x0c
+#define RDA_GPIO_SET                   0x10
+#define RDA_GPIO_CLR                   0x14
+#define RDA_GPIO_INT_CTRL_SET          0x18
+#define RDA_GPIO_INT_CTRL_CLR          0x1c
+#define RDA_GPIO_INT_CLR               0x20
+#define RDA_GPIO_INT_STATUS            0x24
+
+#define RDA_GPIO_IRQ_RISE_SHIFT                0
+#define RDA_GPIO_IRQ_FALL_SHIFT                8
+#define RDA_GPIO_DEBOUCE_SHIFT         16
+#define RDA_GPIO_LEVEL_SHIFT           24
+
+#define RDA_GPIO_IRQ_MASK              0xff
+
+/* Each bank consists of 32 GPIOs */
+#define RDA_GPIO_BANK_NR       32
+
+struct rda_gpio {
+       struct gpio_chip chip;
+       void __iomem *base;
+       spinlock_t lock;
+       struct irq_chip irq_chip;
+       int irq;
+};
+
+static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset,
+                                  u16 reg, int val)
+{
+       struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
+       void __iomem *base = rda_gpio->base;
+       unsigned long flags;
+       u32 tmp;
+
+       spin_lock_irqsave(&rda_gpio->lock, flags);
+       tmp = readl_relaxed(base + reg);
+
+       if (val)
+               tmp |= BIT(offset);
+       else
+               tmp &= ~BIT(offset);
+
+       writel_relaxed(tmp, base + reg);
+       spin_unlock_irqrestore(&rda_gpio->lock, flags);
+}
+
+static void rda_gpio_irq_mask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
+       void __iomem *base = rda_gpio->base;
+       u32 offset = irqd_to_hwirq(data);
+       u32 value;
+
+       value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
+       value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
+
+       writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
+}
+
+static void rda_gpio_irq_ack(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       u32 offset = irqd_to_hwirq(data);
+
+       rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1);
+}
+
+static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset,
+                           unsigned int flow_type)
+{
+       struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
+       void __iomem *base = rda_gpio->base;
+       u32 value;
+
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_RISING:
+               /* Set rising edge trigger */
+               value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
+
+               /* Switch to edge trigger interrupt */
+               value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
+               break;
+
+       case IRQ_TYPE_EDGE_FALLING:
+               /* Set falling edge trigger */
+               value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
+
+               /* Switch to edge trigger interrupt */
+               value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
+               break;
+
+       case IRQ_TYPE_EDGE_BOTH:
+               /* Set both edge trigger */
+               value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
+               value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
+
+               /* Switch to edge trigger interrupt */
+               value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
+               break;
+
+       case IRQ_TYPE_LEVEL_HIGH:
+               /* Set high level trigger */
+               value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
+
+               /* Switch to level trigger interrupt */
+               value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
+               break;
+
+       case IRQ_TYPE_LEVEL_LOW:
+               /* Set low level trigger */
+               value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
+
+               /* Switch to level trigger interrupt */
+               value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
+               writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void rda_gpio_irq_unmask(struct irq_data *data)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       u32 offset = irqd_to_hwirq(data);
+       u32 trigger = irqd_get_trigger_type(data);
+
+       rda_gpio_set_irq(chip, offset, trigger);
+}
+
+static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+       u32 offset = irqd_to_hwirq(data);
+       int ret;
+
+       ret = rda_gpio_set_irq(chip, offset, flow_type);
+       if (ret)
+               return ret;
+
+       if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               irq_set_handler_locked(data, handle_level_irq);
+       else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               irq_set_handler_locked(data, handle_edge_irq);
+
+       return 0;
+}
+
+static void rda_gpio_irq_handler(struct irq_desc *desc)
+{
+       struct gpio_chip *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *ic = irq_desc_get_chip(desc);
+       struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
+       unsigned long status;
+       u32 n, girq;
+
+       chained_irq_enter(ic, desc);
+
+       status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS);
+       /* Only lower 8 bits are capable of generating interrupts */
+       status &= RDA_GPIO_IRQ_MASK;
+
+       for_each_set_bit(n, &status, RDA_GPIO_BANK_NR) {
+               girq = irq_find_mapping(chip->irq.domain, n);
+               generic_handle_irq(girq);
+       }
+
+       chained_irq_exit(ic, desc);
+}
+
+static int rda_gpio_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct gpio_irq_chip *girq;
+       struct rda_gpio *rda_gpio;
+       u32 ngpios;
+       int ret;
+
+       rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL);
+       if (!rda_gpio)
+               return -ENOMEM;
+
+       ret = device_property_read_u32(dev, "ngpios", &ngpios);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Not all ports have interrupt capability. For instance, on
+        * RDA8810PL, GPIOC doesn't support interrupt. So we must handle
+        * those also.
+        */
+       rda_gpio->irq = platform_get_irq(pdev, 0);
+
+       rda_gpio->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(rda_gpio->base))
+               return PTR_ERR(rda_gpio->base);
+
+       spin_lock_init(&rda_gpio->lock);
+
+       ret = bgpio_init(&rda_gpio->chip, dev, 4,
+                        rda_gpio->base + RDA_GPIO_VAL,
+                        rda_gpio->base + RDA_GPIO_SET,
+                        rda_gpio->base + RDA_GPIO_CLR,
+                        rda_gpio->base + RDA_GPIO_OEN_SET_OUT,
+                        rda_gpio->base + RDA_GPIO_OEN_SET_IN,
+                        BGPIOF_READ_OUTPUT_REG_SET);
+       if (ret) {
+               dev_err(dev, "bgpio_init failed\n");
+               return ret;
+       }
+
+       rda_gpio->chip.label = dev_name(dev);
+       rda_gpio->chip.ngpio = ngpios;
+       rda_gpio->chip.base = -1;
+       rda_gpio->chip.parent = dev;
+       rda_gpio->chip.of_node = np;
+
+       if (rda_gpio->irq >= 0) {
+               rda_gpio->irq_chip.name = "rda-gpio",
+               rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack,
+               rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask,
+               rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask,
+               rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type,
+               rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE,
+
+               girq = &rda_gpio->chip.irq;
+               girq->chip = &rda_gpio->irq_chip;
+               girq->handler = handle_bad_irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->parent_handler = rda_gpio_irq_handler;
+               girq->parent_handler_data = rda_gpio;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = rda_gpio->irq;
+       }
+
+       platform_set_drvdata(pdev, rda_gpio);
+
+       return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio);
+}
+
+static const struct of_device_id rda_gpio_of_match[] = {
+       { .compatible = "rda,8810pl-gpio", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rda_gpio_of_match);
+
+static struct platform_driver rda_gpio_driver = {
+       .probe = rda_gpio_probe,
+       .driver = {
+               .name = "rda-gpio",
+               .of_match_table = rda_gpio_of_match,
+       },
+};
+
+module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe);
+
+MODULE_DESCRIPTION("RDA Micro GPIO driver");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_LICENSE("GPL v2");
index a9058fd..8a2a691 100644 (file)
@@ -53,6 +53,7 @@ struct tegra_gpio_soc {
        const struct tegra_gpio_port *ports;
        unsigned int num_ports;
        const char *name;
+       unsigned int instance;
 };
 
 struct tegra_gpio {
@@ -327,7 +328,7 @@ static int tegra186_irq_set_type(struct irq_data *data, unsigned int type)
        else
                irq_set_handler_locked(data, handle_edge_irq);
 
-       return 0;
+       return irq_chip_set_type_parent(data, type);
 }
 
 static void tegra186_gpio_irq(struct irq_desc *desc)
@@ -367,39 +368,80 @@ skip:
        chained_irq_exit(chip, desc);
 }
 
-static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
-                                         struct device_node *np,
-                                         const u32 *spec, unsigned int size,
-                                         unsigned long *hwirq,
-                                         unsigned int *type)
+static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain,
+                                             struct irq_fwspec *fwspec,
+                                             unsigned long *hwirq,
+                                             unsigned int *type)
 {
        struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
        unsigned int port, pin, i, offset = 0;
 
-       if (size < 2)
+       if (WARN_ON(gpio->gpio.of_gpio_n_cells < 2))
+               return -EINVAL;
+
+       if (WARN_ON(fwspec->param_count < gpio->gpio.of_gpio_n_cells))
                return -EINVAL;
 
-       port = spec[0] / 8;
-       pin = spec[0] % 8;
+       port = fwspec->param[0] / 8;
+       pin = fwspec->param[0] % 8;
 
-       if (port >= gpio->soc->num_ports) {
-               dev_err(gpio->gpio.parent, "invalid port number: %u\n", port);
+       if (port >= gpio->soc->num_ports)
                return -EINVAL;
-       }
 
        for (i = 0; i < port; i++)
                offset += gpio->soc->ports[i].pins;
 
-       *type = spec[1] & IRQ_TYPE_SENSE_MASK;
+       *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
        *hwirq = offset + pin;
 
        return 0;
 }
 
-static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = {
-       .map = gpiochip_irq_map,
-       .unmap = gpiochip_irq_unmap,
-       .xlate = tegra186_gpio_irq_domain_xlate,
+static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip,
+                                                struct irq_fwspec *fwspec,
+                                                unsigned int parent_hwirq,
+                                                unsigned int parent_type)
+{
+       struct tegra_gpio *gpio = gpiochip_get_data(chip);
+
+       fwspec->param_count = 3;
+       fwspec->param[0] = gpio->soc->instance;
+       fwspec->param[1] = parent_hwirq;
+       fwspec->param[2] = parent_type;
+}
+
+static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
+                                              unsigned int hwirq,
+                                              unsigned int type,
+                                              unsigned int *parent_hwirq,
+                                              unsigned int *parent_type)
+{
+       *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq);
+       *parent_type = type;
+
+       return 0;
+}
+
+static unsigned int tegra186_gpio_child_offset_to_irq(struct gpio_chip *chip,
+                                                     unsigned int offset)
+{
+       struct tegra_gpio *gpio = gpiochip_get_data(chip);
+       unsigned int i;
+
+       for (i = 0; i < gpio->soc->num_ports; i++) {
+               if (offset < gpio->soc->ports[i].pins)
+                       break;
+
+               offset -= gpio->soc->ports[i].pins;
+       }
+
+       return offset + i * 8;
+}
+
+static const struct of_device_id tegra186_pmc_of_match[] = {
+       { .compatible = "nvidia,tegra186-pmc" },
+       { .compatible = "nvidia,tegra194-pmc" },
+       { /* sentinel */ }
 };
 
 static int tegra186_gpio_probe(struct platform_device *pdev)
@@ -407,6 +449,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        unsigned int i, j, offset;
        struct gpio_irq_chip *irq;
        struct tegra_gpio *gpio;
+       struct device_node *np;
        struct resource *res;
        char **names;
        int err;
@@ -487,10 +530,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->intc.irq_mask = tegra186_irq_mask;
        gpio->intc.irq_unmask = tegra186_irq_unmask;
        gpio->intc.irq_set_type = tegra186_irq_set_type;
+       gpio->intc.irq_set_wake = irq_chip_set_wake_parent;
 
        irq = &gpio->gpio.irq;
        irq->chip = &gpio->intc;
-       irq->domain_ops = &tegra186_gpio_irq_domain_ops;
+       irq->fwnode = of_node_to_fwnode(pdev->dev.of_node);
+       irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq;
+       irq->populate_parent_fwspec = tegra186_gpio_populate_parent_fwspec;
+       irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq;
+       irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate;
        irq->handler = handle_simple_irq;
        irq->default_type = IRQ_TYPE_NONE;
        irq->parent_handler = tegra186_gpio_irq;
@@ -498,6 +546,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        irq->num_parents = gpio->num_irq;
        irq->parents = gpio->irq;
 
+       np = of_find_matching_node(NULL, tegra186_pmc_of_match);
+       if (np) {
+               irq->parent_domain = irq_find_host(np);
+               of_node_put(np);
+
+               if (!irq->parent_domain)
+                       return -EPROBE_DEFER;
+       }
+
        irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
                                sizeof(*irq->map), GFP_KERNEL);
        if (!irq->map)
@@ -564,6 +621,7 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
        .num_ports = ARRAY_SIZE(tegra186_main_ports),
        .ports = tegra186_main_ports,
        .name = "tegra186-gpio",
+       .instance = 0,
 };
 
 #define TEGRA186_AON_GPIO_PORT(port, base, count, controller)  \
@@ -589,6 +647,7 @@ static const struct tegra_gpio_soc tegra186_aon_soc = {
        .num_ports = ARRAY_SIZE(tegra186_aon_ports),
        .ports = tegra186_aon_ports,
        .name = "tegra186-gpio-aon",
+       .instance = 1,
 };
 
 #define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \
@@ -634,6 +693,7 @@ static const struct tegra_gpio_soc tegra194_main_soc = {
        .num_ports = ARRAY_SIZE(tegra194_main_ports),
        .ports = tegra194_main_ports,
        .name = "tegra194-gpio",
+       .instance = 0,
 };
 
 #define TEGRA194_AON_GPIO_PORT(port, base, count, controller)  \
@@ -656,6 +716,7 @@ static const struct tegra_gpio_soc tegra194_aon_soc = {
        .num_ports = ARRAY_SIZE(tegra194_aon_ports),
        .ports = tegra194_aon_ports,
        .name = "tegra194-gpio-aon",
+       .instance = 1,
 };
 
 static const struct of_device_id tegra186_gpio_of_match[] = {
index 2918363..a6e66ac 100644 (file)
@@ -155,28 +155,16 @@ static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
 
 static int xgene_gpio_probe(struct platform_device *pdev)
 {
-       struct resource *res;
        struct xgene_gpio *gpio;
        int err = 0;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
-       if (!gpio) {
-               err = -ENOMEM;
-               goto err;
-       }
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               err = -EINVAL;
-               goto err;
-       }
+       if (!gpio)
+               return -ENOMEM;
 
-       gpio->base = devm_ioremap_nocache(&pdev->dev, res->start,
-                                                       resource_size(res));
-       if (!gpio->base) {
-               err = -ENOMEM;
-               goto err;
-       }
+       gpio->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(gpio->base))
+               return PTR_ERR(gpio->base);
 
        gpio->chip.ngpio = XGENE_MAX_GPIOS;
 
@@ -196,14 +184,11 @@ static int xgene_gpio_probe(struct platform_device *pdev)
        if (err) {
                dev_err(&pdev->dev,
                        "failed to register gpiochip.\n");
-               goto err;
+               return err;
        }
 
        dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n");
        return 0;
-err:
-       dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n");
-       return err;
 }
 
 static const struct of_device_id xgene_gpio_of_match[] = {
diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c
new file mode 100644 (file)
index 0000000..a3fdd95
--- /dev/null
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017 Broadcom
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define IPROC_CCA_INT_F_GPIOINT                BIT(0)
+#define IPROC_CCA_INT_STS              0x20
+#define IPROC_CCA_INT_MASK             0x24
+
+#define IPROC_GPIO_CCA_DIN             0x0
+#define IPROC_GPIO_CCA_DOUT            0x4
+#define IPROC_GPIO_CCA_OUT_EN          0x8
+#define IPROC_GPIO_CCA_INT_LEVEL       0x10
+#define IPROC_GPIO_CCA_INT_LEVEL_MASK  0x14
+#define IPROC_GPIO_CCA_INT_EVENT       0x18
+#define IPROC_GPIO_CCA_INT_EVENT_MASK  0x1C
+#define IPROC_GPIO_CCA_INT_EDGE                0x24
+
+struct iproc_gpio_chip {
+       struct irq_chip irqchip;
+       struct gpio_chip gc;
+       spinlock_t lock;
+       struct device *dev;
+       void __iomem *base;
+       void __iomem *intr;
+};
+
+static inline struct iproc_gpio_chip *
+to_iproc_gpio(struct gpio_chip *gc)
+{
+       return container_of(gc, struct iproc_gpio_chip, gc);
+}
+
+static void iproc_gpio_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+       int pin = d->hwirq;
+       unsigned long flags;
+       u32 irq = d->irq;
+       u32 irq_type, event_status = 0;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       irq_type = irq_get_trigger_type(irq);
+       if (irq_type & IRQ_TYPE_EDGE_BOTH) {
+               event_status |= BIT(pin);
+               writel_relaxed(event_status,
+                              chip->base + IPROC_GPIO_CCA_INT_EVENT);
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void iproc_gpio_irq_unmask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+       int pin = d->hwirq;
+       unsigned long flags;
+       u32 irq = d->irq;
+       u32 int_mask, irq_type, event_mask;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       irq_type = irq_get_trigger_type(irq);
+       event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
+       int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
+
+       if (irq_type & IRQ_TYPE_EDGE_BOTH) {
+               event_mask |= 1 << pin;
+               writel_relaxed(event_mask,
+                              chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
+       } else {
+               int_mask |= 1 << pin;
+               writel_relaxed(int_mask,
+                              chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void iproc_gpio_irq_mask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+       int pin = d->hwirq;
+       unsigned long flags;
+       u32 irq = d->irq;
+       u32 irq_type, int_mask, event_mask;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       irq_type = irq_get_trigger_type(irq);
+       event_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
+       int_mask = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
+
+       if (irq_type & IRQ_TYPE_EDGE_BOTH) {
+               event_mask &= ~BIT(pin);
+               writel_relaxed(event_mask,
+                              chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
+       } else {
+               int_mask &= ~BIT(pin);
+               writel_relaxed(int_mask,
+                              chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
+       }
+       spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int iproc_gpio_irq_set_type(struct irq_data *d, u32 type)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+       int pin = d->hwirq;
+       unsigned long flags;
+       u32 irq = d->irq;
+       u32 event_pol, int_pol;
+       int ret = 0;
+
+       spin_lock_irqsave(&chip->lock, flags);
+       switch (type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_RISING:
+               event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
+               event_pol &= ~BIT(pin);
+               writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               event_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EDGE);
+               event_pol |= BIT(pin);
+               writel_relaxed(event_pol, chip->base + IPROC_GPIO_CCA_INT_EDGE);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
+               int_pol &= ~BIT(pin);
+               writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               int_pol = readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
+               int_pol |= BIT(pin);
+               writel_relaxed(int_pol, chip->base + IPROC_GPIO_CCA_INT_LEVEL);
+               break;
+       default:
+               /* should not come here */
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       if (type & IRQ_TYPE_LEVEL_MASK)
+               irq_set_handler_locked(irq_get_irq_data(irq), handle_level_irq);
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(irq_get_irq_data(irq), handle_edge_irq);
+
+out_unlock:
+       spin_unlock_irqrestore(&chip->lock, flags);
+
+       return ret;
+}
+
+static irqreturn_t iproc_gpio_irq_handler(int irq, void *data)
+{
+       struct gpio_chip *gc = (struct gpio_chip *)data;
+       struct iproc_gpio_chip *chip = to_iproc_gpio(gc);
+       int bit;
+       unsigned long int_bits = 0;
+       u32 int_status;
+
+       /* go through the entire GPIOs and handle all interrupts */
+       int_status = readl_relaxed(chip->intr + IPROC_CCA_INT_STS);
+       if (int_status & IPROC_CCA_INT_F_GPIOINT) {
+               u32 event, level;
+
+               /* Get level and edge interrupts */
+               event =
+                   readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT_MASK);
+               event &= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_EVENT);
+               level = readl_relaxed(chip->base + IPROC_GPIO_CCA_DIN);
+               level ^= readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL);
+               level &=
+                   readl_relaxed(chip->base + IPROC_GPIO_CCA_INT_LEVEL_MASK);
+               int_bits = level | event;
+
+               for_each_set_bit(bit, &int_bits, gc->ngpio)
+                       generic_handle_irq(irq_linear_revmap(gc->irq.domain, bit));
+       }
+
+       return int_bits ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int iproc_gpio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *dn = pdev->dev.of_node;
+       struct iproc_gpio_chip *chip;
+       u32 num_gpios;
+       int irq, ret;
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = dev;
+       platform_set_drvdata(pdev, chip);
+       spin_lock_init(&chip->lock);
+
+       chip->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(chip->base))
+               return PTR_ERR(chip->base);
+
+       ret = bgpio_init(&chip->gc, dev, 4,
+                        chip->base + IPROC_GPIO_CCA_DIN,
+                        chip->base + IPROC_GPIO_CCA_DOUT,
+                        NULL,
+                        chip->base + IPROC_GPIO_CCA_OUT_EN,
+                        NULL,
+                        0);
+       if (ret) {
+               dev_err(dev, "unable to init GPIO chip\n");
+               return ret;
+       }
+
+       chip->gc.label = dev_name(dev);
+       if (of_property_read_u32(dn, "ngpios", &num_gpios))
+               chip->gc.ngpio = num_gpios;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq > 0) {
+               struct gpio_irq_chip *girq;
+               struct irq_chip *irqc;
+               u32 val;
+
+               irqc = &chip->irqchip;
+               irqc->name = dev_name(dev);
+               irqc->irq_ack = iproc_gpio_irq_ack;
+               irqc->irq_mask = iproc_gpio_irq_mask;
+               irqc->irq_unmask = iproc_gpio_irq_unmask;
+               irqc->irq_set_type = iproc_gpio_irq_set_type;
+
+               chip->intr = devm_platform_ioremap_resource(pdev, 1);
+               if (IS_ERR(chip->intr))
+                       return PTR_ERR(chip->intr);
+
+               /* Enable GPIO interrupts for CCA GPIO */
+               val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
+               val |= IPROC_CCA_INT_F_GPIOINT;
+               writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
+
+               /*
+                * Directly request the irq here instead of passing
+                * a flow-handler to gpiochip_set_chained_irqchip,
+                * because the irq is shared.
+                */
+               ret = devm_request_irq(dev, irq, iproc_gpio_irq_handler,
+                                      IRQF_SHARED, chip->gc.label, &chip->gc);
+               if (ret) {
+                       dev_err(dev, "Fail to request IRQ%d: %d\n", irq, ret);
+                       return ret;
+               }
+
+               girq = &chip->gc.irq;
+               girq->chip = irqc;
+               /* 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_simple_irq;
+       }
+
+       ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
+       if (ret) {
+               dev_err(dev, "unable to add GPIO chip\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __exit iproc_gpio_remove(struct platform_device *pdev)
+{
+       struct iproc_gpio_chip *chip;
+
+       chip = platform_get_drvdata(pdev);
+       if (!chip)
+               return -ENODEV;
+
+       if (chip->intr) {
+               u32 val;
+
+               val = readl_relaxed(chip->intr + IPROC_CCA_INT_MASK);
+               val &= ~IPROC_CCA_INT_F_GPIOINT;
+               writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id bcm_iproc_gpio_of_match[] __initconst = {
+       { .compatible = "brcm,iproc-gpio-cca" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match);
+
+static struct platform_driver bcm_iproc_gpio_driver = {
+       .driver = {
+               .name = "iproc-xgs-gpio",
+               .owner = THIS_MODULE,
+               .of_match_table = bcm_iproc_gpio_of_match,
+       },
+       .probe = iproc_gpio_probe,
+       .remove = iproc_gpio_remove,
+};
+
+module_platform_driver(bcm_iproc_gpio_driver);
+
+MODULE_DESCRIPTION("XGS IPROC GPIO driver");
+MODULE_LICENSE("GPL v2");
index 98e3c20..4421be0 100644 (file)
@@ -185,12 +185,11 @@ struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
 EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
 
 /**
- * devm_fwnode_get_index_gpiod_from_child - get a GPIO descriptor from a
- *                                         device's child node
+ * devm_fwnode_gpiod_get_index - get a GPIO descriptor from a given node
  * @dev:       GPIO consumer
+ * @fwnode:    firmware node containing GPIO reference
  * @con_id:    function within the GPIO consumer
  * @index:     index of the GPIO to obtain in the consumer
- * @child:     firmware node (child of @dev)
  * @flags:     GPIO initialization flags
  * @label:     label to attach to the requested GPIO
  *
@@ -200,35 +199,21 @@ EXPORT_SYMBOL_GPL(devm_gpiod_get_from_of_node);
  * On successful request the GPIO pin is configured in accordance with
  * provided @flags.
  */
-struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
-                                               const char *con_id, int index,
-                                               struct fwnode_handle *child,
-                                               enum gpiod_flags flags,
-                                               const char *label)
+struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
+                                             struct fwnode_handle *fwnode,
+                                             const char *con_id, int index,
+                                             enum gpiod_flags flags,
+                                             const char *label)
 {
-       char prop_name[32]; /* 32 is max size of property name */
        struct gpio_desc **dr;
        struct gpio_desc *desc;
-       unsigned int i;
 
        dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
                          GFP_KERNEL);
        if (!dr)
                return ERR_PTR(-ENOMEM);
 
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(prop_name, sizeof(prop_name), "%s-%s",
-                                           con_id, gpio_suffixes[i]);
-               else
-                       snprintf(prop_name, sizeof(prop_name), "%s",
-                                           gpio_suffixes[i]);
-
-               desc = fwnode_get_named_gpiod(child, prop_name, index, flags,
-                                             label);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
-                       break;
-       }
+       desc = fwnode_gpiod_get_index(fwnode, con_id, index, flags, label);
        if (IS_ERR(desc)) {
                devres_free(dr);
                return desc;
@@ -239,7 +224,7 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
 
        return desc;
 }
-EXPORT_SYMBOL_GPL(devm_fwnode_get_index_gpiod_from_child);
+EXPORT_SYMBOL_GPL(devm_fwnode_gpiod_get_index);
 
 /**
  * devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
index 80ea49f..0380a1d 100644 (file)
@@ -84,8 +84,9 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
 /**
  * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
  * to set the .valid_mask
- * @dev: the device for the GPIO provider
- * @return: true if the valid mask needs to be set
+ * @gc: the target gpio_chip
+ *
+ * Return: true if the valid mask needs to be set
  */
 bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
 {
@@ -134,18 +135,20 @@ static void of_gpio_flags_quirks(struct device_node *np,
             (!(strcmp(propname, "enable-gpio") &&
                strcmp(propname, "enable-gpios")) &&
              of_device_is_compatible(np, "regulator-gpio")))) {
+               bool active_low = !of_property_read_bool(np,
+                                                        "enable-active-high");
                /*
                 * The regulator GPIO handles are specified such that the
                 * presence or absence of "enable-active-high" solely controls
                 * the polarity of the GPIO line. Any phandle flags must
                 * be actively ignored.
                 */
-               if (*flags & OF_GPIO_ACTIVE_LOW) {
+               if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
                        pr_warn("%s GPIO handle specifies active low - ignored\n",
                                of_node_full_name(np));
                        *flags &= ~OF_GPIO_ACTIVE_LOW;
                }
-               if (!of_property_read_bool(np, "enable-active-high"))
+               if (active_low)
                        *flags |= OF_GPIO_ACTIVE_LOW;
        }
        /*
index 104ed29..9afbc06 100644 (file)
@@ -422,6 +422,8 @@ struct linehandle_state {
        (GPIOHANDLE_REQUEST_INPUT | \
        GPIOHANDLE_REQUEST_OUTPUT | \
        GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+       GPIOHANDLE_REQUEST_PULL_UP | \
+       GPIOHANDLE_REQUEST_PULL_DOWN | \
        GPIOHANDLE_REQUEST_OPEN_DRAIN | \
        GPIOHANDLE_REQUEST_OPEN_SOURCE)
 
@@ -593,6 +595,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                        set_bit(FLAG_OPEN_DRAIN, &desc->flags);
                if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
                        set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_PULL_DOWN)
+                       set_bit(FLAG_PULL_DOWN, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_PULL_UP)
+                       set_bit(FLAG_PULL_UP, &desc->flags);
 
                ret = gpiod_set_transitory(desc, false);
                if (ret < 0)
@@ -895,6 +901,24 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
                return -EFAULT;
 
+       offset = eventreq.lineoffset;
+       lflags = eventreq.handleflags;
+       eflags = eventreq.eventflags;
+
+       if (offset >= gdev->ngpio)
+               return -EINVAL;
+
+       /* Return an error if a unknown flag is set */
+       if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
+           (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS))
+               return -EINVAL;
+
+       /* This is just wrong: we don't look for events on output lines */
+       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
+               return -EINVAL;
+
        le = kzalloc(sizeof(*le), GFP_KERNEL);
        if (!le)
                return -ENOMEM;
@@ -912,30 +936,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
                }
        }
 
-       offset = eventreq.lineoffset;
-       lflags = eventreq.handleflags;
-       eflags = eventreq.eventflags;
-
-       if (offset >= gdev->ngpio) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
-       /* Return an error if a unknown flag is set */
-       if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
-           (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
-       /* This is just wrong: we don't look for events on output lines */
-       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
-           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
-           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
        desc = &gdev->descs[offset];
        ret = gpiod_request(desc, le->label);
        if (ret)
@@ -1098,6 +1098,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
                        lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
                                           GPIOLINE_FLAG_IS_OUT);
+               if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_PULL_DOWN;
+               if (test_bit(FLAG_PULL_UP, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_PULL_UP;
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
@@ -2790,6 +2794,8 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
                clear_bit(FLAG_REQUESTED, &desc->flags);
                clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
                clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               clear_bit(FLAG_PULL_UP, &desc->flags);
+               clear_bit(FLAG_PULL_DOWN, &desc->flags);
                clear_bit(FLAG_IS_HOGGED, &desc->flags);
                ret = true;
        }
@@ -4355,6 +4361,54 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
        return count;
 }
 
+/**
+ * fwnode_gpiod_get_index - obtain a GPIO from firmware node
+ * @fwnode:    handle of the firmware node
+ * @con_id:    function within the GPIO consumer
+ * @index:     index of the GPIO to obtain for the consumer
+ * @flags:     GPIO initialization flags
+ * @label:     label to attach to the requested GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from opaque firmware.
+ *
+ * The function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @flags.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
+                                        const char *con_id, int index,
+                                        enum gpiod_flags flags,
+                                        const char *label)
+{
+       struct gpio_desc *desc;
+       char prop_name[32]; /* 32 is max size of property name */
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id)
+                       snprintf(prop_name, sizeof(prop_name), "%s-%s",
+                                           con_id, gpio_suffixes[i]);
+               else
+                       snprintf(prop_name, sizeof(prop_name), "%s",
+                                           gpio_suffixes[i]);
+
+               desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
+                                             label);
+               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+                       break;
+       }
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
+
 /**
  * gpiod_count - return the number of GPIOs associated with a device / function
  *             or -ENOENT if no GPIO has been assigned to the requested function
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
deleted file mode 100644 (file)
index 7e99860..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright 2019 American Megatrends International LLC.
- *
- * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
- */
-
-#include <linux/bitfield.h>
-#include <linux/clk.h>
-#include <linux/gpio/driver.h>
-#include <linux/hashtable.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/string.h>
-
-#define MAX_NR_SGPIO                   80
-
-#define ASPEED_SGPIO_CTRL              0x54
-
-#define ASPEED_SGPIO_PINS_MASK         GENMASK(9, 6)
-#define ASPEED_SGPIO_CLK_DIV_MASK      GENMASK(31, 16)
-#define ASPEED_SGPIO_ENABLE            BIT(0)
-
-struct aspeed_sgpio {
-       struct gpio_chip chip;
-       struct clk *pclk;
-       spinlock_t lock;
-       void __iomem *base;
-       uint32_t dir_in[3];
-       int irq;
-};
-
-struct aspeed_sgpio_bank {
-       uint16_t    val_regs;
-       uint16_t    rdata_reg;
-       uint16_t    irq_regs;
-       const char  names[4][3];
-};
-
-/*
- * Note: The "value" register returns the input value when the GPIO is
- *      configured as an input.
- *
- *      The "rdata" register returns the output value when the GPIO is
- *      configured as an output.
- */
-static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
-       {
-               .val_regs = 0x0000,
-               .rdata_reg = 0x0070,
-               .irq_regs = 0x0004,
-               .names = { "A", "B", "C", "D" },
-       },
-       {
-               .val_regs = 0x001C,
-               .rdata_reg = 0x0074,
-               .irq_regs = 0x0020,
-               .names = { "E", "F", "G", "H" },
-       },
-       {
-               .val_regs = 0x0038,
-               .rdata_reg = 0x0078,
-               .irq_regs = 0x003C,
-               .names = { "I", "J" },
-       },
-};
-
-enum aspeed_sgpio_reg {
-       reg_val,
-       reg_rdata,
-       reg_irq_enable,
-       reg_irq_type0,
-       reg_irq_type1,
-       reg_irq_type2,
-       reg_irq_status,
-};
-
-#define GPIO_VAL_VALUE      0x00
-#define GPIO_IRQ_ENABLE     0x00
-#define GPIO_IRQ_TYPE0      0x04
-#define GPIO_IRQ_TYPE1      0x08
-#define GPIO_IRQ_TYPE2      0x0C
-#define GPIO_IRQ_STATUS     0x10
-
-static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
-                                    const struct aspeed_sgpio_bank *bank,
-                                    const enum aspeed_sgpio_reg reg)
-{
-       switch (reg) {
-       case reg_val:
-               return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
-       case reg_rdata:
-               return gpio->base + bank->rdata_reg;
-       case reg_irq_enable:
-               return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
-       case reg_irq_type0:
-               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
-       case reg_irq_type1:
-               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
-       case reg_irq_type2:
-               return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
-       case reg_irq_status:
-               return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
-       default:
-               /* acturally if code runs to here, it's an error case */
-               BUG_ON(1);
-       }
-}
-
-#define GPIO_BANK(x)    ((x) >> 5)
-#define GPIO_OFFSET(x)  ((x) & 0x1f)
-#define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
-
-static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
-{
-       unsigned int bank = GPIO_BANK(offset);
-
-       WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
-       return &aspeed_sgpio_banks[bank];
-}
-
-static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
-{
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       const struct aspeed_sgpio_bank *bank = to_bank(offset);
-       unsigned long flags;
-       enum aspeed_sgpio_reg reg;
-       bool is_input;
-       int rc = 0;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       reg = is_input ? reg_val : reg_rdata;
-       rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return rc;
-}
-
-static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
-{
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       const struct aspeed_sgpio_bank *bank = to_bank(offset);
-       void __iomem *addr;
-       u32 reg = 0;
-
-       addr = bank_reg(gpio, bank, reg_val);
-       reg = ioread32(addr);
-
-       if (val)
-               reg |= GPIO_BIT(offset);
-       else
-               reg &= ~GPIO_BIT(offset);
-
-       iowrite32(reg, addr);
-}
-
-static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
-{
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       sgpio_set_value(gc, offset, val);
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-}
-
-static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
-{
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return 0;
-}
-
-static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
-{
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
-       sgpio_set_value(gc, offset, val);
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return 0;
-}
-
-static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
-{
-       int dir_status;
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gpio->lock, flags);
-       dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       return dir_status;
-
-}
-
-static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
-                                       struct aspeed_sgpio **gpio,
-                                       const struct aspeed_sgpio_bank **bank,
-                                       u32 *bit, int *offset)
-{
-       struct aspeed_sgpio *internal;
-
-       *offset = irqd_to_hwirq(d);
-       internal = irq_data_get_irq_chip_data(d);
-       WARN_ON(!internal);
-
-       *gpio = internal;
-       *bank = to_bank(*offset);
-       *bit = GPIO_BIT(*offset);
-}
-
-static void aspeed_sgpio_irq_ack(struct irq_data *d)
-{
-       const struct aspeed_sgpio_bank *bank;
-       struct aspeed_sgpio *gpio;
-       unsigned long flags;
-       void __iomem *status_addr;
-       int offset;
-       u32 bit;
-
-       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
-
-       status_addr = bank_reg(gpio, bank, reg_irq_status);
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       iowrite32(bit, status_addr);
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-}
-
-static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
-{
-       const struct aspeed_sgpio_bank *bank;
-       struct aspeed_sgpio *gpio;
-       unsigned long flags;
-       u32 reg, bit;
-       void __iomem *addr;
-       int offset;
-
-       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
-       addr = bank_reg(gpio, bank, reg_irq_enable);
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       reg = ioread32(addr);
-       if (set)
-               reg |= bit;
-       else
-               reg &= ~bit;
-
-       iowrite32(reg, addr);
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-}
-
-static void aspeed_sgpio_irq_mask(struct irq_data *d)
-{
-       aspeed_sgpio_irq_set_mask(d, false);
-}
-
-static void aspeed_sgpio_irq_unmask(struct irq_data *d)
-{
-       aspeed_sgpio_irq_set_mask(d, true);
-}
-
-static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
-{
-       u32 type0 = 0;
-       u32 type1 = 0;
-       u32 type2 = 0;
-       u32 bit, reg;
-       const struct aspeed_sgpio_bank *bank;
-       irq_flow_handler_t handler;
-       struct aspeed_sgpio *gpio;
-       unsigned long flags;
-       void __iomem *addr;
-       int offset;
-
-       irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
-
-       switch (type & IRQ_TYPE_SENSE_MASK) {
-       case IRQ_TYPE_EDGE_BOTH:
-               type2 |= bit;
-               /* fall through */
-       case IRQ_TYPE_EDGE_RISING:
-               type0 |= bit;
-               /* fall through */
-       case IRQ_TYPE_EDGE_FALLING:
-               handler = handle_edge_irq;
-               break;
-       case IRQ_TYPE_LEVEL_HIGH:
-               type0 |= bit;
-               /* fall through */
-       case IRQ_TYPE_LEVEL_LOW:
-               type1 |= bit;
-               handler = handle_level_irq;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&gpio->lock, flags);
-
-       addr = bank_reg(gpio, bank, reg_irq_type0);
-       reg = ioread32(addr);
-       reg = (reg & ~bit) | type0;
-       iowrite32(reg, addr);
-
-       addr = bank_reg(gpio, bank, reg_irq_type1);
-       reg = ioread32(addr);
-       reg = (reg & ~bit) | type1;
-       iowrite32(reg, addr);
-
-       addr = bank_reg(gpio, bank, reg_irq_type2);
-       reg = ioread32(addr);
-       reg = (reg & ~bit) | type2;
-       iowrite32(reg, addr);
-
-       spin_unlock_irqrestore(&gpio->lock, flags);
-
-       irq_set_handler_locked(d, handler);
-
-       return 0;
-}
-
-static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
-{
-       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
-       struct irq_chip *ic = irq_desc_get_chip(desc);
-       struct aspeed_sgpio *data = gpiochip_get_data(gc);
-       unsigned int i, p, girq;
-       unsigned long reg;
-
-       chained_irq_enter(ic, desc);
-
-       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
-               const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
-
-               reg = ioread32(bank_reg(data, bank, reg_irq_status));
-
-               for_each_set_bit(p, &reg, 32) {
-                       girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
-                       generic_handle_irq(girq);
-               }
-
-       }
-
-       chained_irq_exit(ic, desc);
-}
-
-static struct irq_chip aspeed_sgpio_irqchip = {
-       .name       = "aspeed-sgpio",
-       .irq_ack    = aspeed_sgpio_irq_ack,
-       .irq_mask   = aspeed_sgpio_irq_mask,
-       .irq_unmask = aspeed_sgpio_irq_unmask,
-       .irq_set_type   = aspeed_sgpio_set_type,
-};
-
-static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
-                                  struct platform_device *pdev)
-{
-       int rc, i;
-       const struct aspeed_sgpio_bank *bank;
-       struct gpio_irq_chip *irq;
-
-       rc = platform_get_irq(pdev, 0);
-       if (rc < 0)
-               return rc;
-
-       gpio->irq = rc;
-
-       /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */
-       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
-               bank =  &aspeed_sgpio_banks[i];
-               /* disable irq enable bits */
-               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
-               /* clear status bits */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
-       }
-
-       irq = &gpio->chip.irq;
-       irq->chip = &aspeed_sgpio_irqchip;
-       irq->handler = handle_bad_irq;
-       irq->default_type = IRQ_TYPE_NONE;
-       irq->parent_handler = aspeed_sgpio_irq_handler;
-       irq->parent_handler_data = gpio;
-       irq->parents = &gpio->irq;
-       irq->num_parents = 1;
-
-       /* set IRQ settings and Enable Interrupt */
-       for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
-               bank = &aspeed_sgpio_banks[i];
-               /* set falling or level-low irq */
-               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
-               /* trigger type is edge */
-               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
-               /* dual edge trigger mode. */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
-               /* enable irq */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
-       }
-
-       return 0;
-}
-
-static const struct of_device_id aspeed_sgpio_of_table[] = {
-       { .compatible = "aspeed,ast2400-sgpio" },
-       { .compatible = "aspeed,ast2500-sgpio" },
-       {}
-};
-
-MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
-
-static int __init aspeed_sgpio_probe(struct platform_device *pdev)
-{
-       struct aspeed_sgpio *gpio;
-       u32 nr_gpios, sgpio_freq, sgpio_clk_div;
-       int rc;
-       unsigned long apb_freq;
-
-       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
-       if (!gpio)
-               return -ENOMEM;
-
-       gpio->base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(gpio->base))
-               return PTR_ERR(gpio->base);
-
-       rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
-       if (rc < 0) {
-               dev_err(&pdev->dev, "Could not read ngpios property\n");
-               return -EINVAL;
-       } else if (nr_gpios > MAX_NR_SGPIO) {
-               dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
-                       MAX_NR_SGPIO, nr_gpios);
-               return -EINVAL;
-       }
-
-       rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
-       if (rc < 0) {
-               dev_err(&pdev->dev, "Could not read bus-frequency property\n");
-               return -EINVAL;
-       }
-
-       gpio->pclk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(gpio->pclk)) {
-               dev_err(&pdev->dev, "devm_clk_get failed\n");
-               return PTR_ERR(gpio->pclk);
-       }
-
-       apb_freq = clk_get_rate(gpio->pclk);
-
-       /*
-        * From the datasheet,
-        *      SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
-        *      period = 2 * (GPIO254[31:16] + 1) / PCLK
-        *      frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
-        *      frequency = PCLK / (2 * (GPIO254[31:16] + 1))
-        *      frequency * 2 * (GPIO254[31:16] + 1) = PCLK
-        *      GPIO254[31:16] = PCLK / (frequency * 2) - 1
-        */
-       if (sgpio_freq == 0)
-               return -EINVAL;
-
-       sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
-
-       if (sgpio_clk_div > (1 << 16) - 1)
-               return -EINVAL;
-
-       iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
-                 FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
-                 ASPEED_SGPIO_ENABLE,
-                 gpio->base + ASPEED_SGPIO_CTRL);
-
-       spin_lock_init(&gpio->lock);
-
-       gpio->chip.parent = &pdev->dev;
-       gpio->chip.ngpio = nr_gpios;
-       gpio->chip.direction_input = aspeed_sgpio_dir_in;
-       gpio->chip.direction_output = aspeed_sgpio_dir_out;
-       gpio->chip.get_direction = aspeed_sgpio_get_direction;
-       gpio->chip.request = NULL;
-       gpio->chip.free = NULL;
-       gpio->chip.get = aspeed_sgpio_get;
-       gpio->chip.set = aspeed_sgpio_set;
-       gpio->chip.set_config = NULL;
-       gpio->chip.label = dev_name(&pdev->dev);
-       gpio->chip.base = -1;
-
-       /* set all SGPIO pins as input (1). */
-       memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
-
-       aspeed_sgpio_setup_irqs(gpio, pdev);
-
-       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-static struct platform_driver aspeed_sgpio_driver = {
-       .driver = {
-               .name = KBUILD_MODNAME,
-               .of_match_table = aspeed_sgpio_of_table,
-       },
-};
-
-module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
-MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
-MODULE_LICENSE("GPL");
index b70af92..5215fdb 100644 (file)
@@ -176,11 +176,15 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         const char *propname, int index,
                                         enum gpiod_flags dflags,
                                         const char *label);
-struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
-                                               const char *con_id, int index,
-                                               struct fwnode_handle *child,
-                                               enum gpiod_flags flags,
-                                               const char *label);
+struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
+                                        const char *con_id, int index,
+                                        enum gpiod_flags flags,
+                                        const char *label);
+struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
+                                             struct fwnode_handle *child,
+                                             const char *con_id, int index,
+                                             enum gpiod_flags flags,
+                                             const char *label);
 
 #else /* CONFIG_GPIOLIB */
 
@@ -531,6 +535,38 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
        return ERR_PTR(-ENOSYS);
 }
 
+static inline
+struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
+                                        const char *con_id, int index,
+                                        enum gpiod_flags flags,
+                                        const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
+                                             struct fwnode_handle *fwnode,
+                                             const char *con_id, int index,
+                                             enum gpiod_flags flags,
+                                             const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+static inline
+struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
+                                       struct fwnode_handle *fwnode,
+                                       const char *con_id,
+                                       enum gpiod_flags flags,
+                                       const char *label)
+{
+       return devm_fwnode_gpiod_get_index(dev, fwnode, con_id, 0,
+                                          flags, label);
+}
+
 static inline
 struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
                                                const char *con_id, int index,
@@ -538,11 +574,10 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
                                                enum gpiod_flags flags,
                                                const char *label)
 {
-       return ERR_PTR(-ENOSYS);
+       return devm_fwnode_gpiod_get_index(dev, child, con_id, index,
+                                          flags, label);
 }
 
-#endif /* CONFIG_GPIOLIB */
-
 static inline
 struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
                                                   const char *con_id,
@@ -550,8 +585,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
                                                   enum gpiod_flags flags,
                                                   const char *label)
 {
-       return devm_fwnode_get_index_gpiod_from_child(dev, con_id, 0, child,
-                                                     flags, label);
+       return devm_fwnode_gpiod_get_index(dev, child, con_id, 0, flags, label);
 }
 
 #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
index 4ebfe0a..c2d1f7d 100644 (file)
@@ -33,6 +33,8 @@ struct gpiochip_info {
 #define GPIOLINE_FLAG_ACTIVE_LOW       (1UL << 2)
 #define GPIOLINE_FLAG_OPEN_DRAIN       (1UL << 3)
 #define GPIOLINE_FLAG_OPEN_SOURCE      (1UL << 4)
+#define GPIOLINE_FLAG_PULL_UP  (1UL << 5)
+#define GPIOLINE_FLAG_PULL_DOWN        (1UL << 6)
 
 /**
  * struct gpioline_info - Information about a certain GPIO line
@@ -62,6 +64,8 @@ struct gpioline_info {
 #define GPIOHANDLE_REQUEST_ACTIVE_LOW  (1UL << 2)
 #define GPIOHANDLE_REQUEST_OPEN_DRAIN  (1UL << 3)
 #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
+#define GPIOHANDLE_REQUEST_PULL_UP     (1UL << 5)
+#define GPIOHANDLE_REQUEST_PULL_DOWN   (1UL << 6)
 
 /**
  * struct gpiohandle_request - Information about a GPIO handle request