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 <linux-kernel@...>
> To: git-commits-head@...
> 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 <benh@...> Tue, 18 Apr
2006 14:11:53 +1000
> committer Paul Mackerras <paulus@...> 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 <benh@...>
> Signed-off-by: Paul Mackerras <paulus@...>
>
> 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 majordomo@...
> 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: k.gavrilenko@...
tel: +44 (0) 870 44 31337
fax: +44 (0) 117 969 0141
PGP: Key ID - 0xE81824F4
PGP: Server - keyserver.pgp.com
--
gentoo-ppc-user@g.o mailing list
|