What is I2C Target Mode?

I2C is a bus typically used for communicating between embedded components. On platforms (SoCs), one will typically have a dedicated I2C controller that manages a set of busses on which peripherals may be attached. The controller does not have to be the one that handles all the communication, the attached peripherals can communicate on the shared bus as they see fit (with some bus arbitration of course).

Normally, the on-board I2C controller will have a driver such that a user may initiate I2C transfers on the bus and have the result returned to the user. In I2C, we talk about a device being a controller-receiver or controller-transmitter. The point is that it is the current bus controller that initiates the transfer with another device (the target). The target is instructed to either receive or transmit a set of bytes. Now, this case is pretty easy to handle, since all we need to do is use the i2c-get/set tools in Linux to instruct the driver to initiate a transfer on the bus.

Now. What if we needed to allow another device on the bus to become the controller and initiate a transfer where the operating system is the target? This is not always possible, since the operating system is not really a device on the bus. The solution is something called "target mode" in the I2C controller and Linux has good support for this in-kernel. One example where we need this, is to implement the Management Component Transport Protocol (MCTP). MCTP is a request/response protocol where both request and response is sent on the I2C bus using a controller-transmitter transfer (in other words, the responder has to gain control of the bus to send the response).

I2C target mode allows the driver to instruct the I2C controller (or bus owner) to set an address and become a potential target on the bus on its own. Whenever the controller notices a transfer on the bus that is addressed to that address, it will use a vendor/driver specific method of submitted the individual bytes to the operation system driver. The MCTP framework in the kernel will buffer up these bytes and assemble them into complete MCTP messages to be delivered to an application with the resvmsg() socket call.

I2C target mode is a powerful functionality and I have recently contributed support for target mode in the Aspeed I2C controller in QEMU. Additionally, to support something like MCTP, I also modified the I2C core in QEMU to allow multiple controllers on the bus. I'll probably write up a post on that at some other time.