V4L/DVB (9598): cx18: Prevent CX23418 from clearing it's outgoing ack interrupts...
authorAndy Walls <awalls@radix.net>
Sun, 9 Nov 2008 21:14:07 +0000 (18:14 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:38:04 +0000 (09:38 -0200)
When the CX23418 CPU unit sent out an ack interrupt to the linux driver, it
also received that interrupt and cleared the flag before the linux driver could
see what the interrupt was for.  This fix prevents the CPU from receiving an
IRQ for it's own outgoing ack's to the linux driver.  This fix is critical now
that the linux driver doesn't poll but relies on these ack interrupts.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx18/cx18-io.c
drivers/media/video/cx18/cx18-io.h
drivers/media/video/cx18/cx18-irq.h

index ab02da727519ee98a75f70be3f36d5f96eac53d8..06f5563d6d5acdea747da57d434a4cddc6535228 100644 (file)
@@ -380,6 +380,17 @@ int cx18_firmware_init(struct cx18 *cx)
                if (sz <= 0)
                        return -EIO;
        }
+
+       /*
+        * The CPU firmware apparently sets up to receive an interrupt for it's
+        * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*).  We get an interrupt
+        * when it sends us an ack, but by the time we process it, that flag in
+        * the SW2 status register has been cleared by the CPU firmware.
+        * We'll prevent that not so useful behavior by clearing the CPU's
+        * interrupt enables for Ack IRQ's we want to process.
+        */
+       cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
        /* initialize GPIO */
        cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
        return 0;
index 48a8adc83c2f70b79249b889b4d273ad8a3b55ae..3c6485fceea06ca8db66fa5d3267a3a890560545 100644 (file)
@@ -262,6 +262,13 @@ void cx18_sw2_irq_disable(struct cx18 *cx, u32 val)
        cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI);
 }
 
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val)
+{
+       u32 r;
+       r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU);
+       cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU);
+}
+
 void cx18_setup_page(struct cx18 *cx, u32 addr)
 {
        u32 val;
index cb695a59670d491d6a728f31730e2a41ca652853..4486b73faf5b52f08b00df55511d937ba31e65fa 100644 (file)
@@ -390,6 +390,7 @@ void cx18_sw1_irq_enable(struct cx18 *cx, u32 val);
 void cx18_sw1_irq_disable(struct cx18 *cx, u32 val);
 void cx18_sw2_irq_enable(struct cx18 *cx, u32 val);
 void cx18_sw2_irq_disable(struct cx18 *cx, u32 val);
+void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val);
 void cx18_setup_page(struct cx18 *cx, u32 addr);
 
 #endif /* CX18_IO_H */
index 6173ca3bc9e4b74e9d2e211c6dd4ef6ea83be558..6f3ec89637626fd9c93c3d96f14fd721d304a160 100644 (file)
@@ -28,6 +28,7 @@
 #define SW1_INT_ENABLE_PCI              0xc7311c
 #define SW2_INT_SET                     0xc73140
 #define SW2_INT_STATUS                  0xc73144
+#define SW2_INT_ENABLE_CPU              0xc73158
 #define SW2_INT_ENABLE_PCI              0xc7315c
 
 irqreturn_t cx18_irq_handler(int irq, void *dev_id);