Merge tag 'v5.3-rc7' into devel
authorLinus Walleij <linus.walleij@linaro.org>
Thu, 5 Sep 2019 09:40:54 +0000 (11:40 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Thu, 5 Sep 2019 09:40:54 +0000 (11:40 +0200)
Linux 5.3-rc7

62 files changed:
Documentation/devicetree/bindings/gpio/gpio-davinci.txt
Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt [new file with mode: 0644]
Documentation/driver-api/gpio/driver.rst
MAINTAINERS
arch/arm/configs/lpc32xx_defconfig
arch/unicore32/kernel/irq.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-arizona.c
drivers/gpio/gpio-aspeed.c
drivers/gpio/gpio-bd70528.c
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-cadence.c
drivers/gpio/gpio-dwapb.c
drivers/gpio/gpio-eic-sprd.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-ep93xx.c
drivers/gpio/gpio-ftgpio010.c
drivers/gpio/gpio-grgpio.c
drivers/gpio/gpio-hlwd.c
drivers/gpio/gpio-ixp4xx.c
drivers/gpio/gpio-ks8695.c [deleted file]
drivers/gpio/gpio-lpc32xx.c
drivers/gpio/gpio-madera.c
drivers/gpio/gpio-max77620.c
drivers/gpio/gpio-max77650.c
drivers/gpio/gpio-mb86s7x.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pmic-eic-sprd.c
drivers/gpio/gpio-sprd.c
drivers/gpio/gpio-tb10x.c
drivers/gpio/gpio-tegra.c
drivers/gpio/gpio-thunderx.c
drivers/gpio/gpio-tqmx86.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpio-viperboard.c
drivers/gpio/gpio-xgene-sb.c
drivers/gpio/gpio-xlp.c
drivers/gpio/gpio-zx.c
drivers/gpio/gpio-zynq.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib-acpi.h [new file with mode: 0644]
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-of.h [new file with mode: 0644]
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpio/sgpio-aspeed.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-stmfx.c
drivers/pinctrl/qcom/Kconfig
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
include/linux/acpi.h
include/linux/gpio.h
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
sound/soc/intel/boards/bytcht_cx2072x.c
sound/soc/intel/boards/cht_bsw_max98090_ti.c
sound/soc/intel/boards/cht_bsw_rt5672.c

index bc6b4b6..cd91d61 100644 (file)
@@ -6,6 +6,7 @@ Required Properties:
                                                66AK2E SoCs
                        "ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G
                        "ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654
+                       "ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs
 
 - reg: Physical base address of the controller and the size of memory mapped
        registers.
index 69d4616..cd28e93 100644 (file)
@@ -4,7 +4,7 @@ Required properties:
 - compatible : Should be "fsl,<soc>-gpio"
   The following <soc>s are known to be supported:
        mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq,
-       ls1021a, ls1043a, ls2080a.
+       ls1021a, ls1043a, ls2080a, ls1028a, ls1088a.
 - reg : Address and length of the register set for the device
 - interrupts : Should be the port interrupt shared by all 32 pins.
 - #gpio-cells : Should be two.  The first cell is the pin number and
@@ -37,3 +37,17 @@ gpio0: gpio@2300000 {
        interrupt-controller;
        #interrupt-cells = <2>;
 };
+
+
+Example of gpio-controller node for a ls1028a/ls1088a SoC:
+
+gpio1: gpio@2300000 {
+       compatible = "fsl,ls1028a-gpio", "fsl,ls1088a-gpio", "fsl,qoriq-gpio";
+       reg = <0x0 0x2300000 0x0 0x10000>;
+       interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+       gpio-controller;
+       #gpio-cells = <2>;
+       interrupt-controller;
+       #interrupt-cells = <2>;
+       little-endian;
+};
diff --git a/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt b/Documentation/devicetree/bindings/gpio/sgpio-aspeed.txt
new file mode 100644 (file)
index 0000000..d4d8391
--- /dev/null
@@ -0,0 +1,45 @@
+Aspeed SGPIO controller Device Tree Bindings
+--------------------------------------------
+
+This SGPIO controller is for ASPEED AST2500 SoC, it supports up to 80 full
+featured Serial GPIOs. Each of the Serial GPIO pins can be programmed to
+support the following options:
+- Support interrupt option for each input port and various interrupt
+  sensitivity option (level-high, level-low, edge-high, edge-low)
+- Support reset tolerance option for each output port
+- Directly connected to APB bus and its shift clock is from APB bus clock
+  divided by a programmable value.
+- Co-work with external signal-chained TTL components (74LV165/74LV595)
+
+Required properties:
+
+- compatible : Should be one of
+  "aspeed,ast2400-sgpio", "aspeed,ast2500-sgpio"
+- #gpio-cells : Should be 2, see gpio.txt
+- reg : Address and length of the register set for the device
+- gpio-controller : Marks the device node as a GPIO controller
+- interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
+- interrupt-controller : Mark the GPIO controller as an interrupt-controller
+- ngpios : number of GPIO lines, see gpio.txt
+  (should be multiple of 8, up to 80 pins)
+- clocks : A phandle to the APB clock for SGPM clock division
+- bus-frequency : SGPM CLK frequency
+
+The sgpio and interrupt properties are further described in their respective
+bindings documentation:
+
+- Documentation/devicetree/bindings/gpio/gpio.txt
+- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+  Example:
+       sgpio: sgpio@1e780200 {
+               #gpio-cells = <2>;
+               compatible = "aspeed,ast2500-sgpio";
+               gpio-controller;
+               interrupts = <40>;
+               reg = <0x1e780200 0x0100>;
+               clocks = <&syscon ASPEED_CLK_APB>;
+               interrupt-controller;
+               ngpios = <8>;
+               bus-frequency = <12000000>;
+       };
index 921c71a..3fdb324 100644 (file)
@@ -69,9 +69,9 @@ driver code:
 
 The code implementing a gpio_chip should support multiple instances of the
 controller, preferably using the driver model. That code will configure each
-gpio_chip and issue ``gpiochip_add[_data]()`` or ``devm_gpiochip_add_data()``.
-Removing a GPIO controller should be rare; use ``[devm_]gpiochip_remove()``
-when it is unavoidable.
+gpio_chip and issue gpiochip_add(), gpiochip_add_data(), or
+devm_gpiochip_add_data().  Removing a GPIO controller should be rare; use
+gpiochip_remove() when it is unavoidable.
 
 Often a gpio_chip is part of an instance-specific structure with states not
 exposed by the GPIO interfaces, such as addressing, power management, and more.
@@ -259,7 +259,7 @@ most often cascaded off a parent interrupt controller, and in some special
 cases the GPIO logic is melded with a SoC's primary interrupt controller.
 
 The IRQ portions of the GPIO block are implemented using an irq_chip, using
-the header <linux/irq.h>. So basically such a driver is utilizing two sub-
+the header <linux/irq.h>. So this combined driver is utilizing two sub-
 systems simultaneously: gpio and irq.
 
 It is legal for any IRQ consumer to request an IRQ from any irqchip even if it
@@ -391,25 +391,119 @@ Infrastructure helpers for GPIO irqchips
 ----------------------------------------
 
 To help out in handling the set-up and management of GPIO irqchips and the
-associated irqdomain and resource allocation callbacks, the gpiolib has
-some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
-symbol:
-
-- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It
-  will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
-  callbacks need to embed the gpio_chip in its state container and obtain a
-  pointer to the container using container_of().
-  (See Documentation/driver-api/driver-model/design-patterns.rst)
+associated irqdomain and resource allocation callbacks. These are activated
+by selecting the Kconfig symbol GPIOLIB_IRQCHIP. If the symbol
+IRQ_DOMAIN_HIERARCHY is also selected, hierarchical helpers will also be
+provided. A big portion of overhead code will be managed by gpiolib,
+under the assumption that your interrupts are 1-to-1-mapped to the
+GPIO line index:
+
+  GPIO line offset   Hardware IRQ
+  0                  0
+  1                  1
+  2                  2
+  ...                ...
+  ngpio-1            ngpio-1
+
+If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask
+and the flag need_valid_mask in gpio_irq_chip can be used to mask off some
+lines as invalid for associating with IRQs.
+
+The preferred way to set up the helpers is to fill in the
+struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
+If you do this, the additional irq_chip will be set up by gpiolib at the
+same time as setting up the rest of the GPIO functionality. The following
+is a typical example of a cascaded interrupt handler using gpio_irq_chip:
+
+  /* Typical state container with dynamic irqchip */
+  struct my_gpio {
+      struct gpio_chip gc;
+      struct irq_chip irq;
+  };
+
+  int irq; /* from platform etc */
+  struct my_gpio *g;
+  struct gpio_irq_chip *girq;
+
+  /* Set up the irqchip dynamically */
+  g->irq.name = "my_gpio_irq";
+  g->irq.irq_ack = my_gpio_ack_irq;
+  g->irq.irq_mask = my_gpio_mask_irq;
+  g->irq.irq_unmask = my_gpio_unmask_irq;
+  g->irq.irq_set_type = my_gpio_set_irq_type;
+
+  /* Get a pointer to the gpio_irq_chip */
+  girq = &g->gc.irq;
+  girq->chip = &g->irq;
+  girq->parent_handler = ftgpio_gpio_irq_handler;
+  girq->num_parents = 1;
+  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
+                               GFP_KERNEL);
+  if (!girq->parents)
+      return -ENOMEM;
+  girq->default_type = IRQ_TYPE_NONE;
+  girq->handler = handle_bad_irq;
+  girq->parents[0] = irq;
+
+  return devm_gpiochip_add_data(dev, &g->gc, g);
+
+The helper support using hierarchical interrupt controllers as well.
+In this case the typical set-up will look like this:
+
+  /* Typical state container with dynamic irqchip */
+  struct my_gpio {
+      struct gpio_chip gc;
+      struct irq_chip irq;
+      struct fwnode_handle *fwnode;
+  };
+
+  int irq; /* from platform etc */
+  struct my_gpio *g;
+  struct gpio_irq_chip *girq;
+
+  /* Set up the irqchip dynamically */
+  g->irq.name = "my_gpio_irq";
+  g->irq.irq_ack = my_gpio_ack_irq;
+  g->irq.irq_mask = my_gpio_mask_irq;
+  g->irq.irq_unmask = my_gpio_unmask_irq;
+  g->irq.irq_set_type = my_gpio_set_irq_type;
+
+  /* Get a pointer to the gpio_irq_chip */
+  girq = &g->gc.irq;
+  girq->chip = &g->irq;
+  girq->default_type = IRQ_TYPE_NONE;
+  girq->handler = handle_bad_irq;
+  girq->fwnode = g->fwnode;
+  girq->parent_domain = parent;
+  girq->child_to_parent_hwirq = my_gpio_child_to_parent_hwirq;
+
+  return devm_gpiochip_add_data(dev, &g->gc, g);
+
+As you can see pretty similar, but you do not supply a parent handler for
+the IRQ, instead a parent irqdomain, an fwnode for the hardware and
+a funcion .child_to_parent_hwirq() that has the purpose of looking up
+the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
+As always it is good to look at examples in the kernel tree for advice
+on how to find the required pieces.
+
+The old way of adding irqchips to gpiochips after registration is also still
+available but we try to move away from this:
+
+- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
+  gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ
+  callbacks, so the callbacks need to embed the gpio_chip in its state
+  container and obtain a pointer to the container using container_of().
+  (See Documentation/driver-model/design-patterns.txt)
 
 - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
   as discussed above regarding different types of cascaded irqchips. The
   cascaded irq has to be handled by a threaded interrupt handler.
   Apart from that it works exactly like the chained irqchip.
 
-- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a
-  gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
-  data. Notice that we pass is as the handler data, since the irqchip data is
-  likely used by the parent irqchip.
+- DEPRECATED: gpiochip_set_chained_irqchip(): sets up a chained cascaded irq
+  handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip*
+  as handler data. Notice that we pass is as the handler data, since the
+  irqchip data is likely used by the parent irqchip.
 
 - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
   gpio_chip from a parent IRQ. As the parent IRQ has usually been
@@ -418,11 +512,11 @@ symbol:
 
 If there is a need to exclude certain GPIO lines from the IRQ domain handled by
 these helpers, we can set .irq.need_valid_mask of the gpiochip before
-``[devm_]gpiochip_add_data()`` is called. This allocates an .irq.valid_mask with as
-many bits set as there are GPIO lines in the chip, each bit representing line
-0..n-1. Drivers can exclude GPIO lines by clearing bits from this mask. The mask
-must be filled in before gpiochip_irqchip_add() or gpiochip_irqchip_add_nested()
-is called.
+devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an
+.irq.valid_mask with as many bits set as there are GPIO lines in the chip, each
+bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits
+from this mask. The mask must be filled in before gpiochip_irqchip_add() or
+gpiochip_irqchip_add_nested() is called.
 
 To use the helpers please keep the following in mind:
 
index e7a47b5..9143240 100644 (file)
@@ -6331,15 +6331,6 @@ S:       Odd Fixes
 L:     linux-block@vger.kernel.org
 F:     drivers/block/floppy.c
 
-FMC SUBSYSTEM
-M:     Alessandro Rubini <rubini@gnudd.com>
-W:     http://www.ohwr.org/projects/fmc-bus
-S:     Supported
-F:     drivers/fmc/
-F:     include/linux/fmc*.h
-F:     include/linux/ipmi-fru.h
-K:     fmc_d.*register
-
 FPGA MANAGER FRAMEWORK
 M:     Moritz Fischer <mdf@kernel.org>
 L:     linux-fpga@vger.kernel.org
index 0cdc6c7..3772d5a 100644 (file)
@@ -93,6 +93,7 @@ CONFIG_SERIAL_HS_LPC32XX_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_PNX=y
+CONFIG_GPIO_LPC32XX=y
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_SYSFS=y
index d112982..c014ae3 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/kallsyms.h>
 #include <linux/proc_fs.h>
 #include <linux/syscore_ops.h>
-#include <linux/gpio.h>
 
 #include <mach/hardware.h>
 
index bb13c26..e193c76 100644 (file)
@@ -288,7 +288,7 @@ config GPIO_IXP4XX
        depends on ARM # For <asm/mach-types.h>
        depends on ARCH_IXP4XX
        select GPIO_GENERIC
-       select IRQ_DOMAIN
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        help
          Say yes here to support the GPIO functionality of a number of Intel
@@ -311,6 +311,13 @@ config GPIO_LPC18XX
          Select this option to enable GPIO driver for
          NXP LPC18XX/43XX devices.
 
+config GPIO_LPC32XX
+       tristate "NXP LPC32XX GPIO support"
+       depends on OF_GPIO && (ARCH_LPC32XX || COMPILE_TEST)
+       help
+         Select this option to enable GPIO driver for
+         NXP LPC32XX devices.
+
 config GPIO_LYNXPOINT
        tristate "Intel Lynxpoint GPIO support"
        depends on ACPI && X86
@@ -539,6 +546,7 @@ config GPIO_THUNDERX
        tristate "Cavium ThunderX/OCTEON-TX GPIO"
        depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
        depends on PCI_MSI
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        select IRQ_FASTEOI_HIERARCHY_HANDLERS
        help
@@ -1465,7 +1473,6 @@ endmenu
 
 config GPIO_MOCKUP
        tristate "GPIO Testing Driver"
-       depends on GPIOLIB
        select IRQ_SIM
        help
          This enables GPIO Testing driver, which provides a way to test GPIO
index a4e9117..f3e051f 100644 (file)
@@ -67,14 +67,13 @@ obj-$(CONFIG_GPIO_IT87)                     += gpio-it87.o
 obj-$(CONFIG_GPIO_IXP4XX)              += gpio-ixp4xx.o
 obj-$(CONFIG_GPIO_JANZ_TTL)            += gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)              += gpio-kempld.o
-obj-$(CONFIG_ARCH_KS8695)              += gpio-ks8695.o
 obj-$(CONFIG_GPIO_LOONGSON1)           += gpio-loongson1.o
 obj-$(CONFIG_GPIO_LOONGSON)            += gpio-loongson.o
 obj-$(CONFIG_GPIO_LP3943)              += gpio-lp3943.o
 obj-$(CONFIG_GPIO_LP873X)              += gpio-lp873x.o
 obj-$(CONFIG_GPIO_LP87565)             += gpio-lp87565.o
 obj-$(CONFIG_GPIO_LPC18XX)             += gpio-lpc18xx.o
-obj-$(CONFIG_ARCH_LPC32XX)             += gpio-lpc32xx.o
+obj-$(CONFIG_GPIO_LPC32XX)             += gpio-lpc32xx.o
 obj-$(CONFIG_GPIO_LYNXPOINT)           += gpio-lynxpoint.o
 obj-$(CONFIG_GPIO_MADERA)              += gpio-madera.o
 obj-$(CONFIG_GPIO_MAX3191X)            += gpio-max3191x.o
index c07fad9..5640efe 100644 (file)
@@ -142,7 +142,7 @@ static const struct gpio_chip template_chip = {
 static int arizona_gpio_probe(struct platform_device *pdev)
 {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
-       struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
+       struct arizona_pdata *pdata = &arizona->pdata;
        struct arizona_gpio *arizona_gpio;
        int ret;
 
@@ -177,7 +177,7 @@ static int arizona_gpio_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                arizona_gpio->gpio_chip.base = pdata->gpio_base;
        else
                arizona_gpio->gpio_chip.base = -1;
index 13d80bf..9defe25 100644 (file)
@@ -711,32 +711,6 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
        }
 }
 
-static int aspeed_gpio_setup_irqs(struct aspeed_gpio *gpio,
-               struct platform_device *pdev)
-{
-       int rc;
-
-       rc = platform_get_irq(pdev, 0);
-       if (rc < 0)
-               return rc;
-
-       gpio->irq = rc;
-
-       set_irq_valid_mask(gpio);
-
-       rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_gpio_irqchip,
-                       0, handle_bad_irq, IRQ_TYPE_NONE);
-       if (rc) {
-               dev_info(&pdev->dev, "Could not add irqchip\n");
-               return rc;
-       }
-
-       gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_gpio_irqchip,
-                                    gpio->irq, aspeed_gpio_irq_handler);
-
-       return 0;
-}
-
 static int aspeed_gpio_reset_tolerance(struct gpio_chip *chip,
                                        unsigned int offset, bool enable)
 {
@@ -1189,7 +1163,6 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
        gpio->chip.set_config = aspeed_gpio_set_config;
        gpio->chip.label = dev_name(&pdev->dev);
        gpio->chip.base = -1;
-       gpio->chip.irq.need_valid_mask = true;
 
        /* Allocate a cache of the output registers */
        banks = gpio->config->nr_gpios >> 5;
@@ -1212,16 +1185,41 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
                aspeed_gpio_change_cmd_source(gpio, bank, 3, GPIO_CMDSRC_ARM);
        }
 
-       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
-       if (rc < 0)
-               return rc;
+       /* Optionally set up an irqchip if there is an IRQ */
+       rc = platform_get_irq(pdev, 0);
+       if (rc > 0) {
+               struct gpio_irq_chip *girq;
+
+               gpio->irq = rc;
+               girq = &gpio->chip.irq;
+               girq->chip = &aspeed_gpio_irqchip;
+               girq->parent_handler = aspeed_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = gpio->irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_bad_irq;
+               girq->need_valid_mask = true;
+       }
 
        gpio->offset_timer =
                devm_kzalloc(&pdev->dev, gpio->chip.ngpio, GFP_KERNEL);
        if (!gpio->offset_timer)
                return -ENOMEM;
 
-       return aspeed_gpio_setup_irqs(gpio, pdev);
+       rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
+       if (rc < 0)
+               return rc;
+
+       /* Now the valid mask is allocated */
+       if (gpio->irq)
+               set_irq_valid_mask(gpio);
+
+       return 0;
 }
 
 static struct platform_driver aspeed_gpio_driver = {
index fd85605..0c1ead1 100644 (file)
@@ -36,7 +36,7 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio,
                break;
        default:
                dev_err(bdgpio->chip.dev,
-                       "Invalid debouce value %u\n", debounce);
+                       "Invalid debounce value %u\n", debounce);
                return -EINVAL;
        }
        return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset),
@@ -153,7 +153,7 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset)
 
 static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset)
 {
-       int ret = -EINVAL;
+       int ret;
        struct bd70528_gpio *bdgpio = gpiochip_get_data(chip);
 
        /*
index af936dc..05e3f99 100644 (file)
@@ -636,10 +636,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
 
        if (of_property_read_bool(np, "interrupt-controller")) {
                priv->parent_irq = platform_get_irq(pdev, 0);
-               if (priv->parent_irq <= 0) {
-                       dev_err(dev, "Couldn't get IRQ");
+               if (priv->parent_irq <= 0)
                        return -ENOENT;
-               }
        } else {
                priv->parent_irq = -ENOENT;
        }
index 712ae21..a4d3239 100644 (file)
@@ -214,27 +214,33 @@ static int cdns_gpio_probe(struct platform_device *pdev)
                goto err_revert_dir;
        }
 
-       ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
-               goto err_disable_clk;
-       }
-
        /*
-        * irq_chip support
+        * Optional irq_chip support
         */
        irq = platform_get_irq(pdev, 0);
        if (irq >= 0) {
-               ret = gpiochip_irqchip_add(&cgpio->gc, &cdns_gpio_irqchip,
-                                          0, handle_level_irq,
-                                          IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(&pdev->dev, "Could not add irqchip, %d\n",
-                               ret);
+               struct gpio_irq_chip *girq;
+
+               girq = &cgpio->gc.irq;
+               girq->chip = &cdns_gpio_irqchip;
+               girq->parent_handler = cdns_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents) {
+                       ret = -ENOMEM;
                        goto err_disable_clk;
                }
-               gpiochip_set_chained_irqchip(&cgpio->gc, &cdns_gpio_irqchip,
-                                            irq, cdns_gpio_irq_handler);
+               girq->parents[0] = irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+       }
+
+       ret = devm_gpiochip_add_data(&pdev->dev, &cgpio->gc, cgpio);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
+               goto err_disable_clk;
        }
 
        cgpio->bypass_orig = ioread32(cgpio->regs + CDNS_GPIO_BYPASS_MODE);
