14
14
#include <linux/list.h>
15
15
#include <linux/io.h>
16
16
#include <linux/irq.h>
17
+ #include <linux/interrupt.h>
17
18
#include <linux/slab.h>
18
19
#include <linux/gpio.h>
19
20
#include <linux/platform_device.h>
22
23
23
24
#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
24
25
#define DRIVER_NAME BCM_GPIO_DRIVER_NAME
25
- #define BCM_GPIO_USE_IRQ 0
26
+ #define BCM_GPIO_USE_IRQ 1
26
27
27
28
#define GPIOFSEL (x ) (0x00+(x)*4)
28
29
#define GPIOSET (x ) (0x1c+(x)*4)
@@ -49,20 +50,14 @@ enum { GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT,
49
50
* the IRQ code simpler.
50
51
*/
51
52
static DEFINE_SPINLOCK (lock ); /* GPIO registers */
52
- static DEFINE_SPINLOCK (irq_lock ); /* IRQ registers */
53
53
54
54
55
55
struct 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
- */
61
56
struct list_head list ;
62
-
63
57
void __iomem * base ;
64
- unsigned irq_base ;
65
58
struct gpio_chip gc ;
59
+ unsigned long rising ;
60
+ unsigned long falling ;
66
61
};
67
62
68
63
static 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
74
69
unsigned gpio_field_offset = (offset - 10 * gpio_bank ) * 3 ;
75
70
76
71
//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 )
78
73
return - EINVAL ;
79
74
80
75
spin_lock_irqsave (& lock , flags );
@@ -112,7 +107,7 @@ static int bcm2708_gpio_get(struct gpio_chip *gc, unsigned offset)
112
107
unsigned gpio_field_offset = (offset - 32 * gpio_bank );
113
108
unsigned lev ;
114
109
115
- if (offset >= ARCH_NR_GPIOS )
110
+ if (offset >= BCM_NR_GPIOS )
116
111
return 0 ;
117
112
lev = readl (gpio -> base + GPIOLEV (gpio_bank ));
118
113
//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)
125
120
unsigned gpio_bank = offset /32 ;
126
121
unsigned gpio_field_offset = (offset - 32 * gpio_bank );
127
122
//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 )
129
124
return ;
130
125
if (value )
131
126
writel (1 <<gpio_field_offset , gpio -> base + GPIOSET (gpio_bank ));
132
127
else
133
128
writel (1 <<gpio_field_offset , gpio -> base + GPIOCLR (gpio_bank ));
134
129
}
135
130
136
- /*
131
+ /*************************************************************************************************************************
137
132
* bcm2708 GPIO IRQ
138
133
*/
139
134
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 ;
146
135
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
151
137
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)
157
139
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 );
161
142
}
162
143
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 ;
171
144
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 ))
173
150
return - EINVAL ;
174
151
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
+ }
176
157
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
+ }
181
165
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 ));
198
173
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
+ }
203
177
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 ));
205
185
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
+ }
207
201
}
208
202
209
203
static struct irq_chip bcm2708_irqchip = {
210
204
.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 ,
214
210
};
215
211
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 ));
238
222
}
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 );
239
244
}
240
- desc -> chip -> unmask ( irq );
245
+ setup_irq ( IRQ_GPIO3 , & bcm2708_gpio_irq );
241
246
}
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 ******************************************************************************************************************/
243
254
244
255
static int bcm2708_gpio_probe (struct platform_device * dev )
245
256
{
@@ -264,7 +275,7 @@ static int bcm2708_gpio_probe(struct platform_device *dev)
264
275
265
276
ucb -> gc .label = "bcm2708_gpio" ;
266
277
ucb -> gc .base = 0 ;
267
- ucb -> gc .ngpio = ARCH_NR_GPIOS ;
278
+ ucb -> gc .ngpio = BCM_NR_GPIOS ;
268
279
ucb -> gc .owner = THIS_MODULE ;
269
280
270
281
ucb -> gc .direction_input = bcm2708_gpio_dir_in ;
@@ -273,6 +284,8 @@ static int bcm2708_gpio_probe(struct platform_device *dev)
273
284
ucb -> gc .set = bcm2708_gpio_set ;
274
285
ucb -> gc .can_sleep = 0 ;
275
286
287
+ bcm2708_gpio_irq_init (ucb );
288
+
276
289
err = gpiochip_add (& ucb -> gc );
277
290
if (err )
278
291
goto err ;
0 commit comments