aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/ezx-pcap.c
diff options
context:
space:
mode:
authorDaniel Ribeiro <drwyrm@gmail.com>2009-06-23 11:34:13 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2009-09-17 03:46:47 -0400
commitb1148fd46c248c8f6c9f3beb79f27cdd83702621 (patch)
treeefbdd1315c17165d868547f4800e67868a5010fe /drivers/mfd/ezx-pcap.c
parentecd78cbdb989fd593bf4fd69cdb572200e70a553 (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.c49
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
22struct pcap_adc_request { 23struct 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
188static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) 193static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)