teranetics.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for Teranetics PHY
  4. *
  5. * Author: Shaohui Xie <[email protected]>
  6. *
  7. * Copyright 2015 Freescale Semiconductor, Inc.
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/mii.h>
  12. #include <linux/ethtool.h>
  13. #include <linux/mdio.h>
  14. #include <linux/phy.h>
  15. MODULE_DESCRIPTION("Teranetics PHY driver");
  16. MODULE_AUTHOR("Shaohui Xie <[email protected]>");
  17. MODULE_LICENSE("GPL v2");
  18. #define PHY_ID_TN2020 0x00a19410
  19. #define MDIO_PHYXS_LNSTAT_SYNC0 0x0001
  20. #define MDIO_PHYXS_LNSTAT_SYNC1 0x0002
  21. #define MDIO_PHYXS_LNSTAT_SYNC2 0x0004
  22. #define MDIO_PHYXS_LNSTAT_SYNC3 0x0008
  23. #define MDIO_PHYXS_LNSTAT_ALIGN 0x1000
  24. #define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \
  25. MDIO_PHYXS_LNSTAT_SYNC1 | \
  26. MDIO_PHYXS_LNSTAT_SYNC2 | \
  27. MDIO_PHYXS_LNSTAT_SYNC3 | \
  28. MDIO_PHYXS_LNSTAT_ALIGN)
  29. static int teranetics_aneg_done(struct phy_device *phydev)
  30. {
  31. /* auto negotiation state can only be checked when using copper
  32. * port, if using fiber port, just lie it's done.
  33. */
  34. if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93))
  35. return genphy_c45_aneg_done(phydev);
  36. return 1;
  37. }
  38. static int teranetics_read_status(struct phy_device *phydev)
  39. {
  40. int reg;
  41. phydev->link = 1;
  42. phydev->speed = SPEED_10000;
  43. phydev->duplex = DUPLEX_FULL;
  44. if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) {
  45. reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT);
  46. if (reg < 0 ||
  47. !((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)) {
  48. phydev->link = 0;
  49. return 0;
  50. }
  51. reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
  52. if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS))
  53. phydev->link = 0;
  54. }
  55. return 0;
  56. }
  57. static int teranetics_match_phy_device(struct phy_device *phydev)
  58. {
  59. return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020;
  60. }
  61. static struct phy_driver teranetics_driver[] = {
  62. {
  63. .phy_id = PHY_ID_TN2020,
  64. .phy_id_mask = 0xffffffff,
  65. .name = "Teranetics TN2020",
  66. .features = PHY_10GBIT_FEATURES,
  67. .aneg_done = teranetics_aneg_done,
  68. .config_aneg = gen10g_config_aneg,
  69. .read_status = teranetics_read_status,
  70. .match_phy_device = teranetics_match_phy_device,
  71. },
  72. };
  73. module_phy_driver(teranetics_driver);
  74. static struct mdio_device_id __maybe_unused teranetics_tbl[] = {
  75. { PHY_ID_TN2020, 0xffffffff },
  76. { }
  77. };
  78. MODULE_DEVICE_TABLE(mdio, teranetics_tbl);