xref: /openbmc/linux/drivers/net/phy/phy-core.c (revision d0e22329)
1 /*
2  * Core PHY library, taken from phy.c
3  *
4  * This program is free software; you can redistribute  it and/or modify it
5  * under  the terms of  the GNU General  Public License as published by the
6  * Free Software Foundation;  either version 2 of the  License, or (at your
7  * option) any later version.
8  */
9 #include <linux/export.h>
10 #include <linux/phy.h>
11 
12 const char *phy_speed_to_str(int speed)
13 {
14 	switch (speed) {
15 	case SPEED_10:
16 		return "10Mbps";
17 	case SPEED_100:
18 		return "100Mbps";
19 	case SPEED_1000:
20 		return "1Gbps";
21 	case SPEED_2500:
22 		return "2.5Gbps";
23 	case SPEED_5000:
24 		return "5Gbps";
25 	case SPEED_10000:
26 		return "10Gbps";
27 	case SPEED_14000:
28 		return "14Gbps";
29 	case SPEED_20000:
30 		return "20Gbps";
31 	case SPEED_25000:
32 		return "25Gbps";
33 	case SPEED_40000:
34 		return "40Gbps";
35 	case SPEED_50000:
36 		return "50Gbps";
37 	case SPEED_56000:
38 		return "56Gbps";
39 	case SPEED_100000:
40 		return "100Gbps";
41 	case SPEED_UNKNOWN:
42 		return "Unknown";
43 	default:
44 		return "Unsupported (update phy-core.c)";
45 	}
46 }
47 EXPORT_SYMBOL_GPL(phy_speed_to_str);
48 
49 const char *phy_duplex_to_str(unsigned int duplex)
50 {
51 	if (duplex == DUPLEX_HALF)
52 		return "Half";
53 	if (duplex == DUPLEX_FULL)
54 		return "Full";
55 	if (duplex == DUPLEX_UNKNOWN)
56 		return "Unknown";
57 	return "Unsupported (update phy-core.c)";
58 }
59 EXPORT_SYMBOL_GPL(phy_duplex_to_str);
60 
61 /* A mapping of all SUPPORTED settings to speed/duplex.  This table
62  * must be grouped by speed and sorted in descending match priority
63  * - iow, descending speed. */
64 static const struct phy_setting settings[] = {
65 	/* 100G */
66 	{
67 		.speed = SPEED_100000,
68 		.duplex = DUPLEX_FULL,
69 		.bit = ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
70 	},
71 	{
72 		.speed = SPEED_100000,
73 		.duplex = DUPLEX_FULL,
74 		.bit = ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
75 	},
76 	{
77 		.speed = SPEED_100000,
78 		.duplex = DUPLEX_FULL,
79 		.bit = ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
80 	},
81 	{
82 		.speed = SPEED_100000,
83 		.duplex = DUPLEX_FULL,
84 		.bit = ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
85 	},
86 	/* 56G */
87 	{
88 		.speed = SPEED_56000,
89 		.duplex = DUPLEX_FULL,
90 		.bit = ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
91 	},
92 	{
93 		.speed = SPEED_56000,
94 		.duplex = DUPLEX_FULL,
95 		.bit = ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
96 	},
97 	{
98 		.speed = SPEED_56000,
99 		.duplex = DUPLEX_FULL,
100 		.bit = ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
101 	},
102 	{
103 		.speed = SPEED_56000,
104 		.duplex = DUPLEX_FULL,
105 		.bit = ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
106 	},
107 	/* 50G */
108 	{
109 		.speed = SPEED_50000,
110 		.duplex = DUPLEX_FULL,
111 		.bit = ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
112 	},
113 	{
114 		.speed = SPEED_50000,
115 		.duplex = DUPLEX_FULL,
116 		.bit = ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
117 	},
118 	{
119 		.speed = SPEED_50000,
120 		.duplex = DUPLEX_FULL,
121 		.bit = ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
122 	},
123 	/* 40G */
124 	{
125 		.speed = SPEED_40000,
126 		.duplex = DUPLEX_FULL,
127 		.bit = ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
128 	},
129 	{
130 		.speed = SPEED_40000,
131 		.duplex = DUPLEX_FULL,
132 		.bit = ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
133 	},
134 	{
135 		.speed = SPEED_40000,
136 		.duplex = DUPLEX_FULL,
137 		.bit = ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
138 	},
139 	{
140 		.speed = SPEED_40000,
141 		.duplex = DUPLEX_FULL,
142 		.bit = ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
143 	},
144 	/* 25G */
145 	{
146 		.speed = SPEED_25000,
147 		.duplex = DUPLEX_FULL,
148 		.bit = ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
149 	},
150 	{
151 		.speed = SPEED_25000,
152 		.duplex = DUPLEX_FULL,
153 		.bit = ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
154 	},
155 	{
156 		.speed = SPEED_25000,
157 		.duplex = DUPLEX_FULL,
158 		.bit = ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
159 	},
160 
161 	/* 20G */
162 	{
163 		.speed = SPEED_20000,
164 		.duplex = DUPLEX_FULL,
165 		.bit = ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
166 	},
167 	{
168 		.speed = SPEED_20000,
169 		.duplex = DUPLEX_FULL,
170 		.bit = ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
171 	},
172 	/* 10G */
173 	{
174 		.speed = SPEED_10000,
175 		.duplex = DUPLEX_FULL,
176 		.bit = ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
177 	},
178 	{
179 		.speed = SPEED_10000,
180 		.duplex = DUPLEX_FULL,
181 		.bit = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
182 	},
183 	{
184 		.speed = SPEED_10000,
185 		.duplex = DUPLEX_FULL,
186 		.bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
187 	},
188 	{
189 		.speed = SPEED_10000,
190 		.duplex = DUPLEX_FULL,
191 		.bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
192 	},
193 	{
194 		.speed = SPEED_10000,
195 		.duplex = DUPLEX_FULL,
196 		.bit = ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
197 	},
198 	{
199 		.speed = SPEED_10000,
200 		.duplex = DUPLEX_FULL,
201 		.bit = ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
202 	},
203 	{
204 		.speed = SPEED_10000,
205 		.duplex = DUPLEX_FULL,
206 		.bit = ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
207 	},
208 	{
209 		.speed = SPEED_10000,
210 		.duplex = DUPLEX_FULL,
211 		.bit = ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
212 	},
213 	{
214 		.speed = SPEED_10000,
215 		.duplex = DUPLEX_FULL,
216 		.bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
217 	},
218 	/* 5G */
219 	{
220 		.speed = SPEED_5000,
221 		.duplex = DUPLEX_FULL,
222 		.bit = ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
223 	},
224 
225 	/* 2.5G */
226 	{
227 		.speed = SPEED_2500,
228 		.duplex = DUPLEX_FULL,
229 		.bit = ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
230 	},
231 	{
232 		.speed = SPEED_2500,
233 		.duplex = DUPLEX_FULL,
234 		.bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
235 	},
236 	/* 1G */
237 	{
238 		.speed = SPEED_1000,
239 		.duplex = DUPLEX_FULL,
240 		.bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
241 	},
242 	{
243 		.speed = SPEED_1000,
244 		.duplex = DUPLEX_FULL,
245 		.bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
246 	},
247 	{
248 		.speed = SPEED_1000,
249 		.duplex = DUPLEX_HALF,
250 		.bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
251 	},
252 	{
253 		.speed = SPEED_1000,
254 		.duplex = DUPLEX_FULL,
255 		.bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
256 	},
257 	/* 100M */
258 	{
259 		.speed = SPEED_100,
260 		.duplex = DUPLEX_FULL,
261 		.bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
262 	},
263 	{
264 		.speed = SPEED_100,
265 		.duplex = DUPLEX_HALF,
266 		.bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
267 	},
268 	/* 10M */
269 	{
270 		.speed = SPEED_10,
271 		.duplex = DUPLEX_FULL,
272 		.bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
273 	},
274 	{
275 		.speed = SPEED_10,
276 		.duplex = DUPLEX_HALF,
277 		.bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
278 	},
279 };
280 
281 /**
282  * phy_lookup_setting - lookup a PHY setting
283  * @speed: speed to match
284  * @duplex: duplex to match
285  * @mask: allowed link modes
286  * @exact: an exact match is required
287  *
288  * Search the settings array for a setting that matches the speed and
289  * duplex, and which is supported.
290  *
291  * If @exact is unset, either an exact match or %NULL for no match will
292  * be returned.
293  *
294  * If @exact is set, an exact match, the fastest supported setting at
295  * or below the specified speed, the slowest supported setting, or if
296  * they all fail, %NULL will be returned.
297  */
298 const struct phy_setting *
299 phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact)
300 {
301 	const struct phy_setting *p, *match = NULL, *last = NULL;
302 	int i;
303 
304 	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
305 		if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
306 		    test_bit(p->bit, mask)) {
307 			last = p;
308 			if (p->speed == speed && p->duplex == duplex) {
309 				/* Exact match for speed and duplex */
310 				match = p;
311 				break;
312 			} else if (!exact) {
313 				if (!match && p->speed <= speed)
314 					/* Candidate */
315 					match = p;
316 
317 				if (p->speed < speed)
318 					break;
319 			}
320 		}
321 	}
322 
323 	if (!match && !exact)
324 		match = last;
325 
326 	return match;
327 }
328 EXPORT_SYMBOL_GPL(phy_lookup_setting);
329 
330 size_t phy_speeds(unsigned int *speeds, size_t size,
331 		  unsigned long *mask)
332 {
333 	size_t count;
334 	int i;
335 
336 	for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
337 		if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
338 		    test_bit(settings[i].bit, mask) &&
339 		    (count == 0 || speeds[count - 1] != settings[i].speed))
340 			speeds[count++] = settings[i].speed;
341 
342 	return count;
343 }
344 
345 /**
346  * phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
347  * @phydev: The phy_device struct
348  *
349  * Resolve our and the link partner advertisements into their corresponding
350  * speed and duplex. If full duplex was negotiated, extract the pause mode
351  * from the link partner mask.
352  */
353 void phy_resolve_aneg_linkmode(struct phy_device *phydev)
354 {
355 	__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
356 
357 	linkmode_and(common, phydev->lp_advertising, phydev->advertising);
358 
359 	if (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, common)) {
360 		phydev->speed = SPEED_10000;
361 		phydev->duplex = DUPLEX_FULL;
362 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
363 				     common)) {
364 		phydev->speed = SPEED_5000;
365 		phydev->duplex = DUPLEX_FULL;
366 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
367 				     common)) {
368 		phydev->speed = SPEED_2500;
369 		phydev->duplex = DUPLEX_FULL;
370 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
371 				     common)) {
372 		phydev->speed = SPEED_1000;
373 		phydev->duplex = DUPLEX_FULL;
374 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
375 				     common)) {
376 		phydev->speed = SPEED_1000;
377 		phydev->duplex = DUPLEX_HALF;
378 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
379 				     common)) {
380 		phydev->speed = SPEED_100;
381 		phydev->duplex = DUPLEX_FULL;
382 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
383 				     common)) {
384 		phydev->speed = SPEED_100;
385 		phydev->duplex = DUPLEX_HALF;
386 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
387 				     common)) {
388 		phydev->speed = SPEED_10;
389 		phydev->duplex = DUPLEX_FULL;
390 	} else if (linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
391 				     common)) {
392 		phydev->speed = SPEED_10;
393 		phydev->duplex = DUPLEX_HALF;
394 	}
395 
396 	if (phydev->duplex == DUPLEX_FULL) {
397 		phydev->pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
398 						  phydev->lp_advertising);
399 		phydev->asym_pause = linkmode_test_bit(
400 			ETHTOOL_LINK_MODE_Asym_Pause_BIT,
401 			phydev->lp_advertising);
402 	}
403 }
404 EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
405 
406 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
407 			     u16 regnum)
408 {
409 	/* Write the desired MMD Devad */
410 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
411 
412 	/* Write the desired MMD register address */
413 	__mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
414 
415 	/* Select the Function : DATA with no post increment */
416 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
417 			devad | MII_MMD_CTRL_NOINCR);
418 }
419 
420 /**
421  * phy_read_mmd - Convenience function for reading a register
422  * from an MMD on a given PHY.
423  * @phydev: The phy_device struct
424  * @devad: The MMD to read from (0..31)
425  * @regnum: The register on the MMD to read (0..65535)
426  *
427  * Same rules as for phy_read();
428  */
429 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
430 {
431 	int val;
432 
433 	if (regnum > (u16)~0 || devad > 32)
434 		return -EINVAL;
435 
436 	if (phydev->drv->read_mmd) {
437 		val = phydev->drv->read_mmd(phydev, devad, regnum);
438 	} else if (phydev->is_c45) {
439 		u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
440 
441 		val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
442 	} else {
443 		struct mii_bus *bus = phydev->mdio.bus;
444 		int phy_addr = phydev->mdio.addr;
445 
446 		mutex_lock(&bus->mdio_lock);
447 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
448 
449 		/* Read the content of the MMD's selected register */
450 		val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
451 		mutex_unlock(&bus->mdio_lock);
452 	}
453 	return val;
454 }
455 EXPORT_SYMBOL(phy_read_mmd);
456 
457 /**
458  * phy_write_mmd - Convenience function for writing a register
459  * on an MMD on a given PHY.
460  * @phydev: The phy_device struct
461  * @devad: The MMD to read from
462  * @regnum: The register on the MMD to read
463  * @val: value to write to @regnum
464  *
465  * Same rules as for phy_write();
466  */
467 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
468 {
469 	int ret;
470 
471 	if (regnum > (u16)~0 || devad > 32)
472 		return -EINVAL;
473 
474 	if (phydev->drv->write_mmd) {
475 		ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
476 	} else if (phydev->is_c45) {
477 		u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
478 
479 		ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
480 				    addr, val);
481 	} else {
482 		struct mii_bus *bus = phydev->mdio.bus;
483 		int phy_addr = phydev->mdio.addr;
484 
485 		mutex_lock(&bus->mdio_lock);
486 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
487 
488 		/* Write the data into MMD's selected register */
489 		__mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
490 		mutex_unlock(&bus->mdio_lock);
491 
492 		ret = 0;
493 	}
494 	return ret;
495 }
496 EXPORT_SYMBOL(phy_write_mmd);
497 
498 /**
499  * __phy_modify() - Convenience function for modifying a PHY register
500  * @phydev: a pointer to a &struct phy_device
501  * @regnum: register number
502  * @mask: bit mask of bits to clear
503  * @set: bit mask of bits to set
504  *
505  * Unlocked helper function which allows a PHY register to be modified as
506  * new register value = (old register value & ~mask) | set
507  */
508 int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
509 {
510 	int ret;
511 
512 	ret = __phy_read(phydev, regnum);
513 	if (ret < 0)
514 		return ret;
515 
516 	ret = __phy_write(phydev, regnum, (ret & ~mask) | set);
517 
518 	return ret < 0 ? ret : 0;
519 }
520 EXPORT_SYMBOL_GPL(__phy_modify);
521 
522 /**
523  * phy_modify - Convenience function for modifying a given PHY register
524  * @phydev: the phy_device struct
525  * @regnum: register number to write
526  * @mask: bit mask of bits to clear
527  * @set: new value of bits set in mask to write to @regnum
528  *
529  * NOTE: MUST NOT be called from interrupt context,
530  * because the bus read/write functions may wait for an interrupt
531  * to conclude the operation.
532  */
533 int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
534 {
535 	int ret;
536 
537 	mutex_lock(&phydev->mdio.bus->mdio_lock);
538 	ret = __phy_modify(phydev, regnum, mask, set);
539 	mutex_unlock(&phydev->mdio.bus->mdio_lock);
540 
541 	return ret;
542 }
543 EXPORT_SYMBOL_GPL(phy_modify);
544 
545 static int __phy_read_page(struct phy_device *phydev)
546 {
547 	return phydev->drv->read_page(phydev);
548 }
549 
550 static int __phy_write_page(struct phy_device *phydev, int page)
551 {
552 	return phydev->drv->write_page(phydev, page);
553 }
554 
555 /**
556  * phy_save_page() - take the bus lock and save the current page
557  * @phydev: a pointer to a &struct phy_device
558  *
559  * Take the MDIO bus lock, and return the current page number. On error,
560  * returns a negative errno. phy_restore_page() must always be called
561  * after this, irrespective of success or failure of this call.
562  */
563 int phy_save_page(struct phy_device *phydev)
564 {
565 	mutex_lock(&phydev->mdio.bus->mdio_lock);
566 	return __phy_read_page(phydev);
567 }
568 EXPORT_SYMBOL_GPL(phy_save_page);
569 
570 /**
571  * phy_select_page() - take the bus lock, save the current page, and set a page
572  * @phydev: a pointer to a &struct phy_device
573  * @page: desired page
574  *
575  * Take the MDIO bus lock to protect against concurrent access, save the
576  * current PHY page, and set the current page.  On error, returns a
577  * negative errno, otherwise returns the previous page number.
578  * phy_restore_page() must always be called after this, irrespective
579  * of success or failure of this call.
580  */
581 int phy_select_page(struct phy_device *phydev, int page)
582 {
583 	int ret, oldpage;
584 
585 	oldpage = ret = phy_save_page(phydev);
586 	if (ret < 0)
587 		return ret;
588 
589 	if (oldpage != page) {
590 		ret = __phy_write_page(phydev, page);
591 		if (ret < 0)
592 			return ret;
593 	}
594 
595 	return oldpage;
596 }
597 EXPORT_SYMBOL_GPL(phy_select_page);
598 
599 /**
600  * phy_restore_page() - restore the page register and release the bus lock
601  * @phydev: a pointer to a &struct phy_device
602  * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
603  * @ret: operation's return code
604  *
605  * Release the MDIO bus lock, restoring @oldpage if it is a valid page.
606  * This function propagates the earliest error code from the group of
607  * operations.
608  *
609  * Returns:
610  *   @oldpage if it was a negative value, otherwise
611  *   @ret if it was a negative errno value, otherwise
612  *   phy_write_page()'s negative value if it were in error, otherwise
613  *   @ret.
614  */
615 int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
616 {
617 	int r;
618 
619 	if (oldpage >= 0) {
620 		r = __phy_write_page(phydev, oldpage);
621 
622 		/* Propagate the operation return code if the page write
623 		 * was successful.
624 		 */
625 		if (ret >= 0 && r < 0)
626 			ret = r;
627 	} else {
628 		/* Propagate the phy page selection error code */
629 		ret = oldpage;
630 	}
631 
632 	mutex_unlock(&phydev->mdio.bus->mdio_lock);
633 
634 	return ret;
635 }
636 EXPORT_SYMBOL_GPL(phy_restore_page);
637 
638 /**
639  * phy_read_paged() - Convenience function for reading a paged register
640  * @phydev: a pointer to a &struct phy_device
641  * @page: the page for the phy
642  * @regnum: register number
643  *
644  * Same rules as for phy_read().
645  */
646 int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
647 {
648 	int ret = 0, oldpage;
649 
650 	oldpage = phy_select_page(phydev, page);
651 	if (oldpage >= 0)
652 		ret = __phy_read(phydev, regnum);
653 
654 	return phy_restore_page(phydev, oldpage, ret);
655 }
656 EXPORT_SYMBOL(phy_read_paged);
657 
658 /**
659  * phy_write_paged() - Convenience function for writing a paged register
660  * @phydev: a pointer to a &struct phy_device
661  * @page: the page for the phy
662  * @regnum: register number
663  * @val: value to write
664  *
665  * Same rules as for phy_write().
666  */
667 int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
668 {
669 	int ret = 0, oldpage;
670 
671 	oldpage = phy_select_page(phydev, page);
672 	if (oldpage >= 0)
673 		ret = __phy_write(phydev, regnum, val);
674 
675 	return phy_restore_page(phydev, oldpage, ret);
676 }
677 EXPORT_SYMBOL(phy_write_paged);
678 
679 /**
680  * phy_modify_paged() - Convenience function for modifying a paged register
681  * @phydev: a pointer to a &struct phy_device
682  * @page: the page for the phy
683  * @regnum: register number
684  * @mask: bit mask of bits to clear
685  * @set: bit mask of bits to set
686  *
687  * Same rules as for phy_read() and phy_write().
688  */
689 int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
690 		     u16 mask, u16 set)
691 {
692 	int ret = 0, oldpage;
693 
694 	oldpage = phy_select_page(phydev, page);
695 	if (oldpage >= 0)
696 		ret = __phy_modify(phydev, regnum, mask, set);
697 
698 	return phy_restore_page(phydev, oldpage, ret);
699 }
700 EXPORT_SYMBOL(phy_modify_paged);
701