index 3108be5..92e127e 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 #define GPIO_SWPORTA_DR                0x00
 #define GPIO_SWPORTA_DDR       0x04
index 7b9ac4a..fe7a73f 100644 (file)
@@ -584,10 +584,8 @@ static int sprd_eic_probe(struct platform_device *pdev)
        sprd_eic->type = pdata->type;
 
        sprd_eic->irq = platform_get_irq(pdev, 0);
-       if (sprd_eic->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get EIC interrupt.\n");
+       if (sprd_eic->irq < 0)
                return sprd_eic->irq;
-       }
 
        for (i = 0; i < SPRD_EIC_MAX_BANK; i++) {
                /*
index a879512..620f25b 100644 (file)
@@ -272,11 +272,12 @@ static int em_gio_probe(struct platform_device *pdev)
        struct resource *io[2], *irq[2];
        struct gpio_chip *gpio_chip;
        struct irq_chip *irq_chip;
-       const char *name = dev_name(&pdev->dev);
+       struct device *dev = &pdev->dev;
+       const char *name = dev_name(dev);
        unsigned int ngpios;
        int ret;
 
-       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+       p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
        if (!p)
                return -ENOMEM;
 
@@ -290,27 +291,27 @@ static int em_gio_probe(struct platform_device *pdev)
        irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
 
        if (!io[0] || !io[1] || !irq[0] || !irq[1]) {
-               dev_err(&pdev->dev, "missing IRQ or IOMEM\n");
+               dev_err(dev, "missing IRQ or IOMEM\n");
                return -EINVAL;
        }
 
-       p->base0 = devm_ioremap_nocache(&pdev->dev, io[0]->start,
+       p->base0 = devm_ioremap_nocache(dev, io[0]->start,
                                        resource_size(io[0]));
        if (!p->base0)
                return -ENOMEM;
 
-       p->base1 = devm_ioremap_nocache(&pdev->dev, io[1]->start,
+       p->base1 = devm_ioremap_nocache(dev, io[1]->start,
                                   resource_size(io[1]));
        if (!p->base1)
                return -ENOMEM;
 
-       if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
-               dev_err(&pdev->dev, "Missing ngpios OF property\n");
+       if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
+               dev_err(dev, "Missing ngpios OF property\n");
                return -EINVAL;
        }
 
        gpio_chip = &p->gpio_chip;
-       gpio_chip->of_node = pdev->dev.of_node;
+       gpio_chip->of_node = dev->of_node;
        gpio_chip->direction_input = em_gio_direction_input;
        gpio_chip->get = em_gio_get;
        gpio_chip->direction_output = em_gio_direction_output;
@@ -319,7 +320,7 @@ static int em_gio_probe(struct platform_device *pdev)
        gpio_chip->request = em_gio_request;
        gpio_chip->free = em_gio_free;
        gpio_chip->label = name;
-       gpio_chip->parent = &pdev->dev;
+       gpio_chip->parent = dev;
        gpio_chip->owner = THIS_MODULE;
        gpio_chip->base = -1;
        gpio_chip->ngpio = ngpios;
@@ -333,33 +334,33 @@ static int em_gio_probe(struct platform_device *pdev)
        irq_chip->irq_release_resources = em_gio_irq_relres;
        irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND;
 
-       p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0,
+       p->irq_domain = irq_domain_add_simple(dev->of_node, ngpios, 0,
                                              &em_gio_irq_domain_ops, p);
        if (!p->irq_domain) {
-               dev_err(&pdev->dev, "cannot initialize irq domain\n");
+               dev_err(dev, "cannot initialize irq domain\n");
                return -ENXIO;
        }
 
-       ret = devm_add_action_or_reset(&pdev->dev, em_gio_irq_domain_remove,
+       ret = devm_add_action_or_reset(dev, em_gio_irq_domain_remove,
                                       p->irq_domain);
        if (ret)
                return ret;
 
-       if (devm_request_irq(&pdev->dev, irq[0]->start,
+       if (devm_request_irq(dev, irq[0]->start,
                             em_gio_irq_handler, 0, name, p)) {
-               dev_err(&pdev->dev, "failed to request low IRQ\n");
+               dev_err(dev, "failed to request low IRQ\n");
                return -ENOENT;
        }
 
-       if (devm_request_irq(&pdev->dev, irq[1]->start,
+       if (devm_request_irq(dev, irq[1]->start,
                             em_gio_irq_handler, 0, name, p)) {
-               dev_err(&pdev->dev, "failed to request high IRQ\n");
+               dev_err(dev, "failed to request high IRQ\n");
                return -ENOENT;
        }
 
-       ret = devm_gpiochip_add_data(&pdev->dev, gpio_chip, p);
+       ret = devm_gpiochip_add_data(dev, gpio_chip, p);
        if (ret) {
-               dev_err(&pdev->dev, "failed to add GPIO controller\n");
+               dev_err(dev, "failed to add GPIO controller\n");
                return ret;
        }
 
index a90870a..226da8d 100644 (file)
@@ -269,56 +269,6 @@ static struct irq_chip ep93xx_gpio_irq_chip = {
        .irq_set_type   = ep93xx_gpio_irq_type,
 };
 
-static int ep93xx_gpio_init_irq(struct platform_device *pdev,
-                               struct ep93xx_gpio *epg)
-{
-       int ab_parent_irq = platform_get_irq(pdev, 0);
-       struct device *dev = &pdev->dev;
-       int gpio_irq;
-       int ret;
-       int i;
-
-       /* The A bank */
-       ret = gpiochip_irqchip_add(&epg->gc[0], &ep93xx_gpio_irq_chip,
-                                   64, handle_level_irq,
-                                   IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "Could not add irqchip 0\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(&epg->gc[0], &ep93xx_gpio_irq_chip,
-                                    ab_parent_irq,
-                                    ep93xx_gpio_ab_irq_handler);
-
-       /* The B bank */
-       ret = gpiochip_irqchip_add(&epg->gc[1], &ep93xx_gpio_irq_chip,
-                                   72, handle_level_irq,
-                                   IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "Could not add irqchip 1\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(&epg->gc[1], &ep93xx_gpio_irq_chip,
-                                    ab_parent_irq,
-                                    ep93xx_gpio_ab_irq_handler);
-
-       /* The F bank */
-       for (i = 0; i < 8; i++) {
-               gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
-               irq_set_chip_data(gpio_irq, &epg->gc[5]);
-               irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip,
-                                        handle_level_irq);
-               irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
-       }
-
-       for (i = 1; i <= 8; i++)
-               irq_set_chained_handler_and_data(platform_get_irq(pdev, i),
-                                                ep93xx_gpio_f_irq_handler,
-                                                &epg->gc[i]);
-       return 0;
-}
-
-
 /*************************************************************************
  * gpiolib interface for EP93xx on-chip GPIOs
  *************************************************************************/
@@ -328,26 +278,33 @@ struct ep93xx_gpio_bank {
        int             dir;
        int             base;
        bool            has_irq;
+       bool            has_hierarchical_irq;
+       unsigned int    irq_base;
 };
 
-#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq) \
+#define EP93XX_GPIO_BANK(_label, _data, _dir, _base, _has_irq, _has_hier, _irq_base) \
        {                                                       \
                .label          = _label,                       \
                .data           = _data,                        \
                .dir            = _dir,                         \
                .base           = _base,                        \
                .has_irq        = _has_irq,                     \
+               .has_hierarchical_irq = _has_hier,              \
+               .irq_base       = _irq_base,                    \
        }
 
 static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
-       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true), /* Bank A has 8 IRQs */
-       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true), /* Bank B has 8 IRQs */
-       EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false),
-       EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false),
-       EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false),
-       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, true), /* Bank F has 8 IRQs */
-       EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false),
-       EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false),
+       /* Bank A has 8 IRQs */
+       EP93XX_GPIO_BANK("A", 0x00, 0x10, 0, true, false, 64),
+       /* Bank B has 8 IRQs */
+       EP93XX_GPIO_BANK("B", 0x04, 0x14, 8, true, false, 72),
+       EP93XX_GPIO_BANK("C", 0x08, 0x18, 40, false, false, 0),
+       EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 24, false, false, 0),
+       EP93XX_GPIO_BANK("E", 0x20, 0x24, 32, false, false, 0),
+       /* Bank F has 8 IRQs */
+       EP93XX_GPIO_BANK("F", 0x30, 0x34, 16, false, true, 0),
+       EP93XX_GPIO_BANK("G", 0x38, 0x3c, 48, false, false, 0),
+       EP93XX_GPIO_BANK("H", 0x40, 0x44, 56, false, false, 0),
 };
 
 static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
@@ -369,12 +326,15 @@ static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset)
        return EP93XX_GPIO_F_IRQ_BASE + offset;
 }
 
-static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
+static int ep93xx_gpio_add_bank(struct gpio_chip *gc,
+                               struct platform_device *pdev,
                                struct ep93xx_gpio *epg,
                                struct ep93xx_gpio_bank *bank)
 {
        void __iomem *data = epg->base + bank->data;
        void __iomem *dir = epg->base + bank->dir;
+       struct device *dev = &pdev->dev;
+       struct gpio_irq_chip *girq;
        int err;
 
        err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
@@ -384,8 +344,59 @@ static int ep93xx_gpio_add_bank(struct gpio_chip *gc, struct device *dev,
        gc->label = bank->label;
        gc->base = bank->base;
 
-       if (bank->has_irq)
+       girq = &gc->irq;
+       if (bank->has_irq || bank->has_hierarchical_irq) {
                gc->set_config = ep93xx_gpio_set_config;
+               girq->chip = &ep93xx_gpio_irq_chip;
+       }
+
+       if (bank->has_irq) {
+               int ab_parent_irq = platform_get_irq(pdev, 0);
+
+               girq->parent_handler = ep93xx_gpio_ab_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+               girq->parents[0] = ab_parent_irq;
+               girq->first = bank->irq_base;
+       }
+
+       /* Only bank F has especially funky IRQ handling */
+       if (bank->has_hierarchical_irq) {
+               int gpio_irq;
+               int i;
+
+               /*
+                * FIXME: convert this to use hierarchical IRQ support!
+                * this requires fixing the root irqchip to be hierarchial.
+                */
+               girq->parent_handler = ep93xx_gpio_f_irq_handler;
+               girq->num_parents = 8;
+               girq->parents = devm_kcalloc(dev, 8,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               /* Pick resources 1..8 for these IRQs */
+               for (i = 1; i <= 8; i++)
+                       girq->parents[i - 1] = platform_get_irq(pdev, i);
+               for (i = 0; i < 8; i++) {
+                       gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i;
+                       irq_set_chip_data(gpio_irq, &epg->gc[5]);
+                       irq_set_chip_and_handler(gpio_irq,
+                                                &ep93xx_gpio_irq_chip,
+                                                handle_level_irq);
+                       irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
+               }
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
+               gc->to_irq = ep93xx_gpio_f_to_irq;
+       }
 
        return devm_gpiochip_add_data(dev, gc, epg);
 }
@@ -407,16 +418,11 @@ static int ep93xx_gpio_probe(struct platform_device *pdev)
                struct gpio_chip *gc = &epg->gc[i];
                struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
 
-               if (ep93xx_gpio_add_bank(gc, &pdev->dev, epg, bank))
+               if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
                        dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
                                 bank->label);
-               /* Only bank F has especially funky IRQ handling */
-               if (i == 5)
-                       gc->to_irq = ep93xx_gpio_f_to_irq;
        }
 
-       ep93xx_gpio_init_irq(pdev, epg);
-
        return 0;
 }
 
index 250e71f..fbddb16 100644 (file)
@@ -290,16 +290,14 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        girq->num_parents = 1;
        girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
                                     GFP_KERNEL);
-       if (!girq->parents)
-               return -ENOMEM;
+       if (!girq->parents) {
+               ret = -ENOMEM;
+               goto dis_clk;
+       }
        girq->default_type = IRQ_TYPE_NONE;
        girq->handler = handle_bad_irq;
        girq->parents[0] = irq;
 
-       ret = devm_gpiochip_add_data(dev, &g->gc, g);
-       if (ret)
-               goto dis_clk;
-
        /* Disable, unmask and clear all interrupts */
        writel(0x0, g->base + GPIO_INT_EN);
        writel(0x0, g->base + GPIO_INT_MASK);
@@ -308,6 +306,10 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
        /* Clear any use of debounce */
        writel(0x0, g->base + GPIO_DEBOUNCE_EN);
 
+       ret = devm_gpiochip_add_data(dev, &g->gc, g);
+       if (ret)
+               goto dis_clk;
+
        platform_set_drvdata(pdev, g);
        dev_info(dev, "FTGPIO010 @%p registered\n", g->base);
 
index 0937b60..08234e6 100644 (file)
@@ -408,8 +408,6 @@ static int grgpio_probe(struct platform_device *ofdev)
                                 * Continue without irq functionality for that
                                 * gpio line
                                 */
-                               dev_err(priv->dev,
-                                       "Failed to get irq for offset %d\n", i);
                                continue;
                        }
                        priv->uirqs[lirq->index].uirq = ret;
index e5fa00f..4a17599 100644 (file)
@@ -244,43 +244,45 @@ static int hlwd_gpio_probe(struct platform_device *pdev)
                ngpios = 32;
        hlwd->gpioc.ngpio = ngpios;
 
-       res = devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
-       if (res)
-               return res;
-
        /* Mask and ack all interrupts */
        iowrite32be(0, hlwd->regs + HW_GPIOB_INTMASK);
        iowrite32be(0xffffffff, hlwd->regs + HW_GPIOB_INTFLAG);
 
        /*
         * If this GPIO controller is not marked as an interrupt controller in
-        * the DT, return.
+        * the DT, skip interrupt support.
         */
-       if (!of_property_read_bool(pdev->dev.of_node, "interrupt-controller"))
-               return 0;
-
-       hlwd->irq = platform_get_irq(pdev, 0);
-       if (hlwd->irq < 0) {
-               dev_info(&pdev->dev, "platform_get_irq returned %d\n",
-                        hlwd->irq);
-               return hlwd->irq;
+       if (of_property_read_bool(pdev->dev.of_node, "interrupt-controller")) {
+               struct gpio_irq_chip *girq;
+
+               hlwd->irq = platform_get_irq(pdev, 0);
+               if (hlwd->irq < 0) {
+                       dev_info(&pdev->dev, "platform_get_irq returned %d\n",
+                                hlwd->irq);
+                       return hlwd->irq;
+               }
+
+               hlwd->irqc.name = dev_name(&pdev->dev);
+               hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
+               hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
+               hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
+               hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
+
+               girq = &hlwd->gpioc.irq;
+               girq->chip = &hlwd->irqc;
+               girq->parent_handler = hlwd_gpio_irqhandler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents)
+                       return -ENOMEM;
+               girq->parents[0] = hlwd->irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_level_irq;
        }
 
-       hlwd->irqc.name = dev_name(&pdev->dev);
-       hlwd->irqc.irq_mask = hlwd_gpio_irq_mask;
-       hlwd->irqc.irq_unmask = hlwd_gpio_irq_unmask;
-       hlwd->irqc.irq_enable = hlwd_gpio_irq_enable;
-       hlwd->irqc.irq_set_type = hlwd_gpio_irq_set_type;
-
-       res = gpiochip_irqchip_add(&hlwd->gpioc, &hlwd->irqc, 0,
-                                  handle_level_irq, IRQ_TYPE_NONE);
-       if (res)
-               return res;
-
-       gpiochip_set_chained_irqchip(&hlwd->gpioc, &hlwd->irqc,
-                                    hlwd->irq, hlwd_gpio_irqhandler);
-
-       return 0;
+       return devm_gpiochip_add_data(&pdev->dev, &hlwd->gpioc, hlwd);
 }
 
 static const struct of_device_id hlwd_gpio_match[] = {
index 670c2a8..b3b0506 100644 (file)
@@ -47,7 +47,6 @@
  * @dev: containing device for this instance
  * @fwnode: the fwnode for this GPIO chip
  * @gc: gpiochip for this instance
- * @domain: irqdomain for this chip instance
  * @base: remapped I/O-memory base
  * @irq_edge: Each bit represents an IRQ: 1: edge-triggered,
  * 0: level triggered
@@ -56,48 +55,22 @@ struct ixp4xx_gpio {
        struct device *dev;
        struct fwnode_handle *fwnode;
        struct gpio_chip gc;
-       struct irq_domain *domain;
        void __iomem *base;
        unsigned long long irq_edge;
 };
 
-/**
- * struct ixp4xx_gpio_map - IXP4 GPIO to parent IRQ map
- * @gpio_offset: offset of the IXP4 GPIO line
- * @parent_hwirq: hwirq on the parent IRQ controller
- */
-struct ixp4xx_gpio_map {
-       int gpio_offset;
-       int parent_hwirq;
-};
-
-/* GPIO lines 0..12 have corresponding IRQs, GPIOs 13..15 have no IRQs */
-const struct ixp4xx_gpio_map ixp4xx_gpiomap[] = {
-       { .gpio_offset = 0, .parent_hwirq = 6 },
-       { .gpio_offset = 1, .parent_hwirq = 7 },
-       { .gpio_offset = 2, .parent_hwirq = 19 },
-       { .gpio_offset = 3, .parent_hwirq = 20 },
-       { .gpio_offset = 4, .parent_hwirq = 21 },
-       { .gpio_offset = 5, .parent_hwirq = 22 },
-       { .gpio_offset = 6, .parent_hwirq = 23 },
-       { .gpio_offset = 7, .parent_hwirq = 24 },
-       { .gpio_offset = 8, .parent_hwirq = 25 },
-       { .gpio_offset = 9, .parent_hwirq = 26 },
-       { .gpio_offset = 10, .parent_hwirq = 27 },
-       { .gpio_offset = 11, .parent_hwirq = 28 },
-       { .gpio_offset = 12, .parent_hwirq = 29 },
-};
-
 static void ixp4xx_gpio_irq_ack(struct irq_data *d)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
 
        __raw_writel(BIT(d->hwirq), g->base + IXP4XX_REG_GPIS);
 }
 
 static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
 
        /* ACK when unmasking if not edge-triggered */
        if (!(g->irq_edge & BIT(d->hwirq)))
@@ -108,7 +81,8 @@ static void ixp4xx_gpio_irq_unmask(struct irq_data *d)
 
 static int ixp4xx_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
-       struct ixp4xx_gpio *g = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
        int line = d->hwirq;
        unsigned long flags;
        u32 int_style;
@@ -187,122 +161,31 @@ static struct irq_chip ixp4xx_gpio_irqchip = {
        .irq_set_type = ixp4xx_gpio_irq_set_type,
 };
 
-static int ixp4xx_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+static int ixp4xx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                            unsigned int child,
+                                            unsigned int child_type,
+                                            unsigned int *parent,
+                                            unsigned int *parent_type)
 {
-       struct ixp4xx_gpio *g = gpiochip_get_data(gc);
-       struct irq_fwspec fwspec;
-
-       fwspec.fwnode = g->fwnode;
-       fwspec.param_count = 2;
-       fwspec.param[0] = offset;
-       fwspec.param[1] = IRQ_TYPE_NONE;
-
-       return irq_create_fwspec_mapping(&fwspec);
-}
+       /* All these interrupts are level high in the CPU */
+       *parent_type = IRQ_TYPE_LEVEL_HIGH;
 
