diff options
author | Daniel Ribeiro <drwyrm@gmail.com> | 2009-06-23 11:34:13 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2009-09-17 03:46:47 -0400 |
commit | b1148fd46c248c8f6c9f3beb79f27cdd83702621 (patch) | |
tree | efbdd1315c17165d868547f4800e67868a5010fe /drivers/mfd/ezx-pcap.c | |
parent | ecd78cbdb989fd593bf4fd69cdb572200e70a553 (diff) |
mfd: fix pcap irq bottom handler
Mask interrupts before servicing them and loop while pcap asserts the interrupt
line.
Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/ezx-pcap.c')
-rw-r--r-- | drivers/mfd/ezx-pcap.c | 49 |
1 files changed, 27 insertions, 22 deletions
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index c5122024f05a..732664f238fe 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
18 | #include <linux/mfd/ezx-pcap.h> | 18 | #include <linux/mfd/ezx-pcap.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/gpio.h> | ||
20 | 21 | ||
21 | #define PCAP_ADC_MAXQ 8 | 22 | #define PCAP_ADC_MAXQ 8 |
22 | struct pcap_adc_request { | 23 | struct pcap_adc_request { |
@@ -155,34 +156,38 @@ static void pcap_isr_work(struct work_struct *work) | |||
155 | u32 msr, isr, int_sel, service; | 156 | u32 msr, isr, int_sel, service; |
156 | int irq; | 157 | int irq; |
157 | 158 | ||
158 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); | 159 | do { |
159 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); | 160 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); |
161 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); | ||
160 | 162 | ||
161 | /* We cant service/ack irqs that are assigned to port 2 */ | 163 | /* We cant service/ack irqs that are assigned to port 2 */ |
162 | if (!(pdata->config & PCAP_SECOND_PORT)) { | 164 | if (!(pdata->config & PCAP_SECOND_PORT)) { |
163 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); | 165 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); |
164 | isr &= ~int_sel; | 166 | isr &= ~int_sel; |
165 | } | 167 | } |
166 | ezx_pcap_write(pcap, PCAP_REG_ISR, isr); | ||
167 | 168 | ||
168 | local_irq_disable(); | 169 | ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr); |
169 | service = isr & ~msr; | 170 | ezx_pcap_write(pcap, PCAP_REG_ISR, isr); |
170 | 171 | ||
171 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { | 172 | local_irq_disable(); |
172 | if (service & 1) { | 173 | service = isr & ~msr; |
173 | struct irq_desc *desc = irq_to_desc(irq); | 174 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { |
175 | if (service & 1) { | ||
176 | struct irq_desc *desc = irq_to_desc(irq); | ||
174 | 177 | ||
175 | if (WARN(!desc, KERN_WARNING | 178 | if (WARN(!desc, KERN_WARNING |
176 | "Invalid PCAP IRQ %d\n", irq)) | 179 | "Invalid PCAP IRQ %d\n", irq)) |
177 | break; | 180 | break; |
178 | 181 | ||
179 | if (desc->status & IRQ_DISABLED) | 182 | if (desc->status & IRQ_DISABLED) |
180 | note_interrupt(irq, desc, IRQ_NONE); | 183 | note_interrupt(irq, desc, IRQ_NONE); |
181 | else | 184 | else |
182 | desc->handle_irq(irq, desc); | 185 | desc->handle_irq(irq, desc); |
186 | } | ||
183 | } | 187 | } |
184 | } | 188 | local_irq_enable(); |
185 | local_irq_enable(); | 189 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); |
190 | } while (gpio_get_value(irq_to_gpio(pcap->spi->irq))); | ||
186 | } | 191 | } |
187 | 192 | ||
188 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) | 193 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) |