Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Driver for the Texas Instruments DP83TD510 PHY
0003  * Copyright (c) 2022 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
0004  */
0005 
0006 #include <linux/bitfield.h>
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/phy.h>
0010 
0011 #define DP83TD510E_PHY_ID           0x20000181
0012 
0013 /* MDIO_MMD_VEND2 registers */
0014 #define DP83TD510E_PHY_STS          0x10
0015 #define DP83TD510E_STS_MII_INT          BIT(7)
0016 #define DP83TD510E_LINK_STATUS          BIT(0)
0017 
0018 #define DP83TD510E_GEN_CFG          0x11
0019 #define DP83TD510E_GENCFG_INT_POLARITY      BIT(3)
0020 #define DP83TD510E_GENCFG_INT_EN        BIT(1)
0021 #define DP83TD510E_GENCFG_INT_OE        BIT(0)
0022 
0023 #define DP83TD510E_INTERRUPT_REG_1      0x12
0024 #define DP83TD510E_INT1_LINK            BIT(13)
0025 #define DP83TD510E_INT1_LINK_EN         BIT(5)
0026 
0027 #define DP83TD510E_AN_STAT_1            0x60c
0028 #define DP83TD510E_MASTER_SLAVE_RESOL_FAIL  BIT(15)
0029 
0030 #define DP83TD510E_MSE_DETECT           0xa85
0031 
0032 #define DP83TD510_SQI_MAX   7
0033 
0034 /* Register values are converted to SNR(dB) as suggested by
0035  * "Application Report - DP83TD510E Cable Diagnostics Toolkit":
0036  * SNR(dB) = -10 * log10 (VAL/2^17) - 1.76 dB.
0037  * SQI ranges are implemented according to "OPEN ALLIANCE - Advanced diagnostic
0038  * features for 100BASE-T1 automotive Ethernet PHYs"
0039  */
0040 static const u16 dp83td510_mse_sqi_map[] = {
0041     0x0569, /* < 18dB */
0042     0x044c, /* 18dB =< SNR < 19dB */
0043     0x0369, /* 19dB =< SNR < 20dB */
0044     0x02b6, /* 20dB =< SNR < 21dB */
0045     0x0227, /* 21dB =< SNR < 22dB */
0046     0x01b6, /* 22dB =< SNR < 23dB */
0047     0x015b, /* 23dB =< SNR < 24dB */
0048     0x0000  /* 24dB =< SNR */
0049 };
0050 
0051 static int dp83td510_config_intr(struct phy_device *phydev)
0052 {
0053     int ret;
0054 
0055     if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
0056         /* Clear any pending interrupts */
0057         ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
0058                     0x0);
0059         if (ret)
0060             return ret;
0061 
0062         ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
0063                     DP83TD510E_INTERRUPT_REG_1,
0064                     DP83TD510E_INT1_LINK_EN);
0065         if (ret)
0066             return ret;
0067 
0068         ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0069                        DP83TD510E_GEN_CFG,
0070                        DP83TD510E_GENCFG_INT_POLARITY |
0071                        DP83TD510E_GENCFG_INT_EN |
0072                        DP83TD510E_GENCFG_INT_OE);
0073     } else {
0074         ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
0075                     DP83TD510E_INTERRUPT_REG_1, 0x0);
0076         if (ret)
0077             return ret;
0078 
0079         ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
0080                      DP83TD510E_GEN_CFG,
0081                      DP83TD510E_GENCFG_INT_EN);
0082         if (ret)
0083             return ret;
0084 
0085         /* Clear any pending interrupts */
0086         ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS,
0087                     0x0);
0088     }
0089 
0090     return ret;
0091 }
0092 
0093 static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev)
0094 {
0095     int  ret;
0096 
0097     ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_PHY_STS);
0098     if (ret < 0) {
0099         phy_error(phydev);
0100         return IRQ_NONE;
0101     } else if (!(ret & DP83TD510E_STS_MII_INT)) {
0102         return IRQ_NONE;
0103     }
0104 
0105     /* Read the current enabled interrupts */
0106     ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1);
0107     if (ret < 0) {
0108         phy_error(phydev);
0109         return IRQ_NONE;
0110     } else if (!(ret & DP83TD510E_INT1_LINK_EN) ||
0111            !(ret & DP83TD510E_INT1_LINK)) {
0112         return IRQ_NONE;
0113     }
0114 
0115     phy_trigger_machine(phydev);
0116 
0117     return IRQ_HANDLED;
0118 }
0119 
0120 static int dp83td510_read_status(struct phy_device *phydev)
0121 {
0122     u16 phy_sts;
0123     int ret;
0124 
0125     phydev->speed = SPEED_UNKNOWN;
0126     phydev->duplex = DUPLEX_UNKNOWN;
0127     phydev->pause = 0;
0128     phydev->asym_pause = 0;
0129     linkmode_zero(phydev->lp_advertising);
0130 
0131     phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);
0132 
0133     phydev->link = !!(phy_sts & DP83TD510E_LINK_STATUS);
0134     if (phydev->link) {
0135         /* This PHY supports only one link mode: 10BaseT1L_Full */
0136         phydev->duplex = DUPLEX_FULL;
0137         phydev->speed = SPEED_10;
0138 
0139         if (phydev->autoneg == AUTONEG_ENABLE) {
0140             ret = genphy_c45_read_lpa(phydev);
0141             if (ret)
0142                 return ret;
0143 
0144             phy_resolve_aneg_linkmode(phydev);
0145         }
0146     }
0147 
0148     if (phydev->autoneg == AUTONEG_ENABLE) {
0149         ret = genphy_c45_baset1_read_status(phydev);
0150         if (ret < 0)
0151             return ret;
0152 
0153         ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
0154                    DP83TD510E_AN_STAT_1);
0155         if (ret < 0)
0156             return ret;
0157 
0158         if (ret & DP83TD510E_MASTER_SLAVE_RESOL_FAIL)
0159             phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;
0160     } else {
0161         return genphy_c45_pma_baset1_read_master_slave(phydev);
0162     }
0163 
0164     return 0;
0165 }
0166 
0167 static int dp83td510_config_aneg(struct phy_device *phydev)
0168 {
0169     bool changed = false;
0170     int ret;
0171 
0172     ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
0173     if (ret < 0)
0174         return ret;
0175 
0176     if (phydev->autoneg == AUTONEG_DISABLE)
0177         return genphy_c45_an_disable_aneg(phydev);
0178 
0179     ret = genphy_c45_an_config_aneg(phydev);
0180     if (ret < 0)
0181         return ret;
0182     if (ret > 0)
0183         changed = true;
0184 
0185     return genphy_c45_check_and_restart_aneg(phydev, changed);
0186 }
0187 
0188 static int dp83td510_get_sqi(struct phy_device *phydev)
0189 {
0190     int sqi, ret;
0191     u16 mse_val;
0192 
0193     if (!phydev->link)
0194         return 0;
0195 
0196     ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT);
0197     if (ret < 0)
0198         return ret;
0199 
0200     mse_val = 0xFFFF & ret;
0201     for (sqi = 0; sqi < ARRAY_SIZE(dp83td510_mse_sqi_map); sqi++) {
0202         if (mse_val >= dp83td510_mse_sqi_map[sqi])
0203             return sqi;
0204     }
0205 
0206     return -EINVAL;
0207 }
0208 
0209 static int dp83td510_get_sqi_max(struct phy_device *phydev)
0210 {
0211     return DP83TD510_SQI_MAX;
0212 }
0213 
0214 static int dp83td510_get_features(struct phy_device *phydev)
0215 {
0216     /* This PHY can't respond on MDIO bus if no RMII clock is enabled.
0217      * In case RMII mode is used (most meaningful mode for this PHY) and
0218      * the PHY do not have own XTAL, and CLK providing MAC is not probed,
0219      * we won't be able to read all needed ability registers.
0220      * So provide it manually.
0221      */
0222 
0223     linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
0224     linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
0225     linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
0226     linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
0227              phydev->supported);
0228 
0229     return 0;
0230 }
0231 
0232 static struct phy_driver dp83td510_driver[] = {
0233 {
0234     PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID),
0235     .name       = "TI DP83TD510E",
0236 
0237     .config_aneg    = dp83td510_config_aneg,
0238     .read_status    = dp83td510_read_status,
0239     .get_features   = dp83td510_get_features,
0240     .config_intr    = dp83td510_config_intr,
0241     .handle_interrupt = dp83td510_handle_interrupt,
0242     .get_sqi    = dp83td510_get_sqi,
0243     .get_sqi_max    = dp83td510_get_sqi_max,
0244 
0245     .suspend    = genphy_suspend,
0246     .resume     = genphy_resume,
0247 } };
0248 module_phy_driver(dp83td510_driver);
0249 
0250 static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
0251     { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
0252     { }
0253 };
0254 MODULE_DEVICE_TABLE(mdio, dp83td510_tbl);
0255 
0256 MODULE_DESCRIPTION("Texas Instruments DP83TD510E PHY driver");
0257 MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
0258 MODULE_LICENSE("GPL v2");