drivers/usb/typec/tcpm/tcpci_maxim_core.c

Source file repositories/reference/linux-study-clean/drivers/usb/typec/tcpm/tcpci_maxim_core.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/tcpm/tcpci_maxim_core.c
Extension
.c
Size
16563 bytes
Lines
608
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

pd_header_cnt_le(msg.header) * sizeof(msg.payload[0])) {
		max_tcpci_write16(chip, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
		dev_err(chip->dev, "Invalid TCPC_RX_BYTE_CNT %d for header cnt %d\n",
			count, pd_header_cnt_le(msg.header));
		return;
	}

	for (payload_index = 0; payload_index < pd_header_cnt_le(msg.header); payload_index++,
	     rx_buf_ptr += sizeof(msg.payload[0]))
		msg.payload[payload_index] = cpu_to_le32(*(u32 *)rx_buf_ptr);

	/*
	 * Read complete, clear RX status alert bit.
	 * Clear overflow as well if set.
	 */
	ret = max_tcpci_write16(chip, TCPC_ALERT,
				TCPC_ALERT_RX_STATUS | (status & TCPC_ALERT_RX_BUF_OVF));
	if (ret < 0)
		return;

	tcpm_pd_receive(chip->port, &msg, rx_type);
}

static int get_vbus_regulator_handle(struct max_tcpci_chip *chip)
{
	if (IS_ERR_OR_NULL(chip->vbus_reg)) {
		chip->vbus_reg = devm_regulator_get_exclusive(chip->dev,
							      "vbus");
		if (IS_ERR_OR_NULL(chip->vbus_reg)) {
			dev_err(chip->dev,
				"Failed to get vbus regulator handle\n");
			return -ENODEV;
		}
	}

	return 0;
}

static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
{
	struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
	int ret;

	if (source && sink) {
		dev_err(chip->dev, "Both source and sink set\n");
		return -EINVAL;
	}

	ret = get_vbus_regulator_handle(chip);
	if (ret) {
		/*
		 * Regulator is not necessary for sink only applications. Return
		 * success in cases where sink mode is being modified.
		 */
		return source ? ret : 1;
	}

	if (source) {
		if (!regulator_is_enabled(chip->vbus_reg))
			ret = regulator_enable(chip->vbus_reg);
	} else {
		if (regulator_is_enabled(chip->vbus_reg))
			ret = regulator_disable(chip->vbus_reg);
	}

	return ret < 0 ? ret : 1;
}

static void process_power_status(struct max_tcpci_chip *chip)
{
	u8 pwr_status;
	int ret;

	ret = max_tcpci_read8(chip, TCPC_POWER_STATUS, &pwr_status);
	if (ret < 0)
		return;

	if (pwr_status == 0xff)
		max_tcpci_init_regs(chip);
	else if (pwr_status & TCPC_POWER_STATUS_SOURCING_VBUS)
		tcpm_sourcing_vbus(chip->port);
	else
		tcpm_vbus_change(chip->port);
}

static void max_tcpci_frs_sourcing_vbus(struct tcpci *tcpci, struct tcpci_data *tdata)
{
	/*
	 * For Fast Role Swap case, Boost turns on autonomously without
	 * AP intervention, but, needs AP to enable source mode explicitly

Annotation

Implementation Notes