drivers/i2c/busses/i2c-kempld.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-kempld.c
Extension
.c
Size
9437 bytes
Lines
397
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 kempld_i2c_data {
	struct device			*dev;
	struct kempld_device_data	*pld;
	struct i2c_adapter		adap;
	struct i2c_msg			*msg;
	int				pos;
	int				nmsgs;
	int				state;
	bool				was_active;
};

static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD;
module_param(bus_frequency, uint, 0);
MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default="
				__MODULE_STRING(KEMPLD_I2C_FREQ_STD)")");

static int i2c_bus = -1;
module_param(i2c_bus, int, 0);
MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)");

static bool i2c_gpio_mux;
module_param(i2c_gpio_mux, bool, 0);
MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)");

/*
 * kempld_get_mutex must be called prior to calling this function.
 */
static int kempld_i2c_process(struct kempld_i2c_data *i2c)
{
	struct kempld_device_data *pld = i2c->pld;
	u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT);
	struct i2c_msg *msg = i2c->msg;
	u8 addr;

	/* Ready? */
	if (stat & I2C_STAT_TIP)
		return -EBUSY;

	if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
		/* Stop has been sent */
		kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
		if (i2c->state == STATE_ERROR)
			return -EIO;
		return 0;
	}

	/* Error? */
	if (stat & I2C_STAT_ARBLOST) {
		i2c->state = STATE_ERROR;
		kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
		return -EAGAIN;
	}

	if (i2c->state == STATE_INIT) {
		if (stat & I2C_STAT_BUSY)
			return -EBUSY;

		i2c->state = STATE_ADDR;
	}

	if (i2c->state == STATE_ADDR) {
		/* 10 bit address? */
		if (i2c->msg->flags & I2C_M_TEN) {
			addr = i2c_10bit_addr_hi_from_msg(msg);
			i2c->state = STATE_ADDR10;
		} else {
			addr = i2c_8bit_addr_from_msg(i2c->msg);
			i2c->state = STATE_START;
		}

		kempld_write8(pld, KEMPLD_I2C_DATA, addr);
		kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);

		return 0;
	}

	/* Second part of 10 bit addressing */
	if (i2c->state == STATE_ADDR10) {
		addr = i2c_10bit_addr_lo_from_msg(msg);
		i2c->state = STATE_START;

		kempld_write8(pld, KEMPLD_I2C_DATA, addr);
		kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);

		return 0;
	}

	if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
		i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;

Annotation

Implementation Notes