diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 661c5a38f..a25d61d54 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -133,7 +134,7 @@ struct mvebu_gpio_chip { struct regmap *regs; u32 offset; struct regmap *percpu_regs; - int irqbase; + int bank_irq[4]; struct irq_domain *domain; int soc_variant; @@ -608,6 +609,33 @@ static void mvebu_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } +/* + * Set interrupt number "irq" in the GPIO as a wake-up source. + * While system is running, all registered GPIO interrupts need to have + * wake-up enabled. When system is suspended, only selected GPIO interrupts + * need to have wake-up enabled. + * @param irq interrupt source number + * @param enable enable as wake-up if equal to non-zero + * @return This function returns 0 on success. + */ +static int mvebu_gpio_set_wake_irq(struct irq_data *d, unsigned int enable) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct mvebu_gpio_chip *mvchip = gc->private; + int irq; + int bank; + + bank = d->hwirq % 8; + irq = mvchip->bank_irq[bank]; + + if (enable) + enable_irq_wake(irq); + else + disable_irq_wake(irq); + + return 0; +} + /* * Functions implementing the pwm_chip methods */ @@ -1277,7 +1305,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) err = irq_alloc_domain_generic_chips( mvchip->domain, ngpios, 2, np->name, handle_level_irq, - IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0); + IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, IRQ_GC_INIT_NESTED_LOCK); if (err) { dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n", mvchip->chip.label); @@ -1295,6 +1323,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) ct->chip.irq_mask = mvebu_gpio_level_irq_mask; ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask; ct->chip.irq_set_type = mvebu_gpio_irq_set_type; + ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; ct->chip.name = mvchip->chip.label; ct = &gc->chip_types[1]; @@ -1303,6 +1333,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) ct->chip.irq_mask = mvebu_gpio_edge_irq_mask; ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask; ct->chip.irq_set_type = mvebu_gpio_irq_set_type; + ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; ct->handler = handle_edge_irq; ct->chip.name = mvchip->chip.label; @@ -1318,6 +1350,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) continue; irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, mvchip); + mvchip->bank_irq[i] = irq; } /* Some MVEBU SoCs have simple PWM support for GPIO lines */