drivers/i2c/busses/i2c-fsi.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-fsi.c
Extension
.c
Size
17808 bytes
Lines
776
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 fsi_i2c_ctrl {
	struct fsi_device	*fsi;
	u8			fifo_size;
	struct list_head	ports;
	struct mutex		lock;
};

struct fsi_i2c_port {
	struct list_head	list;
	struct i2c_adapter	adapter;
	struct fsi_i2c_ctrl	*ctrl;
	u16			port;
	u16			xfrd;
};

static int fsi_i2c_read_reg(struct fsi_device *fsi, unsigned int reg,
			    u32 *data)
{
	int rc;
	__be32 data_be;

	rc = fsi_device_read(fsi, reg, &data_be, sizeof(data_be));
	if (rc)
		return rc;

	*data = be32_to_cpu(data_be);

	return 0;
}

static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg,
			     u32 *data)
{
	__be32 data_be = cpu_to_be32p(data);

	return fsi_device_write(fsi, reg, &data_be, sizeof(data_be));
}

static int fsi_i2c_dev_init(struct fsi_i2c_ctrl *i2c)
{
	int rc;
	u32 mode = I2C_MODE_ENHANCED, extended_status, watermark;
	u32 interrupt = 0;

	/* since we use polling, disable interrupts */
	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_INT_MASK, &interrupt);
	if (rc)
		return rc;

	mode |= FIELD_PREP(I2C_MODE_CLKDIV, I2C_DEFAULT_CLK_DIV);
	rc = fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode);
	if (rc)
		return rc;

	rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_ESTAT, &extended_status);
	if (rc)
		return rc;

	i2c->fifo_size = FIELD_GET(I2C_ESTAT_FIFO_SZ, extended_status);
	watermark = FIELD_PREP(I2C_WATERMARK_HI,
			       i2c->fifo_size - I2C_FIFO_HI_LVL);
	watermark |= FIELD_PREP(I2C_WATERMARK_LO, I2C_FIFO_LO_LVL);

	return fsi_i2c_write_reg(i2c->fsi, I2C_FSI_WATER_MARK, &watermark);
}

static int fsi_i2c_set_port(struct fsi_i2c_port *port)
{
	int rc;
	struct fsi_device *fsi = port->ctrl->fsi;
	u32 mode, dummy = 0;

	rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode);
	if (rc)
		return rc;

	if (FIELD_GET(I2C_MODE_PORT, mode) == port->port)
		return 0;

	mode = (mode & ~I2C_MODE_PORT) | FIELD_PREP(I2C_MODE_PORT, port->port);
	rc = fsi_i2c_write_reg(fsi, I2C_FSI_MODE, &mode);
	if (rc)
		return rc;

	/* reset engine when port is changed */
	return fsi_i2c_write_reg(fsi, I2C_FSI_RESET_ERR, &dummy);
}

static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg,
			 bool stop)

Annotation

Implementation Notes