Re: [PATCH v2 4/4] pinctrl: bcm2835: Add support for wake-up interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Florian,

Am 29.05.20 um 21:15 schrieb Florian Fainelli:
> 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.
>
> To avoid allocating unnecessary resources for other chips, the wake-up
> interrupts are only initialized if we have a brcm,bcm7211-gpio
> compatibility string.
>
> Signed-off-by: Florian Fainelli <f.fainelli@xxxxxxxxx>
> ---
>  drivers/pinctrl/bcm/pinctrl-bcm2835.c | 76 ++++++++++++++++++++++++++-
>  1 file changed, 75 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
> index 1b00d93aa66e..1fbf067a3eed 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;
>  
>  	/* 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,34 @@ 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 (!pc->wake_irq)
> +		return ret;
> +
> +	if (gpio <= 27)
> +		irqgroup = 0;
> +	else if (gpio >= 28 && gpio <= 45)
> +		irqgroup = 1;
> +	else if (gpio >= 46 && gpio <= 53)
> +		irqgroup = 2;
in case the BCM7211 has 58 GPIOs, but the wake up interrupts are only
available for the first 54 this should deserve a comment.
> +	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 +677,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)
> @@ -1154,6 +1191,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
>  	struct resource iomem;
>  	int err, i;
>  	const struct of_device_id *match;
> +	int is_7211 = 0;
>  
>  	BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS);
>  	BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS);
> @@ -1180,6 +1218,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  
>  	pdata = match->data;
> +	is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio");
>  
>  	pc->gpio_chip = *pdata->gpio_chip;
>  	pc->gpio_chip.parent = dev;
> @@ -1214,6 +1253,15 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev)
>  				     GFP_KERNEL);
>  	if (!girq->parents)
>  		return -ENOMEM;
> +
> +	if (is_7211) {
> +		pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
> +					    sizeof(*pc->wake_irq),
> +					    GFP_KERNEL);
> +		if (!pc->wake_irq)
> +			return -ENOMEM;
> +	}
> +
>  	/*
>  	 * Use the same handler for all groups: this is necessary
>  	 * since we use one gpiochip to cover all lines - the
> @@ -1221,8 +1269,34 @@ 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);
> +		if (!is_7211)
> +			continue;
> +
> +		/* 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;
>  




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux