1414#include <linux/list.h>
1515#include <linux/io.h>
1616#include <linux/irq.h>
17+ #include <linux/interrupt.h>
1718#include <linux/slab.h>
1819#include <linux/gpio.h>
1920#include <linux/platform_device.h>
2223
2324#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
2425#define DRIVER_NAME BCM_GPIO_DRIVER_NAME
25- #define BCM_GPIO_USE_IRQ 0
26+ #define BCM_GPIO_USE_IRQ 1
2627
2728#define GPIOFSEL (x ) (0x00+(x)*4)
2829#define GPIOSET (x ) (0x1c+(x)*4)
@@ -49,20 +50,14 @@ enum { GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT,
4950 * the IRQ code simpler.
5051 */
5152static DEFINE_SPINLOCK (lock ); /* GPIO registers */
52- static DEFINE_SPINLOCK (irq_lock ); /* IRQ registers */
5353
5454
5555struct bcm2708_gpio {
56- /* We use a list of bcm2708_gpio structs for each trigger IRQ in the main
57- * interrupts controller of the system. We need this to support systems
58- * in which more that one bcm2708s are connected to the same IRQ. The ISR
59- * interates through this list to find the source of the interrupt.
60- */
6156 struct list_head list ;
62-
6357 void __iomem * base ;
64- unsigned irq_base ;
6558 struct gpio_chip gc ;
59+ unsigned long rising ;
60+ unsigned long falling ;
6661};
6762
6863static int bcm2708_set_function (struct gpio_chip * gc , unsigned offset , int function )
@@ -74,7 +69,7 @@ static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset, int funct
7469 unsigned gpio_field_offset = (offset - 10 * gpio_bank ) * 3 ;
7570
7671//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set_function %p (%d,%d)\n", gc, offset, function);
77- if (offset >= ARCH_NR_GPIOS )
72+ if (offset >= BCM_NR_GPIOS )
7873 return - EINVAL ;
7974
8075 spin_lock_irqsave (& lock , flags );
@@ -112,7 +107,7 @@ static int bcm2708_gpio_get(struct gpio_chip *gc, unsigned offset)
112107 unsigned gpio_field_offset = (offset - 32 * gpio_bank );
113108 unsigned lev ;
114109
115- if (offset >= ARCH_NR_GPIOS )
110+ if (offset >= BCM_NR_GPIOS )
116111 return 0 ;
117112 lev = readl (gpio -> base + GPIOLEV (gpio_bank ));
118113//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_get %p (%d)=%d\n", gc, offset, 0x1 & (lev>>gpio_field_offset));
@@ -125,121 +120,137 @@ static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
125120 unsigned gpio_bank = offset /32 ;
126121 unsigned gpio_field_offset = (offset - 32 * gpio_bank );
127122//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set %p (%d=%d)\n", gc, offset, value);
128- if (offset >= ARCH_NR_GPIOS )
123+ if (offset >= BCM_NR_GPIOS )
129124 return ;
130125 if (value )
131126 writel (1 <<gpio_field_offset , gpio -> base + GPIOSET (gpio_bank ));
132127 else
133128 writel (1 <<gpio_field_offset , gpio -> base + GPIOCLR (gpio_bank ));
134129}
135130
136- /*
131+ /*************************************************************************************************************************
137132 * bcm2708 GPIO IRQ
138133 */
139134
140- #if BCM_GPIO_USE_IRQ
141- static void bcm2708_irq_disable (unsigned irq )
142- {
143- struct bcm2708_gpio * chip = get_irq_chip_data (irq );
144- //int offset = irq - gpio->irq_base;
145- unsigned long flags ;
146135
147- spin_lock_irqsave (& chip -> irq_lock , flags );
148- // disable gpio interrupts here
149- spin_unlock_irqrestore (& chip -> irq_lock , flags );
150- }
136+ #if BCM_GPIO_USE_IRQ
151137
152- static void bcm2708_irq_enable (unsigned irq )
153- {
154- struct bcm2708_gpio * chip = get_irq_chip_data (irq );
155- //int offset = irq - chip->irq_base;
156- unsigned long flags ;
138+ #define IRQ_TO_GPIO (x ) irq_to_gpio(x)
157139
158- spin_lock_irqsave (& chip -> irq_lock , flags );
159- // enable gpio interrupts here
160- spin_unlock_irqrestore (& chip -> irq_lock , flags );
140+ static int bcm2708_gpio_to_irq (struct gpio_chip * chip , unsigned gpio ) {
141+ return gpio_to_irq (gpio );
161142}
162143
163- static int bcm2708_irq_type (unsigned irq , unsigned trigger )
164- {
165- struct bcm2708_gpio * chip = get_irq_chip_data (irq );
166- int offset = irq - chip -> irq_base ;
167- unsigned long flags ;
168- unsigned gpio_bank = offset /32 ;
169- unsigned gpio_field_offset = (offset - 32 * gpio_bank );
170- unsigned gpioren , gpiofen , gpiohen , gpiolen ;
171144
172- if (offset < 0 || offset >= ARCH_NR_GPIOS )
145+ static int bcm2708_gpio_irq_set_type (struct irq_data * d , unsigned type ) {
146+ unsigned irq = d -> irq ;
147+ struct bcm2708_gpio * gpio = irq_get_chip_data (irq );
148+
149+ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING ))
173150 return - EINVAL ;
174151
175- spin_lock_irqsave (& chip -> irq_lock , flags );
152+ if (type & IRQ_TYPE_EDGE_RISING ) {
153+ gpio -> rising |= (1 << IRQ_TO_GPIO (irq ));
154+ } else {
155+ gpio -> rising &= ~(1 << IRQ_TO_GPIO (irq ));
156+ }
176157
177- gpioren = readl (chip -> base + GPIOREN (gpio_bank ));
178- gpiofen = readl (chip -> base + GPIOFEN (gpio_bank ));
179- gpiohen = readl (chip -> base + GPIOHEN (gpio_bank ));
180- gpiolen = readl (chip -> base + GPIOLEN (gpio_bank ));
158+ if (type & IRQ_TYPE_EDGE_FALLING ) {
159+ gpio -> falling |= (1 << IRQ_TO_GPIO (irq ));
160+ } else {
161+ gpio -> falling &= ~(1 << IRQ_TO_GPIO (irq ));
162+ }
163+ return 0 ;
164+ }
181165
182- if (trigger & (IRQ_TYPE_EDGE_RISING ))
183- gpioren |= (1 <<gpio_field_offset );
184- else
185- gpioren &= ~(1 <<gpio_field_offset );
186- if (trigger & (IRQ_TYPE_EDGE_FALLING ))
187- gpiofen |= (1 <<gpio_field_offset );
188- else
189- gpiofen &= ~(1 <<gpio_field_offset );
190- if (trigger & (IRQ_TYPE_LEVEL_HIGH ))
191- gpiohen |= (1 <<gpio_field_offset );
192- else
193- gpiohen &= ~(1 <<gpio_field_offset );
194- if (trigger & (IRQ_TYPE_LEVEL_LOW ))
195- gpiolen |= (1 <<gpio_field_offset );
196- else
197- gpiolen &= ~(1 <<gpio_field_offset );
166+ static void bcm2708_gpio_irq_mask (struct irq_data * d ) {
167+ unsigned irq = d -> irq ;
168+ struct bcm2708_gpio * gpio = irq_get_chip_data (irq );
169+ unsigned gn = IRQ_TO_GPIO (irq );
170+ unsigned gb = gn /32 ;
171+ unsigned long rising = readl (gpio -> base + GPIOREN (gb ));
172+ unsigned long falling = readl (gpio -> base + GPIOFEN (gb ));
198173
199- writel (gpioren , chip -> base + GPIOREN (gpio_bank ));
200- writel (gpiofen , chip -> base + GPIOFEN (gpio_bank ));
201- writel (gpiohen , chip -> base + GPIOHEN (gpio_bank ));
202- writel (gpiolen , chip -> base + GPIOLEN (gpio_bank ));
174+ writel (rising & ~(1 << gn ), gpio -> base + GPIOREN (gb ));
175+ writel (falling & ~(1 << gn ), gpio -> base + GPIOFEN (gb ));
176+ }
203177
204- spin_unlock_irqrestore (& chip -> irq_lock , flags );
178+ static void bcm2708_gpio_irq_unmask (struct irq_data * d ) {
179+ unsigned irq = d -> irq ;
180+ struct bcm2708_gpio * gpio = irq_get_chip_data (irq );
181+ unsigned gn = IRQ_TO_GPIO (irq );
182+ unsigned gb = gn /32 ;
183+ unsigned long rising = readl (gpio -> base + GPIOREN (gb ));
184+ unsigned long falling = readl (gpio -> base + GPIOFEN (gb ));
205185
206- return 0 ;
186+ gn = gn %32 ;
187+
188+ writel (1 << gn , gpio -> base + GPIOEDS (gb ));
189+
190+ if (gpio -> rising & (1 << gn )) {
191+ writel (rising | (1 << gn ), gpio -> base + GPIOREN (gb ));
192+ } else {
193+ writel (rising & ~(1 << gn ), gpio -> base + GPIOREN (gb ));
194+ }
195+
196+ if (gpio -> falling & (1 << gn )) {
197+ writel (falling | (1 << gn ), gpio -> base + GPIOFEN (gb ));
198+ } else {
199+ writel (falling & ~(1 << gn ), gpio -> base + GPIOFEN (gb ));
200+ }
207201}
208202
209203static struct irq_chip bcm2708_irqchip = {
210204 .name = "GPIO" ,
211- .enable = bcm2708_irq_enable ,
212- .disable = bcm2708_irq_disable ,
213- .set_type = bcm2708_irq_type ,
205+ .irq_enable = bcm2708_gpio_irq_unmask ,
206+ .irq_disable = bcm2708_gpio_irq_mask ,
207+ .irq_unmask = bcm2708_gpio_irq_unmask ,
208+ .irq_mask = bcm2708_gpio_irq_mask ,
209+ .irq_set_type = bcm2708_gpio_irq_set_type ,
214210};
215211
216- static void bcm2708_irq_handler (unsigned irq , struct irq_desc * desc )
217- {
218- struct list_head * chip_list = get_irq_data (irq );
219- struct list_head * ptr ;
220- struct bcm2708_gpio * chip ;
221- unsigned gpio_bank ;
222-
223- desc -> chip -> ack (irq );
224- list_for_each (ptr , chip_list ) {
225- unsigned long pending ;
226- int offset ;
227-
228- chip = list_entry (ptr , struct bcm2708_gpio , list );
229- for (gpio_bank = 0 ; gpio_bank < ARCH_NR_GPIOS /32 ; gpio_bank ++ ) {
230- pending = readl (chip -> base + GPIOEDS (gpio_bank ));
231- writel (pending , chip -> base + GPIOEDS (gpio_bank ));
232-
233- if (pending == 0 )
234- continue ;
235-
236- for_each_set_bit (offset , & pending , ARCH_NR_GPIOS )
237- generic_handle_irq (gpio_to_irq (offset + 32 * gpio_bank ));
212+ static irqreturn_t bcm2708_gpio_interrupt (int irq , void * dev_id ) {
213+ unsigned long edsr ;
214+ unsigned bank ;
215+ int i ;
216+ unsigned gpio ;
217+ for (bank = 0 ; bank <=1 ; bank ++ ) {
218+ edsr = readl (__io_address (GPIO_BASE )+ GPIOEDS (bank ));
219+ for_each_set_bit (i , & edsr , 32 ) {
220+ gpio = i + bank * 32 ;
221+ generic_handle_irq (gpio_to_irq (gpio ));
238222 }
223+ writel (0xffffffff , __io_address (GPIO_BASE )+ GPIOEDS (bank ));
224+ }
225+ return IRQ_HANDLED ;
226+ }
227+
228+ static struct irqaction bcm2708_gpio_irq = {
229+ .name = "BCM2708 GPIO catchall handler" ,
230+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
231+ .handler = bcm2708_gpio_interrupt ,
232+ };
233+
234+
235+ static void bcm2708_gpio_irq_init (struct bcm2708_gpio * ucb ) {
236+ unsigned irq ;
237+
238+ ucb -> gc .to_irq = bcm2708_gpio_to_irq ;
239+
240+ for (irq = GPIO_IRQ_START ; irq < (GPIO_IRQ_START + GPIO_IRQS ); irq ++ ) {
241+ irq_set_chip_data (irq , ucb );
242+ irq_set_chip (irq , & bcm2708_irqchip );
243+ set_irq_flags (irq , IRQF_VALID );
239244 }
240- desc -> chip -> unmask ( irq );
245+ setup_irq ( IRQ_GPIO3 , & bcm2708_gpio_irq );
241246}
242- #endif /* #if BCM_GPIO_USE_IRQ */
247+
248+ #else
249+
250+ static void bcm2708_gpio_irq_init (struct bcm2708_gpio * ucb ) {
251+ }
252+
253+ #endif /* #if BCM_GPIO_USE_IRQ ******************************************************************************************************************/
243254
244255static int bcm2708_gpio_probe (struct platform_device * dev )
245256{
@@ -264,7 +275,7 @@ static int bcm2708_gpio_probe(struct platform_device *dev)
264275
265276 ucb -> gc .label = "bcm2708_gpio" ;
266277 ucb -> gc .base = 0 ;
267- ucb -> gc .ngpio = ARCH_NR_GPIOS ;
278+ ucb -> gc .ngpio = BCM_NR_GPIOS ;
268279 ucb -> gc .owner = THIS_MODULE ;
269280
270281 ucb -> gc .direction_input = bcm2708_gpio_dir_in ;
@@ -273,6 +284,8 @@ static int bcm2708_gpio_probe(struct platform_device *dev)
273284 ucb -> gc .set = bcm2708_gpio_set ;
274285 ucb -> gc .can_sleep = 0 ;
275286
287+ bcm2708_gpio_irq_init (ucb );
288+
276289 err = gpiochip_add (& ucb -> gc );
277290 if (err )
278291 goto err ;
0 commit comments