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

Reply via email to