drivers/i2c/busses/i2c-tegra-bpmp.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-tegra-bpmp.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-tegra-bpmp.c
Extension
.c
Size
8611 bytes
Lines
346
Domain
Driver Families
Bucket
drivers/i2c
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct tegra_bpmp_i2c {
	struct i2c_adapter adapter;
	struct device *dev;

	struct tegra_bpmp *bpmp;
	unsigned int bus;
};

/*
 * Linux flags are translated to BPMP defined I2C flags that are used in BPMP
 * firmware I2C driver to avoid any issues in future if Linux I2C flags are
 * changed.
 */
static void tegra_bpmp_xlate_flags(u16 flags, u16 *out)
{
	if (flags & I2C_M_TEN)
		*out |= SERIALI2C_TEN;

	if (flags & I2C_M_RD)
		*out |= SERIALI2C_RD;

	if (flags & I2C_M_STOP)
		*out |= SERIALI2C_STOP;

	if (flags & I2C_M_NOSTART)
		*out |= SERIALI2C_NOSTART;

	if (flags & I2C_M_REV_DIR_ADDR)
		*out |= SERIALI2C_REV_DIR_ADDR;

	if (flags & I2C_M_IGNORE_NAK)
		*out |= SERIALI2C_IGNORE_NAK;

	if (flags & I2C_M_NO_RD_ACK)
		*out |= SERIALI2C_NO_RD_ACK;

	if (flags & I2C_M_RECV_LEN)
		*out |= SERIALI2C_RECV_LEN;
}

/*
 * The serialized I2C format is simply the following:
 * [addr little-endian][flags little-endian][len little-endian][data if write]
 * [addr little-endian][flags little-endian][len little-endian][data if write]
 *  ...
 *
 * The flags are translated from Linux kernel representation to seriali2c
 * representation. Any undefined flag being set causes an error.
 *
 * The data is there only for writes. Reads have the data transferred in the
 * other direction, and thus data is not present.
 *
 * See deserialize_i2c documentation for the data format in the other direction.
 */
static void tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
					struct mrq_i2c_request *request,
					struct i2c_msg *msgs,
					unsigned int num)
{
	char *buf = request->xfer.data_buf;
	unsigned int i, j, pos = 0;

	for (i = 0; i < num; i++) {
		struct i2c_msg *msg = &msgs[i];
		u16 flags = 0;

		tegra_bpmp_xlate_flags(msg->flags, &flags);

		buf[pos++] = msg->addr & 0xff;
		buf[pos++] = (msg->addr & 0xff00) >> 8;
		buf[pos++] = flags & 0xff;
		buf[pos++] = (flags & 0xff00) >> 8;
		buf[pos++] = msg->len & 0xff;
		buf[pos++] = (msg->len & 0xff00) >> 8;

		if ((flags & SERIALI2C_RD) == 0) {
			for (j = 0; j < msg->len; j++)
				buf[pos++] = msg->buf[j];
		}
	}

	request->xfer.data_size = pos;
}

/*
 * The data in the BPMP -> CPU direction is composed of sequential blocks for
 * those messages that have I2C_M_RD. So, for example, if you have:
 *
 * - !I2C_M_RD, len == 5, data == a0 01 02 03 04
 * - !I2C_M_RD, len == 1, data == a0

Annotation

Implementation Notes