As documented in the device tree binding, #interrupt-cells should be 1 for this driver because the interrupt type is fixed in the hardware. When the device tree is configured as documented, an interrupt would trigger kernel/irq/irqdomain.c: WARN_ON(intsize < 2). The driver was attempting to use gpiochip_irqchip_add(), which uses gpiochip_irqchip_add_key() and is documented to work only with two celled IRQs. This appears to have been broken in the v7 -> v8 transition of the original patch adding the driver. Signed-off-by: Chris Lesiak <chris.lesiak@xxxxxxxxx> --- drivers/gpio/gpio-altera.c | 88 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index ccc02ed65b3c..2a989777eb66 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -112,6 +112,30 @@ static unsigned int altera_gpio_irq_startup(struct irq_data *d) return 0; } +static int altera_gpio_irq_reqres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + if (gpiochip_lock_as_irq(chip, d->hwirq)) { + dev_err(chip->parent, "unable to lock HW IRQ %lu for IRQ\n", + d->hwirq); + module_put(THIS_MODULE); + return -EINVAL; + } + return 0; +} + +static void altera_gpio_irq_relres(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + + gpiochip_unlock_as_irq(chip, d->hwirq); + module_put(THIS_MODULE); +} + static struct irq_chip altera_irq_chip = { .name = "altera-gpio", .irq_mask = altera_gpio_irq_mask, @@ -119,6 +143,8 @@ static struct irq_chip altera_irq_chip = { .irq_set_type = altera_gpio_irq_set_type, .irq_startup = altera_gpio_irq_startup, .irq_shutdown = altera_gpio_irq_mask, + .irq_request_resources = altera_gpio_irq_reqres, + .irq_release_resources = altera_gpio_irq_relres, }; static int altera_gpio_get(struct gpio_chip *gc, unsigned offset) @@ -252,6 +278,64 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +static int altera_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gpio_chip *chip = d->host_data; + + irq_set_chip_data(irq, chip); + /* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ + irq_set_lockdep_class(irq, chip->lock_key); + irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); + irq_set_noprobe(irq); + + return 0; +} + +static void altera_gpio_irq_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops altera_gpio_domain_ops = { + .map = altera_gpio_irq_map, + .unmap = altera_gpio_irq_unmap, + .xlate = irq_domain_xlate_onecell, +}; + +static int altera_gpiochip_irqchip_add(struct gpio_chip *gpiochip, + struct irq_chip *irqchip) +{ + static struct lock_class_key key; + + if (!gpiochip || !irqchip) + return -EINVAL; + + if (!gpiochip->parent) { + pr_err("missing gpiochip .dev parent pointer\n"); + return -EINVAL; + } + gpiochip->irq_nested = false; + gpiochip->irqchip = irqchip; + gpiochip->irq_handler = handle_bad_irq; + gpiochip->irq_default_type = IRQ_TYPE_NONE; + gpiochip->to_irq = NULL; + gpiochip->lock_key = &key; + gpiochip->irqdomain = irq_domain_add_simple( + gpiochip->parent->of_node, gpiochip->ngpio, 0, + &altera_gpio_domain_ops, gpiochip); + if (!gpiochip->irqdomain) { + gpiochip->irqchip = NULL; + return -EINVAL; + } + + return 0; +} + static int altera_gpio_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -305,8 +389,8 @@ static int altera_gpio_probe(struct platform_device *pdev) } altera_gc->interrupt_trigger = reg; - ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0, - handle_bad_irq, IRQ_TYPE_NONE); + ret = altera_gpiochip_irqchip_add(&altera_gc->mmchip.gc, + &altera_irq_chip); if (ret) { dev_err(&pdev->dev, "could not add irqchip\n"); -- 2.14.3 -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html