This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM3352: Unsure if SMBus Block Read support is even possible given the way the AM335x I2C subsystem functions

Part Number: AM3352

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







  • Hello Bill,

    I will check into this.

    Regards,
    Nick
  • From a quick search i2c-algo-bit.c appears to be a big-banged I2C driver for am335x-linux which includes comments about SMbus. Bit-banging an I2C master involves more software overhead, but gives the opportunity to bypass limitations in the I2C subsystem.

    Is that of any use?

  • Hi Chester,

    I believe using the i2c-algo-bit  (i2c-gpio) driver is the only option on the AM335x, to have robust SMBus block read functionality over I2C. I've been using that driver up to this point. I'm looking to reduce the software overhead involved and want to confirm with TI that that AM335x I2C subsystem is indeed incapable of being able to perform SMBus block read transfer as designed.

    --Bill

  • Hello Bill,

    It does look like the hardware does not support a way to do I2C SMBus Block Read, since it is not possible to reload DCOUNT without sending a start/restart on the bus.

    I am continuing to dig around on this end to see if there are any other alternatives.

    Regards,
    Nick
  • Hi Nick,

    Thanks for looking into this. Just trying to get this clarified, not just for myself but for the other threads that didn't exactly have a resolution (other than using a gpio i2c driver).

    Appreciate your time.

    Thanks,
    Bill

  • Hello Bill,

    It looks like you are correct: HW does not seem to support a way to do I2C SMBus Block Read.

    From Note1 in I2C_CNT.DCOUNT field (per AM335x TRM):

    "In case of I2C mode of operation, if I2C_CON.STP = 0, then the I2C asserts SCL = 0 when DCOUNT reaches 0. The CPU can then reprogram DCOUNT to a new value and resume sending or receiving data with a new start condition (restart). This process repeats until the CPU sets to 1 the I2C_CON.STP bit. The ARDY flag is set each time DCOUNT reaches 0 and DCOUNT is reloaded to its initial value."

    So it is not possible to reload DCOUNT without sending a start/restart on the bus.

    Regards,
    Nick
  • Hi Nick,

    I appreciate you digging into this, and confirming what I was thinking was the case.

    Thanks for the help,
    Bill