mfd: fix pcap irq bottom handler
authorDaniel Ribeiro <drwyrm@gmail.com>
Tue, 23 Jun 2009 15:34:13 +0000 (12:34 -0300)
committerSamuel Ortiz <sameo@linux.intel.com>
Thu, 17 Sep 2009 07:46:47 +0000 (09:46 +0200)
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>
drivers/mfd/ezx-pcap.c

index c512202..732664f 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/irq.h>
 #include <linux/mfd/ezx-pcap.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 
 #define PCAP_ADC_MAXQ          8
 struct pcap_adc_request {
@@ -155,34 +156,38 @@ static void pcap_isr_work(struct work_struct *work)
        u32 msr, isr, int_sel, service;
        int irq;
 
-       ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
-       ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);
+       do {
+               ezx_pcap_read(pcap, PCAP_REG_MSR, &msr);
+               ezx_pcap_read(pcap, PCAP_REG_ISR, &isr);
 
-       /* We cant service/ack irqs that are assigned to port 2 */
-       if (!(pdata->config & PCAP_SECOND_PORT)) {
-               ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
-               isr &= ~int_sel;
-       }
-       ezx_pcap_write(pcap, PCAP_REG_ISR, isr);
+               /* We cant service/ack irqs that are assigned to port 2 */
+               if (!(pdata->config & PCAP_SECOND_PORT)) {
+                       ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel);
+                       isr &= ~int_sel;
+               }
 
-       local_irq_disable();
-       service = isr & ~msr;
+               ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr);
+               ezx_pcap_write(pcap, PCAP_REG_ISR, isr);
 
-       for (irq = pcap->irq_base; service; service >>= 1, irq++) {
-               if (service & 1) {
-                       struct irq_desc *desc = irq_to_desc(irq);
+               local_irq_disable();
+               service = isr & ~msr;
+               for (irq = pcap->irq_base; service; service >>= 1, irq++) {
+                       if (service & 1) {
+                               struct irq_desc *desc = irq_to_desc(irq);
 
-                       if (WARN(!desc, KERN_WARNING
-                                       "Invalid PCAP IRQ %d\n", irq))
-                               break;
+                               if (WARN(!desc, KERN_WARNING
+                                               "Invalid PCAP IRQ %d\n", irq))
+                                       break;
 
-                       if (desc->status & IRQ_DISABLED)
-                               note_interrupt(irq, desc, IRQ_NONE);
-                       else
-                               desc->handle_irq(irq, desc);
+                               if (desc->status & IRQ_DISABLED)
+                                       note_interrupt(irq, desc, IRQ_NONE);
+                               else
+                                       desc->handle_irq(irq, desc);
+                       }
                }
-       }
-       local_irq_enable();
+               local_irq_enable();
+               ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
+       } while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
 }
 
 static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)