i2c-omap: Fix support for OMAP15xx
Subsystems (4)
PATCH 2/2 i2c-omap: Fix support for OMAP15xx
Current implementation of omap_i2c_isr doesn't work on OMAP5910 (Too much work in one IRQ). Interrupt service routine is broken in these aspects:
* it tries to ack interrupt by writing to read-only status register.
* it doesn't ackowledge interrupt properly by reading interrupt vector register.
I'm assuming that driver works correctly on other OMAPs (right? ;-)), so proposed patch adds interrupt service routine for 15xx cpus and deletes rev1 stuff from omap_i2c_isr. Tested on OMAP5910 with DS1339 clock on I2C bus.
Signed-off-by Ladislav Michl <[email protected]>
drivers/i2c/busses/i2c-omap.c +60 -16
@@ -429,6 +429,60 @@ omap_i2c_ack_stat(struct omap_i2c_dev *domap_i2c_write_reg (dev,OMAP_I2C_STAT_REG , stat); } +#ifdef CONFIG_ARCH_OMAP15XX +static irqreturn_t +omap_i2c_rev1_isr (int this_irq,void *dev_id,struct pt_regs *regs) +{ +struct omap_i2c_dev *dev = dev_id; +u16 iv, w; + + iv =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG ); +switch (iv) { +case 0x00 :/* None */ +break ; +case 0x01 :/* Arbitration lost */ +dev_err (dev->dev,"Arbitration lost\n" ); +omap_i2c_complete_cmd (dev,OMAP_I2C_STAT_AL ); +break ; +case 0x02 :/* No acknowledgement */ +omap_i2c_complete_cmd (dev,OMAP_I2C_STAT_NACK ); +omap_i2c_write_reg (dev,OMAP_I2C_CON_REG ,OMAP_I2C_CON_STP ); +break ; +case 0x03 :/* Register access ready */ +omap_i2c_complete_cmd (dev,0 ); +break ; +case 0x04 :/* Receive data ready */ +if (dev->buf_len) { + w =omap_i2c_read_reg (dev,OMAP_I2C_DATA_REG ); + *dev->buf++ = w; + dev->buf_len--; +if (dev->buf_len) { + *dev->buf++ = w >>8 ; + dev->buf_len--; + } + }else +dev_err (dev->dev,"RRDY IRQ while no data requested\n" ); +break ; +case 0x05 :/* Transmit data ready */ +if (dev->buf_len) { + w = *dev->buf++; + dev->buf_len--; +if (dev->buf_len) { + w |= *dev->buf++ <<8 ; + dev->buf_len--; + } +omap_i2c_write_reg (dev,OMAP_I2C_DATA_REG , w); + }else +dev_err (dev->dev,"XRDY IRQ while no data to send\n" ); +break ; +default : +return IRQ_NONE ; + } + +return IRQ_HANDLED ; +} +#endif +static irqreturn_t omap_i2c_isr (int this_irq,void *dev_id,struct pt_regs *regs) {
@@ -436,7 +490,6 @@ omap_i2c_isr(int this_irq, void *dev_id,u16 bits;u16 stat, w;int count =0 ; -u16 iv_read; bits =omap_i2c_read_reg (dev,OMAP_I2C_IE_REG );while ((stat = (omap_i2c_read_reg (dev,OMAP_I2C_STAT_REG ))) & bits) {
@@ -450,8 +503,6 @@ omap_i2c_isr(int this_irq, void *dev_id,if (stat &OMAP_I2C_STAT_ARDY ) {omap_i2c_complete_cmd (dev,0 ); -if (dev->rev1) - iv_read =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG );continue ; }if (stat &OMAP_I2C_STAT_RRDY ) {
@@ -463,13 +514,9 @@ omap_i2c_isr(int this_irq, void *dev_id, *dev->buf++ = w >>8 ; dev->buf_len--; } -if (dev->rev1 && !dev->buf_len) -omap_i2c_complete_cmd (dev,0 ); }else dev_err (dev->dev,"RRDY IRQ while no data requested\n" );omap_i2c_ack_stat (dev,OMAP_I2C_STAT_RRDY ); -if (dev->rev1) - iv_read =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG );continue ; }if (stat &OMAP_I2C_STAT_XRDY ) {
@@ -493,11 +540,6 @@ omap_i2c_isr(int this_irq, void *dev_id,#endif omap_i2c_write_reg (dev,OMAP_I2C_DATA_REG , w);omap_i2c_ack_stat (dev,OMAP_I2C_STAT_XRDY ); -if (dev->rev1) { - iv_read =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG ); -if (!dev->buf_len) -omap_i2c_complete_cmd (dev,0 ); - }if (bail_out)omap_i2c_complete_cmd (dev,1 <<15 );continue ;
@@ -518,8 +560,6 @@ omap_i2c_isr(int this_irq, void *dev_id,dev_err (dev->dev,"Arbitration lost\n" );omap_i2c_complete_cmd (dev,OMAP_I2C_STAT_AL ); } -if (dev->rev1) - iv_read =omap_i2c_read_reg (dev,OMAP_I2C_IV_REG ); }return count ?IRQ_HANDLED :IRQ_NONE ;
@@ -591,8 +631,12 @@ omap_i2c_probe(struct platform_device *p/* reset ASAP, clearing any IRQs */ omap_i2c_reset (dev); - r =request_irq (dev->irq, omap_i2c_isr,0 , - driver_name, dev); +#ifdef CONFIG_ARCH_OMAP15XX + r =request_irq (dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr, +0 , driver_name, dev); +#else + r =request_irq (dev->irq, omap_i2c_isr,0 , driver_name, dev); +#endif if (r) {dev_err (dev->dev,"failure requesting irq %i\n" , dev->irq); goto do_unuse_clocks;