/* The master PHY would power on the slave PHY. */ if (cfg->is_slave) return 0;
ret = clk_prepare_enable(priv->phy_ref_clk); if (ret < 0) {
dev_err(&phy->dev, "failed to enable PHY reference clock: %d\n", ret); return ret;
}
mutex_lock(&priv->lock); if (cfg->bits_per_lane_and_dclk_cycle == 7) { if (cfg->differential_clk_rate < 44000000)
val |= M(0x2); elseif (cfg->differential_clk_rate < 90000000)
val |= M(0x1); else
val |= M(0x0);
} else {
val = NB;
if (cfg->differential_clk_rate < 32000000)
val |= M(0x2); elseif (cfg->differential_clk_rate < 63000000)
val |= M(0x1); else
val |= M(0x0);
}
regmap_update_bits(priv->regmap, PHY_CTRL, M_MASK | NB, val);
/* * Enable two channels synchronously, * if the companion PHY is a slave PHY.
*/ if (companion->cfg.is_slave)
val = CH_EN(0) | CH_EN(1); else
val = CH_EN(lvds_phy->id);
regmap_write(priv->regmap, PHY_CTRL + REG_SET, val);
ret = regmap_read_poll_timeout(priv->regmap, PHY_STATUS, locked,
locked, PLL_LOCK_SLEEP,
PLL_LOCK_TIMEOUT); if (ret < 0) {
dev_err(&phy->dev, "failed to get PHY lock: %d\n", ret);
clk_disable_unprepare(priv->phy_ref_clk);
}
mutex_unlock(&priv->lock);
staticint mixel_lvds_phy_configure(struct phy *phy, union phy_configure_opts *opts)
{ struct mixel_lvds_phy_priv *priv = dev_get_drvdata(phy->dev.parent); struct phy_configure_opts_lvds *cfg = &opts->lvds; int ret;
ret = clk_set_rate(priv->phy_ref_clk, cfg->differential_clk_rate); if (ret)
dev_err(&phy->dev, "failed to set PHY reference clock rate(%lu): %d\n",
cfg->differential_clk_rate, ret);
mutex_lock(&priv->lock); /* cache configuration set of our own for check */
memcpy(&lvds_phy->cfg, cfg, sizeof(*cfg));
if (cfg->is_slave) {
ret = mixel_lvds_phy_check_slave(phy); if (ret)
dev_err(&phy->dev, "failed to check slave PHY: %d\n", ret);
}
mutex_unlock(&priv->lock);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->regmap = syscon_node_to_regmap(dev->of_node->parent); if (IS_ERR(priv->regmap)) return dev_err_probe(dev, PTR_ERR(priv->regmap), "failed to get regmap\n");
priv->phy_ref_clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->phy_ref_clk)) return dev_err_probe(dev, PTR_ERR(priv->phy_ref_clk), "failed to get PHY reference clock\n");
mutex_init(&priv->lock);
dev_set_drvdata(dev, priv);
pm_runtime_enable(dev);
ret = mixel_lvds_phy_reset(dev); if (ret) {
dev_err(dev, "failed to do POR reset: %d\n", ret); return ret;
}
for (i = 0; i < PHY_NUM; i++) {
lvds_phy = devm_kzalloc(dev, sizeof(*lvds_phy), GFP_KERNEL); if (!lvds_phy) {
ret = -ENOMEM; goto err;
}
phy = devm_phy_create(dev, NULL, &mixel_lvds_phy_ops); if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
dev_err(dev, "failed to create PHY for channel%d: %d\n",
i, ret); goto err;
}
/* power up + control initialization */
mutex_lock(&priv->lock);
regmap_update_bits(priv->regmap, PHY_CTRL,
CTRL_INIT_MASK | PD, CTRL_INIT_VAL);
mutex_unlock(&priv->lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.