gpio: mb86s7x: Enable ACPI support

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>
This commit is contained in:
Ard Biesheuvel 2019-05-28 15:36:47 +02:00 committed by Marc Zyngier
parent 3d090a36c8
commit f3d705d506

View 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,