dp83td510.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Driver for the Texas Instruments DP83TD510 PHY
  3. * Copyright (c) 2022 Pengutronix, Oleksij Rempel <[email protected]>
  4. */
  5. #include <linux/bitfield.h>
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/phy.h>
  9. #define DP83TD510E_PHY_ID 0x20000181
  10. /* MDIO_MMD_VEND2 registers */
  11. #define DP83TD510E_PHY_STS 0x10
  12. /* Bit 7 - mii_interrupt, active high. Clears on read.
  13. * Note: Clearing does not necessarily deactivate IRQ pin if interrupts pending.
  14. * This differs from the DP83TD510E datasheet (2020) which states this bit
  15. * clears on write 0.
  16. */
  17. #define DP83TD510E_STS_MII_INT BIT(7)
  18. #define DP83TD510E_LINK_STATUS BIT(0)
  19. #define DP83TD510E_GEN_CFG 0x11
  20. #define DP83TD510E_GENCFG_INT_POLARITY BIT(3)
  21. #define DP83TD510E_GENCFG_INT_EN BIT(1)
  22. #define DP83TD510E_GENCFG_INT_OE BIT(0)
  23. #define DP83TD510E_INTERRUPT_REG_1 0x12
  24. #define DP83TD510E_INT1_LINK BIT(13)
  25. #define DP83TD510E_INT1_LINK_EN BIT(5)
  26. #define DP83TD510E_AN_STAT_1 0x60c
  27. #define DP83TD510E_MASTER_SLAVE_RESOL_FAIL BIT(15)
  28. #define DP83TD510E_MSE_DETECT 0xa85
  29. #define DP83TD510_SQI_MAX 7
  30. /* Register values are converted to SNR(dB) as suggested by
  31. * "Application Report - DP83TD510E Cable Diagnostics Toolkit":
  32. * SNR(dB) = -10 * log10 (VAL/2^17) - 1.76 dB.
  33. * SQI ranges are implemented according to "OPEN ALLIANCE - Advanced diagnostic
  34. * features for 100BASE-T1 automotive Ethernet PHYs"
  35. */
  36. static const u16 dp83td510_mse_sqi_map[] = {
  37. 0x0569, /* < 18dB */
  38. 0x044c, /* 18dB =< SNR < 19dB */
  39. 0x0369, /* 19dB =< SNR < 20dB */
  40. 0x02b6, /* 20dB =< SNR < 21dB */
  41. 0x0227, /* 21dB =< SNR < 22dB */
  42. 0x01b6, /* 22dB =< SNR < 23dB */
  43. 0x015b, /* 23dB =< SNR < 24dB */
  44. 0x0000 /* 24dB =< SNR */
  45. };
  46. static int dp83td510_config_intr(struct phy_device *phydev)
  47. {
  48. int ret;
  49. if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  50. ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
  51. DP83TD510E_INTERRUPT_REG_1,
  52. DP83TD510E_INT1_LINK_EN);
  53. if (ret)
  54. return ret;
  55. ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
  56. DP83TD510E_GEN_CFG,
  57. DP83TD510E_GENCFG_INT_POLARITY |
  58. DP83TD510E_GENCFG_INT_EN |
  59. DP83TD510E_GENCFG_INT_OE);
  60. } else {
  61. ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,
  62. DP83TD510E_INTERRUPT_REG_1, 0x0);
  63. if (ret)
  64. return ret;
  65. ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
  66. DP83TD510E_GEN_CFG,
  67. DP83TD510E_GENCFG_INT_EN);
  68. if (ret)
  69. return ret;
  70. }
  71. return ret;
  72. }
  73. static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev)
  74. {
  75. int ret;
  76. /* Read the current enabled interrupts */
  77. ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1);
  78. if (ret < 0) {
  79. phy_error(phydev);
  80. return IRQ_NONE;
  81. } else if (!(ret & DP83TD510E_INT1_LINK_EN) ||
  82. !(ret & DP83TD510E_INT1_LINK)) {
  83. return IRQ_NONE;
  84. }
  85. phy_trigger_machine(phydev);
  86. return IRQ_HANDLED;
  87. }
  88. static int dp83td510_read_status(struct phy_device *phydev)
  89. {
  90. u16 phy_sts;
  91. int ret;
  92. phydev->speed = SPEED_UNKNOWN;
  93. phydev->duplex = DUPLEX_UNKNOWN;
  94. phydev->pause = 0;
  95. phydev->asym_pause = 0;
  96. linkmode_zero(phydev->lp_advertising);
  97. phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);
  98. phydev->link = !!(phy_sts & DP83TD510E_LINK_STATUS);
  99. if (phydev->link) {
  100. /* This PHY supports only one link mode: 10BaseT1L_Full */
  101. phydev->duplex = DUPLEX_FULL;
  102. phydev->speed = SPEED_10;
  103. if (phydev->autoneg == AUTONEG_ENABLE) {
  104. ret = genphy_c45_read_lpa(phydev);
  105. if (ret)
  106. return ret;
  107. phy_resolve_aneg_linkmode(phydev);
  108. }
  109. }
  110. if (phydev->autoneg == AUTONEG_ENABLE) {
  111. ret = genphy_c45_baset1_read_status(phydev);
  112. if (ret < 0)
  113. return ret;
  114. ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
  115. DP83TD510E_AN_STAT_1);
  116. if (ret < 0)
  117. return ret;
  118. if (ret & DP83TD510E_MASTER_SLAVE_RESOL_FAIL)
  119. phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;
  120. } else {
  121. return genphy_c45_pma_baset1_read_master_slave(phydev);
  122. }
  123. return 0;
  124. }
  125. static int dp83td510_config_aneg(struct phy_device *phydev)
  126. {
  127. bool changed = false;
  128. int ret;
  129. ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
  130. if (ret < 0)
  131. return ret;
  132. if (phydev->autoneg == AUTONEG_DISABLE)
  133. return genphy_c45_an_disable_aneg(phydev);
  134. ret = genphy_c45_an_config_aneg(phydev);
  135. if (ret < 0)
  136. return ret;
  137. if (ret > 0)
  138. changed = true;
  139. return genphy_c45_check_and_restart_aneg(phydev, changed);
  140. }
  141. static int dp83td510_get_sqi(struct phy_device *phydev)
  142. {
  143. int sqi, ret;
  144. u16 mse_val;
  145. if (!phydev->link)
  146. return 0;
  147. ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT);
  148. if (ret < 0)
  149. return ret;
  150. mse_val = 0xFFFF & ret;
  151. for (sqi = 0; sqi < ARRAY_SIZE(dp83td510_mse_sqi_map); sqi++) {
  152. if (mse_val >= dp83td510_mse_sqi_map[sqi])
  153. return sqi;
  154. }
  155. return -EINVAL;
  156. }
  157. static int dp83td510_get_sqi_max(struct phy_device *phydev)
  158. {
  159. return DP83TD510_SQI_MAX;
  160. }
  161. static int dp83td510_get_features(struct phy_device *phydev)
  162. {
  163. /* This PHY can't respond on MDIO bus if no RMII clock is enabled.
  164. * In case RMII mode is used (most meaningful mode for this PHY) and
  165. * the PHY do not have own XTAL, and CLK providing MAC is not probed,
  166. * we won't be able to read all needed ability registers.
  167. * So provide it manually.
  168. */
  169. linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
  170. linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);
  171. linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
  172. linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
  173. phydev->supported);
  174. return 0;
  175. }
  176. static struct phy_driver dp83td510_driver[] = {
  177. {
  178. PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID),
  179. .name = "TI DP83TD510E",
  180. .config_aneg = dp83td510_config_aneg,
  181. .read_status = dp83td510_read_status,
  182. .get_features = dp83td510_get_features,
  183. .config_intr = dp83td510_config_intr,
  184. .handle_interrupt = dp83td510_handle_interrupt,
  185. .get_sqi = dp83td510_get_sqi,
  186. .get_sqi_max = dp83td510_get_sqi_max,
  187. .suspend = genphy_suspend,
  188. .resume = genphy_resume,
  189. } };
  190. module_phy_driver(dp83td510_driver);
  191. static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {
  192. { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },
  193. { }
  194. };
  195. MODULE_DEVICE_TABLE(mdio, dp83td510_tbl);
  196. MODULE_DESCRIPTION("Texas Instruments DP83TD510E PHY driver");
  197. MODULE_AUTHOR("Oleksij Rempel <[email protected]>");
  198. MODULE_LICENSE("GPL v2");