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 linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb