Message ID | 20201002152305.4963-3-ceggers@arri.de |
---|---|
State | New |
Headers | show |
Series | i2c: imx: Fix handling of arbitration loss | expand |
On Fri, Oct 02, 2020 at 05:23:04PM +0200, Christian Eggers wrote: > Arbitration Lost (IAL) can happen after every single byte transfer. If > arbitration is lost, the I2C hardware will autonomously switch from > master mode to slave. If a transfer is not aborted in this state, > consecutive transfers will not be executed by the hardware and will > timeout. > > Signed-off-by: Christian Eggers <ceggers@arri.de> > Cc: stable@vger.kernel.org > --- > drivers/i2c/busses/i2c-imx.c | 18 ++++++++++++++++++ > 1 file changed, 18 insertions(+) > Tested (not extensively) on Vybrid VF500 (Toradex VF50): Tested-by: Krzysztof Kozlowski <krzk@kernel.org> The I2C on Vybrid VF500 still works fine. I did not test this actual condition (arbitration) but only a regular I2C driver (BQ27xxx fuel gauge). Obviously this only proves that regular operation is not broken... Alternatively if you have a specific testing procedure (reproduction of a problem), please share. Best regards, Krzysztof
On Monday, 5 October 2020, 10:07:25 CEST, Krzysztof Kozlowski wrote: > The I2C on Vybrid VF500 still works fine. I did not test this actual > condition (arbitration) but only a regular I2C driver (BQ27xxx fuel > gauge). Obviously this only proves that regular operation is not > broken... thank you very much for testing on Vybrid. > Alternatively if you have a specific testing procedure (reproduction of > a problem), please share. The IAL errors happen due to noise on our I2C bus. We have our power supply connected via I2C. The hardware designers wanted to make sure that no high currents flow through the ground pins of the I2C interface. So they added a series resistor (30 Ohm) in the GND line between the power supply and the i.MX board. If you have an I2C device on an external PCB, adding some small series resistance in the GND line may cause IAL errors. On the other hand, if everything else works fine, also handling if IAL should work on Vybrid. > Best regards, > Krzysztof Best regards Christian
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 34648df7f1a6..1db1e2f5296e 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -483,6 +483,24 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic) dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__); return -ETIMEDOUT; } + + /* check for arbitration lost */ + if (i2c_imx->i2csr & I2SR_IAL) { + unsigned int temp; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__); + /* + * i2sr_clr_opcode is the value to clear all interrupts. + * Here we want to clear only I2SR_IAL, so we write + * ~i2sr_clr_opcode with just the I2SR_IAL bit toggled. + */ + temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ I2SR_IAL; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); + + i2c_imx->i2csr = 0; + return -EAGAIN; + } + dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__); i2c_imx->i2csr = 0; return 0;
Arbitration Lost (IAL) can happen after every single byte transfer. If arbitration is lost, the I2C hardware will autonomously switch from master mode to slave. If a transfer is not aborted in this state, consecutive transfers will not be executed by the hardware and will timeout. Signed-off-by: Christian Eggers <ceggers@arri.de> Cc: stable@vger.kernel.org --- drivers/i2c/busses/i2c-imx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)