drivers/i2c/busses/i2c-cgbc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-cgbc.c
Extension
.c
Size
9827 bytes
Lines
407
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 i2c_algo_cgbc_data {
	u8		bus_id;
	unsigned long	read_maxtime_us;
};

struct cgbc_i2c_data {
	struct device		*dev;
	struct cgbc_device_data *cgbc;
	struct i2c_adapter      adap;
	struct i2c_msg		*msg;
	int			nmsgs;
	int			pos;
	enum cgbc_i2c_state	state;
};

struct cgbc_i2c_transfer {
	u8 bus_id;
	bool start;
	bool stop;
	bool last_ack;
	u8 read;
	u8 write;
	u8 addr;
	u8 data[CGBC_I2C_WRITE_MAX_LEN];
};

static u8 cgbc_i2c_freq_to_reg(unsigned int bus_frequency)
{
	u8 reg;

	if (bus_frequency <= 10000)
		reg = CGBC_I2C_FREQ_UNIT_1KHZ | (bus_frequency / 1000);
	else if (bus_frequency <= 100000)
		reg = CGBC_I2C_FREQ_UNIT_10KHZ | (bus_frequency / 10000);
	else
		reg = CGBC_I2C_FREQ_UNIT_100KHZ | (bus_frequency / 100000);

	return reg;
}

static unsigned int cgbc_i2c_reg_to_freq(u8 reg)
{
	unsigned int freq = reg & CGBC_I2C_FREQ_VALUE_MASK;
	u8 unit = reg & CGBC_I2C_FREQ_UNIT_MASK;

	if (unit == CGBC_I2C_FREQ_UNIT_100KHZ)
		return freq * 100000;
	else if (unit == CGBC_I2C_FREQ_UNIT_10KHZ)
		return freq * 10000;
	else
		return freq * 1000;
}

static int cgbc_i2c_get_status(struct i2c_adapter *adap)
{
	struct i2c_algo_cgbc_data *algo_data = adap->algo_data;
	struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
	struct cgbc_device_data *cgbc = i2c->cgbc;
	u8 cmd = CGBC_I2C_CMD_STAT | algo_data->bus_id;
	u8 status;
	int ret;

	ret = cgbc_command(cgbc, &cmd, sizeof(cmd), NULL, 0, &status);
	if (ret)
		return ret;

	return status;
}

static int cgbc_i2c_set_frequency(struct i2c_adapter *adap,
				  unsigned int bus_frequency)
{
	struct i2c_algo_cgbc_data *algo_data = adap->algo_data;
	struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap);
	struct cgbc_device_data *cgbc = i2c->cgbc;
	u8 cmd[2], data;
	int ret;

	if (bus_frequency > CGBC_I2C_FREQ_MAX_HZ ||
	    bus_frequency < CGBC_I2C_FREQ_MIN_HZ) {
		dev_info(i2c->dev, "invalid frequency %u, using default\n", bus_frequency);
		bus_frequency = I2C_MAX_STANDARD_MODE_FREQ;
	}

	cmd[0] = CGBC_I2C_CMD_SPEED | algo_data->bus_id;
	cmd[1] = cgbc_i2c_freq_to_reg(bus_frequency);

	ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL);
	if (ret)
		return dev_err_probe(i2c->dev, ret,

Annotation

Implementation Notes