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