1*7eaf9132SAlexandru Ardelean // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2*7eaf9132SAlexandru Ardelean /* 3*7eaf9132SAlexandru Ardelean * Driver for Analog Devices Industrial Ethernet T1L PHYs 4*7eaf9132SAlexandru Ardelean * 5*7eaf9132SAlexandru Ardelean * Copyright 2020 Analog Devices Inc. 6*7eaf9132SAlexandru Ardelean */ 7*7eaf9132SAlexandru Ardelean #include <linux/kernel.h> 8*7eaf9132SAlexandru Ardelean #include <linux/bitfield.h> 9*7eaf9132SAlexandru Ardelean #include <linux/delay.h> 10*7eaf9132SAlexandru Ardelean #include <linux/errno.h> 11*7eaf9132SAlexandru Ardelean #include <linux/init.h> 12*7eaf9132SAlexandru Ardelean #include <linux/module.h> 13*7eaf9132SAlexandru Ardelean #include <linux/mii.h> 14*7eaf9132SAlexandru Ardelean #include <linux/phy.h> 15*7eaf9132SAlexandru Ardelean #include <linux/property.h> 16*7eaf9132SAlexandru Ardelean 17*7eaf9132SAlexandru Ardelean #define PHY_ID_ADIN1100 0x0283bc81 18*7eaf9132SAlexandru Ardelean 19*7eaf9132SAlexandru Ardelean #define ADIN_FORCED_MODE 0x8000 20*7eaf9132SAlexandru Ardelean #define ADIN_FORCED_MODE_EN BIT(0) 21*7eaf9132SAlexandru Ardelean 22*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SFT_RST 0x8810 23*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SFT_RST_EN BIT(0) 24*7eaf9132SAlexandru Ardelean 25*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SFT_PD_CNTRL 0x8812 26*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SFT_PD_CNTRL_EN BIT(0) 27*7eaf9132SAlexandru Ardelean 28*7eaf9132SAlexandru Ardelean #define ADIN_AN_PHY_INST_STATUS 0x8030 29*7eaf9132SAlexandru Ardelean #define ADIN_IS_CFG_SLV BIT(2) 30*7eaf9132SAlexandru Ardelean #define ADIN_IS_CFG_MST BIT(3) 31*7eaf9132SAlexandru Ardelean 32*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_STAT 0x8818 33*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SFT_PD_RDY BIT(1) 34*7eaf9132SAlexandru Ardelean #define ADIN_CRSM_SYS_RDY BIT(0) 35*7eaf9132SAlexandru Ardelean 36*7eaf9132SAlexandru Ardelean /** 37*7eaf9132SAlexandru Ardelean * struct adin_priv - ADIN PHY driver private data 38*7eaf9132SAlexandru Ardelean * @tx_level_2v4_able: set if the PHY supports 2.4V TX levels (10BASE-T1L) 39*7eaf9132SAlexandru Ardelean * @tx_level_2v4: set if the PHY requests 2.4V TX levels (10BASE-T1L) 40*7eaf9132SAlexandru Ardelean * @tx_level_prop_present: set if the TX level is specified in DT 41*7eaf9132SAlexandru Ardelean */ 42*7eaf9132SAlexandru Ardelean struct adin_priv { 43*7eaf9132SAlexandru Ardelean unsigned int tx_level_2v4_able:1; 44*7eaf9132SAlexandru Ardelean unsigned int tx_level_2v4:1; 45*7eaf9132SAlexandru Ardelean unsigned int tx_level_prop_present:1; 46*7eaf9132SAlexandru Ardelean }; 47*7eaf9132SAlexandru Ardelean 48*7eaf9132SAlexandru Ardelean static int adin_read_status(struct phy_device *phydev) 49*7eaf9132SAlexandru Ardelean { 50*7eaf9132SAlexandru Ardelean int ret; 51*7eaf9132SAlexandru Ardelean 52*7eaf9132SAlexandru Ardelean ret = genphy_c45_read_status(phydev); 53*7eaf9132SAlexandru Ardelean if (ret) 54*7eaf9132SAlexandru Ardelean return ret; 55*7eaf9132SAlexandru Ardelean 56*7eaf9132SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_AN, ADIN_AN_PHY_INST_STATUS); 57*7eaf9132SAlexandru Ardelean if (ret < 0) 58*7eaf9132SAlexandru Ardelean return ret; 59*7eaf9132SAlexandru Ardelean 60*7eaf9132SAlexandru Ardelean if (ret & ADIN_IS_CFG_SLV) 61*7eaf9132SAlexandru Ardelean phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE; 62*7eaf9132SAlexandru Ardelean 63*7eaf9132SAlexandru Ardelean if (ret & ADIN_IS_CFG_MST) 64*7eaf9132SAlexandru Ardelean phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER; 65*7eaf9132SAlexandru Ardelean 66*7eaf9132SAlexandru Ardelean return 0; 67*7eaf9132SAlexandru Ardelean } 68*7eaf9132SAlexandru Ardelean 69*7eaf9132SAlexandru Ardelean static int adin_config_aneg(struct phy_device *phydev) 70*7eaf9132SAlexandru Ardelean { 71*7eaf9132SAlexandru Ardelean struct adin_priv *priv = phydev->priv; 72*7eaf9132SAlexandru Ardelean int ret; 73*7eaf9132SAlexandru Ardelean 74*7eaf9132SAlexandru Ardelean if (phydev->autoneg == AUTONEG_DISABLE) { 75*7eaf9132SAlexandru Ardelean ret = genphy_c45_pma_setup_forced(phydev); 76*7eaf9132SAlexandru Ardelean if (ret < 0) 77*7eaf9132SAlexandru Ardelean return ret; 78*7eaf9132SAlexandru Ardelean 79*7eaf9132SAlexandru Ardelean if (priv->tx_level_prop_present && priv->tx_level_2v4) 80*7eaf9132SAlexandru Ardelean ret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_B10L_PMA_CTRL, 81*7eaf9132SAlexandru Ardelean MDIO_PMA_10T1L_CTRL_2V4_EN); 82*7eaf9132SAlexandru Ardelean else 83*7eaf9132SAlexandru Ardelean ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_B10L_PMA_CTRL, 84*7eaf9132SAlexandru Ardelean MDIO_PMA_10T1L_CTRL_2V4_EN); 85*7eaf9132SAlexandru Ardelean if (ret < 0) 86*7eaf9132SAlexandru Ardelean return ret; 87*7eaf9132SAlexandru Ardelean 88*7eaf9132SAlexandru Ardelean /* Force PHY to use above configurations */ 89*7eaf9132SAlexandru Ardelean return phy_set_bits_mmd(phydev, MDIO_MMD_AN, ADIN_FORCED_MODE, ADIN_FORCED_MODE_EN); 90*7eaf9132SAlexandru Ardelean } 91*7eaf9132SAlexandru Ardelean 92*7eaf9132SAlexandru Ardelean ret = phy_clear_bits_mmd(phydev, MDIO_MMD_AN, ADIN_FORCED_MODE, ADIN_FORCED_MODE_EN); 93*7eaf9132SAlexandru Ardelean if (ret < 0) 94*7eaf9132SAlexandru Ardelean return ret; 95*7eaf9132SAlexandru Ardelean 96*7eaf9132SAlexandru Ardelean /* Request increased transmit level from LP. */ 97*7eaf9132SAlexandru Ardelean if (priv->tx_level_prop_present && priv->tx_level_2v4) { 98*7eaf9132SAlexandru Ardelean ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, 99*7eaf9132SAlexandru Ardelean MDIO_AN_T1_ADV_H_10L_TX_HI | 100*7eaf9132SAlexandru Ardelean MDIO_AN_T1_ADV_H_10L_TX_HI_REQ); 101*7eaf9132SAlexandru Ardelean if (ret < 0) 102*7eaf9132SAlexandru Ardelean return ret; 103*7eaf9132SAlexandru Ardelean } 104*7eaf9132SAlexandru Ardelean 105*7eaf9132SAlexandru Ardelean /* Disable 2.4 Vpp transmit level. */ 106*7eaf9132SAlexandru Ardelean if ((priv->tx_level_prop_present && !priv->tx_level_2v4) || !priv->tx_level_2v4_able) { 107*7eaf9132SAlexandru Ardelean ret = phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, 108*7eaf9132SAlexandru Ardelean MDIO_AN_T1_ADV_H_10L_TX_HI | 109*7eaf9132SAlexandru Ardelean MDIO_AN_T1_ADV_H_10L_TX_HI_REQ); 110*7eaf9132SAlexandru Ardelean if (ret < 0) 111*7eaf9132SAlexandru Ardelean return ret; 112*7eaf9132SAlexandru Ardelean } 113*7eaf9132SAlexandru Ardelean 114*7eaf9132SAlexandru Ardelean return genphy_c45_config_aneg(phydev); 115*7eaf9132SAlexandru Ardelean } 116*7eaf9132SAlexandru Ardelean 117*7eaf9132SAlexandru Ardelean static int adin_set_powerdown_mode(struct phy_device *phydev, bool en) 118*7eaf9132SAlexandru Ardelean { 119*7eaf9132SAlexandru Ardelean int ret; 120*7eaf9132SAlexandru Ardelean int val; 121*7eaf9132SAlexandru Ardelean 122*7eaf9132SAlexandru Ardelean val = en ? ADIN_CRSM_SFT_PD_CNTRL_EN : 0; 123*7eaf9132SAlexandru Ardelean ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 124*7eaf9132SAlexandru Ardelean ADIN_CRSM_SFT_PD_CNTRL, val); 125*7eaf9132SAlexandru Ardelean if (ret < 0) 126*7eaf9132SAlexandru Ardelean return ret; 127*7eaf9132SAlexandru Ardelean 128*7eaf9132SAlexandru Ardelean return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ADIN_CRSM_STAT, ret, 129*7eaf9132SAlexandru Ardelean (ret & ADIN_CRSM_SFT_PD_RDY) == val, 130*7eaf9132SAlexandru Ardelean 1000, 30000, true); 131*7eaf9132SAlexandru Ardelean } 132*7eaf9132SAlexandru Ardelean 133*7eaf9132SAlexandru Ardelean static int adin_suspend(struct phy_device *phydev) 134*7eaf9132SAlexandru Ardelean { 135*7eaf9132SAlexandru Ardelean return adin_set_powerdown_mode(phydev, true); 136*7eaf9132SAlexandru Ardelean } 137*7eaf9132SAlexandru Ardelean 138*7eaf9132SAlexandru Ardelean static int adin_resume(struct phy_device *phydev) 139*7eaf9132SAlexandru Ardelean { 140*7eaf9132SAlexandru Ardelean return adin_set_powerdown_mode(phydev, false); 141*7eaf9132SAlexandru Ardelean } 142*7eaf9132SAlexandru Ardelean 143*7eaf9132SAlexandru Ardelean static int adin_set_loopback(struct phy_device *phydev, bool enable) 144*7eaf9132SAlexandru Ardelean { 145*7eaf9132SAlexandru Ardelean if (enable) 146*7eaf9132SAlexandru Ardelean return phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_10T1L_CTRL, 147*7eaf9132SAlexandru Ardelean BMCR_LOOPBACK); 148*7eaf9132SAlexandru Ardelean 149*7eaf9132SAlexandru Ardelean /* PCS loopback (according to 10BASE-T1L spec) */ 150*7eaf9132SAlexandru Ardelean return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_10T1L_CTRL, 151*7eaf9132SAlexandru Ardelean BMCR_LOOPBACK); 152*7eaf9132SAlexandru Ardelean } 153*7eaf9132SAlexandru Ardelean 154*7eaf9132SAlexandru Ardelean static int adin_soft_reset(struct phy_device *phydev) 155*7eaf9132SAlexandru Ardelean { 156*7eaf9132SAlexandru Ardelean int ret; 157*7eaf9132SAlexandru Ardelean 158*7eaf9132SAlexandru Ardelean ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, ADIN_CRSM_SFT_RST, ADIN_CRSM_SFT_RST_EN); 159*7eaf9132SAlexandru Ardelean if (ret < 0) 160*7eaf9132SAlexandru Ardelean return ret; 161*7eaf9132SAlexandru Ardelean 162*7eaf9132SAlexandru Ardelean return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, ADIN_CRSM_STAT, ret, 163*7eaf9132SAlexandru Ardelean (ret & ADIN_CRSM_SYS_RDY), 164*7eaf9132SAlexandru Ardelean 10000, 30000, true); 165*7eaf9132SAlexandru Ardelean } 166*7eaf9132SAlexandru Ardelean 167*7eaf9132SAlexandru Ardelean static int adin_get_features(struct phy_device *phydev) 168*7eaf9132SAlexandru Ardelean { 169*7eaf9132SAlexandru Ardelean struct adin_priv *priv = phydev->priv; 170*7eaf9132SAlexandru Ardelean struct device *dev = &phydev->mdio.dev; 171*7eaf9132SAlexandru Ardelean int ret; 172*7eaf9132SAlexandru Ardelean u8 val; 173*7eaf9132SAlexandru Ardelean 174*7eaf9132SAlexandru Ardelean ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10T1L_STAT); 175*7eaf9132SAlexandru Ardelean if (ret < 0) 176*7eaf9132SAlexandru Ardelean return ret; 177*7eaf9132SAlexandru Ardelean 178*7eaf9132SAlexandru Ardelean /* This depends on the voltage level from the power source */ 179*7eaf9132SAlexandru Ardelean priv->tx_level_2v4_able = !!(ret & MDIO_PMA_10T1L_STAT_2V4_ABLE); 180*7eaf9132SAlexandru Ardelean 181*7eaf9132SAlexandru Ardelean phydev_dbg(phydev, "PHY supports 2.4V TX level: %s\n", 182*7eaf9132SAlexandru Ardelean priv->tx_level_2v4_able ? "yes" : "no"); 183*7eaf9132SAlexandru Ardelean 184*7eaf9132SAlexandru Ardelean priv->tx_level_prop_present = device_property_present(dev, "phy-10base-t1l-2.4vpp"); 185*7eaf9132SAlexandru Ardelean if (priv->tx_level_prop_present) { 186*7eaf9132SAlexandru Ardelean ret = device_property_read_u8(dev, "phy-10base-t1l-2.4vpp", &val); 187*7eaf9132SAlexandru Ardelean if (ret < 0) 188*7eaf9132SAlexandru Ardelean return ret; 189*7eaf9132SAlexandru Ardelean 190*7eaf9132SAlexandru Ardelean priv->tx_level_2v4 = val; 191*7eaf9132SAlexandru Ardelean if (!priv->tx_level_2v4 && priv->tx_level_2v4_able) 192*7eaf9132SAlexandru Ardelean phydev_info(phydev, 193*7eaf9132SAlexandru Ardelean "PHY supports 2.4V TX level, but disabled via config\n"); 194*7eaf9132SAlexandru Ardelean } 195*7eaf9132SAlexandru Ardelean 196*7eaf9132SAlexandru Ardelean linkmode_set_bit_array(phy_basic_ports_array, ARRAY_SIZE(phy_basic_ports_array), 197*7eaf9132SAlexandru Ardelean phydev->supported); 198*7eaf9132SAlexandru Ardelean 199*7eaf9132SAlexandru Ardelean return genphy_c45_pma_read_abilities(phydev); 200*7eaf9132SAlexandru Ardelean } 201*7eaf9132SAlexandru Ardelean 202*7eaf9132SAlexandru Ardelean static int adin_probe(struct phy_device *phydev) 203*7eaf9132SAlexandru Ardelean { 204*7eaf9132SAlexandru Ardelean struct device *dev = &phydev->mdio.dev; 205*7eaf9132SAlexandru Ardelean struct adin_priv *priv; 206*7eaf9132SAlexandru Ardelean 207*7eaf9132SAlexandru Ardelean priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 208*7eaf9132SAlexandru Ardelean if (!priv) 209*7eaf9132SAlexandru Ardelean return -ENOMEM; 210*7eaf9132SAlexandru Ardelean 211*7eaf9132SAlexandru Ardelean phydev->priv = priv; 212*7eaf9132SAlexandru Ardelean 213*7eaf9132SAlexandru Ardelean return 0; 214*7eaf9132SAlexandru Ardelean } 215*7eaf9132SAlexandru Ardelean 216*7eaf9132SAlexandru Ardelean static struct phy_driver adin_driver[] = { 217*7eaf9132SAlexandru Ardelean { 218*7eaf9132SAlexandru Ardelean PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100), 219*7eaf9132SAlexandru Ardelean .name = "ADIN1100", 220*7eaf9132SAlexandru Ardelean .get_features = adin_get_features, 221*7eaf9132SAlexandru Ardelean .soft_reset = adin_soft_reset, 222*7eaf9132SAlexandru Ardelean .probe = adin_probe, 223*7eaf9132SAlexandru Ardelean .config_aneg = adin_config_aneg, 224*7eaf9132SAlexandru Ardelean .read_status = adin_read_status, 225*7eaf9132SAlexandru Ardelean .set_loopback = adin_set_loopback, 226*7eaf9132SAlexandru Ardelean .suspend = adin_suspend, 227*7eaf9132SAlexandru Ardelean .resume = adin_resume, 228*7eaf9132SAlexandru Ardelean }, 229*7eaf9132SAlexandru Ardelean }; 230*7eaf9132SAlexandru Ardelean 231*7eaf9132SAlexandru Ardelean module_phy_driver(adin_driver); 232*7eaf9132SAlexandru Ardelean 233*7eaf9132SAlexandru Ardelean static struct mdio_device_id __maybe_unused adin_tbl[] = { 234*7eaf9132SAlexandru Ardelean { PHY_ID_MATCH_MODEL(PHY_ID_ADIN1100) }, 235*7eaf9132SAlexandru Ardelean { } 236*7eaf9132SAlexandru Ardelean }; 237*7eaf9132SAlexandru Ardelean 238*7eaf9132SAlexandru Ardelean MODULE_DEVICE_TABLE(mdio, adin_tbl); 239*7eaf9132SAlexandru Ardelean MODULE_DESCRIPTION("Analog Devices Industrial Ethernet T1L PHY driver"); 240*7eaf9132SAlexandru Ardelean MODULE_LICENSE("Dual BSD/GPL"); 241