I2C reset

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I2C reset

27,235 Views
ToxicAvenger
Contributor III

Hello,

I have custom board based on i.MX53 QSB with PMIC 34708.

It is running Android 2.3, version 10.2 from Adeneo.

I have problems with i2c communication.

Sometimes communication freeze, my battery (bq27541) is keeping data.

Is there any possibility to reset whole i2c?

Best regards,

Toxic

Labels (3)
5 Replies

14,464 Views
TomE
Specialist II

Having the I2C bus lock up is a 35 year old "well known secret".

The easiest way to cause this problem is to reset the main micro part way through a read transfer. The Slave is legitimately driving data onto the bus and won't let go until it is clocked out. So all I2C master chips should start by sending a bunch of clocks. None do. This big fat failure mode was always part of the I2C bus design, and never really addressed or fixed.

There should be a whole section on this problem in the Wikipedia I2C page. There isn't. What there is on that page is a link in the "External links" section to the "Official I2C Specs", which is here:

https://en.wikipedia.org/wiki/I%C2%B2C#Limitations

http://www.nxp.com/documents/user_manual/UM10204.pdf

If you read section "3.1.16 Bus Clear" it tells you to assert the "Reset Pins" of all the I2C devices. The whole point of I2C is to minimise the number of bus pins, so almost no devices have Reset pins. But then it gives the advice that "everybody knows", which is:

If the data line (SDA) is stuck LOW, the master should send nine clock pulses. The device that held the bus LOW should release it sometime within those nine clocks.

Here's the big problem. There's no PORTABLE or GENERIC way to do that. It is really simple to add this to a "bare-metal" system, but trying to add it to Linux requires all of the I2C drivers to have code added and all "platform layers" changed to support this as well. To do that would take a decade or more. Luckily this problem has been known for at least THIRTY FIVE YEARS, so there have been plenty of decades for this to be fixed.

Which has been done (at last). It only took THIRTY ONE YEARS to get this fixed, in Kernel 3.10 in 2013. Here's the code in the current/latest drivers to reset the I2C bus. Look for the functions starting at line 733 under the comment "i2c bus recovery routines", especially "i2c_generic_recovery()".

http://lxr.free-electrons.com/source/drivers/i2c/i2c-core.c

But you're using 3.14, which is quite old. Good news, this feature has been in there since 3.10. As long as it is supported by the "platform layer", meaning that someone at NXP or elsewhere has written the support functions for this some time in the last four years.

Which is unlikely. Google for "i2c_bus_recovery_info" finds this patch adding support for i.MX, but it only happened in August 2016:

https://patchwork.kernel.org/patch/9291261/

So this facility was added in Linux 3.10, but NXP didn't add it to their driver until 4.4. It came in between these two:

http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-imx.c?v=4.3

http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-imx.c?v=4.4

So one solution to to try to run 4.4 or later. Which might work for you or it might not.

The proper "workaround" is to add "i2c_bus_recovery_info" to the Platform. That's the patch/workaround you really need for this.

You can either wait for a fix from your supplier or you can fix it yourself. I've been adding these fixes manually to products for as long as I can remember. If I'd have waited for the supplier to fix it I'd have been waiting at least 15 years, maybe more.

Basically, forget messing around with the I2C controller. Just reprogram the I2C Clock pins as a GPIO and toggle it on and off (at 400kHz or so) nine times. Just add that to your low-level Linux startup code before the ports have been reprogrammed to be I2C, or even better, add some simple code to your Bootstrap (RedBoot, U-Boot or whatever) to do that for you.

I find I've answered this one before back in 2012;

https://community.nxp.com/thread/116562

Searching these forums for "i2c lockup" would have found you four other posts on this subject.

Tom

14,464 Views
wallyyeh
Contributor V

Thankyou for such detailed information!

Your post really saved my day.

0 Kudos

14,464 Views
ericzerbib
Contributor I

Thanks you very much for your response!!!!

0 Kudos

14,464 Views
Yuri
NXP Employee
NXP Employee

There is a general I2C issue, that may take place (or influence) in the case.

I2C receiver may lock up, holding the I2C SDA line low, in a system that has

slow rise/fall time on the I2C clock (I2C SCL) if the environment is noisy.

The following (as a workaround) may help.

"It is sometimes necessary to force the I2C module to become the I2C bus master

out of reset and drive SCLn (even though SDAn may already be driven, which

indicates that the bus is busy). This can occur when a system reset does not

cause all I2C devices to be reset. Thus, SDAn can be negated low by another I2C

device while this I2C module is coming out of reset and will stay low

indefinitely. The following procedure can be used to force this I2C module to

generate SCLn so that the device driving SDAn can finish its transaction:

1.1. Disable the I2C module and set the master bit by setting I2CnCR to 0x20.

1.2. Enable the I2C module by setting I2CnCR to 0xA0.

1.3. Read I2CnDR.

