drivers/i2c/busses/i2c-gxp.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-gxp.c
Extension
.c
Size
15593 bytes
Lines
609
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 gxp_i2c_drvdata {
	struct device *dev;
	void __iomem *base;
	struct i2c_timings t;
	u32 engine;
	int irq;
	struct completion completion;
	struct i2c_adapter adapter;
	struct i2c_msg *curr_msg;
	int msgs_remaining;
	int msgs_num;
	u8 *buf;
	size_t buf_remaining;
	unsigned char state;
	struct i2c_client *slave;
	unsigned char stopped;
};

static struct regmap *i2cg_map;

static void gxp_i2c_start(struct gxp_i2c_drvdata *drvdata)
{
	u16 value;

	drvdata->buf = drvdata->curr_msg->buf;
	drvdata->buf_remaining = drvdata->curr_msg->len;

	/* Note: Address in struct i2c_msg is 7 bits */
	value = drvdata->curr_msg->addr << 9;

	/* Read or Write */
	value |= drvdata->curr_msg->flags & I2C_M_RD ? RW_CMD | START_CMD : START_CMD;

	drvdata->state = GXP_I2C_ADDR_PHASE;
	writew(value, drvdata->base + GXP_I2CMCMD);
}

static int gxp_i2c_master_xfer(struct i2c_adapter *adapter,
			       struct i2c_msg *msgs, int num)
{
	int ret;
	struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(adapter);
	unsigned long time_left;

	drvdata->msgs_remaining = num;
	drvdata->curr_msg = msgs;
	drvdata->msgs_num = num;
	reinit_completion(&drvdata->completion);

	gxp_i2c_start(drvdata);

	time_left = wait_for_completion_timeout(&drvdata->completion,
						adapter->timeout);
	ret = num - drvdata->msgs_remaining;
	if (time_left == 0)
		return -ETIMEDOUT;

	if (drvdata->state == GXP_I2C_ADDR_NACK)
		return -ENXIO;

	if (drvdata->state == GXP_I2C_DATA_NACK)
		return -EIO;

	return ret;
}

static u32 gxp_i2c_func(struct i2c_adapter *adap)
{
	if (IS_ENABLED(CONFIG_I2C_SLAVE))
		return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE;

	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

#if IS_ENABLED(CONFIG_I2C_SLAVE)
static int gxp_i2c_reg_slave(struct i2c_client *slave)
{
	struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter);

	if (drvdata->slave)
		return -EBUSY;

	if (slave->flags & I2C_CLIENT_TEN)
		return -EAFNOSUPPORT;

	drvdata->slave = slave;

	writeb(slave->addr << 1, drvdata->base + GXP_I2COWNADR);
	writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | SLAVE_ACK_ENAB |
	       SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD);

Annotation

Implementation Notes