Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
65static const u32 lan867x_revb1_fixup_registers[12] = {
66 0x00D0, 0x00D1, 0x0084, 0x0085,
67 0x008A, 0x0087, 0x0088, 0x008B,
68 0x0080, 0x00F1, 0x0096, 0x0099,
69};
70
71static const u16 lan867x_revb1_fixup_values[12] = {
72 0x0002, 0x0000, 0x3380, 0x0006,
73 0xC000, 0x801C, 0x033F, 0x0404,
74 0x0600, 0x2400, 0x2000, 0x7F80,
75};
76
77static 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 */
88static 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
96static 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
104static const u16 lan865x_revb_fixup_cfg_regs[2] = {
105 0x0084, 0x008A,
106};
107
108static 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
114static 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
120static 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 */
129static const u16 lan867x_revd0_fixup_regs[8] = {
130 0x0037, 0x008A, 0x0118, 0x00D6,
131 0x0082, 0x00FD, 0x00FD, 0x0091,
132};
133
134static 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 */
147static 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 */
167static 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
188static 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
205static 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
221static 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
241static 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
263static 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
304static 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
329static 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
381static 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
407static 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 */
444static 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
471static 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
494static 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 */
519static 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
528static 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
537static 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
595module_phy_driver(microchip_t1s_driver);
596
597static 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
606MODULE_DEVICE_TABLE(mdio, tbl);
607
608MODULE_DESCRIPTION("Microchip 10BASE-T1S PHYs driver");
609MODULE_AUTHOR("Ramón Nordin Rodriguez");
610MODULE_LICENSE("GPL");