1.4. Return the I2C module to slave mode by setting I2CnCR to 0x80."

2.

Also another problem  when I2C SCL line is low may take place. This may be caused

by I2C slave, when I2C SCL is asserted low by the slave in order to prolong access, because

the slave is not ready. If the I2C hangs in such state there is no way (except reset) to leave this state. 

Often this is a hardware problem : slave is not working properly, also an external I2C expander can cause it.

0 Kudos

14,464 Views
ericzerbib
Contributor I

Hi Yuri

It seems that we have the same behavior in our custom board, the I2C bus stay in SDA low and no other device can be access, I tryied to patch the kernel 3.14 to apply the workaround but the imx6 refuse to switch to I2C slave mode even if i write A0 in IMX_I2C_I2CR  it stay in 0x80 do you know how why? how to force to be slave?

 

reboot: Restarting system
U-Boot SPL 2013.10-rc4-gc6adbac-dirty (Feb 21 2017 - 17:33:50)
Boot Device: SD0
U-Boot 2013.10-rc4-gc6adbac-dirty (Feb 21 2017 - 17:33:50)
CPU:   Freescale i.MX6Q rev1.5 at 792 MHz
Reset cause: WDOG
Board: MX6-HummingBoard2
I2C:   Error, wrong i2c adapter 0 max 0 possible
ready
DRAM:  1 GiB

Front panel Sw Reset is 1!
MMC:   FSL_SDHC: 0, FSL_SDHC: 1
Error, wrong i2c adapter 0 max 0 possible
In:    serial
Out:   vga
Err:   vga
Net:   FEC [PRIME]
(Re)start USB...

USB0:   USB EHCI 1.00

scanning bus 0 for devices... 2 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  0
39548 bytes read in 57 ms (676.8 KiB/s)
4942696 bytes read in 206 ms (22.9 MiB/s)
Kernel image @ 0x10800000 [ 0x000000 - 0x4b6b68 ]
## Flattened Device Tree blob at 11200000
   Booting using the fdt blob at 0x11200000
   Using Device Tree in place at 11200000, end 1120ca7b

Starting kernel ...

imx6q-pinctrl 20e0000.iomuxc: Invalid fsl,pins property in node /soc/aips-bus@02000000/iomuxc@020e0000/hummingboard/tc358743_audio_grp
imx-i2c 21a0000.i2c: EZ: Apply I2C workaround
imx-i2c 21a0000.i2c: EZ: imx_i2c_write_reg(0x20,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a0000.i2c: EZ: imx_i2c_write_reg(0xA0,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a0000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80
imx-i2c 21a0000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR) = 0x00
imx-i2c 21a0000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80
imx-i2c 21a4000.i2c: EZ: Apply I2C workaround
imx-i2c 21a4000.i2c: EZ: imx_i2c_write_reg(0x20,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a4000.i2c: EZ: imx_i2c_write_reg(0xA0,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a4000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80
imx-i2c 21a4000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR) = 0x00
imx-i2c 21a4000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80
imx-i2c 21a8000.i2c: EZ: Apply I2C workaround
imx-i2c 21a8000.i2c: EZ: imx_i2c_write_reg(0x20,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a8000.i2c: EZ: imx_i2c_write_reg(0xA0,        i2c_imx, IMX_I2C_I2CR);
imx-i2c 21a8000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80
imx-i2c 21a8000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR) = 0x00
imx-i2c 21a8000.i2c: EZ: imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR) = 0x80

imx-sgtl5000 sound-sgtl5000.29: ASoC: CODEC (null) not registered
imx-sgtl5000 sound-sgtl5000.29: snd_soc_register_card failed (-517)
imx-sgtl5000 sound-sgtl5000.29: ASoC: CODEC (null) not registered
imx-sgtl5000 sound-sgtl5000.29: snd_soc_register_card failed (-517)
imx-sgtl5000 sound-sgtl5000.29: ASoC: CODEC (null) not registered
imx-sgtl5000 sound-sgtl5000.29: snd_soc_register_card failed (-517)
imx-sgtl5000 sound-sgtl5000.29: ASoC: CODEC (null) not registered
imx-sgtl5000 sound-sgtl5000.29: snd_soc_register_card failed (-517)
EXT4-fs (mmcblk1p2): couldn't mount as ext3 due to feature incompatibilities
EXT4-fs (mmcblk1p2): couldn't mount as ext2 due to feature incompatibilities
imx-sgtl5000 sound-sgtl5000.29: ASoC: CODEC (null) not registered
imx-sgtl5000 sound-sgtl5000.29: snd_soc_register_card failed (-517)

tc358743_read_reg:reg=0 ret=-11
tc358743_probe:cannot find camera
tc358743_probe: failed, error=-19
mxc_v4l_open: Mxc Camera no sensor ipu0/csi0

Debian GNU/Linux stretch/sid KDS-EN4-1 ttymxc0

login:
0 Kudos