drivers/phy/amlogic/phy-meson8-hdmi-tx.c

Source file repositories/reference/linux-study-clean/drivers/phy/amlogic/phy-meson8-hdmi-tx.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/amlogic/phy-meson8-hdmi-tx.c
Extension
.c
Size
4315 bytes
Lines
161
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_meson8_hdmi_tx_priv {
	struct regmap		*hhi;
	struct clk		*tmds_clk;
};

static int phy_meson8_hdmi_tx_init(struct phy *phy)
{
	struct phy_meson8_hdmi_tx_priv *priv = phy_get_drvdata(phy);

	return clk_prepare_enable(priv->tmds_clk);
}

static int phy_meson8_hdmi_tx_exit(struct phy *phy)
{
	struct phy_meson8_hdmi_tx_priv *priv = phy_get_drvdata(phy);

	clk_disable_unprepare(priv->tmds_clk);

	return 0;
}

static int phy_meson8_hdmi_tx_power_on(struct phy *phy)
{
	struct phy_meson8_hdmi_tx_priv *priv = phy_get_drvdata(phy);
	unsigned int i;
	u16 hdmi_ctl0;

	if (clk_get_rate(priv->tmds_clk) >= 2970UL * 1000 * 1000)
		hdmi_ctl0 = 0x1e8b;
	else
		hdmi_ctl0 = 0x4d0b;

	regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0,
		     FIELD_PREP(HHI_HDMI_PHY_CNTL0_HDMI_CTL1, 0x08c3) |
		     FIELD_PREP(HHI_HDMI_PHY_CNTL0_HDMI_CTL0, hdmi_ctl0));

	regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1, 0x0);

	/* Reset three times, just like the vendor driver does */
	for (i = 0; i < 3; i++) {
		regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1,
			     HHI_HDMI_PHY_CNTL1_CLOCK_ENABLE |
			     HHI_HDMI_PHY_CNTL1_SOFT_RESET);
		usleep_range(1000, 2000);

		regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL1,
			     HHI_HDMI_PHY_CNTL1_CLOCK_ENABLE);
		usleep_range(1000, 2000);
	}

	return 0;
}

static int phy_meson8_hdmi_tx_power_off(struct phy *phy)
{
	struct phy_meson8_hdmi_tx_priv *priv = phy_get_drvdata(phy);

	regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0,
		     FIELD_PREP(HHI_HDMI_PHY_CNTL0_HDMI_CTL1, 0x0841) |
		     FIELD_PREP(HHI_HDMI_PHY_CNTL0_HDMI_CTL0, 0x8d00));

	return 0;
}

static const struct phy_ops phy_meson8_hdmi_tx_ops = {
	.init		= phy_meson8_hdmi_tx_init,
	.exit		= phy_meson8_hdmi_tx_exit,
	.power_on	= phy_meson8_hdmi_tx_power_on,
	.power_off	= phy_meson8_hdmi_tx_power_off,
	.owner		= THIS_MODULE,
};

static int phy_meson8_hdmi_tx_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct phy_meson8_hdmi_tx_priv *priv;
	struct phy_provider *phy_provider;
	struct resource *res;
	struct phy *phy;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -EINVAL;

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->hhi = syscon_node_to_regmap(np->parent);
	if (IS_ERR(priv->hhi))

Annotation

Implementation Notes