-static int ixp4xx_gpio_irq_domain_translate(struct irq_domain *domain,
-                                           struct irq_fwspec *fwspec,
-                                           unsigned long *hwirq,
-                                           unsigned int *type)
-{
-       int ret;
-
-       /* We support standard DT translation */
-       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
-               return irq_domain_translate_twocell(domain, fwspec,
-                                                   hwirq, type);
+       /* GPIO lines 0..12 have dedicated IRQs */
+       if (child == 0) {
+               *parent = 6;
+               return 0;
        }
-
-       /* This goes away when we transition to DT */
-       if (is_fwnode_irqchip(fwspec->fwnode)) {
-               ret = irq_domain_translate_twocell(domain, fwspec,
-                                                  hwirq, type);
-               if (ret)
-                       return ret;
-               WARN_ON(*type == IRQ_TYPE_NONE);
+       if (child == 1) {
+               *parent = 7;
                return 0;
        }
-       return -EINVAL;
-}
-
-static int ixp4xx_gpio_irq_domain_alloc(struct irq_domain *d,
-                                       unsigned int irq, unsigned int nr_irqs,
-                                       void *data)
-{
-       struct ixp4xx_gpio *g = d->host_data;
-       irq_hw_number_t hwirq;
-       unsigned int type = IRQ_TYPE_NONE;
-       struct irq_fwspec *fwspec = data;
-       int ret;
-       int i;
-
-       ret = ixp4xx_gpio_irq_domain_translate(d, fwspec, &hwirq, &type);
-       if (ret)
-               return ret;
-
-       dev_dbg(g->dev, "allocate IRQ %d..%d, hwirq %lu..%lu\n",
-               irq, irq + nr_irqs - 1,
-               hwirq, hwirq + nr_irqs - 1);
-
-       for (i = 0; i < nr_irqs; i++) {
-               struct irq_fwspec parent_fwspec;
-               const struct ixp4xx_gpio_map *map;
-               int j;
-
-               /* Not all lines support IRQs */
-               for (j = 0; j < ARRAY_SIZE(ixp4xx_gpiomap); j++) {
-                       map = &ixp4xx_gpiomap[j];
-                       if (map->gpio_offset == hwirq)
-                               break;
-               }
-               if (j == ARRAY_SIZE(ixp4xx_gpiomap)) {
-                       dev_err(g->dev, "can't look up hwirq %lu\n", hwirq);
-                       return -EINVAL;
-               }
-               dev_dbg(g->dev, "found parent hwirq %u\n", map->parent_hwirq);
-
-               /*
-                * We set handle_bad_irq because the .set_type() should
-                * always be invoked and set the right type of handler.
-                */
-               irq_domain_set_info(d,
-                                   irq + i,
-                                   hwirq + i,
-                                   &ixp4xx_gpio_irqchip,
-                                   g,
-                                   handle_bad_irq,
-                                   NULL, NULL);
-               irq_set_probe(irq + i);
-
-               /*
-                * Create a IRQ fwspec to send up to the parent irqdomain:
-                * specify the hwirq we address on the parent and tie it
-                * all together up the chain.
-                */
-               parent_fwspec.fwnode = d->parent->fwnode;
-               parent_fwspec.param_count = 2;
-               parent_fwspec.param[0] = map->parent_hwirq;
-               /* This parent only handles asserted level IRQs */
-               parent_fwspec.param[1] = IRQ_TYPE_LEVEL_HIGH;
-               dev_dbg(g->dev, "alloc_irqs_parent for %d parent hwirq %d\n",
-                       irq + i, map->parent_hwirq);
-               ret = irq_domain_alloc_irqs_parent(d, irq + i, 1,
-                                                  &parent_fwspec);
-               if (ret)
-                       dev_err(g->dev,
-                               "failed to allocate parent hwirq %d for hwirq %lu\n",
-                               map->parent_hwirq, hwirq);
+       if (child >= 2 && child <= 12) {
+               *parent = child + 17;
+               return 0;
        }
-
-       return 0;
+       return -EINVAL;
 }
 
-static const struct irq_domain_ops ixp4xx_gpio_irqdomain_ops = {
-       .translate = ixp4xx_gpio_irq_domain_translate,
-       .alloc = ixp4xx_gpio_irq_domain_alloc,
-       .free = irq_domain_free_irqs_common,
-};
-
 static int ixp4xx_gpio_probe(struct platform_device *pdev)
 {
        unsigned long flags;
@@ -311,8 +194,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
        struct irq_domain *parent;
        struct resource *res;
        struct ixp4xx_gpio *g;
+       struct gpio_irq_chip *girq;
        int ret;
-       int i;
 
        g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
        if (!g)
@@ -321,9 +204,36 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        g->base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(g->base)) {
-               dev_err(dev, "ioremap error\n");
+       if (IS_ERR(g->base))
                return PTR_ERR(g->base);
+
+       /*
+        * When we convert to device tree we will simply look up the
+        * parent irqdomain using irq_find_host(parent) as parent comes
+        * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
+        * the fwnode. For now we need this boardfile style code.
+        */
+       if (np) {
+               struct device_node *irq_parent;
+
+               irq_parent = of_irq_find_parent(np);
+               if (!irq_parent) {
+                       dev_err(dev, "no IRQ parent node\n");
+                       return -ENODEV;
+               }
+               parent = irq_find_host(irq_parent);
+               if (!parent) {
+                       dev_err(dev, "no IRQ parent domain\n");
+                       return -ENODEV;
+               }
+               g->fwnode = of_node_to_fwnode(np);
+       } else {
+               parent = ixp4xx_get_irq_domain();
+               g->fwnode = irq_domain_alloc_fwnode(&res->start);
+               if (!g->fwnode) {
+                       dev_err(dev, "no domain base\n");
+                       return -ENODEV;
+               }
        }
 
        /*
@@ -360,7 +270,6 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
                dev_err(dev, "unable to init generic GPIO\n");
                return ret;
        }
-       g->gc.to_irq = ixp4xx_gpio_to_irq;
        g->gc.ngpio = 16;
        g->gc.label = "IXP4XX_GPIO_CHIP";
        /*
@@ -372,86 +281,22 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev)
        g->gc.parent = &pdev->dev;
        g->gc.owner = THIS_MODULE;
 
+       girq = &g->gc.irq;
+       girq->chip = &ixp4xx_gpio_irqchip;
+       girq->fwnode = g->fwnode;
+       girq->parent_domain = parent;
+       girq->child_to_parent_hwirq = ixp4xx_gpio_child_to_parent_hwirq;
+       girq->handler = handle_bad_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
        ret = devm_gpiochip_add_data(dev, &g->gc, g);
        if (ret) {
                dev_err(dev, "failed to add SoC gpiochip\n");
                return ret;
        }
 
-       /*
-        * When we convert to device tree we will simply look up the
-        * parent irqdomain using irq_find_host(parent) as parent comes
-        * from IRQCHIP_DECLARE(), then use of_node_to_fwnode() to get
-        * the fwnode. For now we need this boardfile style code.
-        */
-       if (np) {
-               struct device_node *irq_parent;
-
-               irq_parent = of_irq_find_parent(np);
-               if (!irq_parent) {
-                       dev_err(dev, "no IRQ parent node\n");
-                       return -ENODEV;
-               }
-               parent = irq_find_host(irq_parent);
-               if (!parent) {
-                       dev_err(dev, "no IRQ parent domain\n");
-                       return -ENODEV;
-               }
-               g->fwnode = of_node_to_fwnode(np);
-       } else {
-               parent = ixp4xx_get_irq_domain();
-               g->fwnode = irq_domain_alloc_fwnode(g->base);
-               if (!g->fwnode) {
-                       dev_err(dev, "no domain base\n");
-                       return -ENODEV;
-               }
-       }
-       g->domain = irq_domain_create_hierarchy(parent,
-                                               IRQ_DOMAIN_FLAG_HIERARCHY,
-                                               ARRAY_SIZE(ixp4xx_gpiomap),
-                                               g->fwnode,
-                                               &ixp4xx_gpio_irqdomain_ops,
-                                               g);
-       if (!g->domain) {
-               irq_domain_free_fwnode(g->fwnode);
-               dev_err(dev, "no hierarchical irq domain\n");
-               return ret;
-       }
-
-       /*
-        * After adding OF support, this is no longer needed: irqs
-        * will be allocated for the respective fwnodes.
-        */
-       if (!np) {
-               for (i = 0; i < ARRAY_SIZE(ixp4xx_gpiomap); i++) {
-                       const struct ixp4xx_gpio_map *map = &ixp4xx_gpiomap[i];
-                       struct irq_fwspec fwspec;
-
-                       fwspec.fwnode = g->fwnode;
-                       /* This is the hwirq for the GPIO line side of things */
-                       fwspec.param[0] = map->gpio_offset;
-                       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
-                       fwspec.param_count = 2;
-                       ret = __irq_domain_alloc_irqs(g->domain,
-                                                     -1, /* just pick something */
-                                                     1,
-                                                     NUMA_NO_NODE,
-                                                     &fwspec,
-                                                     false,
-                                                     NULL);
-                       if (ret < 0) {
-                               irq_domain_free_fwnode(g->fwnode);
-                               dev_err(dev,
-                                       "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
-                                       map->gpio_offset, map->parent_hwirq,
-                                       ret);
-                               return ret;
-                       }
-               }
-       }
-
        platform_set_drvdata(pdev, g);
-       dev_info(dev, "IXP4 GPIO @%p registered\n", g->base);
+       dev_info(dev, "IXP4 GPIO registered\n");
 
        return 0;
 }
diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c
deleted file mode 100644 (file)
index a0f87c1..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * arch/arm/mach-ks8695/gpio.c
- *
- * Copyright (C) 2006 Andrew Victor
- * Updated to GPIOLIB, Copyright 2008 Simtec Electronics
- *                     Daniel Silverstone <dsilvers@simtec.co.uk>
- */
-#include <linux/gpio/driver.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/mach/irq.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/gpio-ks8695.h>
-
-/*
- * Configure a GPIO line for either GPIO function, or its internal
- * function (Interrupt, Timer, etc).
- */
-static void ks8695_gpio_mode(unsigned int pin, short gpio)
-{
-       unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_5)        /* only GPIO 0..5 have internal functions */
-               return;
-
-       local_irq_save(flags);
-
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
-       if (gpio)                       /* GPIO: set bit to 0 */
-               x &= ~enable[pin];
-       else                            /* Internal function: set bit to 1 */
-               x |= enable[pin];
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
-
-       local_irq_restore(flags);
-}
-
-
-static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
-
-/*
- * Configure GPIO pin as external interrupt source.
- */
-int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
-               return -EINVAL;
-
-       local_irq_save(flags);
-
-       /* set pin as input */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x &= ~IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       /* Set IRQ triggering type */
-       irq_set_irq_type(gpio_irq[pin], type);
-
-       /* enable interrupt mode */
-       ks8695_gpio_mode(pin, 0);
-
-       return 0;
-}
-EXPORT_SYMBOL(ks8695_gpio_interrupt);
-
-
-
-/* .... Generic GPIO interface .............................................. */
-
-/*
- * Configure the GPIO line as an input.
- */
-static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       /* set pin to GPIO mode */
-       ks8695_gpio_mode(pin, 1);
-
-       local_irq_save(flags);
-
-       /* set pin as input */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x &= ~IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-
-/*
- * Configure the GPIO line as an output, with default state.
- */
-static int ks8695_gpio_direction_output(struct gpio_chip *gc,
-                                       unsigned int pin, int state)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       /* set pin to GPIO mode */
-       ks8695_gpio_mode(pin, 1);
-
-       local_irq_save(flags);
-
-       /* set line state */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       if (state)
-               x |= IOPD(pin);
-       else
-               x &= ~IOPD(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
-
-       /* set pin as output */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       x |= IOPM(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-
-/*
- * Set the state of an output GPIO line.
- */
-static void ks8695_gpio_set_value(struct gpio_chip *gc,
-                                 unsigned int pin, int state)
-{
-       unsigned long x, flags;
-
-       if (pin > KS8695_GPIO_15)
-               return;
-
-       local_irq_save(flags);
-
-       /* set output line state */
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       if (state)
-               x |= IOPD(pin);
-       else
-               x &= ~IOPD(pin);
-       __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
-
-       local_irq_restore(flags);
-}
-
-
-/*
- * Read the state of a GPIO line.
- */
-static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
-{
-       unsigned long x;
-
-       if (pin > KS8695_GPIO_15)
-               return -EINVAL;
-
-       x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-       return (x & IOPD(pin)) != 0;
-}
-
-
-/*
- * Map GPIO line to IRQ number.
- */
-static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
-{
-       if (pin > KS8695_GPIO_3)        /* only GPIO 0..3 can generate IRQ */
-               return -EINVAL;
-
-       return gpio_irq[pin];
-}
-
-/* GPIOLIB interface */
-
-static struct gpio_chip ks8695_gpio_chip = {
-       .label                  = "KS8695",
-       .direction_input        = ks8695_gpio_direction_input,
-       .direction_output       = ks8695_gpio_direction_output,
-       .get                    = ks8695_gpio_get_value,
-       .set                    = ks8695_gpio_set_value,
-       .to_irq                 = ks8695_gpio_to_irq,
-       .base                   = 0,
-       .ngpio                  = 16,
-       .can_sleep              = false,
-};
-
-/* Register the GPIOs */
-void ks8695_register_gpios(void)
-{
-       if (gpiochip_add_data(&ks8695_gpio_chip, NULL))
-               printk(KERN_ERR "Unable to register core GPIOs\n");
-}
-
-/* .... Debug interface ..................................................... */
-
-#ifdef CONFIG_DEBUG_FS
-
-static int ks8695_gpio_show(struct seq_file *s, void *unused)
-{
-       unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
-       unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
-       unsigned long mode, ctrl, data;
-       int i;
-
-       mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
-       ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
-       data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
-
-       seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
-
-       for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
-               seq_printf(s, "%i:\t", i);
-
-               seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
-
-               if (i <= KS8695_GPIO_3) {
-                       if (ctrl & enable[i]) {
-                               seq_printf(s, "EXT%i ", i);
-
-                               switch ((ctrl & intmask[i]) >> (4 * i)) {
-                               case IOPC_TM_LOW:
-                                       seq_printf(s, "(Low)");         break;
-                               case IOPC_TM_HIGH:
-                                       seq_printf(s, "(High)");        break;
-                               case IOPC_TM_RISING:
-                                       seq_printf(s, "(Rising)");      break;
-                               case IOPC_TM_FALLING:
-                                       seq_printf(s, "(Falling)");     break;
-                               case IOPC_TM_EDGE:
-                                       seq_printf(s, "(Edges)");       break;
-                               }
-                       } else
-                               seq_printf(s, "GPIO\t");
-               } else if (i <= KS8695_GPIO_5) {
-                       if (ctrl & enable[i])
-                               seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
-                       else
-                               seq_printf(s, "GPIO\t");
-               } else {
-                       seq_printf(s, "GPIO\t");
-               }
-
-               seq_printf(s, "\t");
-
-               seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
-       }
-       return 0;
-}
-
-DEFINE_SHOW_ATTRIBUTE(ks8695_gpio);
-
-static int __init ks8695_gpio_debugfs_init(void)
-{
-       /* /sys/kernel/debug/ks8695_gpio */
-       debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL,
-                               &ks8695_gpio_fops);
-       return 0;
-}
-postcore_initcall(ks8695_gpio_debugfs_init);
-
-#endif
index 24885b3..4e626c4 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/module.h>
 
-#include <mach/hardware.h>
-#include <mach/platform.h>
-
-#define LPC32XX_GPIO_P3_INP_STATE              _GPREG(0x000)
-#define LPC32XX_GPIO_P3_OUTP_SET               _GPREG(0x004)
-#define LPC32XX_GPIO_P3_OUTP_CLR               _GPREG(0x008)
-#define LPC32XX_GPIO_P3_OUTP_STATE             _GPREG(0x00C)
-#define LPC32XX_GPIO_P2_DIR_SET                        _GPREG(0x010)
-#define LPC32XX_GPIO_P2_DIR_CLR                        _GPREG(0x014)
-#define LPC32XX_GPIO_P2_DIR_STATE              _GPREG(0x018)
-#define LPC32XX_GPIO_P2_INP_STATE              _GPREG(0x01C)
-#define LPC32XX_GPIO_P2_OUTP_SET               _GPREG(0x020)
-#define LPC32XX_GPIO_P2_OUTP_CLR               _GPREG(0x024)
-#define LPC32XX_GPIO_P2_MUX_SET                        _GPREG(0x028)
-#define LPC32XX_GPIO_P2_MUX_CLR                        _GPREG(0x02C)
-#define LPC32XX_GPIO_P2_MUX_STATE              _GPREG(0x030)
-#define LPC32XX_GPIO_P0_INP_STATE              _GPREG(0x040)
-#define LPC32XX_GPIO_P0_OUTP_SET               _GPREG(0x044)
-#define LPC32XX_GPIO_P0_OUTP_CLR               _GPREG(0x048)
-#define LPC32XX_GPIO_P0_OUTP_STATE             _GPREG(0x04C)
-#define LPC32XX_GPIO_P0_DIR_SET                        _GPREG(0x050)
-#define LPC32XX_GPIO_P0_DIR_CLR                        _GPREG(0x054)
-#define LPC32XX_GPIO_P0_DIR_STATE              _GPREG(0x058)
-#define LPC32XX_GPIO_P1_INP_STATE              _GPREG(0x060)
-#define LPC32XX_GPIO_P1_OUTP_SET               _GPREG(0x064)
-#define LPC32XX_GPIO_P1_OUTP_CLR               _GPREG(0x068)
-#define LPC32XX_GPIO_P1_OUTP_STATE             _GPREG(0x06C)
-#define LPC32XX_GPIO_P1_DIR_SET                        _GPREG(0x070)
-#define LPC32XX_GPIO_P1_DIR_CLR                        _GPREG(0x074)
-#define LPC32XX_GPIO_P1_DIR_STATE              _GPREG(0x078)
+#define LPC32XX_GPIO_P3_INP_STATE              (0x000)
+#define LPC32XX_GPIO_P3_OUTP_SET               (0x004)
+#define LPC32XX_GPIO_P3_OUTP_CLR               (0x008)
+#define LPC32XX_GPIO_P3_OUTP_STATE             (0x00C)
+#define LPC32XX_GPIO_P2_DIR_SET                        (0x010)
+#define LPC32XX_GPIO_P2_DIR_CLR                        (0x014)
+#define LPC32XX_GPIO_P2_DIR_STATE              (0x018)
+#define LPC32XX_GPIO_P2_INP_STATE              (0x01C)
+#define LPC32XX_GPIO_P2_OUTP_SET               (0x020)
+#define LPC32XX_GPIO_P2_OUTP_CLR               (0x024)
+#define LPC32XX_GPIO_P2_MUX_SET                        (0x028)
+#define LPC32XX_GPIO_P2_MUX_CLR                        (0x02C)
+#define LPC32XX_GPIO_P2_MUX_STATE              (0x030)
+#define LPC32XX_GPIO_P0_INP_STATE              (0x040)
+#define LPC32XX_GPIO_P0_OUTP_SET               (0x044)
+#define LPC32XX_GPIO_P0_OUTP_CLR               (0x048)
+#define LPC32XX_GPIO_P0_OUTP_STATE             (0x04C)
+#define LPC32XX_GPIO_P0_DIR_SET                        (0x050)
+#define LPC32XX_GPIO_P0_DIR_CLR                        (0x054)
+#define LPC32XX_GPIO_P0_DIR_STATE              (0x058)
+#define LPC32XX_GPIO_P1_INP_STATE              (0x060)
+#define LPC32XX_GPIO_P1_OUTP_SET               (0x064)
+#define LPC32XX_GPIO_P1_OUTP_CLR               (0x068)
+#define LPC32XX_GPIO_P1_OUTP_STATE             (0x06C)
+#define LPC32XX_GPIO_P1_DIR_SET                        (0x070)
+#define LPC32XX_GPIO_P1_DIR_CLR                        (0x074)
+#define LPC32XX_GPIO_P1_DIR_STATE              (0x078)
 
 #define GPIO012_PIN_TO_BIT(x)                  (1 << (x))
 #define GPIO3_PIN_TO_BIT(x)                    (1 << ((x) + 25))
 #define LPC32XX_GPO_P3_GRP     (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
 
 struct gpio_regs {
-       void __iomem *inp_state;
-       void __iomem *outp_state;
-       void __iomem *outp_set;
-       void __iomem *outp_clr;
-       void __iomem *dir_set;
-       void __iomem *dir_clr;
+       unsigned long inp_state;
+       unsigned long outp_state;
+       unsigned long outp_set;
+       unsigned long outp_clr;
+       unsigned long dir_set;
+       unsigned long dir_clr;
 };
 
 /*
@@ -165,16 +162,27 @@ static struct gpio_regs gpio_grp_regs_p3 = {
 struct lpc32xx_gpio_chip {
        struct gpio_chip        chip;
        struct gpio_regs        *gpio_grp;
+       void __iomem            *reg_base;
 };
 
+static inline u32 gpreg_read(struct lpc32xx_gpio_chip *group, unsigned long offset)
+{
+       return __raw_readl(group->reg_base + offset);
+}
+
+static inline void gpreg_write(struct lpc32xx_gpio_chip *group, u32 val, unsigned long offset)
+{
+       __raw_writel(val, group->reg_base + offset);
+}
+
 static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
        unsigned pin, int input)
 {
        if (input)
-               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+               gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
                        group->gpio_grp->dir_clr);
        else
-               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+               gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
                        group->gpio_grp->dir_set);
 }
 
@@ -184,19 +192,19 @@ static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
        u32 u = GPIO3_PIN_TO_BIT(pin);
 
        if (input)
-               __raw_writel(u, group->gpio_grp->dir_clr);
+               gpreg_write(group, u, group->gpio_grp->dir_clr);
        else
-               __raw_writel(u, group->gpio_grp->dir_set);
+               gpreg_write(group, u, group->gpio_grp->dir_set);
 }
 
 static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
        unsigned pin, int high)
 {
        if (high)
-               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+               gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
                        group->gpio_grp->outp_set);
        else
-               __raw_writel(GPIO012_PIN_TO_BIT(pin),
+               gpreg_write(group, GPIO012_PIN_TO_BIT(pin),
                        group->gpio_grp->outp_clr);
 }
 
@@ -206,31 +214,31 @@ static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
        u32 u = GPIO3_PIN_TO_BIT(pin);
 
        if (high)
-               __raw_writel(u, group->gpio_grp->outp_set);
+               gpreg_write(group, u, group->gpio_grp->outp_set);
        else
-               __raw_writel(u, group->gpio_grp->outp_clr);
+               gpreg_write(group, u, group->gpio_grp->outp_clr);
 }
 
 static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
        unsigned pin, int high)
 {
        if (high)
-               __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
+               gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
        else
-               __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
+               gpreg_write(group, GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
 }
 
 static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
        unsigned pin)
 {
-       return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state),
+       return GPIO012_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state),
                pin);
 }
 
 static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
        unsigned pin)
 {
-       int state = __raw_readl(group->gpio_grp->inp_state);
+       int state = gpreg_read(group, group->gpio_grp->inp_state);
 
        /*
         * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped
@@ -242,13 +250,13 @@ static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
 static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
        unsigned pin)
 {
-       return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
+       return GPI3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->inp_state), pin);
 }
 
 static int __get_gpo_state_p3(struct lpc32xx_gpio_chip *group,
        unsigned pin)
 {
-       return GPO3_PIN_IN_SEL(__raw_readl(group->gpio_grp->outp_state), pin);
+       return GPO3_PIN_IN_SEL(gpreg_read(group, group->gpio_grp->outp_state), pin);
 }
 
 /*
@@ -497,12 +505,18 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc,
 static int lpc32xx_gpio_probe(struct platform_device *pdev)
 {
        int i;
+       void __iomem *reg_base;
+
+       reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg_base))
+               return PTR_ERR(reg_base);
 
        for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) {
                if (pdev->dev.of_node) {
                        lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate;
                        lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
                        lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
+                       lpc32xx_gpiochip[i].reg_base = reg_base;
                }
                devm_gpiochip_add_data(&pdev->dev, &lpc32xx_gpiochip[i].chip,
                                  &lpc32xx_gpiochip[i]);
@@ -527,3 +541,7 @@ static struct platform_driver lpc32xx_gpio_driver = {
 };
 
 module_platform_driver(lpc32xx_gpio_driver);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("GPIO driver for LPC32xx SoC");
index 4dbc837..7086f8b 100644 (file)
@@ -120,7 +120,7 @@ static const struct gpio_chip madera_gpio_chip = {
 static int madera_gpio_probe(struct platform_device *pdev)
 {
        struct madera *madera = dev_get_drvdata(pdev->dev.parent);
-       struct madera_pdata *pdata = dev_get_platdata(madera->dev);
+       struct madera_pdata *pdata = &madera->pdata;
        struct madera_gpio *madera_gpio;
        int ret;
 
@@ -136,6 +136,9 @@ static int madera_gpio_probe(struct platform_device *pdev)
        madera_gpio->gpio_chip.parent = pdev->dev.parent;
 
        switch (madera->type) {
+       case CS47L15:
+               madera_gpio->gpio_chip.ngpio = CS47L15_NUM_GPIOS;
+               break;
        case CS47L35:
                madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS;
                break;
@@ -147,13 +150,18 @@ static int madera_gpio_probe(struct platform_device *pdev)
        case CS47L91:
                madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS;
                break;
+       case CS42L92:
+       case CS47L92:
+       case CS47L93:
+               madera_gpio->gpio_chip.ngpio = CS47L92_NUM_GPIOS;
+               break;
        default:
                dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type);
                return -EINVAL;
        }
 
        /* We want to be usable on systems that don't use devicetree or acpi */
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                madera_gpio->gpio_chip.base = pdata->gpio_base;
        else
                madera_gpio->gpio_chip.base = -1;
