Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md...
[sfrench/cifs-2.6.git] / drivers / net / phy / phy-core.c
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);