u-boot-brain/drivers/i2c
Trent Piepho c854933f50 i2c: mxc_i2c: Fix read and read->write xfers in DM mode
This is an old driver that supports both device mapped and non-mapped
mode, and covers a wide range of hardware.  It's hard to change without
risking breaking something.  I have to tried to be exceedingly detailed
in this patch, so please excuse the length of the commit essay that
follows.

In device mapped mode the I2C xfer function does not handle plain read,
and some other, transfers correctly.

What it can't handle are transactions that:
    Start with a read, or,
    Have a write followed by a read, or,
    Have more than one read in a row.

The common I2C/SMBUS read register and write register transactions
always start with a write, followed by a write or a read, and then end.
These work, so the bug is not apparent for most I2C slaves that only use
these common xfer forms.

The existing xfer loop initializes by sending the chip address in write
mode after it deals with bus arbitration and master setup.  When
processing each message, if the next message will be a read, it sends a
repeated start followed by the chip address in read mode after the
current message.

Obviously, this does not work if the first message is a read, as the
chip is always addressed in write mode initially by i2c_init_transfer().

A write following a read does not work because the repeated start is
only sent when the next message is a read.  There is no logic to send it
when the current message is a read and next is write.  It should be sent
every time the bus changes direction.

The ability to use a plain read was added to this driver in
commit 2feec4eafd ("imx: mxc_i2c: tweak the i2c transfer method"),
but this applied only the non-DM code path.

This patch fixes the DM code path.  The xfer function will call
i2c_init_transfer() with an alen of -1 to avoid sending the chip
address.  The same way the non-DM code achieves this.  The xfer
function's message loop will send the address and mode before each
message if the bus changes direction, and on the first message.

When reading data, the master hardware is one byte ahead of what we
receive.  I.e., reading a byte from the data register returns a byte
*already received* by the master, and causes the master to start the RX
of the *next* byte.  Therefor, before we read the final byte of a
message, we must tell the master what to do next.  I add a "last" flag
to i2c_read_data() to tell it if the message is to be followed by a stop
or a repeated start.  When last == true it acts exactly as before.

The non-DM code can only create an xfer where the read, if any, is the
final message of the xfer.  And so the only callsite of i2c_read_data()
in the non-DM code has the "last" parameter as true.  Therefore, this
change has no effect on the non-DM code.  As all other changes are in
the DM xfer function, which is not even compiled in non-DM code, I am
confident that this patch has no effect on boards not using I2C_DM.
This greatly reduces the range of hardware that could be affected.

For DM boards, I have verified every transaction the "i2c" command can
create on a scope and they are all exactly as they are supposed to be.
I also tested write->read->write, which isn't possible with the i2c
command, and it works as well.  I didn't fix multiple reads in a row, as
it's a lot more invasive and obviously no one has every wanted them
since they've never worked.  It didn't seem like the extra complexity
was justified to support something no one uses.

Cc: Nandor Han <nandor.han@ge.com>
Cc: Heiko Schocher <hs@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: Breno Matheus Lima <brenomatheus@gmail.com>
Signed-off-by: Trent Piepho <tpiepho@impinj.com>
2019-05-17 05:35:23 +02:00
..
muxes i2c: muxes: pca954x: support PCA9543 I2C switch 2019-04-11 15:21:33 +02:00
ast_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
ast_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
at91_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
at91_i2c.h i2c: atmel: add i2c driver 2016-08-15 22:12:00 +02:00
cros_ec_ldo.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
cros_ec_tunnel.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
davinci_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
davinci_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
designware_i2c.c i2c: designware: fix reset handling on socfpga gen5 2019-04-25 00:00:49 +02:00
designware_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
exynos_hs_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
fsl_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
i2c_core.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
i2c-cdns.c i2c: i2c_cdns: Fix below warnings with checker tool 2019-03-21 08:21:43 +01:00
i2c-emul-uclass.c dm: sandbox: i2c: Add a new 'emulation parent' uclass 2018-11-29 09:30:05 -07:00
i2c-gpio.c treewide: replace with error() with pr_err() 2017-10-04 11:59:44 -04:00
i2c-uclass-compat.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
i2c-uclass.c DM: I2C: Introduce 'u-boot, i2c-transaction-bytes' property 2019-04-11 15:21:33 +02:00
i2c-uniphier-f.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
i2c-uniphier.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
i2c-versatile.c i2c: Add support for the Arm's Versatile Express I2C controller. 2018-10-03 06:08:06 +02:00
ihs_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
imx_lpi2c.c i2c: imx_lpi2c: fix typo and register base address format 2018-10-22 14:35:57 +02:00
intel_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
Kconfig Kconfig: tegra: Migrate SYS_I2C_TEGRA 2019-02-20 09:01:44 -07:00
kona_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
lpc32xx_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
Makefile i2c: Remove ancient zynq_i2c driver 2019-02-14 14:31:10 +01:00
meson_i2c.c i2c: meson: add configurable divider factors 2019-04-10 16:50:02 +02:00
mv_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
mv_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
mvtwsi.c i2c: mvtwsi: fix reading status register after interrupt 2019-05-03 08:14:39 +02:00
mxc_i2c.c i2c: mxc_i2c: Fix read and read->write xfers in DM mode 2019-05-17 05:35:23 +02:00
omap24xx_i2c.c i2c: omap24xx_i2c: Use platdata to probe the device 2018-12-10 06:11:18 +01:00
omap24xx_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
rcar_i2c.c i2c: rcar_i2c: Move FSDA check to rcar_i2c_recover 2019-03-08 05:53:40 +01:00
rcar_iic.c i2c: rcar_iic: Read ICSR only once 2019-03-07 06:20:09 +01:00
rk_i2c.c rockchip: use 'arch-rockchip' as header file path 2019-05-01 00:00:05 +02:00
s3c24x0_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
s3c24x0_i2c.h SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
sandbox_i2c.c dm: sandbox: i2c: Use new emulator parent uclass 2018-11-29 09:30:05 -07:00
sh_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
soft_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
stm32f7_i2c.c i2c: stm32f7: change setup struct to const 2018-11-16 16:51:58 -05:00
tegra_i2c.c SPDX: Convert all of our single license tags to Linux Kernel style 2018-05-07 09:34:12 -04:00
tegra186_bpmp_i2c.c i2c: tegra: Fix regression by implementing a dummy probe_chip() callback 2018-12-12 06:06:14 +01:00
xilinx_xiic.c i2c: xiic: Add Xilinx AXI I2C driver 2019-01-15 09:04:49 +01:00