Tool/software: Linux
All (Mostly TI),
Recently I've been modifying the i2c-omap Linux driver (in a 4.14 kernel based off TI's ti-linux-kernel repo) in an attempt to support SMBus Block Reads. Side Note: Up till now I've been using the i2c-gpio driver from the kernel (which work well, but hogs CPU time).
A little background on SMBus block reads, in case someone else is finding this thread who doesn't know. A well formed SMBus block read transaction should include first a write to the targeted I2C device address with a command byte, followed by a read (with a repeated start) to the same address. The data is then clocked in, the first byte of which is the total length of data to expect, followed by that amount of data, and finally a stop bit (example of what this looks like below, taken from the smbus-protocol doc from the kernel here)
S Addr Wr [A] Comm [A] S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
The main issues with supporting this new bus packet type in the i2c-omap driver is the need to read the Count first, during an active transfer, and then update the I2C subsystem to read that amount of data before stopping (sending a Stop Bit). This flow goes against how the AM335x I2C subsystem functions, normally.
The i2c-omap driver currently sets up the DCOUNT len in the I2C_CNT register, which controls how many bytes will be sent or received for that message. Before it sends out a start bit to kick off the transfer. This is obviously a problem with SMBus block read since you don't know how long the whole message is from the start. Additionally if you read the "CAUTION" note under section 2.1.4.1.17 of the AM335x TRM it notes that the DCOUNT should not be modified between STT having been set to 1 (i.e. when a start has been set) and the reception of ARDY (when the message is complete, with DCOUNT having counted down to 0).
So, since we don't know how long the full message is when setting up DCOUNT, and since DCOUNT can't be modified during a transfer we can't update it once we do know. Based on that I'm concluding that the I2C subsystem in the am335x without any sort of subystem mangling will not be able to handle block reads.
So with DCOUNT modification off the table I then looked to a more hacky way to get an SMBus block read. My first idea was to do a read to get the count, being sure not to send a stop bit (STP=0), then start another message to read the full data. Though doing this would require that a repeated start and address would not be sent along as well, from what I can tell in the TRM this is not possible. Setting a repeat start is necessary for the I2C subsystem to actually start the transfer, with no option to work around this requirement.
As a hack, I looked briefly at using the I2C_SYSTEST to force the SCL/SDA lines during the start/address to mask that said transfer was even happening but at that point the driver is dealing with terribly hacky timings and delays. Abandoned that quickly.
Apologies if this is a bit confusing/meandering but all in all I'm looking for confirmation from TI that there isn't a reliable way to handle SMBus block reads with the AM335x I2C subsystem. Mostly due to the set it and forget it nature of DCOUNT. And secondly due to the inability to restart a transfer (read) without sending a start bit and address again.
If you need any clarification on any of the above, let me know. Thanks in advance.
--Bill