summaryrefslogtreecommitdiff
path: root/drivers/net/phy/qcom/at803x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/qcom/at803x.c')
-rw-r--r--drivers/net/phy/qcom/at803x.c98
1 files changed, 70 insertions, 28 deletions
diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c
index cacbadf1f484..09105f1e3737 100644
--- a/drivers/net/phy/qcom/at803x.c
+++ b/drivers/net/phy/qcom/at803x.c
@@ -1019,10 +1019,10 @@ static int ipq5018_cable_test_start(struct phy_device *phydev)
return 0;
}
-static int ipq5018_config_init(struct phy_device *phydev)
+static int ipq5018_analog_init(struct phy_device *phydev)
{
struct ipq5018_priv *priv = phydev->priv;
- u16 val;
+ int val, ret;
/*
* set LDO efuse: first temporarily store ANA_DAC_FILTER value from
@@ -1030,39 +1030,66 @@ static int ipq5018_config_init(struct phy_device *phydev)
* is written to
*/
val = at803x_debug_reg_read(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER);
- at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE,
- IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK,
- IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT);
- at803x_debug_reg_write(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER, val);
+ if (val < 0)
+ return val;
+
+ ret = at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE,
+ IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_MASK,
+ IPQ5018_PHY_DEBUG_ANA_LDO_EFUSE_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = at803x_debug_reg_write(phydev, IPQ5018_PHY_DEBUG_ANA_DAC_FILTER,
+ val);
+ if (ret)
+ return ret;
/* set 8023AZ EEE TX and RX timer values */
- phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_TX_TIMER,
- IPQ5018_PHY_PCS_EEE_TX_TIMER_VAL);
- phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_RX_TIMER,
- IPQ5018_PHY_PCS_EEE_RX_TIMER_VAL);
+ ret = phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_TX_TIMER,
+ IPQ5018_PHY_PCS_EEE_TX_TIMER_VAL);
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_PCS, IPQ5018_PHY_PCS_EEE_RX_TIMER,
+ IPQ5018_PHY_PCS_EEE_RX_TIMER_VAL);
+ if (ret)
+ return ret;
/* set MSE threshold values */
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH1,
- IPQ5018_PHY_MMD1_MSE_THRESH1_VAL);
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MSE_THRESH2,
- IPQ5018_PHY_MMD1_MSE_THRESH2_VAL);
+ ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
+ IPQ5018_PHY_MMD1_MSE_THRESH1,
+ IPQ5018_PHY_MMD1_MSE_THRESH1_VAL);
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
+ IPQ5018_PHY_MMD1_MSE_THRESH2,
+ IPQ5018_PHY_MMD1_MSE_THRESH2_VAL);
+ if (ret)
+ return ret;
/* PHY DAC values are optional and only set in a PHY to PHY link architecture */
- if (priv->set_short_cable_dac) {
- /* setting MDAC (Multi-level Digital-to-Analog Converter) in MMD1 */
- phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC,
- IPQ5018_PHY_DAC_MASK,
- FIELD_PREP(IPQ5018_PHY_DAC_MASK,
- IPQ5018_PHY_MMD1_MDAC_VAL));
-
- /* setting EDAC (Error-detection and Correction) in debug register */
- at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC,
- IPQ5018_PHY_DAC_MASK,
- FIELD_PREP(IPQ5018_PHY_DAC_MASK,
- IPQ5018_PHY_DEBUG_EDAC_VAL));
- }
+ if (!priv->set_short_cable_dac)
+ return 0;
- return 0;
+ /* setting MDAC (Multi-level Digital-to-Analog Converter) in MMD1 */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC,
+ IPQ5018_PHY_DAC_MASK,
+ FIELD_PREP(IPQ5018_PHY_DAC_MASK,
+ IPQ5018_PHY_MMD1_MDAC_VAL));
+ if (ret)
+ return ret;
+
+ /* setting EDAC (Error-detection and Correction) in debug register */
+ return at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC,
+ IPQ5018_PHY_DAC_MASK,
+ FIELD_PREP(IPQ5018_PHY_DAC_MASK,
+ IPQ5018_PHY_DEBUG_EDAC_VAL));
+}
+
+static int ipq5018_config_init(struct phy_device *phydev)
+{
+ return ipq5018_analog_init(phydev);
}
static void ipq5018_link_change_notify(struct phy_device *phydev)
@@ -1111,6 +1138,21 @@ static int ipq5018_probe(struct phy_device *phydev)
phydev->priv = priv;
+ /*
+ * The PHY starts autonegotiation as soon as it leaves reset. Apply the
+ * analog settings now instead of waiting for config_init() at attach
+ * time, and restart autonegotiation so that it uses them.
+ */
+ ret = ipq5018_analog_init(phydev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to apply analog settings\n");
+
+ ret = genphy_restart_aneg(phydev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to restart autonegotiation\n");
+
return 0;
}