index b7d89e3..47d05e3 100644 (file)
@@ -270,10 +270,8 @@ static int max77620_gpio_probe(struct platform_device *pdev)
        int ret;
 
        gpio_irq = platform_get_irq(pdev, 0);
-       if (gpio_irq <= 0) {
-               dev_err(&pdev->dev, "GPIO irq not available %d\n", gpio_irq);
+       if (gpio_irq <= 0)
                return -ENODEV;
-       }
 
        mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
        if (!mgpio)
index 3f03f4e..3075f25 100644 (file)
@@ -188,3 +188,4 @@ module_platform_driver(max77650_gpio_driver);
 MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
 MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:max77650-gpio");
index 8f46699..501e895 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 /*
  * Only first 8bits of a register correspond to each pin,
index c8673a5..16a47de 100644 (file)
@@ -32,6 +32,7 @@
 #define GPIO_IMR               0x10
 #define GPIO_ICR               0x14
 #define GPIO_ICR2              0x18
+#define GPIO_IBE               0x18
 
 struct mpc8xxx_gpio_chip {
        struct gpio_chip        gc;
@@ -45,6 +46,27 @@ struct mpc8xxx_gpio_chip {
        unsigned int irqn;
 };
 
+/* The GPIO Input Buffer Enable register(GPIO_IBE) is used to
+ * control the input enable of each individual GPIO port.
+ * When an individual GPIO port’s direction is set to
+ * input (GPIO_GPDIR[DRn=0]), the associated input enable must be
+ * set (GPIOxGPIE[IEn]=1) to propagate the port value to the GPIO
+ * Data Register.
+ */
+static int ls1028a_gpio_dir_in_init(struct gpio_chip *gc)
+{
+       unsigned long flags;
+       struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
+
+       spin_lock_irqsave(&gc->bgpio_lock, flags);
+
+       gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
+
+       spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+
+       return 0;
+}
+
 /*
  * This hardware has a big endian bit assignment such that GPIO line 0 is
  * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
@@ -261,6 +283,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
 };
 
 struct mpc8xxx_gpio_devtype {
+       int (*gpio_dir_in_init)(struct gpio_chip *chip);
        int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int);
        int (*gpio_get)(struct gpio_chip *, unsigned int);
        int (*irq_set_type)(struct irq_data *, unsigned int);
@@ -271,6 +294,10 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = {
        .irq_set_type = mpc512x_irq_set_type,
 };
 
+static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = {
+       .gpio_dir_in_init = ls1028a_gpio_dir_in_init,
+};
+
 static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
        .gpio_dir_out = mpc5125_gpio_dir_out,
        .irq_set_type = mpc512x_irq_set_type,
@@ -291,6 +318,8 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = {
        { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, },
        { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, },
        { .compatible = "fsl,pq3-gpio",     },
+       { .compatible = "fsl,ls1028a-gpio", .data = &ls1028a_gpio_devtype, },
+       { .compatible = "fsl,ls1088a-gpio", .data = &ls1028a_gpio_devtype, },
        { .compatible = "fsl,qoriq-gpio",   },
        {}
 };
@@ -376,6 +405,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
        /* ack and mask all irqs */
        gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
        gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
+       /* enable input buffer  */
+       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);
index 79654fb..d1d785f 100644 (file)
@@ -241,13 +241,6 @@ mediatek_gpio_bank_probe(struct device *dev,
        if (!rg->chip.label)
                return -ENOMEM;
 
-       ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
-       if (ret < 0) {
-               dev_err(dev, "Could not register gpio %d, ret=%d\n",
-                       rg->chip.ngpio, ret);
-               return ret;
-       }
-
        rg->irq_chip.name = dev_name(dev);
        rg->irq_chip.parent_device = dev;
        rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;
@@ -256,8 +249,10 @@ mediatek_gpio_bank_probe(struct device *dev,
        rg->irq_chip.irq_set_type = mediatek_gpio_irq_type;
 
        if (mtk->gpio_irq) {
+               struct gpio_irq_chip *girq;
+
                /*
-                * Manually request the irq here instead of passing
+                * Directly request the irq here instead of passing
                 * a flow-handler to gpiochip_set_chained_irqchip,
                 * because the irq is shared.
                 */
@@ -271,15 +266,21 @@ mediatek_gpio_bank_probe(struct device *dev,
                        return ret;
                }
 
-               ret = gpiochip_irqchip_add(&rg->chip, &rg->irq_chip,
-                                          0, handle_simple_irq, IRQ_TYPE_NONE);
-               if (ret) {
-                       dev_err(dev, "failed to add gpiochip_irqchip\n");
-                       return ret;
-               }
+               girq = &rg->chip.irq;
+               girq->chip = &rg->irq_chip;
+               /* 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;
+       }
 
-               gpiochip_set_chained_irqchip(&rg->chip, &rg->irq_chip,
-                                            mtk->gpio_irq, NULL);
+       ret = devm_gpiochip_add_data(dev, &rg->chip, mtk);
+       if (ret < 0) {
+               dev_err(dev, "Could not register gpio %d, ret=%d\n",
+                       rg->chip.ngpio, ret);
+               return ret;
        }
 
        /* set polarity to low for all gpios */
index b281358..7907a87 100644 (file)
@@ -435,12 +435,9 @@ static int mxc_gpio_probe(struct platform_device *pdev)
                return port->irq;
 
        /* the controller clock is optional */
-       port->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(port->clk)) {
-               if (PTR_ERR(port->clk) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-               port->clk = NULL;
-       }
+       port->clk = devm_clk_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(port->clk))
+               return PTR_ERR(port->clk);
 
        err = clk_prepare_enable(port->clk);
        if (err) {
index 378b206..64d02ca 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/bits.h>
 #include <linux/gpio/driver.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
@@ -28,9 +29,9 @@
 #define PCA953X_INVERT         0x02
 #define PCA953X_DIRECTION      0x03
 
-#define REG_ADDR_MASK          0x3f
-#define REG_ADDR_EXT           0x40
-#define REG_ADDR_AI            0x80
+#define REG_ADDR_MASK          GENMASK(5, 0)
+#define REG_ADDR_EXT           BIT(6)
+#define REG_ADDR_AI            BIT(7)
 
 #define PCA957X_IN             0x00
 #define PCA957X_INVRT          0x01
 #define PCAL6524_OUT_INDCONF   0x2c
 #define PCAL6524_DEBOUNCE      0x2d
 
-#define PCA_GPIO_MASK          0x00FF
+#define PCA_GPIO_MASK          GENMASK(7, 0)
 
-#define PCAL_GPIO_MASK         0x1f
-#define PCAL_PINCTRL_MASK      0x60
+#define PCAL_GPIO_MASK         GENMASK(4, 0)
+#define PCAL_PINCTRL_MASK      GENMASK(6, 5)
 
-#define PCA_INT                        0x0100
-#define PCA_PCAL               0x0200
+#define PCA_INT                        BIT(8)
+#define PCA_PCAL               BIT(9)
 #define PCA_LATCH_INT          (PCA_PCAL | PCA_INT)
-#define PCA953X_TYPE           0x1000
-#define PCA957X_TYPE           0x2000
-#define PCA_TYPE_MASK          0xF000
+#define PCA953X_TYPE           BIT(12)
+#define PCA957X_TYPE           BIT(13)
+#define PCA_TYPE_MASK          GENMASK(15, 12)
 
 #define PCA_CHIP_TYPE(x)       ((x) & PCA_TYPE_MASK)
 
@@ -565,7 +566,7 @@ static void pca953x_irq_mask(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
 
-       chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
+       chip->irq_mask[d->hwirq / BANK_SZ] &= ~BIT(d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
@@ -573,7 +574,7 @@ static void pca953x_irq_unmask(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
 
-       chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
+       chip->irq_mask[d->hwirq / BANK_SZ] |= BIT(d->hwirq % BANK_SZ);
 }
 
 static int pca953x_irq_set_wake(struct irq_data *d, unsigned int on)
@@ -641,7 +642,7 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
        int bank_nb = d->hwirq / BANK_SZ;
-       u8 mask = 1 << (d->hwirq % BANK_SZ);
+       u8 mask = BIT(d->hwirq % BANK_SZ);
 
        if (!(type & IRQ_TYPE_EDGE_BOTH)) {
                dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -666,7 +667,7 @@ static void pca953x_irq_shutdown(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 mask = 1 << (d->hwirq % BANK_SZ);
+       u8 mask = BIT(d->hwirq % BANK_SZ);
 
        chip->irq_trig_raise[d->hwirq / BANK_SZ] &= ~mask;
        chip->irq_trig_fall[d->hwirq / BANK_SZ] &= ~mask;
@@ -849,12 +850,12 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
 
        ret = regcache_sync_region(chip->regmap, chip->regs->output,
                                   chip->regs->output + NBANK(chip));
-       if (ret != 0)
+       if (ret)
                goto out;
 
        ret = regcache_sync_region(chip->regmap, chip->regs->direction,
                                   chip->regs->direction + NBANK(chip));
-       if (ret != 0)
+       if (ret)
                goto out;
 
        /* set platform specific polarity inversion */
@@ -949,19 +950,15 @@ static int pca953x_probe(struct i2c_client *client,
        if (i2c_id) {
                chip->driver_data = i2c_id->driver_data;
        } else {
-               const struct acpi_device_id *acpi_id;
-               struct device *dev = &client->dev;
-
-               chip->driver_data = (uintptr_t)of_device_get_match_data(dev);
-               if (!chip->driver_data) {
-                       acpi_id = acpi_match_device(pca953x_acpi_ids, dev);
-                       if (!acpi_id) {
-                               ret = -ENODEV;
-                               goto err_exit;
-                       }
-
-                       chip->driver_data = acpi_id->driver_data;
+               const void *match;
+
+               match = device_get_match_data(&client->dev);
+               if (!match) {
+                       ret = -ENODEV;
+                       goto err_exit;
                }
+
+               chip->driver_data = (uintptr_t)match;
        }
 
        i2c_set_clientdata(client, chip);
@@ -1041,8 +1038,7 @@ static int pca953x_remove(struct i2c_client *client)
                ret = pdata->teardown(client, chip->gpio_chip.base,
                                chip->gpio_chip.ngpio, pdata->context);
                if (ret < 0)
-                       dev_err(&client->dev, "%s failed, %d\n",
-                                       "teardown", ret);
+                       dev_err(&client->dev, "teardown failed, %d\n", ret);
        } else {
                ret = 0;
        }
@@ -1064,14 +1060,14 @@ static int pca953x_regcache_sync(struct device *dev)
         */
        ret = regcache_sync_region(chip->regmap, chip->regs->direction,
                                   chip->regs->direction + NBANK(chip));
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
                return ret;
        }
 
        ret = regcache_sync_region(chip->regmap, chip->regs->output,
                                   chip->regs->output + NBANK(chip));
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
                return ret;
        }
@@ -1080,7 +1076,7 @@ static int pca953x_regcache_sync(struct device *dev)
        if (chip->driver_data & PCA_PCAL) {
                ret = regcache_sync_region(chip->regmap, PCAL953X_IN_LATCH,
                                           PCAL953X_IN_LATCH + NBANK(chip));
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to sync INT latch registers: %d\n",
                                ret);
                        return ret;
@@ -1088,7 +1084,7 @@ static int pca953x_regcache_sync(struct device *dev)
 
                ret = regcache_sync_region(chip->regmap, PCAL953X_INT_MASK,
                                           PCAL953X_INT_MASK + NBANK(chip));
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to sync INT mask registers: %d\n",
                                ret);
                        return ret;
@@ -1120,7 +1116,7 @@ static int pca953x_resume(struct device *dev)
 
        if (!atomic_read(&chip->wakeup_path)) {
                ret = regulator_enable(chip->regulator);
-               if (ret != 0) {
+               if (ret) {
                        dev_err(dev, "Failed to enable regulator: %d\n", ret);
                        return 0;
                }
@@ -1133,7 +1129,7 @@ static int pca953x_resume(struct device *dev)
                return ret;
 
        ret = regcache_sync(chip->regmap);
-       if (ret != 0) {
+       if (ret) {
                dev_err(dev, "Failed to restore register map: %d\n", ret);
                return ret;
        }
index 24228cf..05000ca 100644 (file)
@@ -305,10 +305,8 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev)
        mutex_init(&pmic_eic->buslock);
 
        pmic_eic->irq = platform_get_irq(pdev, 0);
-       if (pmic_eic->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get PMIC EIC interrupt.\n");
+       if (pmic_eic->irq < 0)
                return pmic_eic->irq;
-       }
 
        pmic_eic->map = dev_get_regmap(pdev->dev.parent, NULL);
        if (!pmic_eic->map)
index f5c8b3a..d7314d3 100644 (file)
@@ -226,10 +226,8 @@ static int sprd_gpio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        sprd_gpio->irq = platform_get_irq(pdev, 0);
-       if (sprd_gpio->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get GPIO interrupt.\n");
+       if (sprd_gpio->irq < 0)
                return sprd_gpio->irq;
-       }
 
        sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(sprd_gpio->base))
index bd1f3f7..5e37518 100644 (file)
@@ -171,10 +171,8 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
                struct irq_chip_generic *gc;
 
                ret = platform_get_irq(pdev, 0);
-               if (ret < 0) {
-                       dev_err(dev, "No interrupt specified.\n");
+               if (ret < 0)
                        return ret;
-               }
 
                tb10x_gpio->gc.to_irq   = tb10x_gpio_to_irq;
                tb10x_gpio->irq         = ret;
index 0f59161..8a01d36 100644 (file)
@@ -624,10 +624,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
        for (i = 0; i < tgi->bank_count; i++) {
                ret = platform_get_irq(pdev, i);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "Missing IRQ resource: %d\n", ret);
+               if (ret < 0)
                        return ret;
-               }
 
                bank = &tgi->bank_info[i];
                bank->bank = i;
index 715371b..ddad5c7 100644 (file)
@@ -53,7 +53,6 @@ struct thunderx_line {
 struct thunderx_gpio {
        struct gpio_chip        chip;
        u8 __iomem              *register_base;
-       struct irq_domain       *irqd;
        struct msix_entry       *msix_entries;  /* per line MSI-X */
        struct thunderx_line    *line_entries;  /* per line irq info */
        raw_spinlock_t          lock;
@@ -283,54 +282,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip,
        }
 }
 
-static void thunderx_gpio_irq_ack(struct irq_data *data)
+static void thunderx_gpio_irq_ack(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_INTR,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_mask(struct irq_data *data)
+static void thunderx_gpio_irq_mask(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1C,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
+static void thunderx_gpio_irq_mask_ack(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static void thunderx_gpio_irq_unmask(struct irq_data *data)
+static void thunderx_gpio_irq_unmask(struct irq_data *d)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
        writeq(GPIO_INTR_ENA_W1S,
-              txline->txgpio->register_base + intr_reg(txline->line));
+              txgpio->register_base + intr_reg(irqd_to_hwirq(d)));
 }
 
-static int thunderx_gpio_irq_set_type(struct irq_data *data,
+static int thunderx_gpio_irq_set_type(struct irq_data *d,
                                      unsigned int flow_type)
 {
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
+       struct thunderx_line *txline =
+               &txgpio->line_entries[irqd_to_hwirq(d)];
        u64 bit_cfg;
 
-       irqd_set_trigger_type(data, flow_type);
+       irqd_set_trigger_type(d, flow_type);
 
        bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN;
 
        if (flow_type & IRQ_TYPE_EDGE_BOTH) {
-               irq_set_handler_locked(data, handle_fasteoi_ack_irq);
+               irq_set_handler_locked(d, handle_fasteoi_ack_irq);
                bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
        } else {
-               irq_set_handler_locked(data, handle_fasteoi_mask_irq);
+               irq_set_handler_locked(d, handle_fasteoi_mask_irq);
        }
 
        raw_spin_lock(&txgpio->lock);
@@ -359,33 +364,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data)
        irq_chip_disable_parent(data);
 }
 
-static int thunderx_gpio_irq_request_resources(struct irq_data *data)
-{
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
-       int r;
-
-       r = gpiochip_lock_as_irq(&txgpio->chip, txline->line);
-       if (r)
-               return r;
-
-       r = irq_chip_request_resources_parent(data);
-       if (r)
-               gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
-
-       return r;
-}
-
-static void thunderx_gpio_irq_release_resources(struct irq_data *data)
-{
-       struct thunderx_line *txline = irq_data_get_irq_chip_data(data);
-       struct thunderx_gpio *txgpio = txline->txgpio;
-
-       irq_chip_release_resources_parent(data);
-
-       gpiochip_unlock_as_irq(&txgpio->chip, txline->line);
-}
-
 /*
  * Interrupts are chained from underlying MSI-X vectors.  We have
  * these irq_chip functions to be able to handle level triggering
@@ -402,48 +380,22 @@ static struct irq_chip thunderx_gpio_irq_chip = {
        .irq_unmask             = thunderx_gpio_irq_unmask,
        .irq_eoi                = irq_chip_eoi_parent,
        .irq_set_affinity       = irq_chip_set_affinity_parent,
-       .irq_request_resources  = thunderx_gpio_irq_request_resources,
-       .irq_release_resources  = thunderx_gpio_irq_release_resources,
        .irq_set_type           = thunderx_gpio_irq_set_type,
 
        .flags                  = IRQCHIP_SET_TYPE_MASKED
 };
 
-static int thunderx_gpio_irq_translate(struct irq_domain *d,
-                                      struct irq_fwspec *fwspec,
-                                      irq_hw_number_t *hwirq,
-                                      unsigned int *type)
+static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
+                                              unsigned int child,
+                                              unsigned int child_type,
+                                              unsigned int *parent,
+                                              unsigned int *parent_type)
 {
-       struct thunderx_gpio *txgpio = d->host_data;
-
-       if (WARN_ON(fwspec->param_count < 2))
-               return -EINVAL;
-       if (fwspec->param[0] >= txgpio->chip.ngpio)
-               return -EINVAL;
-       *hwirq = fwspec->param[0];
-       *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
-       return 0;
-}
-
-static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq,
-                                  unsigned int nr_irqs, void *arg)
-{
-       struct thunderx_line *txline = arg;
+       struct thunderx_gpio *txgpio = gpiochip_get_data(gc);
 
-       return irq_domain_set_hwirq_and_chip(d, virq, txline->line,
-                                            &thunderx_gpio_irq_chip, txline);
-}
-
-static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
-       .alloc          = thunderx_gpio_irq_alloc,
-       .translate      = thunderx_gpio_irq_translate
-};
-
-static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
-{
-       struct thunderx_gpio *txgpio = gpiochip_get_data(chip);
-
-       return irq_find_mapping(txgpio->irqd, offset);
+       *parent = txgpio->base_msi + (2 * child);
+       *parent_type = IRQ_TYPE_LEVEL_HIGH;
+       return 0;
 }
 
 static int thunderx_gpio_probe(struct pci_dev *pdev,
@@ -453,6 +405,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        struct device *dev = &pdev->dev;
        struct thunderx_gpio *txgpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        int ngpio, i;
        int err = 0;
 
@@ -497,8 +450,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        }
 
        txgpio->msix_entries = devm_kcalloc(dev,
-                                         ngpio, sizeof(struct msix_entry),
-                                         GFP_KERNEL);
+                                           ngpio, sizeof(struct msix_entry),
+                                           GFP_KERNEL);
        if (!txgpio->msix_entries) {
                err = -ENOMEM;
                goto out;
@@ -539,27 +492,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        if (err < 0)
                goto out;
 
-       /*
-        * Push GPIO specific irqdomain on hierarchy created as a side
-        * effect of the pci_enable_msix()
-        */
-       txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain,
-                                                  0, 0, of_node_to_fwnode(dev->of_node),
-                                                  &thunderx_gpio_irqd_ops, txgpio);
-       if (!txgpio->irqd) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       /* Push on irq_data and the domain for each line. */
-       for (i = 0; i < ngpio; i++) {
-               err = irq_domain_push_irq(txgpio->irqd,
-                                         txgpio->msix_entries[i].vector,
-                                         &txgpio->line_entries[i]);
-               if (err < 0)
-                       dev_err(dev, "irq_domain_push_irq: %d\n", err);
-       }
-
        chip->label = KBUILD_MODNAME;
        chip->parent = dev;
        chip->owner = THIS_MODULE;
@@ -574,11 +506,28 @@ static int thunderx_gpio_probe(struct pci_dev *pdev,
        chip->set = thunderx_gpio_set;
        chip->set_multiple = thunderx_gpio_set_multiple;
        chip->set_config = thunderx_gpio_set_config;
-       chip->to_irq = thunderx_gpio_to_irq;
+       girq = &chip->irq;
+       girq->chip = &thunderx_gpio_irq_chip;
+       girq->fwnode = of_node_to_fwnode(dev->of_node);
+       girq->parent_domain =
+               irq_get_irq_data(txgpio->msix_entries[0].vector)->domain;
+       girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq;
+       girq->handler = handle_bad_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
        err = devm_gpiochip_add_data(dev, chip, txgpio);
        if (err)
                goto out;
 
+       /* Push on irq_data and the domain for each line. */
+       for (i = 0; i < ngpio; i++) {
+               err = irq_domain_push_irq(chip->irq.domain,
+                                         txgpio->msix_entries[i].vector,
+                                         chip);
+               if (err < 0)
+                       dev_err(dev, "irq_domain_push_irq: %d\n", err);
+       }
+
        dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
                 ngpio, chip->base);
        return 0;
@@ -593,10 +542,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev)
        struct thunderx_gpio *txgpio = pci_get_drvdata(pdev);
 
        for (i = 0; i < txgpio->chip.ngpio; i++)
-               irq_domain_pop_irq(txgpio->irqd,
+               irq_domain_pop_irq(txgpio->chip.irq.domain,
                                   txgpio->msix_entries[i].vector);
 
-       irq_domain_remove(txgpio->irqd);
+       irq_domain_remove(txgpio->chip.irq.domain);
 
        pci_set_drvdata(pdev, NULL);
 }
index d5880db..07050cd 100644 (file)
@@ -219,6 +219,7 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct tqmx86_gpio_data *gpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        void __iomem *io_base;
        struct resource *res;
        int ret, irq;
@@ -264,12 +265,6 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = devm_gpiochip_add_data(dev, chip, gpio);
-       if (ret) {
-               dev_err(dev, "Could not register GPIO chip\n");
-               goto out_pm_dis;
-       }
-
        if (irq) {
                struct irq_chip *irq_chip = &gpio->irq_chip;
                u8 irq_status;
@@ -287,23 +282,35 @@ static int tqmx86_gpio_probe(struct platform_device *pdev)
                irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);
                tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);
 
-               ret = gpiochip_irqchip_add(chip, irq_chip,
-                                          0, handle_simple_irq,
-                                          IRQ_TYPE_EDGE_BOTH);
-               if (ret) {
-                       dev_err(dev, "Could not add irq chip\n");
+               girq = &chip->irq;
+               girq->chip = irq_chip;
+               girq->parent_handler = tqmx86_gpio_irq_handler;
+               girq->num_parents = 1;
+               girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                            sizeof(*girq->parents),
+                                            GFP_KERNEL);
+               if (!girq->parents) {
+                       ret = -ENOMEM;
                        goto out_pm_dis;
                }
+               girq->parents[0] = irq;
+               girq->default_type = IRQ_TYPE_NONE;
+               girq->handler = handle_simple_irq;
+       }
 
-               gpiochip_set_chained_irqchip(chip, irq_chip,
-                                            irq, tqmx86_gpio_irq_handler);
+       ret = devm_gpiochip_add_data(dev, chip, gpio);
+       if (ret) {
+               dev_err(dev, "Could not register GPIO chip\n");
+               goto out_pm_dis;
        }
 
        /* Only GPIOs 4-7 are valid for interrupts. Clear the others */
-       clear_bit(0, chip->irq.valid_mask);
-       clear_bit(1, chip->irq.valid_mask);
-       clear_bit(2, chip->irq.valid_mask);
-       clear_bit(3, chip->irq.valid_mask);
+       if (irq) {
+               clear_bit(0, girq->valid_mask);
+               clear_bit(1, girq->valid_mask);
+               clear_bit(2, girq->valid_mask);
+               clear_bit(3, girq->valid_mask);
+       }
 
        dev_info(dev, "GPIO functionality initialized with %d pins\n",
                 chip->ngpio);
index 7ba668d..58776f2 100644 (file)
@@ -243,6 +243,7 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        struct device_node *np = dev->of_node;
        struct vf610_gpio_port *port;
        struct gpio_chip *gc;
+       struct gpio_irq_chip *girq;
        struct irq_chip *ic;
        int i;
        int ret;
@@ -318,10 +319,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        ic->irq_set_type = vf610_gpio_irq_set_type;
        ic->irq_set_wake = vf610_gpio_irq_set_wake;
 
-       ret = devm_gpiochip_add_data(dev, gc, port);
-       if (ret < 0)
-               return ret;
-
        /* Mask all GPIO interrupts */
        for (i = 0; i < gc->ngpio; i++)
                vf610_gpio_writel(0, port->base + PORT_PCR(i));
@@ -329,15 +326,20 @@ static int vf610_gpio_probe(struct platform_device *pdev)
        /* Clear the interrupt status register for all GPIO's */
        vf610_gpio_writel(~0, port->base + PORT_ISFR);
 
-       ret = gpiochip_irqchip_add(gc, ic, 0, handle_edge_irq, IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "failed to add irqchip\n");
-               return ret;
-       }
-       gpiochip_set_chained_irqchip(gc, ic, port->irq,
-                                    vf610_gpio_irq_handler);
+       girq = &gc->irq;
+       girq->chip = ic;
+       girq->parent_handler = vf610_gpio_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = port->irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_edge_irq;
 
-       return 0;
+       return devm_gpiochip_add_data(dev, gc, port);
 }
 
 static struct platform_driver vf610_gpio_driver = {
index 9b604f1..c301c1d 100644 (file)
@@ -79,7 +79,7 @@ MODULE_PARM_DESC(gpioa_freq,
 /* ----- begin of gipo a chip -------------------------------------------- */
 
 static int vprbrd_gpioa_get(struct gpio_chip *chip,
-               unsigned offset)
+               unsigned int offset)
 {
        int ret, answer, error = 0;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -129,7 +129,7 @@ static int vprbrd_gpioa_get(struct gpio_chip *chip,
 }
 
 static void vprbrd_gpioa_set(struct gpio_chip *chip,
-               unsigned offset, int value)
+               unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -170,7 +170,7 @@ static void vprbrd_gpioa_set(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
-                       unsigned offset)
+                       unsigned int offset)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -207,7 +207,7 @@ static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
-                       unsigned offset, int value)
+                       unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -251,8 +251,8 @@ static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
 
 /* ----- begin of gipo b chip -------------------------------------------- */
 
