Here is an answer from Ben, I still have to test it myself.
Benjamin Herrenschmidt wrote: > On Tue, 2006-05-30 at 21:09 +0100, Konstantin V. Gavrilenko wrote: > SNIP < > Does this help ? > > Ben. > > ------ > From: Linux Kernel Mailing List <[email protected]> > To: [email protected] > Subject: [PATCH] powermac: Fix i2c on keywest based chips > Date: Sun, 23 Apr 2006 17:11:14 GMT > > commit 60162e498e220d1f03bbee5bac0a9ddd6de60ae7 > tree 8cbcbea6060eb2b9f7d39784385efdfc6e947b52 > parent 28897731318dc8f63f683eed9091e446916ad706 > author Benjamin Herrenschmidt <[EMAIL PROTECTED]> Tue, 18 Apr 2006 14:11:53 +1000 > committer Paul Mackerras <[EMAIL PROTECTED]> Fri, 21 Apr 2006 22:29:46 +1000 > > [PATCH] powermac: Fix i2c on keywest based chips > > The new i2c implementation for PowerMac has a regression that causes the > hardware to go out of state when probing non-existent devices. While > fixing that, I also found & fixed a couple of other corner cases. This > fixes booting with a pbbuttons version that scans the i2c bus for an LMU > controller among others. Tested on a dual G5 with thermal control (which > has heavy i2c activity) with no problem so far. > > Signed-off-by: Benjamin Herrenschmidt <[EMAIL PROTECTED]> > Signed-off-by: Paul Mackerras <[EMAIL PROTECTED]> > > arch/powerpc/platforms/powermac/low_i2c.c | 78 +++++++++++++----------------- > 1 files changed, 35 insertions(+), 43 deletions(-) > > diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c > index e14f9ac..df2343e 100644 > --- a/arch/powerpc/platforms/powermac/low_i2c.c > +++ b/arch/powerpc/platforms/powermac/low_i2c.c > @@ -231,6 +231,14 @@ static u8 kw_i2c_wait_interrupt(struct p > return isr; > } > > +static void kw_i2c_do_stop(struct pmac_i2c_host_kw *host, int result) > +{ > + kw_write_reg(reg_control, KW_I2C_CTL_STOP); > + host->state = state_stop; > + host->result = result; > +} > + > + > static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr) > { > u8 ack; > @@ -246,42 +254,36 @@ static void kw_i2c_handle_interrupt(stru > } > > if (isr == 0) { > + printk(KERN_WARNING "low_i2c: Timeout in i2c transfer" > + " on keywest !\n"); > if (host->state != state_stop) { > - DBG_LOW("KW: Timeout !\n"); > - host->result = -EIO; > - goto stop; > - } > - if (host->state == state_stop) { > - ack = kw_read_reg(reg_status); > - if (ack & KW_I2C_STAT_BUSY) > - kw_write_reg(reg_status, 0); > - host->state = state_idle; > - kw_write_reg(reg_ier, 0x00); > - if (!host->polled) > - complete(&host->complete); > + kw_i2c_do_stop(host, -EIO); > + return; > } > + ack = kw_read_reg(reg_status); > + if (ack & KW_I2C_STAT_BUSY) > + kw_write_reg(reg_status, 0); > + host->state = state_idle; > + kw_write_reg(reg_ier, 0x00); > + if (!host->polled) > + complete(&host->complete); > return; > } > > if (isr & KW_I2C_IRQ_ADDR) { > ack = kw_read_reg(reg_status); > if (host->state != state_addr) { > - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); > WRONG_STATE("KW_I2C_IRQ_ADDR"); > - host->result = -EIO; > - goto stop; > + kw_i2c_do_stop(host, -EIO); > } > if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { > - host->result = -ENODEV; > - DBG_LOW("KW: NAK on address\n"); > + host->result = -ENXIO; > host->state = state_stop; > - return; > + DBG_LOW("KW: NAK on address\n"); > } else { > - if (host->len == 0) { > - kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR); > - goto stop; > - } > - if (host->rw) { > + if (host->len == 0) > + kw_i2c_do_stop(host, 0); > + else if (host->rw) { > host->state = state_read; > if (host->len > 1) > kw_write_reg(reg_control, > @@ -308,25 +310,19 @@ static void kw_i2c_handle_interrupt(stru > ack = kw_read_reg(reg_status); > if ((ack & KW_I2C_STAT_LAST_AAK) == 0) { > DBG_LOW("KW: nack on data write\n"); > - host->result = -EIO; > - goto stop; > + host->result = -EFBIG; > + host->state = state_stop; > } else if (host->len) { > kw_write_reg(reg_data, *(host->data++)); > host->len--; > - } else { > - kw_write_reg(reg_control, KW_I2C_CTL_STOP); > - host->state = state_stop; > - host->result = 0; > - } > - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); > + } else > + kw_i2c_do_stop(host, 0); > } else { > - kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); > WRONG_STATE("KW_I2C_IRQ_DATA"); > - if (host->state != state_stop) { > - host->result = -EIO; > - goto stop; > - } > + if (host->state != state_stop) > + kw_i2c_do_stop(host, -EIO); > } > + kw_write_reg(reg_isr, KW_I2C_IRQ_DATA); > } > > if (isr & KW_I2C_IRQ_STOP) { > @@ -340,14 +336,10 @@ static void kw_i2c_handle_interrupt(stru > complete(&host->complete); > } > > + /* Below should only happen in manual mode which we don't use ... */ > if (isr & KW_I2C_IRQ_START) > kw_write_reg(reg_isr, KW_I2C_IRQ_START); > > - return; > - stop: > - kw_write_reg(reg_control, KW_I2C_CTL_STOP); > - host->state = state_stop; > - return; > } > > /* Interrupt handler */ > @@ -544,11 +536,11 @@ static struct pmac_i2c_host_kw *__init k > return NULL; > } > > - /* Make sure IRA is disabled */ > + /* Make sure IRQ is disabled */ > kw_write_reg(reg_ier, 0); > > /* Request chip interrupt */ > - if (request_irq(host->irq, kw_i2c_irq, SA_SHIRQ, "keywest i2c", host)) > + if (request_irq(host->irq, kw_i2c_irq, 0, "keywest i2c", host)) > host->irq = NO_IRQ; > > printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n", > - > To unsubscribe from this list: send the line "unsubscribe git-commits-head" in > the body of a message to [EMAIL PROTECTED] > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- Respectfully, Konstantin V. Gavrilenko Managing Director Arhont Ltd - Information Security web: http://www.arhont.com http://www.wi-foo.com e-mail: [EMAIL PROTECTED] tel: +44 (0) 870 44 31337 fax: +44 (0) 117 969 0141 PGP: Key ID - 0xE81824F4 PGP: Server - keyserver.pgp.com -- [email protected] mailing list
