drivers/usb/typec/hd3ss3220.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/typec/hd3ss3220.c
Extension
.c
Size
14652 bytes
Lines
548
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 hd3ss3220 {
	struct device *dev;
	struct regmap *regmap;
	struct usb_role_switch	*role_sw;
	struct typec_port *port;
	struct delayed_work output_poll_work;
	enum usb_role role_state;
	bool poll;

	struct gpio_desc *id_gpiod;
	int id_irq;

	struct regulator *vbus;
};

static int hd3ss3220_set_power_opmode(struct hd3ss3220 *hd3ss3220, int power_opmode)
{
	int current_mode;

	switch (power_opmode) {
	case TYPEC_PWR_MODE_USB:
		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_DEFAULT;
		break;
	case TYPEC_PWR_MODE_1_5A:
		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_MID;
		break;
	case TYPEC_PWR_MODE_3_0A:
		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_HIGH;
		break;
	case TYPEC_PWR_MODE_PD: /* Power delivery not supported */
	default:
		dev_err(hd3ss3220->dev, "bad power operation mode: %d\n", power_opmode);
		return -EINVAL;
	}

	return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT,
				  HD3SS3220_REG_CN_STAT_CURRENT_MODE_MASK,
				  current_mode);
}

static int hd3ss3220_set_port_type(struct hd3ss3220 *hd3ss3220, int type)
{
	int mode_select, err;

	switch (type) {
	case TYPEC_PORT_SRC:
		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DFP;
		break;
	case TYPEC_PORT_SNK:
		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP;
		break;
	case TYPEC_PORT_DRP:
		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP;
		break;
	default:
		dev_err(hd3ss3220->dev, "bad port type: %d\n", type);
		return -EINVAL;
	}

	/* Disable termination before changing MODE_SELECT as required by datasheet */
	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM,
				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM);
	if (err < 0) {
		dev_err(hd3ss3220->dev, "Failed to disable port for mode change: %d\n", err);
		return err;
	}

	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
				 HD3SS3220_REG_GEN_CTRL_MODE_SELECT_MASK,
				 mode_select);
	if (err < 0) {
		dev_err(hd3ss3220->dev, "Failed to change mode: %d\n", err);
		regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
				   HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0);
		return err;
	}

	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0);
	if (err < 0)
		dev_err(hd3ss3220->dev, "Failed to re-enable port after mode change: %d\n", err);

	return err;
}

static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int prefer_role)
{
	int src_pref;

Annotation

Implementation Notes