1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Driver for Microchip 10BASE-T1S PHYs 4 * 5 * Support: Microchip Phys: 6 * lan8670/1/2 Rev.B1/C1/C2/D0 7 * lan8650/1 Rev.B0/B1 Internal PHYs 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/phy.h> 13 14 #define PHY_ID_LAN867X_REVB1 0x0007C162 15 #define PHY_ID_LAN867X_REVC1 0x0007C164 16 #define PHY_ID_LAN867X_REVC2 0x0007C165 17 #define PHY_ID_LAN867X_REVD0 0x0007C166 18 /* Both Rev.B0 and B1 clause 22 PHYID's are same due to B1 chip limitation */ 19 #define PHY_ID_LAN865X_REVB 0x0007C1B3 20 21 #define LAN867X_REG_STS2 0x0019 22 23 #define LAN867x_RESET_COMPLETE_STS BIT(11) 24 25 #define LAN865X_REG_CFGPARAM_ADDR 0x00D8 26 #define LAN865X_REG_CFGPARAM_DATA 0x00D9 27 #define LAN865X_REG_CFGPARAM_CTRL 0x00DA 28 #define LAN865X_REG_STS2 0x0019 29 30 /* Collision Detector Control 0 Register */ 31 #define LAN86XX_REG_COL_DET_CTRL0 0x0087 32 #define COL_DET_CTRL0_ENABLE_BIT_MASK BIT(15) 33 #define COL_DET_ENABLE BIT(15) 34 #define COL_DET_DISABLE 0x0000 35 36 /* LAN8670/1/2 Rev.D0 Link Status Selection Register */ 37 #define LAN867X_REG_LINK_STATUS_CTRL 0x0012 38 #define LINK_STATUS_CONFIGURATION GENMASK(12, 11) 39 #define LINK_STATUS_SEMAPHORE BIT(0) 40 41 /* Link Status Configuration */ 42 #define LINK_STATUS_CONFIG_PLCA_STATUS 0x1 43 #define LINK_STATUS_CONFIG_SEMAPHORE 0x2 44 45 #define LINK_STATUS_SEMAPHORE_SET 0x1 46 47 #define LAN865X_CFGPARAM_READ_ENABLE BIT(1) 48 49 /* The arrays below are pulled from the following table from AN1699 50 * Access MMD Address Value Mask 51 * RMW 0x1F 0x00D0 0x0002 0x0E03 52 * RMW 0x1F 0x00D1 0x0000 0x0300 53 * RMW 0x1F 0x0084 0x3380 0xFFC0 54 * RMW 0x1F 0x0085 0x0006 0x000F 55 * RMW 0x1F 0x008A 0xC000 0xF800 56 * RMW 0x1F 0x0087 0x801C 0x801C 57 * RMW 0x1F 0x0088 0x033F 0x1FFF 58 * W 0x1F 0x008B 0x0404 ------ 59 * RMW 0x1F 0x0080 0x0600 0x0600 60 * RMW 0x1F 0x00F1 0x2400 0x7F00 61 * RMW 0x1F 0x0096 0x2000 0x2000 62 * W 0x1F 0x0099 0x7F80 ------ 63 */ 64 65 static const u32 lan867x_revb1_fixup_registers[12] = { 66 0x00D0, 0x00D1, 0x0084, 0x0085, 67 0x008A, 0x0087, 0x0088, 0x008B, 68 0x0080, 0x00F1, 0x0096, 0x0099, 69 }; 70 71 static const u16 lan867x_revb1_fixup_values[12] = { 72 0x0002, 0x0000, 0x3380, 0x0006, 73 0xC000, 0x801C, 0x033F, 0x0404, 74 0x0600, 0x2400, 0x2000, 0x7F80, 75 }; 76 77 static const u16 lan867x_revb1_fixup_masks[12] = { 78 0x0E03, 0x0300, 0xFFC0, 0x000F, 79 0xF800, 0x801C, 0x1FFF, 0xFFFF, 80 0x0600, 0x7F00, 0x2000, 0xFFFF, 81 }; 82 83 /* LAN865x Rev.B0/B1 configuration parameters from AN1760 84 * As per the Configuration Application Note AN1760 published in the below link, 85 * https://www.microchip.com/en-us/application-notes/an1760 86 * Revision F (DS60001760G - June 2024) 87 */ 88 static const u32 lan865x_revb_fixup_registers[17] = { 89 0x00D0, 0x00E0, 0x00E9, 0x00F5, 90 0x00F4, 0x00F8, 0x00F9, 0x0081, 91 0x0091, 0x0043, 0x0044, 0x0045, 92 0x0053, 0x0054, 0x0055, 0x0040, 93 0x0050, 94 }; 95 96 static const u16 lan865x_revb_fixup_values[17] = { 97 0x3F31, 0xC000, 0x9E50, 0x1CF8, 98 0xC020, 0xB900, 0x4E53, 0x0080, 99 0x9660, 0x00FF, 0xFFFF, 0x0000, 100 0x00FF, 0xFFFF, 0x0000, 0x0002, 101 0x0002, 102 }; 103 104 static const u16 lan865x_revb_fixup_cfg_regs[2] = { 105 0x0084, 0x008A, 106 }; 107 108 static const u32 lan865x_revb_sqi_fixup_regs[12] = { 109 0x00B0, 0x00B1, 0x00B2, 0x00B3, 110 0x00B4, 0x00B5, 0x00B6, 0x00B7, 111 0x00B8, 0x00B9, 0x00BA, 0x00BB, 112 }; 113 114 static const u16 lan865x_revb_sqi_fixup_values[12] = { 115 0x0103, 0x0910, 0x1D26, 0x002A, 116 0x0103, 0x070D, 0x1720, 0x0027, 117 0x0509, 0x0E13, 0x1C25, 0x002B, 118 }; 119 120 static const u16 lan865x_revb_sqi_fixup_cfg_regs[3] = { 121 0x00AD, 0x00AE, 0x00AF, 122 }; 123 124 /* LAN867x Rev.D0 configuration parameters from AN1699 125 * As per the Configuration Application Note AN1699 published in the below link, 126 * https://www.microchip.com/en-us/application-notes/an1699 127 * Revision G (DS60001699G - October 2025) 128 */ 129 static const u16 lan867x_revd0_fixup_regs[8] = { 130 0x0037, 0x008A, 0x0118, 0x00D6, 131 0x0082, 0x00FD, 0x00FD, 0x0091, 132 }; 133 134 static const u16 lan867x_revd0_fixup_values[8] = { 135 0x0800, 0xBFC0, 0x029C, 0x1001, 136 0x001C, 0x0C0B, 0x8C07, 0x9660, 137 }; 138 139 /* Pulled from AN1760 describing 'indirect read' 140 * 141 * write_register(0x4, 0x00D8, addr) 142 * write_register(0x4, 0x00DA, 0x2) 143 * return (int8)(read_register(0x4, 0x00D9)) 144 * 145 * 0x4 refers to memory map selector 4, which maps to MDIO_MMD_VEND2 146 */ 147 static int lan865x_revb_indirect_read(struct phy_device *phydev, u16 addr) 148 { 149 int ret; 150 151 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_ADDR, 152 addr); 153 if (ret) 154 return ret; 155 156 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_CTRL, 157 LAN865X_CFGPARAM_READ_ENABLE); 158 if (ret) 159 return ret; 160 161 return phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN865X_REG_CFGPARAM_DATA); 162 } 163 164 /* This is pulled straight from AN1760 from 'calculation of offset 1' & 165 * 'calculation of offset 2' 166 */ 167 static int lan865x_generate_cfg_offsets(struct phy_device *phydev, s8 offsets[]) 168 { 169 const u16 fixup_regs[2] = {0x0004, 0x0008}; 170 int ret; 171 172 for (int i = 0; i < ARRAY_SIZE(fixup_regs); i++) { 173 ret = lan865x_revb_indirect_read(phydev, fixup_regs[i]); 174 if (ret < 0) 175 return ret; 176 177 /* 5-bit signed value, sign extend */ 178 ret &= GENMASK(4, 0); 179 if (ret & BIT(4)) 180 offsets[i] = ret | 0xE0; 181 else 182 offsets[i] = ret; 183 } 184 185 return 0; 186 } 187 188 static int lan865x_read_cfg_params(struct phy_device *phydev, 189 const u16 cfg_regs[], u16 cfg_params[], 190 u8 count) 191 { 192 int ret; 193 194 for (int i = 0; i < count; i++) { 195 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, 196 cfg_regs[i]); 197 if (ret < 0) 198 return ret; 199 cfg_params[i] = (u16)ret; 200 } 201 202 return 0; 203 } 204 205 static int lan865x_write_cfg_params(struct phy_device *phydev, 206 const u16 cfg_regs[], u16 cfg_params[], 207 u8 count) 208 { 209 int ret; 210 211 for (int i = 0; i < count; i++) { 212 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, cfg_regs[i], 213 cfg_params[i]); 214 if (ret) 215 return ret; 216 } 217 218 return 0; 219 } 220 221 static int lan865x_setup_cfgparam(struct phy_device *phydev, s8 offsets[]) 222 { 223 u16 cfg_results[ARRAY_SIZE(lan865x_revb_fixup_cfg_regs)]; 224 u16 cfg_params[ARRAY_SIZE(lan865x_revb_fixup_cfg_regs)]; 225 int ret; 226 227 ret = lan865x_read_cfg_params(phydev, lan865x_revb_fixup_cfg_regs, 228 cfg_params, ARRAY_SIZE(cfg_params)); 229 if (ret) 230 return ret; 231 232 cfg_results[0] = FIELD_PREP(GENMASK(15, 10), 9 + offsets[0]) | 233 FIELD_PREP(GENMASK(9, 4), 14 + offsets[0]) | 234 0x03; 235 cfg_results[1] = FIELD_PREP(GENMASK(15, 10), 40 + offsets[1]); 236 237 return lan865x_write_cfg_params(phydev, lan865x_revb_fixup_cfg_regs, 238 cfg_results, ARRAY_SIZE(cfg_results)); 239 } 240 241 static int lan865x_setup_sqi_cfgparam(struct phy_device *phydev, s8 offsets[]) 242 { 243 u16 cfg_results[ARRAY_SIZE(lan865x_revb_sqi_fixup_cfg_regs)]; 244 u16 cfg_params[ARRAY_SIZE(lan865x_revb_sqi_fixup_cfg_regs)]; 245 int ret; 246 247 ret = lan865x_read_cfg_params(phydev, lan865x_revb_sqi_fixup_cfg_regs, 248 cfg_params, ARRAY_SIZE(cfg_params)); 249 if (ret) 250 return ret; 251 252 cfg_results[0] = FIELD_PREP(GENMASK(13, 8), 5 + offsets[0]) | 253 (9 + offsets[0]); 254 cfg_results[1] = FIELD_PREP(GENMASK(13, 8), 9 + offsets[0]) | 255 (14 + offsets[0]); 256 cfg_results[2] = FIELD_PREP(GENMASK(13, 8), 17 + offsets[0]) | 257 (22 + offsets[0]); 258 259 return lan865x_write_cfg_params(phydev, lan865x_revb_sqi_fixup_cfg_regs, 260 cfg_results, ARRAY_SIZE(cfg_results)); 261 } 262 263 static int lan865x_revb_config_init(struct phy_device *phydev) 264 { 265 s8 offsets[2]; 266 int ret; 267 268 /* Reference to AN1760 269 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8650-1-Configuration-60001760.pdf 270 */ 271 ret = lan865x_generate_cfg_offsets(phydev, offsets); 272 if (ret) 273 return ret; 274 275 for (int i = 0; i < ARRAY_SIZE(lan865x_revb_fixup_registers); i++) { 276 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 277 lan865x_revb_fixup_registers[i], 278 lan865x_revb_fixup_values[i]); 279 if (ret) 280 return ret; 281 282 if (i == 1) { 283 ret = lan865x_setup_cfgparam(phydev, offsets); 284 if (ret) 285 return ret; 286 } 287 } 288 289 ret = lan865x_setup_sqi_cfgparam(phydev, offsets); 290 if (ret) 291 return ret; 292 293 for (int i = 0; i < ARRAY_SIZE(lan865x_revb_sqi_fixup_regs); i++) { 294 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 295 lan865x_revb_sqi_fixup_regs[i], 296 lan865x_revb_sqi_fixup_values[i]); 297 if (ret) 298 return ret; 299 } 300 301 return 0; 302 } 303 304 static int lan867x_check_reset_complete(struct phy_device *phydev) 305 { 306 int err; 307 308 /* The chip completes a reset in 3us, we might get here earlier than 309 * that, as an added margin we'll conditionally sleep 5us. 310 */ 311 err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2); 312 if (err < 0) 313 return err; 314 315 if (!(err & LAN867x_RESET_COMPLETE_STS)) { 316 udelay(5); 317 err = phy_read_mmd(phydev, MDIO_MMD_VEND2, LAN867X_REG_STS2); 318 if (err < 0) 319 return err; 320 if (!(err & LAN867x_RESET_COMPLETE_STS)) { 321 phydev_err(phydev, "PHY reset failed\n"); 322 return -ENODEV; 323 } 324 } 325 326 return 0; 327 } 328 329 static int lan867x_revc_config_init(struct phy_device *phydev) 330 { 331 s8 offsets[2]; 332 int ret; 333 334 ret = lan867x_check_reset_complete(phydev); 335 if (ret) 336 return ret; 337 338 ret = lan865x_generate_cfg_offsets(phydev, offsets); 339 if (ret) 340 return ret; 341 342 /* LAN867x Rev.C1/C2 configuration settings are equal to the first 9 343 * configuration settings and all the sqi fixup settings from LAN865x 344 * Rev.B0/B1. So the same fixup registers and values from LAN865x 345 * Rev.B0/B1 are used for LAN867x Rev.C1/C2 to avoid duplication. 346 * Refer the below links for the comparison. 347 * https://www.microchip.com/en-us/application-notes/an1760 348 * Revision F (DS60001760G - June 2024) 349 * https://www.microchip.com/en-us/application-notes/an1699 350 * Revision E (DS60001699F - June 2024) 351 */ 352 for (int i = 0; i < 9; i++) { 353 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 354 lan865x_revb_fixup_registers[i], 355 lan865x_revb_fixup_values[i]); 356 if (ret) 357 return ret; 358 359 if (i == 1) { 360 ret = lan865x_setup_cfgparam(phydev, offsets); 361 if (ret) 362 return ret; 363 } 364 } 365 366 ret = lan865x_setup_sqi_cfgparam(phydev, offsets); 367 if (ret) 368 return ret; 369 370 for (int i = 0; i < ARRAY_SIZE(lan865x_revb_sqi_fixup_regs); i++) { 371 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 372 lan865x_revb_sqi_fixup_regs[i], 373 lan865x_revb_sqi_fixup_values[i]); 374 if (ret) 375 return ret; 376 } 377 378 return 0; 379 } 380 381 static int lan867x_revb1_config_init(struct phy_device *phydev) 382 { 383 int err; 384 385 err = lan867x_check_reset_complete(phydev); 386 if (err) 387 return err; 388 389 /* Reference to AN1699 390 * https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/SupportingCollateral/AN-LAN8670-1-2-config-60001699.pdf 391 * AN1699 says Read, Modify, Write, but the Write is not required if the 392 * register already has the required value. So it is safe to use 393 * phy_modify_mmd here. 394 */ 395 for (int i = 0; i < ARRAY_SIZE(lan867x_revb1_fixup_registers); i++) { 396 err = phy_modify_mmd(phydev, MDIO_MMD_VEND2, 397 lan867x_revb1_fixup_registers[i], 398 lan867x_revb1_fixup_masks[i], 399 lan867x_revb1_fixup_values[i]); 400 if (err) 401 return err; 402 } 403 404 return 0; 405 } 406 407 static int lan867x_revd0_link_active_selection(struct phy_device *phydev, 408 bool plca_enabled) 409 { 410 u16 value; 411 412 if (plca_enabled) { 413 /* 0x1 - When PLCA is enabled: link status reflects plca_status. 414 */ 415 value = FIELD_PREP(LINK_STATUS_CONFIGURATION, 416 LINK_STATUS_CONFIG_PLCA_STATUS); 417 } else { 418 /* 0x2 - Link status is controlled by the value written into the 419 * LINK_STATUS_SEMAPHORE bit written. Here the link semaphore 420 * bit is written with 0x1 to set the link always active in 421 * CSMA/CD mode as it doesn't support autoneg. 422 */ 423 value = FIELD_PREP(LINK_STATUS_CONFIGURATION, 424 LINK_STATUS_CONFIG_SEMAPHORE) | 425 FIELD_PREP(LINK_STATUS_SEMAPHORE, 426 LINK_STATUS_SEMAPHORE_SET); 427 } 428 429 return phy_write_mmd(phydev, MDIO_MMD_VEND2, 430 LAN867X_REG_LINK_STATUS_CTRL, value); 431 } 432 433 /* As per LAN8650/1 Rev.B0/B1 AN1760 (Revision F (DS60001760G - June 2024)) and 434 * LAN8670/1/2 Rev.C1/C2 AN1699 (Revision E (DS60001699F - June 2024)), under 435 * normal operation, the device should be operated in PLCA mode. Disabling 436 * collision detection is recommended to allow the device to operate in noisy 437 * environments or when reflections and other inherent transmission line 438 * distortion cause poor signal quality. Collision detection must be re-enabled 439 * if the device is configured to operate in CSMA/CD mode. 440 * 441 * AN1760: https://www.microchip.com/en-us/application-notes/an1760 442 * AN1699: https://www.microchip.com/en-us/application-notes/an1699 443 */ 444 static int lan86xx_plca_set_cfg(struct phy_device *phydev, 445 const struct phy_plca_cfg *plca_cfg) 446 { 447 int ret; 448 449 /* Link status selection must be configured for LAN8670/1/2 Rev.D0 */ 450 if (phydev->phy_id == PHY_ID_LAN867X_REVD0) { 451 ret = lan867x_revd0_link_active_selection(phydev, 452 plca_cfg->enabled); 453 if (ret) 454 return ret; 455 } 456 457 ret = genphy_c45_plca_set_cfg(phydev, plca_cfg); 458 if (ret) 459 return ret; 460 461 if (plca_cfg->enabled) 462 return phy_modify_mmd(phydev, MDIO_MMD_VEND2, 463 LAN86XX_REG_COL_DET_CTRL0, 464 COL_DET_CTRL0_ENABLE_BIT_MASK, 465 COL_DET_DISABLE); 466 467 return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LAN86XX_REG_COL_DET_CTRL0, 468 COL_DET_CTRL0_ENABLE_BIT_MASK, COL_DET_ENABLE); 469 } 470 471 static int lan867x_revd0_config_init(struct phy_device *phydev) 472 { 473 int ret; 474 475 ret = lan867x_check_reset_complete(phydev); 476 if (ret) 477 return ret; 478 479 for (int i = 0; i < ARRAY_SIZE(lan867x_revd0_fixup_regs); i++) { 480 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, 481 lan867x_revd0_fixup_regs[i], 482 lan867x_revd0_fixup_values[i]); 483 if (ret) 484 return ret; 485 } 486 487 /* Initially the PHY will be in CSMA/CD mode by default. So it is 488 * required to set the link always active as it doesn't support 489 * autoneg. 490 */ 491 return lan867x_revd0_link_active_selection(phydev, false); 492 } 493 494 static int lan86xx_read_status(struct phy_device *phydev) 495 { 496 /* The phy has some limitations, namely: 497 * - always reports link up 498 * - only supports 10MBit half duplex 499 * - does not support auto negotiate 500 */ 501 phydev->link = 1; 502 phydev->duplex = DUPLEX_HALF; 503 phydev->speed = SPEED_10; 504 phydev->autoneg = AUTONEG_DISABLE; 505 506 return 0; 507 } 508 509 /* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and 510 * C45 registers space. If the PHY is discovered via C22 bus protocol it assumes 511 * it uses C22 protocol and always uses C22 registers indirect access to access 512 * C45 registers. This is because, we don't have a clean separation between 513 * C22/C45 register space and C22/C45 MDIO bus protocols. Resulting, PHY C45 514 * registers direct access can't be used which can save multiple SPI bus access. 515 * To support this feature, set .read_mmd/.write_mmd in the PHY driver to call 516 * .read_c45/.write_c45 in the OPEN Alliance framework 517 * drivers/net/ethernet/oa_tc6.c 518 */ 519 static int lan865x_phy_read_mmd(struct phy_device *phydev, int devnum, 520 u16 regnum) 521 { 522 struct mii_bus *bus = phydev->mdio.bus; 523 int addr = phydev->mdio.addr; 524 525 return __mdiobus_c45_read(bus, addr, devnum, regnum); 526 } 527 528 static int lan865x_phy_write_mmd(struct phy_device *phydev, int devnum, 529 u16 regnum, u16 val) 530 { 531 struct mii_bus *bus = phydev->mdio.bus; 532 int addr = phydev->mdio.addr; 533 534 return __mdiobus_c45_write(bus, addr, devnum, regnum, val); 535 } 536 537 static struct phy_driver microchip_t1s_driver[] = { 538 { 539 PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1), 540 .name = "LAN867X Rev.B1", 541 .features = PHY_BASIC_T1S_P2MP_FEATURES, 542 .config_init = lan867x_revb1_config_init, 543 .read_status = lan86xx_read_status, 544 .get_plca_cfg = genphy_c45_plca_get_cfg, 545 .set_plca_cfg = genphy_c45_plca_set_cfg, 546 .get_plca_status = genphy_c45_plca_get_status, 547 }, 548 { 549 PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC1), 550 .name = "LAN867X Rev.C1", 551 .features = PHY_BASIC_T1S_P2MP_FEATURES, 552 .config_init = lan867x_revc_config_init, 553 .read_status = lan86xx_read_status, 554 .get_plca_cfg = genphy_c45_plca_get_cfg, 555 .set_plca_cfg = lan86xx_plca_set_cfg, 556 .get_plca_status = genphy_c45_plca_get_status, 557 }, 558 { 559 PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC2), 560 .name = "LAN867X Rev.C2", 561 .features = PHY_BASIC_T1S_P2MP_FEATURES, 562 .config_init = lan867x_revc_config_init, 563 .read_status = lan86xx_read_status, 564 .get_plca_cfg = genphy_c45_plca_get_cfg, 565 .set_plca_cfg = lan86xx_plca_set_cfg, 566 .get_plca_status = genphy_c45_plca_get_status, 567 }, 568 { 569 PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVD0), 570 .name = "LAN867X Rev.D0", 571 .features = PHY_BASIC_T1S_P2MP_FEATURES, 572 .config_init = lan867x_revd0_config_init, 573 .get_plca_cfg = genphy_c45_plca_get_cfg, 574 .set_plca_cfg = lan86xx_plca_set_cfg, 575 .get_plca_status = genphy_c45_plca_get_status, 576 .cable_test_start = genphy_c45_oatc14_cable_test_start, 577 .cable_test_get_status = genphy_c45_oatc14_cable_test_get_status, 578 .get_sqi = genphy_c45_oatc14_get_sqi, 579 .get_sqi_max = genphy_c45_oatc14_get_sqi_max, 580 }, 581 { 582 PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB), 583 .name = "LAN865X Rev.B0/B1 Internal Phy", 584 .features = PHY_BASIC_T1S_P2MP_FEATURES, 585 .config_init = lan865x_revb_config_init, 586 .read_status = lan86xx_read_status, 587 .read_mmd = lan865x_phy_read_mmd, 588 .write_mmd = lan865x_phy_write_mmd, 589 .get_plca_cfg = genphy_c45_plca_get_cfg, 590 .set_plca_cfg = lan86xx_plca_set_cfg, 591 .get_plca_status = genphy_c45_plca_get_status, 592 }, 593 }; 594 595 module_phy_driver(microchip_t1s_driver); 596 597 static const struct mdio_device_id __maybe_unused tbl[] = { 598 { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1) }, 599 { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC1) }, 600 { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVC2) }, 601 { PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVD0) }, 602 { PHY_ID_MATCH_EXACT(PHY_ID_LAN865X_REVB) }, 603 { } 604 }; 605 606 MODULE_DEVICE_TABLE(mdio, tbl); 607 608 MODULE_DESCRIPTION("Microchip 10BASE-T1S PHYs driver"); 609 MODULE_AUTHOR("Ramón Nordin Rodriguez"); 610 MODULE_LICENSE("GPL"); 611