drivers/phy/spacemit/phy-k1-usb2.c

Source file repositories/reference/linux-study-clean/drivers/phy/spacemit/phy-k1-usb2.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/spacemit/phy-k1-usb2.c
Extension
.c
Size
6206 bytes
Lines
214
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 spacemit_usb2phy {
	struct phy *phy;
	struct clk *clk;
	struct regmap *regmap_base;
};

static const struct regmap_config phy_regmap_config = {
	.reg_bits = 32,
	.val_bits = 32,
	.reg_stride = 4,
	.max_register = 0x200,
};

static int spacemit_usb2phy_init(struct phy *phy)
{
	struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);
	struct regmap *map = sphy->regmap_base;
	u32 val;
	int ret;

	ret = clk_enable(sphy->clk);
	if (ret) {
		dev_err(&phy->dev, "failed to enable clock\n");
		return ret;
	}

	/*
	 * make sure the usb controller is not under reset process before
	 * any configuration
	 */
	usleep_range(150, 200);

	/* 24M ref clk */
	val = FIELD_PREP(FDIV_REG_MASK, FDIV_REG_VAL) |
	      FIELD_PREP(PHY_FDIV_FRACT_0_1, PHY_SEL_FREQ_24MHZ) |
	      PHY_DIV_LOCAL_EN;
	regmap_write(map, PHY_PLL_DIV_CFG, val);

	ret = regmap_read_poll_timeout(map, PHY_RST_MODE_CTRL, val,
				       (val & PHY_PLL_RDY),
				       500, K1_USB2PHY_RESET_TIME_MS * 1000);
	if (ret) {
		dev_err(&phy->dev, "wait PLLREADY timeout\n");
		clk_disable(sphy->clk);
		return ret;
	}

	/* release usb2 phy internal reset and enable clock gating */
	val = (PHY_INIT_MODE_BITS | PHY_CLK_ENABLE_BITS | PHY_DEASSERT_RST_BITS);
	regmap_write(map, PHY_RST_MODE_CTRL, val);

	val = (PHY_HSTXP_RSTN | PHY_CLK_HSTXP_EN | PHY_HSTXP_MODE);
	regmap_write(map, PHY_HSTXP_HW_CTRL, val);

	/* auto clear host disc */
	regmap_update_bits(map, PHY_TX_HOST_CTRL, PHY_HST_DISC_AUTO_CLR,
			   PHY_HST_DISC_AUTO_CLR);

	return 0;
}

static int spacemit_usb2phy_exit(struct phy *phy)
{
	struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);

	clk_disable(sphy->clk);

	return 0;
}

static int spacemit_usb2phy_disconnect(struct phy *phy, int port)
{
	struct spacemit_usb2phy *sphy = phy_get_drvdata(phy);

	regmap_update_bits(sphy->regmap_base, PHY_K1_HS_HOST_DISC,
			   PHY_K1_HS_HOST_DISC_CLR, PHY_K1_HS_HOST_DISC_CLR);

	return 0;
}

static const struct phy_ops spacemit_usb2phy_ops = {
	.init = spacemit_usb2phy_init,
	.exit = spacemit_usb2phy_exit,
	.disconnect = spacemit_usb2phy_disconnect,
	.owner = THIS_MODULE,
};

static int spacemit_usb2phy_probe(struct platform_device *pdev)
{
	struct phy_provider *phy_provider;

Annotation

Implementation Notes