drivers/usb/typec/ucsi/thunderbolt.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/ucsi/thunderbolt.c
Extension
.c
Size
4829 bytes
Lines
213
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 ucsi_tbt {
	struct ucsi_connector *con;
	struct typec_altmode *alt;
	struct work_struct work;
	int cam;
	u32 header;
};

static void ucsi_thunderbolt_work(struct work_struct *work)
{
	struct ucsi_tbt *tbt = container_of(work, struct ucsi_tbt, work);

	if (typec_altmode_vdm(tbt->alt, tbt->header, NULL, 0))
		dev_err(&tbt->alt->dev, "VDM 0x%x failed\n", tbt->header);

	tbt->header = 0;
}

static int ucsi_thunderbolt_set_altmode(struct ucsi_tbt *tbt,
					bool enter, u32 vdo)
{
	int svdm_version;
	int cmd;
	int ret;
	u64 command = UCSI_SET_NEW_CAM |
		      UCSI_CONNECTOR_NUMBER(tbt->con->num) |
		      UCSI_SET_NEW_CAM_SET_AM(tbt->cam) |
		      ((u64)vdo << 32);

	if (enter)
		command |= (1 << 23);

	ret = ucsi_send_command(tbt->con->ucsi, command, NULL, 0);
	if (ret < 0)
		return ret;

	svdm_version = typec_altmode_get_svdm_version(tbt->alt);
	if (svdm_version < 0)
		return svdm_version;

	if (enter)
		cmd = CMD_ENTER_MODE;
	else
		cmd = CMD_EXIT_MODE;
	tbt->header = VDO(USB_TYPEC_TBT_SID, 1, svdm_version, cmd);
	tbt->header |= VDO_OPOS(TYPEC_TBT_MODE);
	tbt->header |= VDO_CMDT(CMDT_RSP_ACK);

	schedule_work(&tbt->work);

	return 0;
}

static int ucsi_thunderbolt_enter(struct typec_altmode *alt, u32 *vdo)
{
	struct ucsi_tbt *tbt = typec_altmode_get_drvdata(alt);
	struct ucsi_connector *con = tbt->con;
	u64 command;
	u8 cur = 0;
	int ret;

	if (!ucsi_con_mutex_lock(con))
		return -ENOTCONN;

	command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num);
	ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur));
	if (ret < 0) {
		if (con->ucsi->version > 0x0100)
			goto err_unlock;
		cur = 0xff;
	}

	if (cur != 0xff) {
		if (cur >= UCSI_MAX_ALTMODES || con->port_altmode[cur] != alt)
			ret = -EBUSY;
		else
			ret = 0;
		goto err_unlock;
	}

	ret = ucsi_thunderbolt_set_altmode(tbt, true, *vdo);
	ucsi_altmode_update_active(tbt->con);

err_unlock:
	ucsi_con_mutex_unlock(con);

	return ret;
}

static int ucsi_thunderbolt_exit(struct typec_altmode *alt)

Annotation

Implementation Notes