I2C: Fix twl4030 timeouts on omap3430
PATCH 1/1 I2C: Fix twl4030 timeouts on omap3430
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
Regards,
Tony
Quoted 1 line
From
25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72eMon Sep 17 00:00:00 2001
From: Tony Lindgren <[email protected]>
Date: Thu, 27 Mar 2008 19:05:30 +0200
Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430
For some reason doing a twl4030 write-read cycle can hang the I2C bus on omap3430. And doing the write and read separately in twl4030_i2c_read() seems to fix the problem...
Not intended for applying, just a temporary workaround.
drivers/i2c/chips/twl4030-core.c +9 -1
@@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)return -EPERM ; }mutex_lock (&twl->xfer_lock); +/* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0 ]; msg->addr = twl->address;
@@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) msg->flags =0 ;/* Read the register value */ val = twl4030_map[mod_no].base + reg; msg->buf = &val; + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); +if (ret <0 ) + goto out; +/* [MSG2] fill the data rx buffer */ msg = &twl->xfer_msg[1 ]; msg->addr = twl->address; msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + +out:mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ if (ret >=0 ) ret =0 ; +return ret; }
Quoted 7 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Tony
Quoted 50 lines
From
25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72eMon Sep 17 00:00:00 2001
From: Tony Lindgren <[email protected]>
Date: Thu, 27 Mar 2008 19:05:30 +0200
Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430For some reason doing a twl4030 write-read cycle can hang the I2C bus on omap3430. And doing the write and read separately in
twl4030_i2c_read()seems to fix the problem...Not intended for applying, just a temporary workaround.
drivers/i2c/chips/twl4030-core.c +9
-1@@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)return -EPERM ; }mutex_lock (&twl->xfer_lock); +/* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0 ]; msg->addr = twl->address;@@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) msg->flags =0 ;/* Read the register value */ val = twl4030_map[mod_no].base + reg; msg->buf = &val; + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); +if (ret <0 ) + goto out; +/* [MSG2] fill the data rx buffer */ msg = &twl->xfer_msg[1 ]; msg->addr = twl->address; msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + +out:mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ if (ret >=0 ) ret =0 ; +return ret; }
Quoted 10 lines · Tony Lindgren
Quoted 7 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Looks like this kills twl4030 interrupts, so I've reverted it.
Tony
Quoted 51 lines
Quoted 50 lines
From
25c4c8f449819cb6f40b59ed1a9b25ebcc7cd72eMon Sep 17 00:00:00 2001
From: Tony Lindgren <[email protected]>
Date: Thu, 27 Mar 2008 19:05:30 +0200
Subject: [PATCH] I2C: Fix twl4030 timeouts on omap3430For some reason doing a twl4030 write-read cycle can hang the I2C bus on omap3430. And doing the write and read separately in
twl4030_i2c_read()seems to fix the problem...Not intended for applying, just a temporary workaround.
drivers/i2c/chips/twl4030-core.c +9
-1@@ -327,6 +327,7 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes)return -EPERM ; }mutex_lock (&twl->xfer_lock); +/* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0 ]; msg->addr = twl->address;@@ -334,18 +335,25 @@ int twl4030_i2c_read(u8 mod_no, u8 * value, u8 reg, u8 num_bytes) msg->flags =0 ;/* Read the register value */ val = twl4030_map[mod_no].base + reg; msg->buf = &val; + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); +if (ret <0 ) + goto out; +/* [MSG2] fill the data rx buffer */ msg = &twl->xfer_msg[1 ]; msg->addr = twl->address; msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + +out:mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ if (ret >=0 ) ret =0 ; +return ret; }
Quoted 7 lines · Tony Lindgren
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Looks like this kills twl4030 interrupts, so I've reverted it.
After looking into this problem a bit more, looks like twl4030 reads to anything in "POWER ID" (modules 0x10 and higher) will hang twl4030 eventually and I2C controller gets stuck in mode where STP never clears.
Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030.
Tony
Quoted 13 lines · ext Tony Lindgren
Quoted 12 lines · Tony Lindgren
Quoted 10 lines · Tony Lindgren
Quoted 7 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Quoted 8 lines
Quoted 1 line
Looks like this kills twl4030 interrupts, so I've reverted it.
After looking into this problem a bit more, looks like twl4030 reads to anything in "POWER ID" (modules
0x10and higher) will hang twl4030 eventually and I2C controller gets stuck in mode where STP never clears.Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030.
I remember seeing something similar when doing the powerbutton code. Klaus Pedersen found out that leaving CFG_BOOT to its reset value solved the problem. Unfortunately this breaks MADC and USB afaics, so it's not a real solution. CFG_BOOT is programmed in power_companion_init().
Cheers,
Peter.
Signature · 1 line
goa is a state of mind
Quoted 20 lines · * Peter 'p2' De Schrijver <[email protected]> [080401 16:01]:
Quoted 19 lines · ext Tony Lindgren
Quoted 7 lines · Tony Lindgren
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Looks like this kills twl4030 interrupts, so I've reverted it.
After looking into this problem a bit more, looks like twl4030 reads to anything in "POWER ID" (modules
0x10and higher) will hang twl4030 eventually and I2C controller gets stuck in mode where STP never clears.
Quoted 7 lines
Quoted 2 lines
Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030.
I remember seeing something similar when doing the powerbutton code. Klaus Pedersen found out that leaving
CFG_BOOTto its reset value solved the problem. Unfortunately this breaks MADC and USB afaics, so it's not a real solution.CFG_BOOTis programmed inpower_companion_init().
Great, this helped a lot! Looks like power_companion_init() tries to get osc_ck without checking for clkg_get() return value, and osc_ck does not exist in clock34xx.h. So R_CFG_BOOT gets set to default 26MHz value :)
Will post a patch when available.
Tony
Quoted 29 lines · Tony Lindgren
Quoted 20 lines · * Peter 'p2' De Schrijver <[email protected]> [080401 16:01]:
Quoted 19 lines · ext Tony Lindgren
Quoted 7 lines · Tony Lindgren
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Tony Lindgren
Hi all,
This helps with the annoying I2C timeouts. Does anybody have an idea why the twl4030 chip does not like doing multiple transfers in a row?
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
To me the only difference seems to be that clocks are idled between writing the twl4030 register and reading the register value.
I'll push this today with a REVISIT comment added.
Looks like this kills twl4030 interrupts, so I've reverted it.
After looking into this problem a bit more, looks like twl4030 reads to anything in "POWER ID" (modules
0x10and higher) will hang twl4030 eventually and I2C controller gets stuck in mode where STP never clears.Quoted 7 lines
Quoted 2 lines
Repeated reads to "USB ID", "AUD ID" or "AUX ID" will not hang twl4030.
I remember seeing something similar when doing the powerbutton code. Klaus Pedersen found out that leaving
CFG_BOOTto its reset value solved the problem. Unfortunately this breaks MADC and USB afaics, so it's not a real solution.CFG_BOOTis programmed inpower_companion_init().
Quoted 5 lines
Great, this helped a lot! Looks like
power_companion_init()tries to getosc_ckwithout checking forclkg_get()return value, andosc_ckdoes not exist inclock34xx.h. SoR_CFG_BOOTgets set to default 26MHz value :)Will post a patch when available.
Thanks again, here's a patch, I've pushed it also.
Tony
From: Tony Lindgren <[email protected]>
Date: Tue, 1 Apr 2008 16:58:02 +0300
Subject: [PATCH] I2C: Fix twl4030 clock init
Without this patch twl4030 clock can get programmed to incorrect rate which can eventually hang twl4030 reads. Also minor formatting fixes.
drivers/i2c/chips/twl4030-core.c +12 -3
@@ -672,11 +672,20 @@ static int power_companion_init(void)u32 rate, ctrl =HFCLK_FREQ_26_MHZ ;int e =0 ; - osc =clk_get (NULL ,"osc_ck" ); +if (cpu_is_omap2430 ()) + osc =clk_get (NULL ,"osc_ck" ); +else + osc =clk_get (NULL ,"osc_sys_ck" ); +if (IS_ERR (osc)) { +printk (KERN_ERR "Skipping twl3040 internal clock init and " +"using bootloader value (unknown osc rate)\n" ); +return 0 ; + } + rate =clk_get_rate (osc);clk_put (osc); -switch (rate) { +switch (rate) {case 19200000 : ctrl = HFCLK_FREQ_19p2_MHZ;break ;case 26000000 : ctrl =HFCLK_FREQ_26_MHZ ;break ;case 38400000 : ctrl = HFCLK_FREQ_38p4_MHZ;break ;
@@ -684,7 +693,7 @@ static int power_companion_init(void) ctrl |=HIGH_PERF_SQ ; e |=unprotect_pm_master (); -/* effect->MADC+USB ck en */ +/* effect->MADC+USB ck en */ e |=twl4030_i2c_write_u8 (TWL4030_MODULE_PM_MASTER , ctrl,R_CFG_BOOT ); e |=protect_pm_master ();