ax88796b_rust.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com>
  3. //! Rust Asix PHYs driver
  4. //!
  5. //! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c)
  6. use kernel::{
  7. net::phy::{self, reg::C22, DeviceId, Driver},
  8. prelude::*,
  9. uapi,
  10. };
  11. kernel::module_phy_driver! {
  12. drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B],
  13. device_table: [
  14. DeviceId::new_with_driver::<PhyAX88772A>(),
  15. DeviceId::new_with_driver::<PhyAX88772C>(),
  16. DeviceId::new_with_driver::<PhyAX88796B>()
  17. ],
  18. name: "rust_asix_phy",
  19. authors: ["FUJITA Tomonori <fujita.tomonori@gmail.com>"],
  20. description: "Rust Asix PHYs driver",
  21. license: "GPL",
  22. }
  23. const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16;
  24. const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16;
  25. // Performs a software PHY reset using the standard
  26. // BMCR_RESET bit and poll for the reset bit to be cleared.
  27. // Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation
  28. // such as used on the Individual Computers' X-Surf 100 Zorro card.
  29. fn asix_soft_reset(dev: &mut phy::Device) -> Result {
  30. dev.write(C22::BMCR, 0)?;
  31. dev.genphy_soft_reset()
  32. }
  33. struct PhyAX88772A;
  34. #[vtable]
  35. impl Driver for PhyAX88772A {
  36. const FLAGS: u32 = phy::flags::IS_INTERNAL;
  37. const NAME: &'static CStr = c"Asix Electronics AX88772A";
  38. const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861);
  39. // AX88772A is not working properly with some old switches (NETGEAR EN 108TP):
  40. // after autoneg is done and the link status is reported as active, the MII_LPA
  41. // register is 0. This issue is not reproducible on AX88772C.
  42. fn read_status(dev: &mut phy::Device) -> Result<u16> {
  43. dev.genphy_update_link()?;
  44. if !dev.is_link_up() {
  45. return Ok(0);
  46. }
  47. // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
  48. // linkmode so use MII_BMCR as default values.
  49. let ret = dev.read(C22::BMCR)?;
  50. if ret & BMCR_SPEED100 != 0 {
  51. dev.set_speed(uapi::SPEED_100);
  52. } else {
  53. dev.set_speed(uapi::SPEED_10);
  54. }
  55. let duplex = if ret & BMCR_FULLDPLX != 0 {
  56. phy::DuplexMode::Full
  57. } else {
  58. phy::DuplexMode::Half
  59. };
  60. dev.set_duplex(duplex);
  61. dev.genphy_read_lpa()?;
  62. if dev.is_autoneg_enabled() && dev.is_autoneg_completed() {
  63. dev.resolve_aneg_linkmode();
  64. }
  65. Ok(0)
  66. }
  67. fn suspend(dev: &mut phy::Device) -> Result {
  68. dev.genphy_suspend()
  69. }
  70. fn resume(dev: &mut phy::Device) -> Result {
  71. dev.genphy_resume()
  72. }
  73. fn soft_reset(dev: &mut phy::Device) -> Result {
  74. asix_soft_reset(dev)
  75. }
  76. fn link_change_notify(dev: &mut phy::Device) {
  77. // Reset PHY, otherwise MII_LPA will provide outdated information.
  78. // This issue is reproducible only with some link partner PHYs.
  79. if dev.state() == phy::DeviceState::NoLink {
  80. let _ = dev.init_hw();
  81. let _ = dev.start_aneg();
  82. }
  83. }
  84. }
  85. struct PhyAX88772C;
  86. #[vtable]
  87. impl Driver for PhyAX88772C {
  88. const FLAGS: u32 = phy::flags::IS_INTERNAL;
  89. const NAME: &'static CStr = c"Asix Electronics AX88772C";
  90. const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881);
  91. fn suspend(dev: &mut phy::Device) -> Result {
  92. dev.genphy_suspend()
  93. }
  94. fn resume(dev: &mut phy::Device) -> Result {
  95. dev.genphy_resume()
  96. }
  97. fn soft_reset(dev: &mut phy::Device) -> Result {
  98. asix_soft_reset(dev)
  99. }
  100. }
  101. struct PhyAX88796B;
  102. #[vtable]
  103. impl Driver for PhyAX88796B {
  104. const NAME: &'static CStr = c"Asix Electronics AX88796B";
  105. const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841);
  106. fn soft_reset(dev: &mut phy::Device) -> Result {
  107. asix_soft_reset(dev)
  108. }
  109. }