-static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
-       unsigned dir)
+static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
+       unsigned int dir)
 {
        struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
        int ret;
@@ -273,7 +273,7 @@ static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned offset,
 }
 
 static int vprbrd_gpiob_get(struct gpio_chip *chip,
-               unsigned offset)
+               unsigned int offset)
 {
        int ret;
        u16 val;
@@ -305,7 +305,7 @@ static int vprbrd_gpiob_get(struct gpio_chip *chip,
 }
 
 static void vprbrd_gpiob_set(struct gpio_chip *chip,
-               unsigned offset, int value)
+               unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -338,7 +338,7 @@ static void vprbrd_gpiob_set(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
-                       unsigned offset)
+                       unsigned int offset)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
@@ -359,7 +359,7 @@ static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
 }
 
 static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
-                       unsigned offset, int value)
+                       unsigned int offset, int value)
 {
        int ret;
        struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
index 38c0191..25d8644 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/acpi.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 /* Common property names */
 #define XGENE_NIRQ_PROPERTY            "apm,nr-irqs"
index 54d3359..d7b16bb 100644 (file)
@@ -290,6 +290,7 @@ MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
 static int xlp_gpio_probe(struct platform_device *pdev)
 {
        struct gpio_chip *gc;
+       struct gpio_irq_chip *girq;
        struct xlp_gpio_priv *priv;
        void __iomem *gpio_base;
        int irq_base, irq, err;
@@ -395,27 +396,27 @@ static int xlp_gpio_probe(struct platform_device *pdev)
                irq_base = 0;
        }
 
+       girq = &gc->irq;
+       girq->chip = &xlp_gpio_irq_chip;
+       girq->parent_handler = xlp_gpio_generic_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = irq;
+       girq->first = irq_base;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
+
        err = gpiochip_add_data(gc, priv);
        if (err < 0)
                return err;
 
-       err = gpiochip_irqchip_add(gc, &xlp_gpio_irq_chip, irq_base,
-                               handle_level_irq, IRQ_TYPE_NONE);
-       if (err) {
-               dev_err(&pdev->dev, "Could not connect irqchip to gpiochip!\n");
-               goto out_gpio_remove;
-       }
-
-       gpiochip_set_chained_irqchip(gc, &xlp_gpio_irq_chip, irq,
-                       xlp_gpio_generic_handler);
-
        dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
 
        return 0;
-
-out_gpio_remove:
-       gpiochip_remove(gc);
-       return err;
 }
 
 #ifdef CONFIG_ACPI
index 8637adb..98cbaf0 100644 (file)
@@ -215,6 +215,7 @@ static int zx_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct zx_gpio *chip;
+       struct gpio_irq_chip *girq;
        int irq, id, ret;
 
        chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
@@ -242,32 +243,30 @@ static int zx_gpio_probe(struct platform_device *pdev)
        chip->gc.parent = dev;
        chip->gc.owner = THIS_MODULE;
 
-       ret = gpiochip_add_data(&chip->gc, chip);
-       if (ret)
-               return ret;
-
        /*
         * irq_chip support
         */
        writew_relaxed(0xffff, chip->base + ZX_GPIO_IM);
        writew_relaxed(0, chip->base + ZX_GPIO_IE);
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "invalid IRQ\n");
-               gpiochip_remove(&chip->gc);
-               return -ENODEV;
-       }
+       if (irq < 0)
+               return irq;
+       girq = &chip->gc.irq;
+       girq->chip = &zx_irqchip;
+       girq->parent_handler = zx_irq_handler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents)
+               return -ENOMEM;
+       girq->parents[0] = irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_simple_irq;
 
-       ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip,
-                                  0, handle_simple_irq,
-                                  IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(dev, "could not add irqchip\n");
-               gpiochip_remove(&chip->gc);
+       ret = gpiochip_add_data(&chip->gc, chip);
+       if (ret)
                return ret;
-       }
-       gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip,
-                                    irq, zx_irq_handler);
 
        platform_set_drvdata(pdev, chip);
        dev_info(dev, "ZX GPIO chip registered\n");
index f241b6c..cd475ff 100644 (file)
@@ -830,6 +830,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        int ret, bank_num;
        struct zynq_gpio *gpio;
        struct gpio_chip *chip;
+       struct gpio_irq_chip *girq;
        const struct of_device_id *match;
 
        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
@@ -849,10 +850,8 @@ static int zynq_gpio_probe(struct platform_device *pdev)
                return PTR_ERR(gpio->base_addr);
 
        gpio->irq = platform_get_irq(pdev, 0);
-       if (gpio->irq < 0) {
-               dev_err(&pdev->dev, "invalid IRQ\n");
+       if (gpio->irq < 0)
                return gpio->irq;
-       }
 
        /* configure the gpio chip */
        chip = &gpio->chip;
@@ -887,34 +886,38 @@ static int zynq_gpio_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_pm_dis;
 
-       /* report a bug if gpio chip registration fails */
-       ret = gpiochip_add_data(chip, gpio);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to add gpio chip\n");
-               goto err_pm_put;
-       }
-
        /* disable interrupts for all banks */
        for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++)
                writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr +
                               ZYNQ_GPIO_INTDIS_OFFSET(bank_num));
 
-       ret = gpiochip_irqchip_add(chip, &zynq_gpio_edge_irqchip, 0,
-                                  handle_level_irq, IRQ_TYPE_NONE);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to add irq chip\n");
-               goto err_rm_gpiochip;
+       /* Set up the GPIO irqchip */
+       girq = &chip->irq;
+       girq->chip = &zynq_gpio_edge_irqchip;
+       girq->parent_handler = zynq_gpio_irqhandler;
+       girq->num_parents = 1;
+       girq->parents = devm_kcalloc(&pdev->dev, 1,
+                                    sizeof(*girq->parents),
+                                    GFP_KERNEL);
+       if (!girq->parents) {
+               ret = -ENOMEM;
+               goto err_pm_put;
        }
+       girq->parents[0] = gpio->irq;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
 
-       gpiochip_set_chained_irqchip(chip, &zynq_gpio_edge_irqchip, gpio->irq,
-                                    zynq_gpio_irqhandler);
+       /* report a bug if gpio chip registration fails */
+       ret = gpiochip_add_data(chip, gpio);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to add gpio chip\n");
+               goto err_pm_put;
+       }
 
        pm_runtime_put(&pdev->dev);
 
        return 0;
 
-err_rm_gpiochip:
-       gpiochip_remove(chip);
 err_pm_put:
        pm_runtime_put(&pdev->dev);
 err_pm_dis:
index 39f2f90..fdee8af 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pinctrl/pinctrl.h>
 
 #include "gpiolib.h"
+#include "gpiolib-acpi.h"
 
 /**
  * struct acpi_gpio_event - ACPI GPIO event handler data
@@ -382,6 +383,13 @@ int acpi_dev_add_driver_gpios(struct acpi_device *adev,
 }
 EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
 
+void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
+       if (adev)
+               adev->driver_gpios = NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios);
+
 static void devm_acpi_dev_release_driver_gpios(struct device *dev, void *res)
 {
        acpi_dev_remove_driver_gpios(ACPI_COMPANION(dev));
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
new file mode 100644 (file)
index 0000000..d7241b4
--- /dev/null
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ACPI helpers for GPIO API
+ *
+ * Copyright (C) 2012,2019 Intel Corporation
+ */
+
+#ifndef GPIOLIB_ACPI_H
+#define GPIOLIB_ACPI_H
+
+struct acpi_device;
+
+/**
+ * struct acpi_gpio_info - ACPI GPIO specific information
+ * @adev: reference to ACPI device which consumes GPIO resource
+ * @flags: GPIO initialization flags
+ * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
+ * @pin_config: pin bias as provided by ACPI
+ * @polarity: interrupt polarity as provided by ACPI
+ * @triggering: triggering type as provided by ACPI
+ * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
+ */
+struct acpi_gpio_info {
+       struct acpi_device *adev;
+       enum gpiod_flags flags;
+       bool gpioint;
+       int pin_config;
+       int polarity;
+       int triggering;
+       unsigned int quirks;
+};
+
+#ifdef CONFIG_ACPI
+void acpi_gpiochip_add(struct gpio_chip *chip);
+void acpi_gpiochip_remove(struct gpio_chip *chip);
+
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
+
+int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
+                                struct acpi_gpio_info *info);
+int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                       struct acpi_gpio_info *info);
+
+struct gpio_desc *acpi_find_gpio(struct device *dev,
+                                const char *con_id,
+                                unsigned int idx,
+                                enum gpiod_flags *dflags,
+                                unsigned long *lookupflags);
+struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
+                                     const char *propname, int index,
+                                     struct acpi_gpio_info *info);
+
+int acpi_gpio_count(struct device *dev, const char *con_id);
+
+bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
+#else
+static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
+static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
+
+static inline void
+acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
+
+static inline void
+acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
+
+static inline int
+acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
+{
+       return 0;
+}
+static inline int
+acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+                                   struct acpi_gpio_info *info)
+{
+       return 0;
+}
+
+static inline struct gpio_desc *
+acpi_find_gpio(struct device *dev, const char *con_id,
+              unsigned int idx, enum gpiod_flags *dflags,
+              unsigned long *lookupflags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline struct gpio_desc *
+acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
+                   int index, struct acpi_gpio_info *info)
+{
+       return ERR_PTR(-ENXIO);
+}
+static inline int acpi_gpio_count(struct device *dev, const char *con_id)
+{
+       return -ENODEV;
+}
+
+static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
+                                           const char *con_id)
+{
+       return false;
+}
+#endif
+
+#endif /* GPIOLIB_ACPI_H */
index 9762dd6..5c38ede 100644 (file)
 #include <linux/gpio/machine.h>
 
 #include "gpiolib.h"
+#include "gpiolib-of.h"
+
+/*
+ * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
+ *
+ * FIXME: get rid of those external users by converting them to GPIO
+ * descriptors and let them all use gpiod_get_count()
+ */
+int of_gpio_get_count(struct device *dev, const char *con_id)
+{
+       int ret;
+       char propname[32];
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
+               if (con_id)
+                       snprintf(propname, sizeof(propname), "%s-%s",
+                                con_id, gpio_suffixes[i]);
+               else
+                       snprintf(propname, sizeof(propname), "%s",
+                                gpio_suffixes[i]);
+
+               ret = of_gpio_named_count(dev->of_node, propname);
+               if (ret > 0)
+                       break;
+       }
+       return ret ? ret : -ENOENT;
+}
 
 static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
 {
@@ -53,6 +81,23 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
        return gpiochip_get_desc(chip, ret);
 }
 
+/**
+ * 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
+ */
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
+{
+       int size;
+       struct device_node *np = gc->of_node;
+
+       size = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
+       if (size > 0 && size % 2 == 0)
+               return true;
+       return false;
+}
+
 static void of_gpio_flags_quirks(struct device_node *np,
                                 const char *propname,
                                 enum of_gpio_flags *flags,
@@ -231,6 +276,75 @@ int of_get_named_gpio_flags(struct device_node *np, const char *list_name,
 }
 EXPORT_SYMBOL(of_get_named_gpio_flags);
 
+/**
+ * gpiod_get_from_of_node() - obtain a GPIO from an OF node
+ * @node:      handle of the OF node
+ * @propname:  name of the DT property representing the GPIO
+ * @index:     index of the GPIO to obtain for the consumer
+ * @dflags:    GPIO initialization flags
+ * @label:     label to attach to the requested GPIO
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @dflags.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label)
+{
+       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
+       struct gpio_desc *desc;
+       enum of_gpio_flags flags;
+       bool active_low = false;
+       bool single_ended = false;
+       bool open_drain = false;
+       bool transitory = false;
+       int ret;
+
+       desc = of_get_named_gpiod_flags(node, propname,
+                                       index, &flags);
+
+       if (!desc || IS_ERR(desc)) {
+               return desc;
+       }
+
+       active_low = flags & OF_GPIO_ACTIVE_LOW;
+       single_ended = flags & OF_GPIO_SINGLE_ENDED;
+       open_drain = flags & OF_GPIO_OPEN_DRAIN;
+       transitory = flags & OF_GPIO_TRANSITORY;
+
+       ret = gpiod_request(desc, label);
+       if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
+               return desc;
+       if (ret)
+               return ERR_PTR(ret);
+
+       if (active_low)
+               lflags |= GPIO_ACTIVE_LOW;
+
+       if (single_ended) {
+               if (open_drain)
+                       lflags |= GPIO_OPEN_DRAIN;
+               else
+                       lflags |= GPIO_OPEN_SOURCE;
+       }
+
+       if (transitory)
+               lflags |= GPIO_TRANSITORY;
+
+       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       if (ret < 0) {
+               gpiod_put(desc);
+               return ERR_PTR(ret);
+       }
+
+       return desc;
+}
+EXPORT_SYMBOL(gpiod_get_from_of_node);
+
 /*
  * The SPI GPIO bindings happened before we managed to establish that GPIO
  * properties should be named "foo-gpios" so we have this special kludge for
@@ -734,7 +848,7 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
 
 int of_gpiochip_add(struct gpio_chip *chip)
 {
-       int status;
+       int ret;
 
        if (!chip->of_node)
                return 0;
@@ -749,9 +863,9 @@ int of_gpiochip_add(struct gpio_chip *chip)
 
        of_gpiochip_init_valid_mask(chip);
 
-       status = of_gpiochip_add_pin_range(chip);
-       if (status)
-               return status;
+       ret = of_gpiochip_add_pin_range(chip);
+       if (ret)
+               return ret;
 
        /* If the chip defines names itself, these take precedence */
        if (!chip->names)
@@ -760,13 +874,13 @@ int of_gpiochip_add(struct gpio_chip *chip)
 
        of_node_get(chip->of_node);
 
-       status = of_gpiochip_scan_gpios(chip);
-       if (status) {
+       ret = of_gpiochip_scan_gpios(chip);
+       if (ret) {
                of_node_put(chip->of_node);
                gpiochip_remove_pin_ranges(chip);
        }
 
-       return status;
+       return ret;
 }
 
 void of_gpiochip_remove(struct gpio_chip *chip)
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
new file mode 100644 (file)
index 0000000..454d165
--- /dev/null
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef GPIOLIB_OF_H
+#define GPIOLIB_OF_H
+
+struct gpio_chip;
+enum of_gpio_flags;
+
+#ifdef CONFIG_OF_GPIO
+struct gpio_desc *of_find_gpio(struct device *dev,
+                              const char *con_id,
+                              unsigned int idx,
+                              unsigned long *lookupflags);
+struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+                  const char *list_name, int index, enum of_gpio_flags *flags);
+int of_gpiochip_add(struct gpio_chip *gc);
+void of_gpiochip_remove(struct gpio_chip *gc);
+int of_gpio_get_count(struct device *dev, const char *con_id);
+bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
+#else
+static inline struct gpio_desc *of_find_gpio(struct device *dev,
+                                            const char *con_id,
+                                            unsigned int idx,
+                                            unsigned long *lookupflags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
+                  const char *list_name, int index, enum of_gpio_flags *flags)
+{
+       return ERR_PTR(-ENOENT);
+}
+static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
+static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
+static inline int of_gpio_get_count(struct device *dev, const char *con_id)
+{
+       return 0;
+}
+static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
+{
+       return false;
+}
+#endif /* CONFIG_OF_GPIO */
+
+#endif /* GPIOLIB_OF_H */
index cca7490..5b351f8 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/gpio.h>
-#include <linux/of_gpio.h>
 #include <linux/idr.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
@@ -30,6 +29,8 @@
 #include <uapi/linux/gpio.h>
 
 #include "gpiolib.h"
+#include "gpiolib-of.h"
+#include "gpiolib-acpi.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/gpio.h>
@@ -213,7 +214,7 @@ int gpiod_get_direction(struct gpio_desc *desc)
 {
        struct gpio_chip *chip;
        unsigned offset;
-       int status;
+       int ret;
 
        chip = gpiod_to_chip(desc);
        offset = gpio_chip_hwgpio(desc);
@@ -221,17 +222,17 @@ int gpiod_get_direction(struct gpio_desc *desc)
        if (!chip->get_direction)
                return -ENOTSUPP;
 
-       status = chip->get_direction(chip, offset);
-       if (status > 0) {
+       ret = chip->get_direction(chip, offset);
+       if (ret > 0) {
                /* GPIOF_DIR_IN, or other positive */
-               status = 1;
+               ret = 1;
                clear_bit(FLAG_IS_OUT, &desc->flags);
        }
-       if (status == 0) {
+       if (ret == 0) {
                /* GPIOF_DIR_OUT */
                set_bit(FLAG_IS_OUT, &desc->flags);
        }
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiod_get_direction);
 
@@ -350,7 +351,7 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
 {
        unsigned long *p;
 
-       p = kmalloc_array(BITS_TO_LONGS(chip->ngpio), sizeof(*p), GFP_KERNEL);
+       p = bitmap_alloc(chip->ngpio, GFP_KERNEL);
        if (!p)
                return NULL;
 
@@ -360,38 +361,31 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *chip)
        return p;
 }
 
-static int gpiochip_alloc_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
 {
-#ifdef CONFIG_OF_GPIO
-       int size;
-       struct device_node *np = gpiochip->of_node;
-
-       size = of_property_count_u32_elems(np,  "gpio-reserved-ranges");
-       if (size > 0 && size % 2 == 0)
-               gpiochip->need_valid_mask = true;
-#endif
-
-       if (!gpiochip->need_valid_mask)
+       if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask))
                return 0;
 
-       gpiochip->valid_mask = gpiochip_allocate_mask(gpiochip);
-       if (!gpiochip->valid_mask)
+       gc->valid_mask = gpiochip_allocate_mask(gc);
+       if (!gc->valid_mask)
                return -ENOMEM;
 
        return 0;
 }
 
-static int gpiochip_init_valid_mask(struct gpio_chip *gpiochip)
+static int gpiochip_init_valid_mask(struct gpio_chip *gc)
 {
-       if (gpiochip->init_valid_mask)
-               return gpiochip->init_valid_mask(gpiochip);
+       if (gc->init_valid_mask)
+               return gc->init_valid_mask(gc,
+                                          gc->valid_mask,
+                                          gc->ngpio);
 
        return 0;
 }
 
 static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-       kfree(gpiochip->valid_mask);
+       bitmap_free(gpiochip->valid_mask);
        gpiochip->valid_mask = NULL;
 }
 
@@ -1176,21 +1170,21 @@ static void gpiodevice_release(struct device *dev)
 
 static int gpiochip_setup_dev(struct gpio_device *gdev)
 {
-       int status;
+       int ret;
 
        cdev_init(&gdev->chrdev, &gpio_fileops);
        gdev->chrdev.owner = THIS_MODULE;
        gdev->dev.devt = MKDEV(MAJOR(gpio_devt), gdev->id);
 
-       status = cdev_device_add(&gdev->chrdev, &gdev->dev);
-       if (status)
-               return status;
+       ret = cdev_device_add(&gdev->chrdev, &gdev->dev);
+       if (ret)
+               return ret;
 
        chip_dbg(gdev->chip, "added GPIO chardev (%d:%d)\n",
                 MAJOR(gpio_devt), gdev->id);
 
-       status = gpiochip_sysfs_register(gdev);
-       if (status)
+       ret = gpiochip_sysfs_register(gdev);
+       if (ret)
                goto err_remove_device;
 
        /* From this point, the .release() function cleans up gpio_device */
@@ -1203,7 +1197,7 @@ static int gpiochip_setup_dev(struct gpio_device *gdev)
 
 err_remove_device:
        cdev_device_del(&gdev->chrdev, &gdev->dev);
-       return status;
+       return ret;
 }
 
 static void gpiochip_machine_hog(struct gpio_chip *chip, struct gpiod_hog *hog)
@@ -1244,13 +1238,13 @@ static void machine_gpiochip_add(struct gpio_chip *chip)
 static void gpiochip_setup_devs(void)
 {
        struct gpio_device *gdev;
-       int err;
+       int ret;
 
        list_for_each_entry(gdev, &gpio_devices, list) {
-               err = gpiochip_setup_dev(gdev);
-               if (err)
+               ret = gpiochip_setup_dev(gdev);
+               if (ret)
                        pr_err("%s: Failed to initialize gpio device (%d)\n",
-                              dev_name(&gdev->dev), err);
+                              dev_name(&gdev->dev), ret);
        }
 }
 
@@ -1259,7 +1253,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
                               struct lock_class_key *request_key)
 {
        unsigned long   flags;
-       int             status = 0;
+       int             ret = 0;
        unsigned        i;
        int             base = chip->base;
        struct gpio_device *gdev;
@@ -1289,7 +1283,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->id = ida_simple_get(&gpio_ida, 0, 0, GFP_KERNEL);
        if (gdev->id < 0) {
-               status = gdev->id;
+               ret = gdev->id;
                goto err_free_gdev;
        }
        dev_set_name(&gdev->dev, "gpiochip%d", gdev->id);
@@ -1305,13 +1299,13 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->descs = kcalloc(chip->ngpio, sizeof(gdev->descs[0]), GFP_KERNEL);
        if (!gdev->descs) {
-               status = -ENOMEM;
+               ret = -ENOMEM;
                goto err_free_ida;
        }
 
        if (chip->ngpio == 0) {
                chip_err(chip, "tried to insert a GPIO chip with zero lines\n");
-               status = -EINVAL;
+               ret = -EINVAL;
                goto err_free_descs;
        }
 
@@ -1321,7 +1315,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL);
        if (!gdev->label) {
-               status = -ENOMEM;
+               ret = -ENOMEM;
                goto err_free_descs;
        }
 
@@ -1340,7 +1334,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        if (base < 0) {
                base = gpiochip_find_base(chip->ngpio);
                if (base < 0) {
-                       status = base;
+                       ret = base;
                        spin_unlock_irqrestore(&gpio_lock, flags);
                        goto err_free_label;
                }
@@ -1354,8 +1348,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        }
        gdev->base = base;
 
-       status = gpiodev_add_to_list(gdev);
-       if (status) {
+       ret = gpiodev_add_to_list(gdev);
+       if (ret) {
                spin_unlock_irqrestore(&gpio_lock, flags);
                goto err_free_label;
        }
@@ -1369,20 +1363,20 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
        INIT_LIST_HEAD(&gdev->pin_ranges);
 #endif
 
-       status = gpiochip_set_desc_names(chip);
-       if (status)
+       ret = gpiochip_set_desc_names(chip);
+       if (ret)
                goto err_remove_from_list;
 
-       status = gpiochip_alloc_valid_mask(chip);
-       if (status)
+       ret = gpiochip_alloc_valid_mask(chip);
+       if (ret)
                goto err_remove_from_list;
 
-       status = of_gpiochip_add(chip);
-       if (status)
+       ret = of_gpiochip_add(chip);
+       if (ret)
                goto err_free_gpiochip_mask;
 
-       status = gpiochip_init_valid_mask(chip);
-       if (status)
+       ret = gpiochip_init_valid_mask(chip);
+       if (ret)
                goto err_remove_of_chip;
 
        for (i = 0; i < chip->ngpio; i++) {
@@ -1422,8 +1416,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
         * Otherwise, defer until later.
         */
        if (gpiolib_initialized) {
-               status = gpiochip_setup_dev(gdev);
-               if (status)
+               ret = gpiochip_setup_dev(gdev);
+               if (ret)
                        goto err_remove_irqchip;
        }
        return 0;
@@ -1453,9 +1447,9 @@ err_free_gdev:
        /* failures here can mean systems won't boot... */
        pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
               gdev->base, gdev->base + gdev->ngpio - 1,
-              chip->label ? : "generic", status);
+              chip->label ? : "generic", ret);
        kfree(gdev);
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key);
 
@@ -1635,7 +1629,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-       kfree(gpiochip->irq.valid_mask);
+       bitmap_free(gpiochip->irq.valid_mask);
        gpiochip->irq.valid_mask = NULL;
 }
 
@@ -1735,6 +1729,273 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
 
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+
+/**
+ * gpiochip_set_hierarchical_irqchip() - connects a hierarchical irqchip
+ * to a gpiochip
+ * @gc: the gpiochip to set the irqchip hierarchical handler to
+ * @irqchip: the irqchip to handle this level of the hierarchy, the interrupt
+ * will then percolate up to the parent
+ */
+static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
+                                             struct irq_chip *irqchip)
+{
+       /* DT will deal with mapping each IRQ as we go along */
+       if (is_of_node(gc->irq.fwnode))
+               return;
+
+       /*
+        * This is for legacy and boardfile "irqchip" fwnodes: allocate
+        * irqs upfront instead of dynamically since we don't have the
+        * dynamic type of allocation that hardware description languages
+        * provide. Once all GPIO drivers using board files are gone from
+        * the kernel we can delete this code, but for a transitional period
+        * it is necessary to keep this around.
+        */
+       if (is_fwnode_irqchip(gc->irq.fwnode)) {
+               int i;
+               int ret;
+
+               for (i = 0; i < gc->ngpio; i++) {
+                       struct irq_fwspec fwspec;
+                       unsigned int parent_hwirq;
+                       unsigned int parent_type;
+                       struct gpio_irq_chip *girq = &gc->irq;
+
+                       /*
+                        * We call the child to parent translation function
+                        * only to check if the child IRQ is valid or not.
+                        * Just pick the rising edge type here as that is what
+                        * we likely need to support.
+                        */
+                       ret = girq->child_to_parent_hwirq(gc, i,
+                                                         IRQ_TYPE_EDGE_RISING,
+                                                         &parent_hwirq,
+                                                         &parent_type);
+                       if (ret) {
+                               chip_err(gc, "skip set-up on hwirq %d\n",
+                                        i);
+                               continue;
+                       }
+
+                       fwspec.fwnode = gc->irq.fwnode;
+                       /* This is the hwirq for the GPIO line side of things */
+                       fwspec.param[0] = girq->child_offset_to_irq(gc, i);
+                       /* Just pick something */
+                       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
+                       fwspec.param_count = 2;
+                       ret = __irq_domain_alloc_irqs(gc->irq.domain,
+                                                     /* just pick something */
+                                                     -1,
+                                                     1,
+                                                     NUMA_NO_NODE,
+                                                     &fwspec,
+                                                     false,
+                                                     NULL);
+                       if (ret < 0) {
+                               chip_err(gc,
+                                        "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
+                                        i, parent_hwirq,
+                                        ret);
+                       }
+               }
+       }
+
+       chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__);
+
+       return;
+}
+
+static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d,
+                                                  struct irq_fwspec *fwspec,
+                                                  unsigned long *hwirq,
+                                                  unsigned int *type)
+{
+       /* We support standard DT translation */
+       if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
+               return irq_domain_translate_twocell(d, fwspec, hwirq, type);
+       }
+
+       /* This is for board files and others not using DT */
+       if (is_fwnode_irqchip(fwspec->fwnode)) {
+               int ret;
+
+               ret = irq_domain_translate_twocell(d, fwspec, hwirq, type);
+               if (ret)
+                       return ret;
+               WARN_ON(*type == IRQ_TYPE_NONE);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
+                                              unsigned int irq,
+                                              unsigned int nr_irqs,
+                                              void *data)
+{
+       struct gpio_chip *gc = d->host_data;
+       irq_hw_number_t hwirq;
+       unsigned int type = IRQ_TYPE_NONE;
+       struct irq_fwspec *fwspec = data;
+       struct irq_fwspec parent_fwspec;
+       unsigned int parent_hwirq;
+       unsigned int parent_type;
+       struct gpio_irq_chip *girq = &gc->irq;
+       int ret;
+
+       /*
+        * The nr_irqs parameter is always one except for PCI multi-MSI
+        * so this should not happen.
+        */
+       WARN_ON(nr_irqs != 1);
+
+       ret = gc->irq.child_irq_domain_ops.translate(d, fwspec, &hwirq, &type);
+       if (ret)
+               return ret;
+
+       chip_info(gc, "allocate IRQ %d, hwirq %lu\n", irq,  hwirq);
+
+       ret = girq->child_to_parent_hwirq(gc, hwirq, type,
+                                         &parent_hwirq, &parent_type);
+       if (ret) {
+               chip_err(gc, "can't look up hwirq %lu\n", hwirq);
+               return ret;
+       }
+       chip_info(gc, "found parent hwirq %u\n", parent_hwirq);
+
+       /*
+        * We set handle_bad_irq because the .set_type() should
+        * always be invoked and set the right type of handler.
+        */
+       irq_domain_set_info(d,
+                           irq,
+                           hwirq,
+                           gc->irq.chip,
+                           gc,
+                           girq->handler,
+                           NULL, NULL);
+       irq_set_probe(irq);
+
+       /*
+        * Create a IRQ fwspec to send up to the parent irqdomain:
+        * specify the hwirq we address on the parent and tie it
+        * all together up the chain.
+        */
+       parent_fwspec.fwnode = d->parent->fwnode;
+       /* This parent only handles asserted level IRQs */
+       girq->populate_parent_fwspec(gc, &parent_fwspec, parent_hwirq,
+                                    parent_type);
+       chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
+                 irq, parent_hwirq);
+       ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec);
+       if (ret)
+               chip_err(gc,
+                        "failed to allocate parent hwirq %d for hwirq %lu\n",
+                        parent_hwirq, hwirq);
+
+       return ret;
+}
+
+static unsigned int gpiochip_child_offset_to_irq_noop(struct gpio_chip *chip,
+                                                     unsigned int offset)
+{
+       return offset;
+}
+
+static void gpiochip_hierarchy_setup_domain_ops(struct irq_domain_ops *ops)
+{
+       ops->activate = gpiochip_irq_domain_activate;
+       ops->deactivate = gpiochip_irq_domain_deactivate;
+       ops->alloc = gpiochip_hierarchy_irq_domain_alloc;
+       ops->free = irq_domain_free_irqs_common;
+
+       /*
+        * We only allow overriding the translate() function for
+        * hierarchical chips, and this should only be done if the user
+        * really need something other than 1:1 translation.
+        */
+       if (!ops->translate)
+               ops->translate = gpiochip_hierarchy_irq_domain_translate;
+}
+
+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+{
+       if (!gc->irq.child_to_parent_hwirq ||
+           !gc->irq.fwnode) {
+               chip_err(gc, "missing irqdomain vital data\n");
+               return -EINVAL;
+       }
+
+       if (!gc->irq.child_offset_to_irq)
+               gc->irq.child_offset_to_irq = gpiochip_child_offset_to_irq_noop;
+
+       if (!gc->irq.populate_parent_fwspec)
+               gc->irq.populate_parent_fwspec =
+                       gpiochip_populate_parent_fwspec_twocell;
+
+       gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops);
+
+       gc->irq.domain = irq_domain_create_hierarchy(
+               gc->irq.parent_domain,
+               0,
+               gc->ngpio,
+               gc->irq.fwnode,
+               &gc->irq.child_irq_domain_ops,
+               gc);
+
+       if (!gc->irq.domain)
+               return -ENOMEM;
+
+       gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip);
+
+       return 0;
+}
+
+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
+{
+       return !!gc->irq.parent_domain;
+}
+
+void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                            struct irq_fwspec *fwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type)
+{
+       fwspec->param_count = 2;
+       fwspec->param[0] = parent_hwirq;
+       fwspec->param[1] = parent_type;
+}
+EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell);
+
+void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                             struct irq_fwspec *fwspec,
+                                             unsigned int parent_hwirq,
+                                             unsigned int parent_type)
+{
+       fwspec->param_count = 4;
+       fwspec->param[0] = 0;
+       fwspec->param[1] = parent_hwirq;
+       fwspec->param[2] = 0;
+       fwspec->param[3] = parent_type;
+}
+EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell);
+
+#else
+
+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+{
+       return -EINVAL;
+}
+
+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
+{
+       return false;
+}
+
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
+
 /**
  * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
  * @d: the irqdomain used by this irqchip
@@ -1749,7 +2010,7 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq)
 {
        struct gpio_chip *chip = d->host_data;
-       int err = 0;
+       int ret = 0;
 
        if (!gpiochip_irqchip_irq_valid(chip, hwirq))
                return -ENXIO;
@@ -1767,12 +2028,12 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
        irq_set_noprobe(irq);
 
        if (chip->irq.num_parents == 1)
-               err = irq_set_parent(irq, chip->irq.parents[0]);
+               ret = irq_set_parent(irq, chip->irq.parents[0]);
        else if (chip->irq.map)
-               err = irq_set_parent(irq, chip->irq.map[hwirq]);
+               ret = irq_set_parent(irq, chip->irq.map[hwirq]);
 
-       if (err < 0)
-               return err;
+       if (ret < 0)
+               return ret;
 
        /*
         * No set-up of the hardware will happen if IRQ_TYPE_NONE
@@ -1803,6 +2064,11 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
+/*
+ * TODO: move these activate/deactivate in under the hierarchicial
+ * irqchip implementation as static once SPMI and SSBI (all external
+ * users) are phased over.
+ */
 /**
  * gpiochip_irq_domain_activate() - Lock a GPIO to be used as an IRQ
  * @domain: The IRQ domain used by this IRQ chip
@@ -1842,10 +2108,25 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+       struct irq_domain *domain = chip->irq.domain;
+
        if (!gpiochip_irqchip_irq_valid(chip, offset))
                return -ENXIO;
 
-       return irq_create_mapping(chip->irq.domain, offset);
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       if (irq_domain_is_hierarchy(domain)) {
+               struct irq_fwspec spec;
+
+               spec.fwnode = domain->fwnode;
+               spec.param_count = 2;
+               spec.param[0] = chip->irq.child_offset_to_irq(chip, offset);
+               spec.param[1] = IRQ_TYPE_NONE;
+
+               return irq_create_fwspec_mapping(&spec);
+       }
+#endif
+
+       return irq_create_mapping(domain, offset);
 }
 
 static int gpiochip_irq_reqres(struct irq_data *d)
@@ -1922,7 +2203,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
                                struct lock_class_key *request_key)
 {
        struct irq_chip *irqchip = gpiochip->irq.chip;
-       const struct irq_domain_ops *ops;
+       const struct irq_domain_ops *ops = NULL;
        struct device_node *np;
        unsigned int type;
        unsigned int i;
@@ -1958,16 +2239,25 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
        gpiochip->irq.lock_key = lock_key;
        gpiochip->irq.request_key = request_key;
 
-       if (gpiochip->irq.domain_ops)
-               ops = gpiochip->irq.domain_ops;
-       else
-               ops = &gpiochip_domain_ops;
-
-       gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-                                                    gpiochip->irq.first,
-                                                    ops, gpiochip);
-       if (!gpiochip->irq.domain)
-               return -EINVAL;
+       /* If a parent irqdomain is provided, let's build a hierarchy */
+       if (gpiochip_hierarchy_is_hierarchical(gpiochip)) {
+               int ret = gpiochip_hierarchy_add_domain(gpiochip);
+               if (ret)
+                       return ret;
+       } else {
+               /* Some drivers provide custom irqdomain ops */
+               if (gpiochip->irq.domain_ops)
+                       ops = gpiochip->irq.domain_ops;
+
+               if (!ops)
+                       ops = &gpiochip_domain_ops;
+               gpiochip->irq.domain = irq_domain_add_simple(np,
+                       gpiochip->ngpio,
+                       gpiochip->irq.first,
+                       ops, gpiochip);
+               if (!gpiochip->irq.domain)
+                       return -EINVAL;
+       }
 
        if (gpiochip->irq.parent_handler) {
                void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
@@ -2330,7 +2620,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
 static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 {
        struct gpio_chip        *chip = desc->gdev->chip;
-       int                     status;
+       int                     ret;
        unsigned long           flags;
        unsigned                offset;
 
@@ -2348,10 +2638,10 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
 
        if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
                desc_set_label(desc, label ? : "?");
-               status = 0;
+               ret = 0;
        } else {
                kfree_const(label);
-               status = -EBUSY;
+               ret = -EBUSY;
                goto done;
        }
 
@@ -2360,12 +2650,12 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
                spin_unlock_irqrestore(&gpio_lock, flags);
                offset = gpio_chip_hwgpio(desc);
                if (gpiochip_line_is_valid(chip, offset))
-                       status = chip->request(chip, offset);
+                       ret = chip->request(chip, offset);
                else
-                       status = -EINVAL;
+                       ret = -EINVAL;
                spin_lock_irqsave(&gpio_lock, flags);
 
-               if (status < 0) {
+               if (ret < 0) {
                        desc_set_label(desc, NULL);
                        kfree_const(label);
                        clear_bit(FLAG_REQUESTED, &desc->flags);
@@ -2380,7 +2670,7 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
        }
 done:
        spin_unlock_irqrestore(&gpio_lock, flags);
-       return status;
+       return ret;
 }
 
 /*
@@ -2423,24 +2713,24 @@ static int validate_desc(const struct gpio_desc *desc, const char *func)
 
 int gpiod_request(struct gpio_desc *desc, const char *label)
 {
-       int status = -EPROBE_DEFER;
+       int ret = -EPROBE_DEFER;
        struct gpio_device *gdev;
 
        VALIDATE_DESC(desc);
        gdev = desc->gdev;
 
        if (try_module_get(gdev->owner)) {
-               status = gpiod_request_commit(desc, label);
-               if (status < 0)
+               ret = gpiod_request_commit(desc, label);
+               if (ret < 0)
                        module_put(gdev->owner);
                else
                        get_device(&gdev->dev);
        }
 
-       if (status)
-               gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       if (ret)
+               gpiod_dbg(desc, "%s: status %d\n", __func__, ret);
 
-       return status;
+       return ret;
 }
 
 static bool gpiod_free_commit(struct gpio_desc *desc)
@@ -2542,22 +2832,22 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum,
                                            enum gpiod_flags dflags)
 {
        struct gpio_desc *desc = gpiochip_get_desc(chip, hwnum);
-       int err;
+       int ret;
 
        if (IS_ERR(desc)) {
                chip_err(chip, "failed to get GPIO descriptor\n");
                return desc;
        }
 
-       err = gpiod_request_commit(desc, label);
-       if (err < 0)
-               return ERR_PTR(err);
+       ret = gpiod_request_commit(desc, label);
+       if (ret < 0)
+               return ERR_PTR(ret);
 
-       err = gpiod_configure_flags(desc, label, lflags, dflags);
-       if (err) {
+       ret = gpiod_configure_flags(desc, label, lflags, dflags);
+       if (ret) {
                chip_err(chip, "setup of own GPIO %s failed\n", label);
                gpiod_free_commit(desc);
-               return ERR_PTR(err);
+               return ERR_PTR(ret);
        }
 
        return desc;
@@ -2620,7 +2910,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
 int gpiod_direction_input(struct gpio_desc *desc)
 {
        struct gpio_chip        *chip;
-       int                     status = 0;
+       int                     ret = 0;
 
        VALIDATE_DESC(desc);
        chip = desc->gdev->chip;
@@ -2644,7 +2934,7 @@ int gpiod_direction_input(struct gpio_desc *desc)
         * assume we are in input mode after this.
         */
        if (chip->direction_input) {
-               status = chip->direction_input(chip, gpio_chip_hwgpio(desc));
+               ret = chip->direction_input(chip, gpio_chip_hwgpio(desc));
        } else if (chip->get_direction &&
                  (chip->get_direction(chip, gpio_chip_hwgpio(desc)) != 1)) {
                gpiod_warn(desc,
@@ -2652,7 +2942,7 @@ int gpiod_direction_input(struct gpio_desc *desc)
                           __func__);
                return -EIO;
        }
-       if (status == 0)
+       if (ret == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
        if (test_bit(FLAG_PULL_UP, &desc->flags))
@@ -2662,9 +2952,9 @@ int gpiod_direction_input(struct gpio_desc *desc)
                gpio_set_config(chip, gpio_chip_hwgpio(desc),
                                PIN_CONFIG_BIAS_PULL_DOWN);
 
-       trace_gpio_direction(desc_to_gpio(desc), 1, status);
+       trace_gpio_direction(desc_to_gpio(desc), 1, ret);
 
-       return status;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
@@ -2936,7 +3226,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                                  struct gpio_array *array_info,
                                  unsigned long *value_bitmap)
 {
-       int err, i = 0;
+       int ret, i = 0;
 
        /*
         * Validate array_info against desc_array and its size.
@@ -2949,11 +3239,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
                if (!can_sleep)
                        WARN_ON(array_info->chip->can_sleep);
 
-               err = gpio_chip_get_multiple(array_info->chip,
+               ret = gpio_chip_get_multiple(array_info->chip,
                                             array_info->get_mask,
                                             value_bitmap);
-               if (err)
-                       return err;
+               if (ret)
+                       return ret;
 
                if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
                        bitmap_xor(value_bitmap, value_bitmap,
@@ -3141,24 +3431,24 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value);
  */
 static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
 {
-       int err = 0;
+       int ret = 0;
        struct gpio_chip *chip = desc->gdev->chip;
        int offset = gpio_chip_hwgpio(desc);
 
        if (value) {
-               err = chip->direction_input(chip, offset);
-               if (!err)
+               ret = chip->direction_input(chip, offset);
+               if (!ret)
                        clear_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_output(chip, offset, 0);
-               if (!err)
+               ret = chip->direction_output(chip, offset, 0);
+               if (!ret)
                        set_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(desc_to_gpio(desc), value, err);
-       if (err < 0)
+       trace_gpio_direction(desc_to_gpio(desc), value, ret);
+       if (ret < 0)
                gpiod_err(desc,
                          "%s: Error in set_value for open drain err %d\n",
-                         __func__, err);
+                         __func__, ret);
 }
 
 /*
@@ -3168,24 +3458,24 @@ static void gpio_set_open_drain_value_commit(struct gpio_desc *desc, bool value)
  */
 static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value)
 {
-       int err = 0;
+       int ret = 0;
        struct gpio_chip *chip = desc->gdev->chip;
        int offset = gpio_chip_hwgpio(desc);
 
        if (value) {
-               err = chip->direction_output(chip, offset, 1);
-               if (!err)
+               ret = chip->direction_output(chip, offset, 1);
+               if (!ret)
                        set_bit(FLAG_IS_OUT, &desc->flags);
        } else {
-               err = chip->direction_input(chip, offset);
-               if (!err)
+               ret = chip->direction_input(chip, offset);
+               if (!ret)
                        clear_bit(FLAG_IS_OUT, &desc->flags);
        }
-       trace_gpio_direction(desc_to_gpio(desc), !value, err);
-       if (err < 0)
+       trace_gpio_direction(desc_to_gpio(desc), !value, ret);
+       if (ret < 0)
                gpiod_err(desc,
                          "%s: Error in set_value for open source err %d\n",
-                         __func__, err);
+                         __func__, ret);
 }
 
 static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
