drivers/usb/typec/ucsi/ucsi_yoga_c630.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/ucsi/ucsi_yoga_c630.c
Extension
.c
Size
8209 bytes
Lines
334
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 yoga_c630_ucsi {
	struct yoga_c630_ec *ec;
	struct ucsi *ucsi;
	struct auxiliary_device *bridge;
	struct notifier_block nb;
	u16 version;
};

static int yoga_c630_ucsi_read_version(struct ucsi *ucsi, u16 *version)
{
	struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);

	*version = uec->version;

	return 0;
}

static int yoga_c630_ucsi_read_cci(struct ucsi *ucsi, u32 *cci)
{
	struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);
	u8 buf[YOGA_C630_UCSI_READ_SIZE];
	int ret;

	ret = yoga_c630_ec_ucsi_read(uec->ec, buf);
	if (ret)
		return ret;

	memcpy(cci, buf, sizeof(*cci));

	return 0;
}

static int yoga_c630_ucsi_read_message_in(struct ucsi *ucsi,
					  void *val, size_t val_len)
{
	struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);
	u8 buf[YOGA_C630_UCSI_READ_SIZE];
	int ret;

	ret = yoga_c630_ec_ucsi_read(uec->ec, buf);
	if (ret)
		return ret;

	memcpy(val, buf + YOGA_C630_UCSI_CCI_SIZE,
	       min(val_len, YOGA_C630_UCSI_DATA_SIZE));

	return 0;
}

static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command)
{
	struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);

	return yoga_c630_ec_ucsi_write(uec->ec, (u8*)&command);
}

static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi,
				       u64 command,
				       u32 *cci,
				       void *data, size_t size)
{
	int ret;

	/*
	 * EC doesn't return connector's DP mode even though it is supported.
	 * Fake it.
	 */
	if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES &&
	    UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 1 &&
	    UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_CON &&
	    UCSI_ALTMODE_OFFSET(command) == 0) {
		static const struct ucsi_altmode alt = {
			.svid = USB_TYPEC_DP_SID,
			.mid = USB_TYPEC_DP_MODE,
		};

		dev_dbg(ucsi->dev, "faking DP altmode for con1\n");
		memset(data, 0, size);
		memcpy(data, &alt, min(sizeof(alt), size));
		*cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt));
		return 0;
	}

	/*
	 * EC can return AltModes present on CON1 (port0, right) for CON2
	 * (port1, left) too. Ignore all requests going to CON2 (it doesn't
	 * support DP anyway).
	 */
	if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES &&
	    UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) {

Annotation

Implementation Notes