diff options
Diffstat (limited to 'drivers/net/phy/qcom/at803x.c')
| -rw-r--r-- | drivers/net/phy/qcom/at803x.c | 98 |
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; } |
