gpio: mb86s7x: Enable ACPI support
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Tue, 28 May 2019 13:36:47 +0000 (15:36 +0200)
committerMarc Zyngier <marc.zyngier@arm.com>
Wed, 29 May 2019 09:42:19 +0000 (10:42 +0100)
Make the mb86s7x GPIO block discoverable via ACPI. In addition, add
support for ACPI GPIO interrupts routed via platform interrupts, by
wiring the two together via the to_irq() gpiochip callback.

Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
drivers/gpio/gpio-mb86s7x.c

index 9308081e0a4a42aec1c607b25462a22e0b006ab8..64027f57a8aa3c54ea6fd61f2074163177d5dfa3 100644 (file)
@@ -14,6 +14,7 @@
  *  GNU General Public License for more details.
  */
 
+#include <linux/acpi.h>
 #include <linux/io.h>
 #include <linux/init.h>
 #include <linux/clk.h>
@@ -27,6 +28,8 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 
+#include "gpiolib.h"
+
 /*
  * Only first 8bits of a register correspond to each pin,
  * so there are 4 registers for 32 pins.
@@ -143,6 +146,20 @@ static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
        spin_unlock_irqrestore(&gchip->lock, flags);
 }
 
+static int mb86s70_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+       int irq, index;
+
+       for (index = 0;; index++) {
+               irq = platform_get_irq(to_platform_device(gc->parent), index);
+               if (irq <= 0)
+                       break;
+               if (irq_get_irq_data(irq)->hwirq == offset)
+                       return irq;
+       }
+       return -EINVAL;
+}
+
 static int mb86s70_gpio_probe(struct platform_device *pdev)
 {
        struct mb86s70_gpio_chip *gchip;
@@ -158,13 +175,15 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
        if (IS_ERR(gchip->base))
                return PTR_ERR(gchip->base);
 
-       gchip->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(gchip->clk))
-               return PTR_ERR(gchip->clk);
+       if (!has_acpi_companion(&pdev->dev)) {
+               gchip->clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(gchip->clk))
+                       return PTR_ERR(gchip->clk);
 
-       ret = clk_prepare_enable(gchip->clk);
-       if (ret)
-               return ret;
+               ret = clk_prepare_enable(gchip->clk);
+               if (ret)
+                       return ret;
+       }
 
        spin_lock_init(&gchip->lock);
 
@@ -180,19 +199,28 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
        gchip->gc.parent = &pdev->dev;
        gchip->gc.base = -1;
 
+       if (has_acpi_companion(&pdev->dev))
+               gchip->gc.to_irq = mb86s70_gpio_to_irq;
+
        ret = gpiochip_add_data(&gchip->gc, gchip);
        if (ret) {
                dev_err(&pdev->dev, "couldn't register gpio driver\n");
                clk_disable_unprepare(gchip->clk);
+               return ret;
        }
 
-       return ret;
+       if (has_acpi_companion(&pdev->dev))
+               acpi_gpiochip_request_interrupts(&gchip->gc);
+
+       return 0;
 }
 
 static int mb86s70_gpio_remove(struct platform_device *pdev)
 {
        struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
 
+       if (has_acpi_companion(&pdev->dev))
+               acpi_gpiochip_free_interrupts(&gchip->gc);
        gpiochip_remove(&gchip->gc);
        clk_disable_unprepare(gchip->clk);
 
@@ -205,10 +233,19 @@ static const struct of_device_id mb86s70_gpio_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id mb86s70_gpio_acpi_ids[] = {
+       { "SCX0007" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(acpi, mb86s70_gpio_acpi_ids);
+#endif
+
 static struct platform_driver mb86s70_gpio_driver = {
        .driver = {
                .name = "mb86s70-gpio",
                .of_match_table = mb86s70_gpio_dt_ids,
+               .acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
        },
        .probe = mb86s70_gpio_probe,
        .remove = mb86s70_gpio_remove,