147 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 6f92d02f7af5a9b5ed5ded7dbeb18bf2bbb2ad85 Mon Sep 17 00:00:00 2001
 | |
| From: Phil Elwell <phil@raspberrypi.org>
 | |
| Date: Tue, 24 Feb 2015 13:40:50 +0000
 | |
| Subject: [PATCH] pinctrl-bcm2835: Fix interrupt handling for GPIOs 28-31 and
 | |
|  46-53
 | |
| 
 | |
| Contrary to the documentation, the BCM2835 GPIO controller actually has
 | |
| four interrupt lines - one each for the three IRQ groups and one common. Rather
 | |
| confusingly, the GPIO interrupt groups don't correspond directly with the GPIO
 | |
| control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and
 | |
| 46-53 GPIO2.
 | |
| 
 | |
| Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is
 | |
| cleaner to split out a function to process the interrupts for a single GPIO
 | |
| bank.
 | |
| 
 | |
| This bug has only just been observed because GPIOs above 27 can only be
 | |
| accessed on an old Raspberry Pi with the optional P5 header fitted, where
 | |
| the pins are often used for I2S instead.
 | |
| ---
 | |
|  drivers/pinctrl/bcm/pinctrl-bcm2835.c | 51 ++++++++++++++++++++++++++---------
 | |
|  1 file changed, 39 insertions(+), 12 deletions(-)
 | |
| 
 | |
| --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
 | |
| +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
 | |
| @@ -47,6 +47,7 @@
 | |
|  #define MODULE_NAME "pinctrl-bcm2835"
 | |
|  #define BCM2835_NUM_GPIOS 54
 | |
|  #define BCM2835_NUM_BANKS 2
 | |
| +#define BCM2835_NUM_IRQS  3
 | |
|  
 | |
|  #define BCM2835_PIN_BITMAP_SZ \
 | |
|  	DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
 | |
| @@ -82,13 +83,13 @@ enum bcm2835_pinconf_param {
 | |
|  
 | |
|  struct bcm2835_gpio_irqdata {
 | |
|  	struct bcm2835_pinctrl *pc;
 | |
| -	int bank;
 | |
| +	int irqgroup;
 | |
|  };
 | |
|  
 | |
|  struct bcm2835_pinctrl {
 | |
|  	struct device *dev;
 | |
|  	void __iomem *base;
 | |
| -	int irq[BCM2835_NUM_BANKS];
 | |
| +	int irq[BCM2835_NUM_IRQS];
 | |
|  
 | |
|  	/* note: locking assumes each bank will have its own unsigned long */
 | |
|  	unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
 | |
| @@ -99,7 +100,7 @@ struct bcm2835_pinctrl {
 | |
|  	struct gpio_chip gpio_chip;
 | |
|  	struct pinctrl_gpio_range gpio_range;
 | |
|  
 | |
| -	struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS];
 | |
| +	struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS];
 | |
|  	spinlock_t irq_lock[BCM2835_NUM_BANKS];
 | |
|  };
 | |
|  
 | |
| @@ -385,17 +386,16 @@ static struct gpio_chip bcm2835_gpio_chi
 | |
|  	.can_sleep = false,
 | |
|  };
 | |
|  
 | |
| -static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
 | |
| +static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
 | |
| +					unsigned int bank, u32 mask)
 | |
|  {
 | |
| -	struct bcm2835_gpio_irqdata *irqdata = dev_id;
 | |
| -	struct bcm2835_pinctrl *pc = irqdata->pc;
 | |
| -	int bank = irqdata->bank;
 | |
|  	unsigned long events;
 | |
|  	unsigned offset;
 | |
|  	unsigned gpio;
 | |
|  	unsigned int type;
 | |
|  
 | |
|  	events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
 | |
| +	events &= mask;
 | |
|  	events &= pc->enabled_irq_map[bank];
 | |
|  	for_each_set_bit(offset, &events, 32) {
 | |
|  		gpio = (32 * bank) + offset;
 | |
| @@ -403,7 +403,30 @@ static irqreturn_t bcm2835_gpio_irq_hand
 | |
|  
 | |
|  		generic_handle_irq(irq_linear_revmap(pc->irq_domain, gpio));
 | |
|  	}
 | |
| -	return events ? IRQ_HANDLED : IRQ_NONE;
 | |
| +
 | |
| +	return (events != 0);
 | |
| +}
 | |
| +
 | |
| +static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
 | |
| +{
 | |
| +	struct bcm2835_gpio_irqdata *irqdata = dev_id;
 | |
| +	struct bcm2835_pinctrl *pc = irqdata->pc;
 | |
| +	int handled = 0;
 | |
| +
 | |
| +	switch (irqdata->irqgroup) {
 | |
| +	case 0: /* IRQ0 covers GPIOs 0-27 */
 | |
| +		handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff);
 | |
| +		break;
 | |
| +	case 1: /* IRQ1 covers GPIOs 28-45 */
 | |
| +		handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) |
 | |
| +			  bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
 | |
| +		break;
 | |
| +	case 2: /* IRQ2 covers GPIOs 46-53 */
 | |
| +		handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +	return handled ? IRQ_HANDLED : IRQ_NONE;
 | |
|  }
 | |
|  
 | |
|  static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
 | |
| @@ -992,8 +1015,6 @@ static int bcm2835_pinctrl_probe(struct
 | |
|  	for (i = 0; i < BCM2835_NUM_BANKS; i++) {
 | |
|  		unsigned long events;
 | |
|  		unsigned offset;
 | |
| -		int len;
 | |
| -		char *name;
 | |
|  
 | |
|  		/* clear event detection flags */
 | |
|  		bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
 | |
| @@ -1008,10 +1029,15 @@ static int bcm2835_pinctrl_probe(struct
 | |
|  		for_each_set_bit(offset, &events, 32)
 | |
|  			bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
 | |
|  
 | |
| +		spin_lock_init(&pc->irq_lock[i]);
 | |
| +	}
 | |
| +
 | |
| +	for (i = 0; i < BCM2835_NUM_IRQS; i++) {
 | |
| +		int len;
 | |
| +		char *name;
 | |
|  		pc->irq[i] = irq_of_parse_and_map(np, i);
 | |
|  		pc->irq_data[i].pc = pc;
 | |
| -		pc->irq_data[i].bank = i;
 | |
| -		spin_lock_init(&pc->irq_lock[i]);
 | |
| +		pc->irq_data[i].irqgroup = i;
 | |
|  
 | |
|  		len = strlen(dev_name(pc->dev)) + 16;
 | |
|  		name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
 | |
| @@ -1068,6 +1094,7 @@ static struct platform_driver bcm2835_pi
 | |
|  	.remove = bcm2835_pinctrl_remove,
 | |
|  	.driver = {
 | |
|  		.name = MODULE_NAME,
 | |
| +		.owner = THIS_MODULE,
 | |
|  		.of_match_table = bcm2835_pinctrl_match,
 | |
|  	},
 | |
|  };
 | 
