]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
gpio: dwapb: Add support for 1 interrupt per port A GPIO
authorPhil Edworthy <phil.edworthy@renesas.com>
Thu, 26 Apr 2018 16:19:47 +0000 (17:19 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 16 May 2018 12:35:24 +0000 (14:35 +0200)
The DesignWare GPIO IP can be configured for either 1 interrupt or 1
per GPIO in port A, but the driver currently only supports 1 interrupt.
See the DesignWare DW_apb_gpio Databook description of the
'GPIO_INTR_IO' parameter.

This change allows the driver to work with up to 32 interrupts, it will
get as many interrupts as specified in the DT 'interrupts' property.
It doesn't do anything clever with the different interrupts, it just calls
the same handler used for single interrupt hardware.

ACPI companion code provided by Hoan Tran <hotran@apm.com>. This was tested
on X-Gene by Hoan.

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Hoan Tran <hotran@apm.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Documentation/devicetree/bindings/gpio/snps-dwapb-gpio.txt
drivers/gpio/gpio-dwapb.c
drivers/mfd/intel_quark_i2c_gpio.c
include/linux/platform_data/gpio-dwapb.h

index 4a75da7051bd218c12ef8ff3bf49e555e2e0991c..3c1118bc67f50cb1214327a06d4ff57366d92eaf 100644 (file)
@@ -26,8 +26,13 @@ controller.
   the second encodes the triger flags encoded as described in
   Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 - interrupt-parent : The parent interrupt controller.
-- interrupts : The interrupt to the parent controller raised when GPIOs
-  generate the interrupts.
+- interrupts : The interrupts to the parent controller raised when GPIOs
+  generate the interrupts. If the controller provides one combined interrupt
+  for all GPIOs, specify a single interrupt. If the controller provides one
+  interrupt for each GPIO, provide a list of interrupts that correspond to each
+  of the GPIO pins. When specifying multiple interrupts, if any are unconnected,
+  use the interrupts-extended property to specify the interrupts and set the
+  interrupt controller handle for unused interrupts to 0.
 - snps,nr-gpios : The number of pins in the port, a single cell.
 - resets : Reset line for the controller.
 
index 226977f78482a842a79bde8bad43e40db7ddf261..7dcd06b11570f74c12cae40bfce1db8d5be74348 100644 (file)
@@ -441,14 +441,19 @@ static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
        irq_gc->chip_types[1].handler = handle_edge_irq;
 
        if (!pp->irq_shared) {
-               irq_set_chained_handler_and_data(pp->irq, dwapb_irq_handler,
-                                                gpio);
+               int i;
+
+               for (i = 0; i < pp->ngpio; i++) {
+                       if (pp->irq[i])
+                               irq_set_chained_handler_and_data(pp->irq[i],
+                                               dwapb_irq_handler, gpio);
+               }
        } else {
                /*
                 * Request a shared IRQ since where MFD would have devices
                 * using the same irq pin
                 */
-               err = devm_request_irq(gpio->dev, pp->irq,
+               err = devm_request_irq(gpio->dev, pp->irq[0],
                                       dwapb_irq_handler_mfd,
                                       IRQF_SHARED, "gpio-dwapb-mfd", gpio);
                if (err) {
@@ -524,7 +529,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
        if (pp->idx == 0)
                port->gc.set_config = dwapb_gpio_set_config;
 
-       if (pp->irq)
+       if (pp->has_irq)
                dwapb_configure_irqs(gpio, port, pp);
 
        err = gpiochip_add_data(&port->gc, port);
@@ -535,7 +540,7 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
                port->is_registered = true;
 
        /* Add GPIO-signaled ACPI event support */
-       if (pp->irq)
+       if (pp->has_irq)
                acpi_gpiochip_request_interrupts(&port->gc);
 
        return err;
@@ -601,13 +606,36 @@ dwapb_gpio_get_pdata(struct device *dev)
                if (dev->of_node && pp->idx == 0 &&
                        fwnode_property_read_bool(fwnode,
                                                  "interrupt-controller")) {
-                       pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
-                       if (!pp->irq)
+                       struct device_node *np = to_of_node(fwnode);
+                       unsigned int j;
+
+                       /*
+                        * The IP has configuration options to allow a single
+                        * combined interrupt or one per gpio. If one per gpio,
+                        * some might not be used.
+                        */
+                       for (j = 0; j < pp->ngpio; j++) {
+                               int irq = of_irq_get(np, j);
+                               if (irq < 0)
+                                       continue;
+
+                               pp->irq[j] = irq;
+                               pp->has_irq = true;
+                       }
+
+                       if (!pp->has_irq)
                                dev_warn(dev, "no irq for port%d\n", pp->idx);
                }
 
-               if (has_acpi_companion(dev) && pp->idx == 0)
-                       pp->irq = platform_get_irq(to_platform_device(dev), 0);
+               if (has_acpi_companion(dev) && pp->idx == 0) {
+                       unsigned int j;
+
+                       for (j = 0; j < pp->ngpio; j++) {
+                               pp->irq[j] = platform_get_irq(to_platform_device(dev), j);
+                               if (pp->irq[j])
+                                       pp->has_irq = true;
+                       }
+               }
 
                pp->irq_shared  = false;
                pp->gpio_base   = -1;
index 90e35dec8648f3235c41a0b380c16e686eb53fcc..5bddb84cfc1f477b8b0c19bce799b0176731d5f5 100644 (file)
@@ -233,7 +233,8 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
        pdata->properties->idx          = 0;
        pdata->properties->ngpio        = INTEL_QUARK_MFD_NGPIO;
        pdata->properties->gpio_base    = INTEL_QUARK_MFD_GPIO_BASE;
-       pdata->properties->irq          = pdev->irq;
+       pdata->properties->irq[0]       = pdev->irq;
+       pdata->properties->has_irq      = true;
        pdata->properties->irq_shared   = true;
 
        cell->platform_data = pdata;
index 2dc7f4a8ab095a0d87c8f5bd649624b13c303d33..5a52d69c13f31d5968c3c290bdc7de065208aa3d 100644 (file)
@@ -19,7 +19,8 @@ struct dwapb_port_property {
        unsigned int    idx;
        unsigned int    ngpio;
        unsigned int    gpio_base;
-       unsigned int    irq;
+       unsigned int    irq[32];
+       bool            has_irq;
        bool            irq_shared;
 };