drivers/phy/marvell/phy-pxa-28nm-usb2.c

Source file repositories/reference/linux-study-clean/drivers/phy/marvell/phy-pxa-28nm-usb2.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/marvell/phy-pxa-28nm-usb2.c
Extension
.c
Size
9330 bytes
Lines
341
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 mv_usb2_phy {
	struct phy		*phy;
	struct platform_device	*pdev;
	void __iomem		*base;
	struct clk		*clk;
};

static int wait_for_reg(void __iomem *reg, u32 mask, u32 ms)
{
	u32 val;

	return readl_poll_timeout(reg, val, ((val & mask) == mask),
				   1000, 1000 * ms);
}

static int mv_usb2_phy_28nm_init(struct phy *phy)
{
	struct mv_usb2_phy *mv_phy = phy_get_drvdata(phy);
	struct platform_device *pdev = mv_phy->pdev;
	void __iomem *base = mv_phy->base;
	u32 reg;
	int ret;

	clk_prepare_enable(mv_phy->clk);

	/* PHY_28NM_PLL_REG0 */
	reg = readl(base + PHY_28NM_PLL_REG0) &
		~(PHY_28NM_PLL_SELLPFR_MASK | PHY_28NM_PLL_FBDIV_MASK
		| PHY_28NM_PLL_ICP_MASK	| PHY_28NM_PLL_REFDIV_MASK);
	writel(reg | (0x1 << PHY_28NM_PLL_SELLPFR_SHIFT
		| 0xf0 << PHY_28NM_PLL_FBDIV_SHIFT
		| 0x3 << PHY_28NM_PLL_ICP_SHIFT
		| 0xd << PHY_28NM_PLL_REFDIV_SHIFT),
		base + PHY_28NM_PLL_REG0);

	/* PHY_28NM_PLL_REG1 */
	reg = readl(base + PHY_28NM_PLL_REG1);
	writel(reg | PHY_28NM_PLL_PU_PLL | PHY_28NM_PLL_PU_BY_REG,
		base + PHY_28NM_PLL_REG1);

	/* PHY_28NM_TX_REG0 */
	reg = readl(base + PHY_28NM_TX_REG0) & ~PHY_28NM_TX_AMP_MASK;
	writel(reg | PHY_28NM_TX_PU_BY_REG | 0x3 << PHY_28NM_TX_AMP_SHIFT |
		PHY_28NM_TX_PU_ANA,
		base + PHY_28NM_TX_REG0);

	/* PHY_28NM_RX_REG0 */
	reg = readl(base + PHY_28NM_RX_REG0) & ~PHY_28NM_RX_SQ_THRESH_MASK;
	writel(reg | 0xa << PHY_28NM_RX_SQ_THRESH_SHIFT,
		base + PHY_28NM_RX_REG0);

	/* PHY_28NM_DIG_REG0 */
	reg = readl(base + PHY_28NM_DIG_REG0) &
		~(PHY_28NM_DIG_BITSTAFFING_ERR | PHY_28NM_DIG_SYNC_ERR |
		PHY_28NM_DIG_SQ_FILT_MASK | PHY_28NM_DIG_SQ_BLK_MASK |
		PHY_28NM_DIG_SYNC_NUM_MASK);
	writel(reg | (0x1 << PHY_28NM_DIG_SYNC_NUM_SHIFT |
		PHY_28NM_PLL_LOCK_BYPASS),
		base + PHY_28NM_DIG_REG0);

	/* PHY_28NM_OTG_REG */
	reg = readl(base + PHY_28NM_OTG_REG) | PHY_28NM_OTG_PU_OTG;
	writel(reg & ~PHY_28NM_OTG_CONTROL_BY_PIN, base + PHY_28NM_OTG_REG);

	/*
	 *  Calibration Timing
	 *		   ____________________________
	 *  CAL START   ___|
	 *			   ____________________
	 *  CAL_DONE    ___________|
	 *		   | 400us |
	 */

	/* Make sure PHY Calibration is ready */
	ret = wait_for_reg(base + PHY_28NM_CAL_REG,
			   PHY_28NM_PLL_PLLCAL_DONE | PHY_28NM_PLL_IMPCAL_DONE,
			   100);
	if (ret) {
		dev_warn(&pdev->dev, "USB PHY PLL calibrate not done after 100mS.");
		goto err_clk;
	}
	ret = wait_for_reg(base + PHY_28NM_RX_REG1,
			   PHY_28NM_RX_SQCAL_DONE, 100);
	if (ret) {
		dev_warn(&pdev->dev, "USB PHY RX SQ calibrate not done after 100mS.");
		goto err_clk;
	}
	/* Make sure PHY PLL is ready */
	ret = wait_for_reg(base + PHY_28NM_PLL_REG0, PHY_28NM_PLL_READY, 100);
	if (ret) {

Annotation

Implementation Notes