drivers/usb/typec/ucsi/ucsi_stm32g0.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/ucsi/ucsi_stm32g0.c
Extension
.c
Size
18680 bytes
Lines
761
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_stm32g0_fw_info {
	u32 version;
	u32 keyword;
};

struct ucsi_stm32g0 {
	struct i2c_client *client;
	struct i2c_client *i2c_bl;
	bool in_bootloader;
	u8 bl_version;
	struct device *dev;
	const char *fw_name;
	struct ucsi *ucsi;
	bool suspended;
	bool wakeup_event;
};

/*
 * Bootloader commands helpers:
 * - send command (2 bytes)
 * - check ack
 * Then either:
 * - receive data
 * - receive data + check ack
 * - send data + check ack
 * These operations depends on the command and have various length.
 */
static int ucsi_stm32g0_bl_check_ack(struct ucsi *ucsi)
{
	struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
	struct i2c_client *client = g0->i2c_bl;
	unsigned char ack;
	struct i2c_msg msg[] = {
		{
			.addr	= client->addr,
			.flags  = I2C_M_RD,
			.len	= 1,
			.buf	= &ack,
		},
	};
	int ret;

	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
	if (ret != ARRAY_SIZE(msg)) {
		dev_err(g0->dev, "i2c bl ack (%02x), error: %d\n", client->addr, ret);

		return ret < 0 ? ret : -EIO;
	}

	/* The 'ack' byte should contain bootloader answer: ack/nack/busy */
	switch (ack) {
	case STM32G0_I2C_BL_ACK:
		return 0;
	case STM32G0_I2C_BL_NACK:
		return -ENOENT;
	case STM32G0_I2C_BL_BUSY:
		return -EBUSY;
	default:
		dev_err(g0->dev, "i2c bl ack (%02x), invalid byte: %02x\n",
			client->addr, ack);
		return -EINVAL;
	}
}

static int ucsi_stm32g0_bl_cmd_check_ack(struct ucsi *ucsi, unsigned int cmd, bool check_ack)
{
	struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
	struct i2c_client *client = g0->i2c_bl;
	unsigned char buf[2];
	struct i2c_msg msg[] = {
		{
			.addr	= client->addr,
			.flags  = 0,
			.len	= sizeof(buf),
			.buf	= buf,
		},
	};
	int ret;

	/*
	 * Send STM32 bootloader command format is two bytes:
	 * - command code
	 * - XOR'ed command code
	 */
	buf[0] = cmd;
	buf[1] = cmd ^ 0xff;

	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
	if (ret != ARRAY_SIZE(msg)) {
		dev_dbg(g0->dev, "i2c bl cmd %d (%02x), error: %d\n", cmd, client->addr, ret);

Annotation

Implementation Notes