drivers/phy/qualcomm/phy-qcom-apq8064-sata.c

Source file repositories/reference/linux-study-clean/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
Extension
.c
Size
8098 bytes
Lines
271
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 qcom_apq8064_sata_phy {
	void __iomem *mmio;
	struct clk *cfg_clk;
	struct device *dev;
};

/* Helper function to do poll and timeout */
static int poll_timeout(void __iomem *addr, u32 mask)
{
	u32 val;

	return readl_relaxed_poll_timeout(addr, val, (val & mask),
					DELAY_INTERVAL_US, TIMEOUT_MS * 1000);
}

static int qcom_apq8064_sata_phy_init(struct phy *generic_phy)
{
	struct qcom_apq8064_sata_phy *phy = phy_get_drvdata(generic_phy);
	void __iomem *base = phy->mmio;
	int ret = 0;

	/* SATA phy initialization */
	writel_relaxed(0x01, base + SATA_PHY_SER_CTRL);
	writel_relaxed(0xB1, base + SATA_PHY_POW_DWN_CTRL0);
	/* Make sure the power down happens before power up */
	mb();
	usleep_range(10, 60);

	writel_relaxed(0x01, base + SATA_PHY_POW_DWN_CTRL0);
	writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1);
	writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0);
	writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0);
	writel_relaxed(0x02, base + SATA_PHY_TX_IMCAL2);

	/* Write UNIPHYPLL registers to configure PLL */
	writel_relaxed(0x04, base + UNIPHY_PLL_REFCLK_CFG);
	writel_relaxed(0x00, base + UNIPHY_PLL_PWRGEN_CFG);

	writel_relaxed(0x0A, base + UNIPHY_PLL_CAL_CFG0);
	writel_relaxed(0xF3, base + UNIPHY_PLL_CAL_CFG8);
	writel_relaxed(0x01, base + UNIPHY_PLL_CAL_CFG9);
	writel_relaxed(0xED, base + UNIPHY_PLL_CAL_CFG10);
	writel_relaxed(0x02, base + UNIPHY_PLL_CAL_CFG11);

	writel_relaxed(0x36, base + UNIPHY_PLL_SDM_CFG0);
	writel_relaxed(0x0D, base + UNIPHY_PLL_SDM_CFG1);
	writel_relaxed(0xA3, base + UNIPHY_PLL_SDM_CFG2);
	writel_relaxed(0xF0, base + UNIPHY_PLL_SDM_CFG3);
	writel_relaxed(0x00, base + UNIPHY_PLL_SDM_CFG4);

	writel_relaxed(0x19, base + UNIPHY_PLL_SSC_CFG0);
	writel_relaxed(0xE1, base + UNIPHY_PLL_SSC_CFG1);
	writel_relaxed(0x00, base + UNIPHY_PLL_SSC_CFG2);
	writel_relaxed(0x11, base + UNIPHY_PLL_SSC_CFG3);

	writel_relaxed(0x04, base + UNIPHY_PLL_LKDET_CFG0);
	writel_relaxed(0xFF, base + UNIPHY_PLL_LKDET_CFG1);

	writel_relaxed(0x02, base + UNIPHY_PLL_GLB_CFG);
	/* make sure global config LDO power down happens before power up */
	mb();

	writel_relaxed(0x03, base + UNIPHY_PLL_GLB_CFG);
	writel_relaxed(0x05, base + UNIPHY_PLL_LKDET_CFG2);

	/* PLL Lock wait */
	ret = poll_timeout(base + UNIPHY_PLL_STATUS, UNIPHY_PLL_LOCK);
	if (ret) {
		dev_err(phy->dev, "poll timeout UNIPHY_PLL_STATUS\n");
		return ret;
	}

	/* TX Calibration */
	ret = poll_timeout(base + SATA_PHY_TX_IMCAL_STAT, SATA_PHY_TX_CAL);
	if (ret) {
		dev_err(phy->dev, "poll timeout SATA_PHY_TX_IMCAL_STAT\n");
		return ret;
	}

	/* RX Calibration */
	ret = poll_timeout(base + SATA_PHY_RX_IMCAL_STAT, SATA_PHY_RX_CAL);
	if (ret) {
		dev_err(phy->dev, "poll timeout SATA_PHY_RX_IMCAL_STAT\n");
		return ret;
	}

	/* SATA phy calibrated successfully, power up to functional mode */
	writel_relaxed(0x3E, base + SATA_PHY_POW_DWN_CTRL1);
	writel_relaxed(0x01, base + SATA_PHY_RX_IMCAL0);
	writel_relaxed(0x01, base + SATA_PHY_TX_IMCAL0);

Annotation

Implementation Notes