drivers/phy/phy-lgm-usb.c

Source file repositories/reference/linux-study-clean/drivers/phy/phy-lgm-usb.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/phy-lgm-usb.c
Extension
.c
Size
6727 bytes
Lines
283
Domain
Driver Families
Bucket
drivers/phy
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 tca_apb {
	struct reset_control *resets[ARRAY_SIZE(PHY_RESETS)];
	struct regulator *vbus;
	struct work_struct wk;
	struct usb_phy phy;

	bool regulator_enabled;
	bool phy_initialized;
	bool connected;
};

static int get_flipped(struct tca_apb *ta, bool *flipped)
{
	union extcon_property_value property;
	int ret;

	ret = extcon_get_property(ta->phy.edev, EXTCON_USB_HOST,
				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
	if (ret) {
		dev_err(ta->phy.dev, "no polarity property from extcon\n");
		return ret;
	}

	*flipped = property.intval;

	return 0;
}

static int phy_init(struct usb_phy *phy)
{
	struct tca_apb *ta = container_of(phy, struct tca_apb, phy);
	void __iomem *ctrl1 = phy->io_priv + CTRL1_OFFSET;
	int val, ret, i;

	if (ta->phy_initialized)
		return 0;

	for (i = 0; i < ARRAY_SIZE(PHY_RESETS); i++)
		reset_control_deassert(ta->resets[i]);

	ret = readl_poll_timeout(ctrl1, val, val & SRAM_INIT_DONE, 10, 10 * 1000);
	if (ret) {
		dev_err(ta->phy.dev, "SRAM init failed, 0x%x\n", val);
		return ret;
	}

	writel(readl(ctrl1) | SRAM_EXT_LD_DONE, ctrl1);

	ta->phy_initialized = true;
	if (!ta->phy.edev) {
		writel(TCPC_CONN, ta->phy.io_priv + TCPC_OFFSET);
		return phy->set_vbus(phy, true);
	}

	schedule_work(&ta->wk);

	return ret;
}

static void phy_shutdown(struct usb_phy *phy)
{
	struct tca_apb *ta = container_of(phy, struct tca_apb, phy);
	int i;

	if (!ta->phy_initialized)
		return;

	ta->phy_initialized = false;
	flush_work(&ta->wk);
	ta->phy.set_vbus(&ta->phy, false);

	ta->connected = false;
	writel(TCPC_DISCONN, ta->phy.io_priv + TCPC_OFFSET);

	for (i = 0; i < ARRAY_SIZE(PHY_RESETS); i++)
		reset_control_assert(ta->resets[i]);
}

static int phy_set_vbus(struct usb_phy *phy, int on)
{
	struct tca_apb *ta = container_of(phy, struct tca_apb, phy);
	int ret;

	if (!!on == ta->regulator_enabled)
		return 0;

	if (on)
		ret = regulator_enable(ta->vbus);
	else
		ret = regulator_disable(ta->vbus);

Annotation

Implementation Notes