@@ -4002,27 +4292,6 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
        return desc;
 }
 
-static int dt_gpio_count(struct device *dev, const char *con_id)
-{
-       int ret;
-       char propname[32];
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(propname, sizeof(propname), "%s-%s",
-                                con_id, gpio_suffixes[i]);
-               else
-                       snprintf(propname, sizeof(propname), "%s",
-                                gpio_suffixes[i]);
-
-               ret = of_gpio_named_count(dev->of_node, propname);
-               if (ret > 0)
-                       break;
-       }
-       return ret ? ret : -ENOENT;
-}
-
 static int platform_gpio_count(struct device *dev, const char *con_id)
 {
        struct gpiod_lookup_table *table;
@@ -4055,7 +4324,7 @@ int gpiod_count(struct device *dev, const char *con_id)
        int count = -ENOENT;
 
        if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
-               count = dt_gpio_count(dev, con_id);
+               count = of_gpio_get_count(dev, con_id);
        else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
                count = acpi_gpio_count(dev, con_id);
 
@@ -4117,7 +4386,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_optional);
 int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
                unsigned long lflags, enum gpiod_flags dflags)
 {
-       int status;
+       int ret;
 
        if (lflags & GPIO_ACTIVE_LOW)
                set_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -4150,9 +4419,9 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
        else if (lflags & GPIO_PULL_DOWN)
                set_bit(FLAG_PULL_DOWN, &desc->flags);
 
-       status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
-       if (status < 0)
-               return status;
+       ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
+       if (ret < 0)
+               return ret;
 
        /* No particular flag request, return here... */
        if (!(dflags & GPIOD_FLAGS_BIT_DIR_SET)) {
@@ -4162,12 +4431,12 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
 
        /* Process flags */
        if (dflags & GPIOD_FLAGS_BIT_DIR_OUT)
-               status = gpiod_direction_output(desc,
+               ret = gpiod_direction_output(desc,
                                !!(dflags & GPIOD_FLAGS_BIT_DIR_VAL));
        else
-               status = gpiod_direction_input(desc);
+               ret = gpiod_direction_input(desc);
 
-       return status;
+       return ret;
 }
 
 /**
@@ -4191,7 +4460,7 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
 {
        unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
        struct gpio_desc *desc = NULL;
-       int status;
+       int ret;
        /* Maybe we have a device name, maybe not */
        const char *devname = dev ? dev_name(dev) : "?";
 
@@ -4226,9 +4495,9 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
         * If a connection label was passed use that, else attempt to use
         * the device name as label
         */
-       status = gpiod_request(desc, con_id ? con_id : devname);
-       if (status < 0) {
-               if (status == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
+       ret = gpiod_request(desc, con_id ? con_id : devname);
+       if (ret < 0) {
+               if (ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE) {
                        /*
                         * This happens when there are several consumers for
                         * the same GPIO line: we just return here without
@@ -4241,89 +4510,20 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
                                 con_id ? con_id : devname);
                        return desc;
                } else {
-                       return ERR_PTR(status);
+                       return ERR_PTR(ret);
                }
        }
 
-       status = gpiod_configure_flags(desc, con_id, lookupflags, flags);
-       if (status < 0) {
-               dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
-               gpiod_put(desc);
-               return ERR_PTR(status);
-       }
-
-       return desc;
-}
-EXPORT_SYMBOL_GPL(gpiod_get_index);
-
-/**
- * gpiod_get_from_of_node() - obtain a GPIO from an OF node
- * @node:      handle of the OF node
- * @propname:  name of the DT property representing the GPIO
- * @index:     index of the GPIO to obtain for the consumer
- * @dflags:    GPIO initialization flags
- * @label:     label to attach to the requested GPIO
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label)
-{
-       unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
-       struct gpio_desc *desc;
-       enum of_gpio_flags flags;
-       bool active_low = false;
-       bool single_ended = false;
-       bool open_drain = false;
-       bool transitory = false;
-       int ret;
-
-       desc = of_get_named_gpiod_flags(node, propname,
-                                       index, &flags);
-
-       if (!desc || IS_ERR(desc)) {
-               return desc;
-       }
-
-       active_low = flags & OF_GPIO_ACTIVE_LOW;
-       single_ended = flags & OF_GPIO_SINGLE_ENDED;
-       open_drain = flags & OF_GPIO_OPEN_DRAIN;
-       transitory = flags & OF_GPIO_TRANSITORY;
-
-       ret = gpiod_request(desc, label);
-       if (ret == -EBUSY && (flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
-               return desc;
-       if (ret)
-               return ERR_PTR(ret);
-
-       if (active_low)
-               lflags |= GPIO_ACTIVE_LOW;
-
-       if (single_ended) {
-               if (open_drain)
-                       lflags |= GPIO_OPEN_DRAIN;
-               else
-                       lflags |= GPIO_OPEN_SOURCE;
-       }
-
-       if (transitory)
-               lflags |= GPIO_TRANSITORY;
-
-       ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+       ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
        if (ret < 0) {
+               dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
                gpiod_put(desc);
                return ERR_PTR(ret);
        }
 
        return desc;
 }
-EXPORT_SYMBOL(gpiod_get_from_of_node);
+EXPORT_SYMBOL_GPL(gpiod_get_index);
 
 /**
  * fwnode_get_named_gpiod - obtain a GPIO from firmware node
@@ -4433,7 +4633,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
        struct gpio_chip *chip;
        struct gpio_desc *local_desc;
        int hwnum;
-       int status;
+       int ret;
 
        chip = gpiod_to_chip(desc);
        hwnum = gpio_chip_hwgpio(desc);
@@ -4441,10 +4641,10 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
        local_desc = gpiochip_request_own_desc(chip, hwnum, name,
                                               lflags, dflags);
        if (IS_ERR(local_desc)) {
-               status = PTR_ERR(local_desc);
+               ret = PTR_ERR(local_desc);
                pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
-                      name, chip->label, hwnum, status);
-               return status;
+                      name, chip->label, hwnum, ret);
+               return ret;
        }
 
        /* Mark GPIO as hogged so it can be identified and removed later */
index 7c52c24..b8b10a4 100644 (file)
@@ -16,9 +16,6 @@
 #include <linux/module.h>
 #include <linux/cdev.h>
 
-enum of_gpio_flags;
-struct acpi_device;
-
 /**
  * struct gpio_device - internal state container for GPIO devices
  * @id: numerical ID number for the GPIO chip
@@ -69,126 +66,9 @@ struct gpio_device {
 #endif
 };
 
-/**
- * struct acpi_gpio_info - ACPI GPIO specific information
- * @adev: reference to ACPI device which consumes GPIO resource
- * @flags: GPIO initialization flags
- * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
- * @pin_config: pin bias as provided by ACPI
- * @polarity: interrupt polarity as provided by ACPI
- * @triggering: triggering type as provided by ACPI
- * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
- */
-struct acpi_gpio_info {
-       struct acpi_device *adev;
-       enum gpiod_flags flags;
-       bool gpioint;
-       int pin_config;
-       int polarity;
-       int triggering;
-       unsigned int quirks;
-};
-
 /* gpio suffixes used for ACPI and device tree lookup */
 static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
 
-#ifdef CONFIG_OF_GPIO
-struct gpio_desc *of_find_gpio(struct device *dev,
-                              const char *con_id,
-                              unsigned int idx,
-                              unsigned long *lookupflags);
-struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
-                  const char *list_name, int index, enum of_gpio_flags *flags);
-int of_gpiochip_add(struct gpio_chip *gc);
-void of_gpiochip_remove(struct gpio_chip *gc);
-#else
-static inline struct gpio_desc *of_find_gpio(struct device *dev,
-                                            const char *con_id,
-                                            unsigned int idx,
-                                            unsigned long *lookupflags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
-                  const char *list_name, int index, enum of_gpio_flags *flags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
-static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
-#endif /* CONFIG_OF_GPIO */
-
-#ifdef CONFIG_ACPI
-void acpi_gpiochip_add(struct gpio_chip *chip);
-void acpi_gpiochip_remove(struct gpio_chip *chip);
-
-void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
-void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-
-int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
-                                struct acpi_gpio_info *info);
-int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
-                                       struct acpi_gpio_info *info);
-
-struct gpio_desc *acpi_find_gpio(struct device *dev,
-                                const char *con_id,
-                                unsigned int idx,
-                                enum gpiod_flags *dflags,
-                                unsigned long *lookupflags);
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
-                                     const char *propname, int index,
-                                     struct acpi_gpio_info *info);
-
-int acpi_gpio_count(struct device *dev, const char *con_id);
-
-bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
-#else
-static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
-static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
-
-static inline void
-acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
-
-static inline void
-acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
-
-static inline int
-acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
-{
-       return 0;
-}
-static inline int
-acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
-                                   struct acpi_gpio_info *info)
-{
-       return 0;
-}
-
-static inline struct gpio_desc *
-acpi_find_gpio(struct device *dev, const char *con_id,
-              unsigned int idx, enum gpiod_flags *dflags,
-              unsigned long *lookupflags)
-{
-       return ERR_PTR(-ENOENT);
-}
-static inline struct gpio_desc *
-acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
-                   int index, struct acpi_gpio_info *info)
-{
-       return ERR_PTR(-ENXIO);
-}
-static inline int acpi_gpio_count(struct device *dev, const char *con_id)
-{
-       return -ENODEV;
-}
-
-static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
-                                           const char *con_id)
-{
-       return false;
-}
-#endif
-
 struct gpio_array {
        struct gpio_desc        **desc;
        unsigned int            size;
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.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 d3332da..dd5aa9a 100644 (file)
@@ -585,12 +585,24 @@ static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl)
        return stmfx_function_enable(pctl->stmfx, func);
 }
 
+static int stmfx_pinctrl_gpio_init_valid_mask(struct gpio_chip *gc,
+                                             unsigned long *valid_mask,
+                                             unsigned int ngpios)
+{
+       struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
+       u32 n;
+
+       for_each_clear_bit(n, &pctl->gpio_valid_mask, ngpios)
+               clear_bit(n, valid_mask);
+
+       return 0;
+}
+
 static int stmfx_pinctrl_probe(struct platform_device *pdev)
 {
        struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent);
        struct device_node *np = pdev->dev.of_node;
        struct stmfx_pinctrl *pctl;
-       u32 n;
        int irq, ret;
 
        pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL);
@@ -650,7 +662,7 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
        pctl->gpio_chip.ngpio = pctl->pctl_desc.npins;
        pctl->gpio_chip.can_sleep = true;
        pctl->gpio_chip.of_node = np;
-       pctl->gpio_chip.need_valid_mask = true;
+       pctl->gpio_chip.init_valid_mask = stmfx_pinctrl_gpio_init_valid_mask;
 
        ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
        if (ret) {
@@ -668,8 +680,6 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev)
        pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type;
        pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock;
        pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock;
-       for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio)
-               clear_bit(n, pctl->gpio_chip.valid_mask);
 
        ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip,
                                          0, handle_bad_irq, IRQ_TYPE_NONE);
index 8e14a5f..fa2c878 100644 (file)
@@ -138,6 +138,7 @@ config PINCTRL_QCOM_SPMI_PMIC
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN_HIERARCHY
        help
          This is the pinctrl, pinmux, pinconf and gpiolib driver for the
index 7f35c19..b8a1c43 100644 (file)
@@ -593,24 +593,25 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 #define msm_gpio_dbg_show NULL
 #endif
 
