drivers/phy/amlogic/phy-meson8b-usb2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/phy/amlogic/phy-meson8b-usb2.c
Extension
.c
Size
10051 bytes
Lines
331
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_meson8b_usb2_match_data {
	bool			host_enable_aca;
};

struct phy_meson8b_usb2_priv {
	struct regmap					*regmap;
	enum usb_dr_mode				dr_mode;
	struct clk					*clk_usb_general;
	struct clk					*clk_usb;
	struct reset_control				*reset;
	const struct phy_meson8b_usb2_match_data	*match;
};

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

static int phy_meson8b_usb2_power_on(struct phy *phy)
{
	struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy);
	u32 reg;
	int ret;

	if (!IS_ERR_OR_NULL(priv->reset)) {
		ret = reset_control_reset(priv->reset);
		if (ret) {
			dev_err(&phy->dev, "Failed to trigger USB reset\n");
			return ret;
		}
	}

	ret = clk_prepare_enable(priv->clk_usb_general);
	if (ret) {
		dev_err(&phy->dev, "Failed to enable USB general clock\n");
		reset_control_rearm(priv->reset);
		return ret;
	}

	ret = clk_prepare_enable(priv->clk_usb);
	if (ret) {
		dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
		clk_disable_unprepare(priv->clk_usb_general);
		reset_control_rearm(priv->reset);
		return ret;
	}

	regmap_set_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL);

	regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK,
			   FIELD_PREP(REG_CTRL_REF_CLK_SEL_MASK, 0x2));

	regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_FSEL_MASK,
			   FIELD_PREP(REG_CTRL_FSEL_MASK, 0x5));

	/* reset the PHY */
	regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
	udelay(RESET_COMPLETE_TIME);
	regmap_clear_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET);
	udelay(RESET_COMPLETE_TIME);

	regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT);

	if (priv->dr_mode == USB_DR_MODE_HOST) {
		regmap_clear_bits(priv->regmap, REG_DBG_UART,
				  REG_DBG_UART_SET_IDDQ);

		if (priv->match->host_enable_aca) {
			regmap_set_bits(priv->regmap, REG_ADP_BC,
					REG_ADP_BC_ACA_ENABLE);

			udelay(ACA_ENABLE_COMPLETE_TIME);

			regmap_read(priv->regmap, REG_ADP_BC, &reg);
			if (reg & REG_ADP_BC_ACA_PIN_FLOAT) {
				dev_warn(&phy->dev, "USB ID detect failed!\n");
				clk_disable_unprepare(priv->clk_usb);
				clk_disable_unprepare(priv->clk_usb_general);
				reset_control_rearm(priv->reset);
				return -EINVAL;
			}
		}
	}

	return 0;
}

static int phy_meson8b_usb2_power_off(struct phy *phy)

Annotation

Implementation Notes