Skip to content

Commit 15a0e62

Browse files
committed
Merge pull request #1 from selsinork/rpi-3.2.21-gpio-interrupt
Rpi 3.2.21 gpio interrupt
2 parents a1f8d7a + e6c795e commit 15a0e62

File tree

3 files changed

+124
-106
lines changed

3 files changed

+124
-106
lines changed

arch/arm/mach-bcm2708/bcm2708_gpio.c

Lines changed: 108 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
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>
@@ -22,7 +23,7 @@
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
*/
5152
static DEFINE_SPINLOCK(lock); /* GPIO registers */
52-
static DEFINE_SPINLOCK(irq_lock); /* IRQ registers */
5353

5454

5555
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-
*/
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

6863
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
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

209203
static 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

244255
static 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;

arch/arm/mach-bcm2708/include/mach/gpio.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
#ifndef __ASM_ARCH_GPIO_H
1010
#define __ASM_ARCH_GPIO_H
1111

12-
#define ARCH_NR_GPIOS 54 // number of gpio lines
12+
#define BCM_NR_GPIOS 54 // number of gpio lines
1313

1414
#include <asm-generic/gpio.h>
15-
15+
#include <mach/platform.h>
16+
#include <mach/irqs.h>
1617

1718
#ifdef CONFIG_GPIOLIB
1819

@@ -31,17 +32,15 @@ static inline int gpio_cansleep(unsigned gpio)
3132
return __gpio_cansleep(gpio);
3233
}
3334

34-
static inline int gpio_to_irq(unsigned gpio)
35-
{
36-
WARN_ON(1);
37-
return -ENOSYS;
35+
36+
static inline unsigned irq_to_gpio(unsigned irq) {
37+
return (irq-GPIO_IRQ_START);
3838
}
3939

40-
static inline int irq_to_gpio(unsigned int irq)
41-
{
42-
WARN_ON(1);
43-
return -EINVAL;
40+
static inline unsigned gpio_to_irq(unsigned gpio) {
41+
return GPIO_IRQ_START+gpio;
4442
}
43+
#define gpio_to_irq gpio_to_irq
4544

4645
#endif /* CONFIG_GPIOLIB */
4746

arch/arm/mach-bcm2708/include/mach/irqs.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@
185185
#define FIQ_PENDING1 INT_PENDING1
186186
#define FIQ_PENDING2 INT_PENDING2
187187

188-
#define NR_IRQS (64 + 21)
188+
#define HARD_IRQS (64 + 21)
189+
#define GPIO_IRQ_START HARD_IRQS
190+
191+
#define GPIO_IRQS 32*5
192+
193+
#define NR_IRQS HARD_IRQS+GPIO_IRQS
194+
189195

190196
#endif /* _BCM2708_IRQS_H_ */

0 commit comments

Comments
 (0)