-static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
+static int msm_gpio_init_valid_mask(struct gpio_chip *gc,
+                                   unsigned long *valid_mask,
+                                   unsigned int ngpios)
 {
-       struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
+       struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
        int ret;
        unsigned int len, i;
-       unsigned int max_gpios = pctrl->soc->ngpios;
        const int *reserved = pctrl->soc->reserved_gpios;
        u16 *tmp;
 
        /* Driver provided reserved list overrides DT and ACPI */
        if (reserved) {
-               bitmap_fill(chip->valid_mask, max_gpios);
+               bitmap_fill(valid_mask, ngpios);
                for (i = 0; reserved[i] >= 0; i++) {
-                       if (i >= max_gpios || reserved[i] >= max_gpios) {
+                       if (i >= ngpios || reserved[i] >= ngpios) {
                                dev_err(pctrl->dev, "invalid list of reserved GPIOs\n");
                                return -EINVAL;
                        }
-                       clear_bit(reserved[i], chip->valid_mask);
+                       clear_bit(reserved[i], valid_mask);
                }
 
                return 0;
@@ -622,7 +623,7 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
        if (ret < 0)
                return 0;
 
-       if (ret > max_gpios)
+       if (ret > ngpios)
                return -EINVAL;
 
        tmp = kmalloc_array(len, sizeof(*tmp), GFP_KERNEL);
@@ -635,9 +636,9 @@ static int msm_gpio_init_valid_mask(struct gpio_chip *chip)
                goto out;
        }
 
-       bitmap_zero(chip->valid_mask, max_gpios);
+       bitmap_zero(valid_mask, ngpios);
        for (i = 0; i < len; i++)
-               set_bit(tmp[i], chip->valid_mask);
+               set_bit(tmp[i], valid_mask);
 
 out:
        kfree(tmp);
@@ -653,7 +654,6 @@ static const struct gpio_chip msm_gpio_template = {
        .request          = gpiochip_generic_request,
        .free             = gpiochip_generic_free,
        .dbg_show         = msm_gpio_dbg_show,
-       .init_valid_mask  = msm_gpio_init_valid_mask,
 };
 
 /* For dual-edge interrupts in software, since some hardware has no
@@ -1015,7 +1015,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        chip->parent = pctrl->dev;
        chip->owner = THIS_MODULE;
        chip->of_node = pctrl->dev->of_node;
-       chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
+       if (msm_gpio_needs_valid_mask(pctrl))
+               chip->init_valid_mask = msm_gpio_init_valid_mask;
 
        pctrl->irq_chip.name = "msmgpio";
        pctrl->irq_chip.irq_enable = msm_gpio_irq_enable;
index f39da87..442db15 100644 (file)
@@ -170,8 +170,6 @@ struct pmic_gpio_state {
        struct regmap   *map;
        struct pinctrl_dev *ctrl;
        struct gpio_chip chip;
-       struct fwnode_handle *fwnode;
-       struct irq_domain *domain;
 };
 
 static const struct pinconf_generic_params pmic_gpio_bindings[] = {
@@ -751,23 +749,6 @@ static int pmic_gpio_of_xlate(struct gpio_chip *chip,
        return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
 }
 
-static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
-{
-       struct pmic_gpio_state *state = gpiochip_get_data(chip);
-       struct irq_fwspec fwspec;
-
-       fwspec.fwnode = state->fwnode;
-       fwspec.param_count = 2;
-       fwspec.param[0] = pin + PMIC_GPIO_PHYSICAL_OFFSET;
-       /*
-        * Set the type to a safe value temporarily. This will be overwritten
-        * later with the proper value by irq_set_type.
-        */
-       fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
-
-       return irq_create_fwspec_mapping(&fwspec);
-}
-
 static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        struct pmic_gpio_state *state = gpiochip_get_data(chip);
@@ -787,7 +768,6 @@ static const struct gpio_chip pmic_gpio_gpio_template = {
        .request                = gpiochip_generic_request,
        .free                   = gpiochip_generic_free,
        .of_xlate               = pmic_gpio_of_xlate,
-       .to_irq                 = pmic_gpio_to_irq,
        .dbg_show               = pmic_gpio_dbg_show,
 };
 
@@ -964,46 +944,24 @@ static int pmic_gpio_domain_translate(struct irq_domain *domain,
        return 0;
 }
 
-static int pmic_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
-                                 unsigned int nr_irqs, void *data)
+static unsigned int pmic_gpio_child_offset_to_irq(struct gpio_chip *chip,
+                                                 unsigned int offset)
 {
-       struct pmic_gpio_state *state = container_of(domain->host_data,
-                                                    struct pmic_gpio_state,
-                                                    chip);
-       struct irq_fwspec *fwspec = data;
-       struct irq_fwspec parent_fwspec;
-       irq_hw_number_t hwirq;
-       unsigned int type;
-       int ret, i;
-
-       ret = pmic_gpio_domain_translate(domain, fwspec, &hwirq, &type);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < nr_irqs; i++)
-               irq_domain_set_info(domain, virq + i, hwirq + i,
-                                   &pmic_gpio_irq_chip, state,
-                                   handle_level_irq, NULL, NULL);
+       return offset + PMIC_GPIO_PHYSICAL_OFFSET;
+}
 
-       parent_fwspec.fwnode = domain->parent->fwnode;
-       parent_fwspec.param_count = 4;
-       parent_fwspec.param[0] = 0;
-       parent_fwspec.param[1] = hwirq + 0xc0;
-       parent_fwspec.param[2] = 0;
-       parent_fwspec.param[3] = fwspec->param[1];
+static int pmic_gpio_child_to_parent_hwirq(struct gpio_chip *chip,
+                                          unsigned int child_hwirq,
+                                          unsigned int child_type,
+                                          unsigned int *parent_hwirq,
+                                          unsigned int *parent_type)
+{
+       *parent_hwirq = child_hwirq + 0xc0;
+       *parent_type = child_type;
 
-       return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
-                                           &parent_fwspec);
+       return 0;
 }
 
-static const struct irq_domain_ops pmic_gpio_domain_ops = {
-       .activate = gpiochip_irq_domain_activate,
-       .alloc = pmic_gpio_domain_alloc,
-       .deactivate = gpiochip_irq_domain_deactivate,
-       .free = irq_domain_free_irqs_common,
-       .translate = pmic_gpio_domain_translate,
-};
-
 static int pmic_gpio_probe(struct platform_device *pdev)
 {
        struct irq_domain *parent_domain;
@@ -1013,6 +971,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
        struct pinctrl_desc *pctrldesc;
        struct pmic_gpio_pad *pad, *pads;
        struct pmic_gpio_state *state;
+       struct gpio_irq_chip *girq;
        int ret, npins, i;
        u32 reg;
 
@@ -1092,19 +1051,21 @@ static int pmic_gpio_probe(struct platform_device *pdev)
        if (!parent_domain)
                return -ENXIO;
 
-       state->fwnode = of_node_to_fwnode(state->dev->of_node);
-       state->domain = irq_domain_create_hierarchy(parent_domain, 0,
-                                                   state->chip.ngpio,
-                                                   state->fwnode,
-                                                   &pmic_gpio_domain_ops,
-                                                   &state->chip);
-       if (!state->domain)
-               return -ENODEV;
+       girq = &state->chip.irq;
+       girq->chip = &pmic_gpio_irq_chip;
+       girq->default_type = IRQ_TYPE_NONE;
+       girq->handler = handle_level_irq;
+       girq->fwnode = of_node_to_fwnode(state->dev->of_node);
+       girq->parent_domain = parent_domain;
+       girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq;
+       girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell;
+       girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq;
+       girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate;
 
        ret = gpiochip_add_data(&state->chip, state);
        if (ret) {
                dev_err(state->dev, "can't add gpio chip\n");
-               goto err_chip_add_data;
+               return ret;
        }
 
        /*
@@ -1130,8 +1091,6 @@ static int pmic_gpio_probe(struct platform_device *pdev)
 
 err_range:
        gpiochip_remove(&state->chip);
-err_chip_add_data:
-       irq_domain_remove(state->domain);
        return ret;
 }
 
@@ -1140,7 +1099,6 @@ static int pmic_gpio_remove(struct platform_device *pdev)
        struct pmic_gpio_state *state = platform_get_drvdata(pdev);
 
        gpiochip_remove(&state->chip);
-       irq_domain_remove(state->domain);
        return 0;
 }
 
index 9426b9a..e40e1e2 100644 (file)
@@ -994,62 +994,11 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
 #endif
 #endif
 
-struct acpi_gpio_params {
-       unsigned int crs_entry_index;
-       unsigned int line_index;
-       bool active_low;
-};
-
-struct acpi_gpio_mapping {
-       const char *name;
-       const struct acpi_gpio_params *data;
-       unsigned int size;
-
-/* Ignore IoRestriction field */
-#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION      BIT(0)
-/*
- * When ACPI GPIO mapping table is in use the index parameter inside it
- * refers to the GPIO resource in _CRS method. That index has no
- * distinction of actual type of the resource. When consumer wants to
- * get GpioIo type explicitly, this quirk may be used.
- */
-#define ACPI_GPIO_QUIRK_ONLY_GPIOIO            BIT(1)
-
-       unsigned int quirks;
-};
-
 #if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
-int acpi_dev_add_driver_gpios(struct acpi_device *adev,
-                             const struct acpi_gpio_mapping *gpios);
-
-static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
-{
-       if (adev)
-               adev->driver_gpios = NULL;
-}
-
-int devm_acpi_dev_add_driver_gpios(struct device *dev,
-                                  const struct acpi_gpio_mapping *gpios);
-void devm_acpi_dev_remove_driver_gpios(struct device *dev);
-
 bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                struct acpi_resource_gpio **agpio);
 int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index);
 #else
-static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
-                             const struct acpi_gpio_mapping *gpios)
-{
-       return -ENXIO;
-}
-static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
-
-static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
-                             const struct acpi_gpio_mapping *gpios)
-{
-       return -ENXIO;
-}
-static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
-
 static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
                                              struct acpi_resource_gpio **agpio)
 {
index f757a58..2157717 100644 (file)
@@ -221,19 +221,6 @@ static inline int gpio_to_irq(unsigned gpio)
        return -EINVAL;
 }
 
-static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
-                                      unsigned int offset)
-{
-       WARN_ON(1);
-       return -EINVAL;
-}
-
-static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
-                                         unsigned int offset)
-{
-       WARN_ON(1);
-}
-
 static inline int irq_to_gpio(unsigned irq)
 {
        /* irq can never have been returned from gpio_to_irq() */
index a7f08fb..b70af92 100644 (file)
@@ -170,18 +170,8 @@ struct gpio_desc *gpio_to_desc(unsigned gpio);
 int desc_to_gpio(const struct gpio_desc *desc);
 
 /* Child properties interface */
-struct device_node;
 struct fwnode_handle;
 
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label);
-struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
-                                             struct device_node *node,
-                                             const char *propname, int index,
-                                             enum gpiod_flags dflags,
-                                             const char *label);
 struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         const char *propname, int index,
                                         enum gpiod_flags dflags,
@@ -530,28 +520,8 @@ static inline int desc_to_gpio(const struct gpio_desc *desc)
 }
 
 /* Child properties interface */
-struct device_node;
 struct fwnode_handle;
 
-static inline
-struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
-                                        const char *propname, int index,
-                                        enum gpiod_flags dflags,
-                                        const char *label)
-{
-       return ERR_PTR(-ENOSYS);
-}
-
-static inline
-struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
-                                             struct device_node *node,
-                                             const char *propname, int index,
-                                             enum gpiod_flags dflags,
-                                             const char *label)
-{
-       return ERR_PTR(-ENOSYS);
-}
-
 static inline
 struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
                                         const char *propname, int index,
@@ -584,6 +554,111 @@ struct gpio_desc *devm_fwnode_get_gpiod_from_child(struct device *dev,
                                                      flags, label);
 }
 
+#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_OF_GPIO)
+struct device_node;
+
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label);
+
+#else  /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
+
+struct device_node;
+
+static inline
+struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
+                                        const char *propname, int index,
+                                        enum gpiod_flags dflags,
+                                        const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+#endif /* CONFIG_GPIOLIB && CONFIG_OF_GPIO */
+
+#ifdef CONFIG_GPIOLIB
+struct device_node;
+
+struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
+                                             struct device_node *node,
+                                             const char *propname, int index,
+                                             enum gpiod_flags dflags,
+                                             const char *label);
+
+#else  /* CONFIG_GPIOLIB */
+
+struct device_node;
+
+static inline
+struct gpio_desc *devm_gpiod_get_from_of_node(struct device *dev,
+                                             struct device_node *node,
+                                             const char *propname, int index,
+                                             enum gpiod_flags dflags,
+                                             const char *label)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+struct acpi_gpio_params {
+       unsigned int crs_entry_index;
+       unsigned int line_index;
+       bool active_low;
+};
+
+struct acpi_gpio_mapping {
+       const char *name;
+       const struct acpi_gpio_params *data;
+       unsigned int size;
+
+/* Ignore IoRestriction field */
+#define ACPI_GPIO_QUIRK_NO_IO_RESTRICTION      BIT(0)
+/*
+ * When ACPI GPIO mapping table is in use the index parameter inside it
+ * refers to the GPIO resource in _CRS method. That index has no
+ * distinction of actual type of the resource. When consumer wants to
+ * get GpioIo type explicitly, this quirk may be used.
+ */
+#define ACPI_GPIO_QUIRK_ONLY_GPIOIO            BIT(1)
+
+       unsigned int quirks;
+};
+
+#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_ACPI)
+
+struct acpi_device;
+
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios);
+void acpi_dev_remove_driver_gpios(struct acpi_device *adev);
+
+int devm_acpi_dev_add_driver_gpios(struct device *dev,
+                                  const struct acpi_gpio_mapping *gpios);
+void devm_acpi_dev_remove_driver_gpios(struct device *dev);
+
+#else  /* CONFIG_GPIOLIB && CONFIG_ACPI */
+
+struct acpi_device;
+
+static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+                             const struct acpi_gpio_mapping *gpios)
+{
+       return -ENXIO;
+}
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
+
+static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
+                             const struct acpi_gpio_mapping *gpios)
+{
+       return -ENXIO;
+}
+static inline void devm_acpi_dev_remove_driver_gpios(struct device *dev) {}
+
+#endif /* CONFIG_GPIOLIB && CONFIG_ACPI */
+
+
 #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
 
 int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
index 6a0e420..c667ad0 100644 (file)
@@ -20,9 +20,8 @@ struct module;
 enum gpiod_flags;
 enum gpio_lookup_flags;
 
-#ifdef CONFIG_GPIOLIB
+struct gpio_chip;
 
-#ifdef CONFIG_GPIOLIB_IRQCHIP
 /**
  * struct gpio_irq_chip - GPIO interrupt controller
  */
@@ -49,6 +48,84 @@ struct gpio_irq_chip {
         */
        const struct irq_domain_ops *domain_ops;
 
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+       /**
+        * @fwnode:
+        *
+        * Firmware node corresponding to this gpiochip/irqchip, necessary
+        * for hierarchical irqdomain support.
+        */
+       struct fwnode_handle *fwnode;
+
+       /**
+        * @parent_domain:
+        *
+        * If non-NULL, will be set as the parent of this GPIO interrupt
+        * controller's IRQ domain to establish a hierarchical interrupt
+        * domain. The presence of this will activate the hierarchical
+        * interrupt support.
+        */
+       struct irq_domain *parent_domain;
+
+       /**
+        * @child_to_parent_hwirq:
+        *
+        * This callback translates a child hardware IRQ offset to a parent
+        * hardware IRQ offset on a hierarchical interrupt chip. The child
+        * hardware IRQs correspond to the GPIO index 0..ngpio-1 (see the
+        * ngpio field of struct gpio_chip) and the corresponding parent
+        * hardware IRQ and type (such as IRQ_TYPE_*) shall be returned by
+        * the driver. The driver can calculate this from an offset or using
+        * a lookup table or whatever method is best for this chip. Return
+        * 0 on successful translation in the driver.
+        *
+        * If some ranges of hardware IRQs do not have a corresponding parent
+        * HWIRQ, return -EINVAL, but also make sure to fill in @valid_mask and
+        * @need_valid_mask to make these GPIO lines unavailable for
+        * translation.
+        */
+       int (*child_to_parent_hwirq)(struct gpio_chip *chip,
+                                    unsigned int child_hwirq,
+                                    unsigned int child_type,
+                                    unsigned int *parent_hwirq,
+                                    unsigned int *parent_type);
+
+       /**
+        * @populate_parent_fwspec:
+        *
+        * This optional callback populates the &struct irq_fwspec for the
+        * parent's IRQ domain. If this is not specified, then
+        * &gpiochip_populate_parent_fwspec_twocell will be used. A four-cell
+        * variant named &gpiochip_populate_parent_fwspec_fourcell is also
+        * available.
+        */
+       void (*populate_parent_fwspec)(struct gpio_chip *chip,
+                                      struct irq_fwspec *fwspec,
+                                      unsigned int parent_hwirq,
+                                      unsigned int parent_type);
+
+       /**
+        * @child_offset_to_irq:
+        *
+        * This optional callback is used to translate the child's GPIO line
+        * offset on the GPIO chip to an IRQ number for the GPIO to_irq()
+        * callback. If this is not specified, then a default callback will be
+        * provided that returns the line offset.
+        */
+       unsigned int (*child_offset_to_irq)(struct gpio_chip *chip,
+                                           unsigned int pin);
+
+       /**
+        * @child_irq_domain_ops:
+        *
+        * The IRQ domain operations that will be used for this GPIO IRQ
+        * chip. If no operations are provided, then default callbacks will
+        * be populated to setup the IRQ hierarchy. Some drivers need to
+        * supply their own translate function.
+        */
+       struct irq_domain_ops child_irq_domain_ops;
+#endif
+
        /**
         * @handler:
         *
@@ -161,7 +238,6 @@ struct gpio_irq_chip {
         */
        void            (*irq_disable)(struct irq_data *data);
 };
-#endif /* CONFIG_GPIOLIB_IRQCHIP */
 
 /**
  * struct gpio_chip - abstract a GPIO controller
@@ -282,7 +358,9 @@ struct gpio_chip {
        void                    (*dbg_show)(struct seq_file *s,
                                                struct gpio_chip *chip);
 
-       int                     (*init_valid_mask)(struct gpio_chip *chip);
+       int                     (*init_valid_mask)(struct gpio_chip *chip,
+                                                  unsigned long *valid_mask,
+                                                  unsigned int ngpios);
 
        int                     base;
        u16                     ngpio;
@@ -320,15 +398,6 @@ struct gpio_chip {
        struct gpio_irq_chip irq;
 #endif /* CONFIG_GPIOLIB_IRQCHIP */
 
-       /**
-        * @need_valid_mask:
-        *
-        * If set core allocates @valid_mask with all its values initialized
-        * with init_valid_mask() or set to one if init_valid_mask() is not
-        * defined
-        */
-       bool need_valid_mask;
-
        /**
         * @valid_mask:
         *
@@ -421,9 +490,6 @@ extern int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
 extern struct gpio_chip *gpiochip_find(void *data,
                              int (*match)(struct gpio_chip *chip, void *data));
 
-/* lock/unlock as IRQ */
-int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
-void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
 bool gpiochip_line_is_irq(struct gpio_chip *chip, unsigned int offset);
 int gpiochip_reqres_irq(struct gpio_chip *chip, unsigned int offset);
 void gpiochip_relres_irq(struct gpio_chip *chip, unsigned int offset);
@@ -441,15 +507,40 @@ bool gpiochip_line_is_valid(const struct gpio_chip *chip, unsigned int offset);
 /* get driver data */
 void *gpiochip_get_data(struct gpio_chip *chip);
 
-struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
-
 struct bgpio_pdata {
        const char *label;
        int base;
        int ngpio;
 };
 
-#if IS_ENABLED(CONFIG_GPIO_GENERIC)
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+
+void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                            struct irq_fwspec *fwspec,
+                                            unsigned int parent_hwirq,
+                                            unsigned int parent_type);
+void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                             struct irq_fwspec *fwspec,
+                                             unsigned int parent_hwirq,
+                                             unsigned int parent_type);
+
+#else
+
+static inline void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip,
+                                                   struct irq_fwspec *fwspec,
+                                                   unsigned int parent_hwirq,
+                                                   unsigned int parent_type)
+{
+}
+
+static inline void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip,
+                                                    struct irq_fwspec *fwspec,
+                                                    unsigned int parent_hwirq,
+                                                    unsigned int parent_type)
+{
+}
+
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
 int bgpio_init(struct gpio_chip *gc, struct device *dev,
               unsigned long sz, void __iomem *dat, void __iomem *set,
@@ -463,10 +554,6 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 #define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
 #define BGPIOF_NO_OUTPUT               BIT(5) /* only input */
 
-#endif /* CONFIG_GPIO_GENERIC */
-
-#ifdef CONFIG_GPIOLIB_IRQCHIP
-
 int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq);
 void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
@@ -555,15 +642,11 @@ static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
 }
 #endif /* CONFIG_LOCKDEP */
 
-#endif /* CONFIG_GPIOLIB_IRQCHIP */
-
 int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset);
 void gpiochip_generic_free(struct gpio_chip *chip, unsigned offset);
 int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset,
                            unsigned long config);
 
-#ifdef CONFIG_PINCTRL
-
 /**
  * struct gpio_pin_range - pin range controlled by a gpio chip
  * @node: list for maintaining set of pin ranges, used internally
@@ -576,6 +659,8 @@ struct gpio_pin_range {
        struct pinctrl_gpio_range range;
 };
 
+#ifdef CONFIG_PINCTRL
+
 int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                           unsigned int gpio_offset, unsigned int pin_offset,
                           unsigned int npins);
@@ -586,8 +671,6 @@ void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
 
 #else /* ! CONFIG_PINCTRL */
 
-struct pinctrl_dev;
-
 static inline int
 gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                       unsigned int gpio_offset, unsigned int pin_offset,
@@ -619,6 +702,15 @@ void gpiochip_free_own_desc(struct gpio_desc *desc);
 void devprop_gpiochip_set_names(struct gpio_chip *chip,
                                const struct fwnode_handle *fwnode);
 
+#ifdef CONFIG_GPIOLIB
+
+/* lock/unlock as IRQ */
+int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset);
+void gpiochip_unlock_as_irq(struct gpio_chip *chip, unsigned int offset);
+
+
+struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
+
 #else /* CONFIG_GPIOLIB */
 
 static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
@@ -628,6 +720,18 @@ static inline struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
        return ERR_PTR(-ENODEV);
 }
 
+static inline int gpiochip_lock_as_irq(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       WARN_ON(1);
+       return -EINVAL;
+}
+
+static inline void gpiochip_unlock_as_irq(struct gpio_chip *chip,
+                                         unsigned int offset)
+{
+       WARN_ON(1);
+}
 #endif /* CONFIG_GPIOLIB */
 
-#endif
+#endif /* __LINUX_GPIO_DRIVER_H */
index 54ac2fd..67f06c9 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 33eb725..05db311 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/dmi.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 4977b5a..9d65742 100644 (file)
@@ -8,6 +8,7 @@
  *          Mengdong Lin <mengdong.lin@intel.com>
  */
 
+#include <linux/gpio/consumer.h>
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>