drivers/i2c/busses/i2c-xgene-slimpro.c

Source file repositories/reference/linux-study-clean/drivers/i2c/busses/i2c-xgene-slimpro.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-xgene-slimpro.c
Extension
.c
Size
15231 bytes
Lines
565
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 slimpro_i2c_dev {
	struct i2c_adapter adapter;
	struct device *dev;
	struct mbox_chan *mbox_chan;
	struct pcc_mbox_chan *pcc_chan;
	struct mbox_client mbox_client;
	int mbox_idx;
	struct completion rd_complete;
	u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */
	u32 *resp_msg;
};

#define to_slimpro_i2c_dev(cl)	\
		container_of(cl, struct slimpro_i2c_dev, mbox_client)

enum slimpro_i2c_version {
	XGENE_SLIMPRO_I2C_V1 = 0,
	XGENE_SLIMPRO_I2C_V2 = 1,
};

/*
 * This function tests and clears a bitmask then returns its old value
 */
static u16 xgene_word_tst_and_clr(u16 *addr, u16 mask)
{
	u16 ret, val;

	val = le16_to_cpu(READ_ONCE(*addr));
	ret = val & mask;
	val &= ~mask;
	WRITE_ONCE(*addr, cpu_to_le16(val));

	return ret;
}

static void slimpro_i2c_rx_cb(struct mbox_client *cl, void *mssg)
{
	struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl);

	/*
	 * Response message format:
	 * mssg[0] is the return code of the operation
	 * mssg[1] is the first data word
	 * mssg[2] is NOT used
	 */
	if (ctx->resp_msg)
		*ctx->resp_msg = ((u32 *)mssg)[1];

	if (ctx->mbox_client.tx_block)
		complete(&ctx->rd_complete);
}

static void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg)
{
	struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl);
	struct acpi_pcct_shared_memory __iomem *generic_comm_base =
							ctx->pcc_chan->shmem;

	/* Check if platform sends interrupt */
	if (!xgene_word_tst_and_clr(&generic_comm_base->status,
				    PCC_STATUS_SCI_DOORBELL))
		return;

	if (xgene_word_tst_and_clr(&generic_comm_base->status,
				   PCC_STATUS_CMD_COMPLETE)) {
		msg = generic_comm_base + 1;

		/* Response message msg[1] contains the return value. */
		if (ctx->resp_msg)
			*ctx->resp_msg = ((u32 *)msg)[1];

		complete(&ctx->rd_complete);
	}
}

static void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg)
{
	struct acpi_pcct_shared_memory __iomem *generic_comm_base =
							ctx->pcc_chan->shmem;
	u32 *ptr = (void *)(generic_comm_base + 1);
	u16 status;
	int i;

	WRITE_ONCE(generic_comm_base->signature,
		   cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx));

	WRITE_ONCE(generic_comm_base->command,
		   cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR));

	status = le16_to_cpu(READ_ONCE(generic_comm_base->status));

Annotation

Implementation Notes