drivers/phy/qualcomm/phy-qcom-usb-ss.c

Source file repositories/reference/linux-study-clean/drivers/phy/qualcomm/phy-qcom-usb-ss.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/qualcomm/phy-qcom-usb-ss.c
Extension
.c
Size
5888 bytes
Lines
247
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 ssphy_priv {
	void __iomem *base;
	struct device *dev;
	struct reset_control *reset_com;
	struct reset_control *reset_phy;
	struct regulator_bulk_data regs[NUM_BULK_REGS];
	struct clk_bulk_data clks[NUM_BULK_CLKS];
	enum phy_mode mode;
};

static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val)
{
	writel((readl(addr) & ~mask) | val, addr);
}

static int qcom_ssphy_do_reset(struct ssphy_priv *priv)
{
	int ret;

	if (!priv->reset_com) {
		qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET,
				   PHY_RESET);
		usleep_range(10, 20);
		qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0);
	} else {
		ret = reset_control_assert(priv->reset_com);
		if (ret) {
			dev_err(priv->dev, "Failed to assert reset com\n");
			return ret;
		}

		ret = reset_control_assert(priv->reset_phy);
		if (ret) {
			dev_err(priv->dev, "Failed to assert reset phy\n");
			return ret;
		}

		usleep_range(10, 20);

		ret = reset_control_deassert(priv->reset_com);
		if (ret) {
			dev_err(priv->dev, "Failed to deassert reset com\n");
			return ret;
		}

		ret = reset_control_deassert(priv->reset_phy);
		if (ret) {
			dev_err(priv->dev, "Failed to deassert reset phy\n");
			return ret;
		}
	}

	return 0;
}

static int qcom_ssphy_power_on(struct phy *phy)
{
	struct ssphy_priv *priv = phy_get_drvdata(phy);
	int ret;

	ret = regulator_bulk_enable(NUM_BULK_REGS, priv->regs);
	if (ret)
		return ret;

	ret = clk_bulk_prepare_enable(NUM_BULK_CLKS, priv->clks);
	if (ret)
		goto err_disable_regulator;

	ret = qcom_ssphy_do_reset(priv);
	if (ret)
		goto err_disable_clock;

	writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0);
	qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON);
	qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN);
	qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0);

	return 0;
err_disable_clock:
	clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks);
err_disable_regulator:
	regulator_bulk_disable(NUM_BULK_REGS, priv->regs);

	return ret;
}

static int qcom_ssphy_power_off(struct phy *phy)
{
	struct ssphy_priv *priv = phy_get_drvdata(phy);

Annotation

Implementation Notes