drivers/phy/marvell/phy-mvebu-a3700-utmi.c

Source file repositories/reference/linux-study-clean/drivers/phy/marvell/phy-mvebu-a3700-utmi.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/marvell/phy-mvebu-a3700-utmi.c
Extension
.c
Size
7693 bytes
Lines
270
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 mvebu_a3700_utmi_caps {
	int usb32;
	const struct phy_ops *ops;
};

/**
 * struct mvebu_a3700_utmi - PHY driver data
 *
 * @regs: PHY registers
 * @usb_misc: Regmap with USB miscellaneous registers including PHY ones
 * @caps: PHY capabilities
 * @phy: PHY handle
 */
struct mvebu_a3700_utmi {
	void __iomem *regs;
	struct regmap *usb_misc;
	const struct mvebu_a3700_utmi_caps *caps;
	struct phy *phy;
};

static int mvebu_a3700_utmi_phy_power_on(struct phy *phy)
{
	struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
	struct device *dev = &phy->dev;
	int usb32 = utmi->caps->usb32;
	int ret = 0;
	u32 reg;

	/*
	 * Setup PLL. 40MHz clock used to be the default, being 25MHz now.
	 * See "PLL Settings for Typical REFCLK" table.
	 */
	reg = readl(utmi->regs + USB2_PHY_PLL_CTRL_REG0);
	reg &= ~(PLL_REF_DIV_MASK | PLL_FB_DIV_MASK | PLL_SEL_LPFR_MASK);
	reg |= (PLL_REF_DIV_5 << PLL_REF_DIV_OFF) |
	       (PLL_FB_DIV_96 << PLL_FB_DIV_OFF);
	writel(reg, utmi->regs + USB2_PHY_PLL_CTRL_REG0);

	/* Enable PHY pull up and disable USB2 suspend */
	regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
			   RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU,
			   RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU);

	if (usb32) {
		/* Power up OTG module */
		reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
		reg |= PHY_PU_OTG;
		writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);

		/* Disable PHY charger detection */
		reg = readl(utmi->regs + USB2_PHY_CHRGR_DETECT);
		reg &= ~(PHY_CDP_EN | PHY_DCP_EN | PHY_PD_EN | PHY_PU_CHRG_DTC |
			 PHY_CDP_DM_AUTO | PHY_ENSWITCH_DP | PHY_ENSWITCH_DM);
		writel(reg, utmi->regs + USB2_PHY_CHRGR_DETECT);

		/* Disable PHY DP/DM pull-down (used for device mode) */
		regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
				   USB2_DP_PULLDN_DEV_MODE |
				   USB2_DM_PULLDN_DEV_MODE, 0);
	}

	/* Wait for PLL calibration */
	ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
				 reg & PHY_PLLCAL_DONE,
				 PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
	if (ret) {
		dev_err(dev, "Failed to end USB2 PLL calibration\n");
		return ret;
	}

	/* Wait for impedance calibration */
	ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
				 reg & PHY_IMPCAL_DONE,
				 PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
	if (ret) {
		dev_err(dev, "Failed to end USB2 impedance calibration\n");
		return ret;
	}

	/* Wait for squelch calibration */
	ret = readl_poll_timeout(utmi->regs + USB2_RX_CHAN_CTRL1, reg,
				 reg & USB2PHY_SQCAL_DONE,
				 PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
	if (ret) {
		dev_err(dev, "Failed to end USB2 unknown calibration\n");
		return ret;
	}

	/* Wait for PLL to be locked */
	ret = readl_poll_timeout(utmi->regs + USB2_PHY_PLL_CTRL_REG0, reg,

Annotation

Implementation Notes