drivers/phy/amlogic/phy-meson-g12a-usb2.c

Source file repositories/reference/linux-study-clean/drivers/phy/amlogic/phy-meson-g12a-usb2.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/amlogic/phy-meson-g12a-usb2.c
Extension
.c
Size
12577 bytes
Lines
380
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 phy_meson_g12a_usb2_priv {
	struct device		*dev;
	struct regmap		*regmap;
	struct clk		*clk;
	struct reset_control	*reset;
	int                     soc_id;
};

static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = {
	.reg_bits = 8,
	.val_bits = 32,
	.reg_stride = 4,
	.max_register = PHY_CTRL_R23,
};

static int phy_meson_g12a_usb2_init(struct phy *phy)
{
	struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
	int ret;
	unsigned int value;

	ret = clk_prepare_enable(priv->clk);
	if (ret)
		return ret;

	ret = reset_control_reset(priv->reset);
	if (ret) {
		clk_disable_unprepare(priv->clk);
		return ret;
	}

	udelay(RESET_COMPLETE_TIME);

	/* usb2_otg_aca_en == 0 */
	regmap_update_bits(priv->regmap, PHY_CTRL_R21,
			   PHY_CTRL_R21_USB2_OTG_ACA_EN, 0);

	/* PLL Setup : 24MHz * 20 / 1 = 480MHz */
	regmap_write(priv->regmap, PHY_CTRL_R16,
		     FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
		     FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
		     PHY_CTRL_R16_MPLL_LOAD |
		     FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
		     PHY_CTRL_R16_MPLL_FAST_LOCK |
		     PHY_CTRL_R16_MPLL_EN |
		     PHY_CTRL_R16_MPLL_RESET);

	regmap_write(priv->regmap, PHY_CTRL_R17,
		     FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) |
		     FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) |
		     FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) |
		     FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
		     FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));

	value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
		FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
		PHY_CTRL_R18_MPLL_ACG_RANGE;

	if (priv->soc_id == MESON_SOC_A1)
		value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL;

	regmap_write(priv->regmap, PHY_CTRL_R18, value);

	udelay(PLL_RESET_COMPLETE_TIME);

	/* UnReset PLL */
	regmap_write(priv->regmap, PHY_CTRL_R16,
		     FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
		     FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
		     PHY_CTRL_R16_MPLL_LOAD |
		     FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
		     PHY_CTRL_R16_MPLL_FAST_LOCK |
		     PHY_CTRL_R16_MPLL_EN);

	/* PHY Tuning */
	regmap_write(priv->regmap, PHY_CTRL_R20,
		     FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) |
		     PHY_CTRL_R20_USB2_OTG_VBUSDET_EN |
		     FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) |
		     PHY_CTRL_R20_USB2_EDGE_DRV_EN |
		     FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) |
		     FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) |

Annotation

Implementation Notes