drivers/i2c/busses/i2c-cp2615.c

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

File Facts

System
Linux kernel
Corpus path
drivers/i2c/busses/i2c-cp2615.c
Extension
.c
Size
8209 bytes
Lines
339
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

if (msg->flags & I2C_M_RD) {
			i2c_w.read_len = msg->len;
			i2c_w.write_len = 0;
		} else {
			i2c_w.read_len = 0;
			i2c_w.write_len = msg->len;
			memcpy(&i2c_w.data, msg->buf, i2c_w.write_len);
		}
		ret = cp2615_i2c_send(usbif, &i2c_w);
		if (ret)
			break;
		ret = cp2615_i2c_recv(usbif, i2c_w.tag, msg->buf);
	}
	if (ret < 0)
		return ret;
	return i;
}

static u32
cp2615_i2c_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}

static const struct i2c_algorithm cp2615_i2c_algo = {
	.xfer = cp2615_i2c_xfer,
	.functionality = cp2615_i2c_func,
};

/*
 * This chip has some limitations: one is that the USB endpoint
 * can only receive 64 bytes/transfer, that leaves 54 bytes for
 * the I2C transfer. On top of that, EITHER read_len OR write_len
 * may be zero, but not both. If both are non-zero, the adapter
 * issues a write followed by a read. And the chip does not
 * support repeated START between the write and read phases.
 */
static struct i2c_adapter_quirks cp2615_i2c_quirks = {
	.max_write_len = MAX_I2C_SIZE,
	.max_read_len = MAX_I2C_SIZE,
	.flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START,
	.max_comb_1st_msg_len = MAX_I2C_SIZE,
	.max_comb_2nd_msg_len = MAX_I2C_SIZE
};

static void cp2615_i2c_disconnect(struct usb_interface *usbif)
{
	struct i2c_adapter *adap = usb_get_intfdata(usbif);

	usb_set_intfdata(usbif, NULL);
	i2c_del_adapter(adap);
}

static int
cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id)
{
	int ret = 0;
	struct i2c_adapter *adap;
	struct usb_device *usbdev = interface_to_usbdev(usbif);

	ret = usb_set_interface(usbdev, IOP_IFN, IOP_ALTSETTING);
	if (ret)
		return ret;

	ret = cp2615_check_iop(usbif);
	if (ret)
		return ret;

	adap = devm_kzalloc(&usbif->dev, sizeof(struct i2c_adapter), GFP_KERNEL);
	if (!adap)
		return -ENOMEM;

	if (!usbdev->serial)
		return -EINVAL;

	strscpy(adap->name, usbdev->serial, sizeof(adap->name));
	adap->owner = THIS_MODULE;
	adap->dev.parent = &usbif->dev;
	adap->dev.of_node = usbif->dev.of_node;
	adap->timeout = HZ;
	adap->algo = &cp2615_i2c_algo;
	adap->quirks = &cp2615_i2c_quirks;
	adap->algo_data = usbif;

	ret = i2c_add_adapter(adap);
	if (ret)
		return ret;

	usb_set_intfdata(usbif, adap);
	return 0;

Annotation

Implementation Notes