xref: /linux/drivers/net/phy/microchip_t1s.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
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