drivers/usb/typec/ucsi/cros_ec_ucsi.c

Source file repositories/reference/linux-study-clean/drivers/usb/typec/ucsi/cros_ec_ucsi.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/ucsi/cros_ec_ucsi.c
Extension
.c
Size
10498 bytes
Lines
387
Domain
Driver Families
Bucket
drivers/usb
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 cros_ucsi_data {
	struct device *dev;
	struct ucsi *ucsi;

	struct cros_ec_device *ec;
	struct notifier_block nb;
	struct work_struct work;
	struct delayed_work write_tmo;
	int tmo_counter;

	struct completion complete;
	unsigned long flags;
};

static int cros_ucsi_read(struct ucsi *ucsi, unsigned int offset, void *val,
			  size_t val_len)
{
	struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi);
	struct ec_params_ucsi_ppm_get req = {
		.offset = offset,
		.size = val_len,
	};
	int ret;

	if (val_len > MAX_EC_DATA_SIZE) {
		dev_err(udata->dev, "Can't read %zu bytes. Too big.\n", val_len);
		return -EINVAL;
	}

	ret = cros_ec_cmd(udata->ec, 0, EC_CMD_UCSI_PPM_GET,
			  &req, sizeof(req), val, val_len);
	if (ret < 0) {
		dev_warn(udata->dev, "Failed to send EC message UCSI_PPM_GET: error=%d\n", ret);
		return ret;
	}
	return 0;
}

static int cros_ucsi_read_version(struct ucsi *ucsi, u16 *version)
{
	return cros_ucsi_read(ucsi, UCSI_VERSION, version, sizeof(*version));
}

static int cros_ucsi_read_cci(struct ucsi *ucsi, u32 *cci)
{
	return cros_ucsi_read(ucsi, UCSI_CCI, cci, sizeof(*cci));
}

static int cros_ucsi_read_message_in(struct ucsi *ucsi, void *val,
				     size_t val_len)
{
	return cros_ucsi_read(ucsi, UCSI_MESSAGE_IN, val, val_len);
}

static int cros_ucsi_async_control(struct ucsi *ucsi, u64 cmd)
{
	struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi);
	u8 ec_buf[sizeof(struct ec_params_ucsi_ppm_set) + sizeof(cmd)];
	struct ec_params_ucsi_ppm_set *req = (struct ec_params_ucsi_ppm_set *) ec_buf;
	int ret;

	req->offset = UCSI_CONTROL;
	memcpy(req->data, &cmd, sizeof(cmd));
	ret = cros_ec_cmd(udata->ec, 0, EC_CMD_UCSI_PPM_SET,
			  req, sizeof(ec_buf), NULL, 0);
	if (ret < 0) {
		dev_warn(udata->dev, "Failed to send EC message UCSI_PPM_SET: error=%d\n", ret);
		return ret;
	}
	return 0;
}

static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci,
				  void *data, size_t size)
{
	struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi);
	int ret;

	ret = ucsi_sync_control_common(ucsi, cmd, cci, data, size);
	switch (ret) {
	case -EBUSY:
		/* EC may return -EBUSY if CCI.busy is set.
		 * Convert this to a timeout.
		 */
	case -ETIMEDOUT:
		/* Schedule recovery attempt when we timeout
		 * or tried to send a command while still busy.
		 */
		cancel_delayed_work_sync(&udata->write_tmo);
		schedule_delayed_work(&udata->write_tmo,

Annotation

Implementation Notes