summaryrefslogtreecommitdiff
path: root/board
diff options
context:
space:
mode:
authorTrent Piepho <tpiepho@impinj.com>2019-04-30 16:08:19 +0000
committerHeiko Schocher <hs@denx.de>2019-05-17 05:35:23 +0200
commitc854933f50307f7abcb0280f93f8b2bba70b1ddb (patch)
tree9cf0fd31d48b0731395c7f1c93426c116b8bfe03 /board
parent6314b3c7c3acbb81471e2f525c82660ebab5b2fb (diff)
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 2feec4eafd40 ("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>
Diffstat (limited to 'board')
0 files changed, 0 insertions, 0 deletions