Leverage the IRQCHIP_MASK_ON_SUSPEND flag in order to avoid having to specifically treat the GPIO interrupts during suspend and resume, and simply implement an irq_set_wake() callback that is responsible for enabling the parent wake-up interrupt as a wake-up interrupt. Signed-off-by: Florian Fainelli <f.fainelli@xxxxxxxxx> --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 58 ++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index e8ad1824c6b3..367fd8e19f92 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -19,6 +19,7 @@ #include <linux/irq.h> #include <linux/irqdesc.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/of_address.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -76,6 +77,7 @@ struct bcm2835_pinctrl { struct device *dev; void __iomem *base; + int wake_irq[BCM2835_NUM_IRQS]; /* note: locking assumes each bank will have its own unsigned long */ unsigned long enabled_irq_map[BCM2835_NUM_BANKS]; @@ -435,6 +437,11 @@ static void bcm2835_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(host_chip, desc); } +static irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc, unsigned reg, unsigned offset, bool enable) { @@ -634,6 +641,31 @@ static void bcm2835_gpio_irq_ack(struct irq_data *data) bcm2835_gpio_set_bit(pc, GPEDS0, gpio); } +static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(data); + struct bcm2835_pinctrl *pc = gpiochip_get_data(chip); + unsigned gpio = irqd_to_hwirq(data); + unsigned int irqgroup; + int ret = -EINVAL; + + if (gpio <= 27) + irqgroup = 0; + else if (gpio >= 28 && gpio <= 45) + irqgroup = 1; + else if (gpio >= 46 && gpio <= 53) + irqgroup = 2; + else + return ret; + + if (on) + ret = enable_irq_wake(pc->wake_irq[irqgroup]); + else + ret = disable_irq_wake(pc->wake_irq[irqgroup]); + + return ret; +} + static struct irq_chip bcm2835_gpio_irq_chip = { .name = MODULE_NAME, .irq_enable = bcm2835_gpio_irq_enable, @@ -642,6 +674,8 @@ static struct irq_chip bcm2835_gpio_irq_chip = { .irq_ack = bcm2835_gpio_irq_ack, .irq_mask = bcm2835_gpio_irq_disable, .irq_unmask = bcm2835_gpio_irq_enable, + .irq_set_wake = bcm2835_gpio_irq_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, }; static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev) @@ -1221,8 +1255,30 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) * bank that was firing the IRQ and look up the per-group * and bank data. */ - for (i = 0; i < BCM2835_NUM_IRQS; i++) + for (i = 0; i < BCM2835_NUM_IRQS; i++) { + int len; + char *name; + girq->parents[i] = irq_of_parse_and_map(np, i); + /* Skip over the all banks interrupts */ + pc->wake_irq[i] = irq_of_parse_and_map(np, i + + BCM2835_NUM_IRQS + 1); + + len = strlen(dev_name(pc->dev)) + 16; + name = devm_kzalloc(pc->dev, len, GFP_KERNEL); + if (!name) + return -ENOMEM; + + snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i); + + /* These are optional interrupts */ + err = devm_request_irq(dev, pc->wake_irq[i], + bcm2835_gpio_wake_irq_handler, + IRQF_SHARED, name, pc); + if (err) + dev_warn(dev, "unable to request wake IRQ %d\n", + pc->wake_irq[i]); + } girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; -- 2.17.1