Oliver Endriss wrote:
> Imho the interrupt processing was broken:
> - The first I2C interrupt should be used to wake-up the task.
> It does not matter that it takes some time until ERR in IIC_STA
> will be updated. We don't need it.
> - Interrupts must be acknowledged at the end of the ISR.
>
> @all
> Please test the attached patch.
> There shouldn't be any unexpected I2C interrupts anymore.
Attached is an updated patch which does extended status checking.
CU
Oliver
--
----------------------------------------------------------------
VDR Remote Plugin 0.3.9: http://www.escape-edv.de/endriss/vdr/
----------------------------------------------------------------
diff -r 0f9dfb292f40 linux/drivers/media/common/saa7146_core.c
--- a/linux/drivers/media/common/saa7146_core.c Tue Jul 17 02:27:12 2007 +0200
+++ b/linux/drivers/media/common/saa7146_core.c Tue Jul 17 06:49:46 2007 +0200
@@ -252,18 +252,17 @@ static irqreturn_t interrupt_hw(int irq,
#endif
{
struct saa7146_dev *dev = dev_id;
- u32 isr = 0;
+ u32 isr;
+ u32 ack_isr;
/* read out the interrupt status register */
- isr = saa7146_read(dev, ISR);
+ ack_isr = isr = saa7146_read(dev, ISR);
/* is this our interrupt? */
if ( 0 == isr ) {
/* nope, some other device */
return IRQ_NONE;
}
-
- saa7146_write(dev, ISR, isr);
if( 0 != (dev->ext)) {
if( 0 != (dev->ext->irq_mask & isr )) {
@@ -287,21 +286,16 @@ static irqreturn_t interrupt_hw(int irq,
isr &= ~MASK_28;
}
if (0 != (isr & (MASK_16|MASK_17))) {
- u32 status = saa7146_read(dev, I2C_STATUS);
- if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
- SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
- /* only wake up if we expect something */
- if( 0 != dev->i2c_op ) {
- u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
- u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f;
- DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr));
- dev->i2c_op = 0;
- wake_up(&dev->i2c_wq);
- } else {
- DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
- }
+ SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+ /* only wake up if we expect something */
+ if( 0 != dev->i2c_op ) {
+ dev->i2c_op = 0;
+ wake_up(&dev->i2c_wq);
} else {
- DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
+ u32 psr = saa7146_read(dev, PSR);
+ u32 ssr = saa7146_read(dev, SSR);
+ printk(KERN_WARNING "saa7146: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+ isr, psr, ssr);
}
isr &= ~(MASK_16|MASK_17);
}
@@ -310,6 +304,7 @@ static irqreturn_t interrupt_hw(int irq,
ERR(("disabling interrupt source(s)!\n"));
SAA7146_IER_DISABLE(dev,isr);
}
+ saa7146_write(dev, ISR, ack_isr);
return IRQ_HANDLED;
}
diff -r 0f9dfb292f40 linux/drivers/media/common/saa7146_i2c.c
--- a/linux/drivers/media/common/saa7146_i2c.c Tue Jul 17 02:27:12 2007 +0200
+++ b/linux/drivers/media/common/saa7146_i2c.c Tue Jul 17 06:49:46 2007 +0200
@@ -247,8 +247,16 @@ static int saa7146_i2c_writeout(struct s
}
/* give a detailed status report */
- if ( 0 != (status & SAA7146_I2C_ERR)) {
-
+ if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+ SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+ SAA7146_I2C_AL | SAA7146_I2C_ERR |
+ SAA7146_I2C_BUSY)) ) {
+
+ if ( 0 == (status & SAA7146_I2C_ERR) ||
+ 0 == (status & SAA7146_I2C_BUSY) ) {
+ printk(KERN_WARNING "%s: unexpected i2c status %04x\n",
+ __FUNCTION__, status);
+ }
if( 0 != (status & SAA7146_I2C_SPERR) ) {
DEB_I2C(("error due to invalid start/stop condition.\n"));
}
_______________________________________________
linux-dvb mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb