From d8323c6b03533ac870fb665277e6dad7ebf7e4d3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 Jul 2015 14:41:57 +0200 Subject: pinctrl: sunxi: Add custom irq_domain_ops The current interrupt parsing code was working by accident, because the default was actually parsing the first node of interrupts. While that was mostly working (and the flags were actually ignored), this binding has never been documented, and doesn't work with SoCs that have multiple interrupt banks anyway. Add a proper interrupt xlate function, that uses the same description than the GPIOs ( ), that will make things less confusing. The EINT number will still be used as the hwirq number, but won't be exposed through the DT. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 7f7e7bb4..fb4669c0 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -711,6 +711,37 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; +static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct sunxi_desc_function *desc; + int pin, base; + + if (intsize < 3) + return -EINVAL; + + base = PINS_PER_BANK * intspec[0]; + pin = base + intspec[1]; + + desc = sunxi_pinctrl_desc_find_function_by_pin(d->host_data, + pin, "irq"); + if (!desc) + return -EINVAL; + + *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; + *out_type = intspec[2]; + + return 0; +} + +static struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { + .xlate = sunxi_pinctrl_irq_of_xlate, +}; + static void sunxi_pinctrl_irq_handler(unsigned __irq, struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); @@ -986,8 +1017,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK, - &irq_domain_simple_ops, - NULL); + &sunxi_pinctrl_irq_domain_ops, + pctl); if (!pctl->domain) { dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); ret = -ENOMEM; -- cgit v1.1