ax88796b_rust.rs 3.9 KB

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