xref: /openbmc/linux/drivers/net/phy/phy-core.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
29860118bSRussell King /*
39860118bSRussell King  * Core PHY library, taken from phy.c
49860118bSRussell King  */
59860118bSRussell King #include <linux/export.h>
69860118bSRussell King #include <linux/phy.h>
7a4eaed9fSMaxime Chevallier #include <linux/of.h>
89860118bSRussell King 
94069a572SAndrew Lunn /**
104069a572SAndrew Lunn  * phy_speed_to_str - Return a string representing the PHY link speed
114069a572SAndrew Lunn  *
124069a572SAndrew Lunn  * @speed: Speed of the link
134069a572SAndrew Lunn  */
phy_speed_to_str(int speed)14da4625acSRussell King const char *phy_speed_to_str(int speed)
15da4625acSRussell King {
1616178c8eSPiergiorgio Beruto 	BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102,
17c6576bfeSHeiner Kallweit 		"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
18c6576bfeSHeiner Kallweit 		"If a speed or mode has been added please update phy_speed_to_str "
19c6576bfeSHeiner Kallweit 		"and the PHY settings array.\n");
20c6576bfeSHeiner Kallweit 
21da4625acSRussell King 	switch (speed) {
22da4625acSRussell King 	case SPEED_10:
23da4625acSRussell King 		return "10Mbps";
24da4625acSRussell King 	case SPEED_100:
25da4625acSRussell King 		return "100Mbps";
26da4625acSRussell King 	case SPEED_1000:
27da4625acSRussell King 		return "1Gbps";
28da4625acSRussell King 	case SPEED_2500:
29da4625acSRussell King 		return "2.5Gbps";
30da4625acSRussell King 	case SPEED_5000:
31da4625acSRussell King 		return "5Gbps";
32da4625acSRussell King 	case SPEED_10000:
33da4625acSRussell King 		return "10Gbps";
34da4625acSRussell King 	case SPEED_14000:
35da4625acSRussell King 		return "14Gbps";
36da4625acSRussell King 	case SPEED_20000:
37da4625acSRussell King 		return "20Gbps";
38da4625acSRussell King 	case SPEED_25000:
39da4625acSRussell King 		return "25Gbps";
40da4625acSRussell King 	case SPEED_40000:
41da4625acSRussell King 		return "40Gbps";
42da4625acSRussell King 	case SPEED_50000:
43da4625acSRussell King 		return "50Gbps";
44da4625acSRussell King 	case SPEED_56000:
45da4625acSRussell King 		return "56Gbps";
46da4625acSRussell King 	case SPEED_100000:
47da4625acSRussell King 		return "100Gbps";
485a3144e4SHeiner Kallweit 	case SPEED_200000:
495a3144e4SHeiner Kallweit 		return "200Gbps";
5014af7fd1SJiri Pirko 	case SPEED_400000:
5114af7fd1SJiri Pirko 		return "400Gbps";
52404c7678SAmit Cohen 	case SPEED_800000:
53404c7678SAmit Cohen 		return "800Gbps";
54da4625acSRussell King 	case SPEED_UNKNOWN:
55da4625acSRussell King 		return "Unknown";
56da4625acSRussell King 	default:
57da4625acSRussell King 		return "Unsupported (update phy-core.c)";
58da4625acSRussell King 	}
59da4625acSRussell King }
60da4625acSRussell King EXPORT_SYMBOL_GPL(phy_speed_to_str);
61da4625acSRussell King 
624069a572SAndrew Lunn /**
634069a572SAndrew Lunn  * phy_duplex_to_str - Return string describing the duplex
644069a572SAndrew Lunn  *
654069a572SAndrew Lunn  * @duplex: Duplex setting to describe
664069a572SAndrew Lunn  */
phy_duplex_to_str(unsigned int duplex)67da4625acSRussell King const char *phy_duplex_to_str(unsigned int duplex)
68da4625acSRussell King {
69da4625acSRussell King 	if (duplex == DUPLEX_HALF)
70da4625acSRussell King 		return "Half";
71da4625acSRussell King 	if (duplex == DUPLEX_FULL)
72da4625acSRussell King 		return "Full";
73da4625acSRussell King 	if (duplex == DUPLEX_UNKNOWN)
74da4625acSRussell King 		return "Unknown";
75da4625acSRussell King 	return "Unsupported (update phy-core.c)";
76da4625acSRussell King }
77da4625acSRussell King EXPORT_SYMBOL_GPL(phy_duplex_to_str);
78da4625acSRussell King 
79c04ade27SMaxime Chevallier /**
800c3e10cbSSean Anderson  * phy_rate_matching_to_str - Return a string describing the rate matching
810c3e10cbSSean Anderson  *
820c3e10cbSSean Anderson  * @rate_matching: Type of rate matching to describe
830c3e10cbSSean Anderson  */
phy_rate_matching_to_str(int rate_matching)840c3e10cbSSean Anderson const char *phy_rate_matching_to_str(int rate_matching)
850c3e10cbSSean Anderson {
860c3e10cbSSean Anderson 	switch (rate_matching) {
870c3e10cbSSean Anderson 	case RATE_MATCH_NONE:
880c3e10cbSSean Anderson 		return "none";
890c3e10cbSSean Anderson 	case RATE_MATCH_PAUSE:
900c3e10cbSSean Anderson 		return "pause";
910c3e10cbSSean Anderson 	case RATE_MATCH_CRS:
920c3e10cbSSean Anderson 		return "crs";
930c3e10cbSSean Anderson 	case RATE_MATCH_OPEN_LOOP:
940c3e10cbSSean Anderson 		return "open-loop";
950c3e10cbSSean Anderson 	}
960c3e10cbSSean Anderson 	return "Unsupported (update phy-core.c)";
970c3e10cbSSean Anderson }
980c3e10cbSSean Anderson EXPORT_SYMBOL_GPL(phy_rate_matching_to_str);
990c3e10cbSSean Anderson 
1000c3e10cbSSean Anderson /**
101c04ade27SMaxime Chevallier  * phy_interface_num_ports - Return the number of links that can be carried by
102c04ade27SMaxime Chevallier  *			     a given MAC-PHY physical link. Returns 0 if this is
103c04ade27SMaxime Chevallier  *			     unknown, the number of links else.
104c04ade27SMaxime Chevallier  *
105c04ade27SMaxime Chevallier  * @interface: The interface mode we want to get the number of ports
106c04ade27SMaxime Chevallier  */
phy_interface_num_ports(phy_interface_t interface)107c04ade27SMaxime Chevallier int phy_interface_num_ports(phy_interface_t interface)
108c04ade27SMaxime Chevallier {
109c04ade27SMaxime Chevallier 	switch (interface) {
110c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_NA:
111c04ade27SMaxime Chevallier 		return 0;
112c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_INTERNAL:
113c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_MII:
114c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_GMII:
115c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_TBI:
116c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_REVMII:
117c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RMII:
118c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_REVRMII:
119c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RGMII:
120c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RGMII_ID:
121c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RGMII_RXID:
122c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RGMII_TXID:
123c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RTBI:
124c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_XGMII:
125c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_XLGMII:
126c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_MOCA:
127c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_TRGMII:
128c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_USXGMII:
129c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_SGMII:
130c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_SMII:
131c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_1000BASEX:
132c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_2500BASEX:
133c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_5GBASER:
134c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_10GBASER:
135c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_25GBASER:
136c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_10GKR:
137c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_100BASEX:
138c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_RXAUI:
139c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_XAUI:
14005ad5d45SSean Anderson 	case PHY_INTERFACE_MODE_1000BASEKX:
141c04ade27SMaxime Chevallier 		return 1;
142c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_QSGMII:
143c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_QUSGMII:
144c04ade27SMaxime Chevallier 		return 4;
145*83b5f025SGabor Juhos 	case PHY_INTERFACE_MODE_PSGMII:
146*83b5f025SGabor Juhos 		return 5;
147c04ade27SMaxime Chevallier 	case PHY_INTERFACE_MODE_MAX:
148c04ade27SMaxime Chevallier 		WARN_ONCE(1, "PHY_INTERFACE_MODE_MAX isn't a valid interface mode");
149c04ade27SMaxime Chevallier 		return 0;
150c04ade27SMaxime Chevallier 	}
151c04ade27SMaxime Chevallier 	return 0;
152c04ade27SMaxime Chevallier }
153c04ade27SMaxime Chevallier EXPORT_SYMBOL_GPL(phy_interface_num_ports);
154c04ade27SMaxime Chevallier 
1550ccb4fc6SRussell King /* A mapping of all SUPPORTED settings to speed/duplex.  This table
1560ccb4fc6SRussell King  * must be grouped by speed and sorted in descending match priority
1571953feb0SWenpeng Liang  * - iow, descending speed.
1581953feb0SWenpeng Liang  */
159f1538ecaSHeiner Kallweit 
160f1538ecaSHeiner Kallweit #define PHY_SETTING(s, d, b) { .speed = SPEED_ ## s, .duplex = DUPLEX_ ## d, \
161f1538ecaSHeiner Kallweit 			       .bit = ETHTOOL_LINK_MODE_ ## b ## _BIT}
162f1538ecaSHeiner Kallweit 
1630ccb4fc6SRussell King static const struct phy_setting settings[] = {
164404c7678SAmit Cohen 	/* 800G */
165404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseCR8_Full		),
166404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseKR8_Full		),
167404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseDR8_Full		),
168404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseDR8_2_Full		),
169404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseSR8_Full		),
170404c7678SAmit Cohen 	PHY_SETTING( 800000, FULL, 800000baseVR8_Full		),
17114af7fd1SJiri Pirko 	/* 400G */
17214af7fd1SJiri Pirko 	PHY_SETTING( 400000, FULL, 400000baseCR8_Full		),
17314af7fd1SJiri Pirko 	PHY_SETTING( 400000, FULL, 400000baseKR8_Full		),
17414af7fd1SJiri Pirko 	PHY_SETTING( 400000, FULL, 400000baseLR8_ER8_FR8_Full	),
17514af7fd1SJiri Pirko 	PHY_SETTING( 400000, FULL, 400000baseDR8_Full		),
17614af7fd1SJiri Pirko 	PHY_SETTING( 400000, FULL, 400000baseSR8_Full		),
177065e0d42SMeir Lichtinger 	PHY_SETTING( 400000, FULL, 400000baseCR4_Full		),
178065e0d42SMeir Lichtinger 	PHY_SETTING( 400000, FULL, 400000baseKR4_Full		),
179065e0d42SMeir Lichtinger 	PHY_SETTING( 400000, FULL, 400000baseLR4_ER4_FR4_Full	),
180065e0d42SMeir Lichtinger 	PHY_SETTING( 400000, FULL, 400000baseDR4_Full		),
181065e0d42SMeir Lichtinger 	PHY_SETTING( 400000, FULL, 400000baseSR4_Full		),
1825a3144e4SHeiner Kallweit 	/* 200G */
1835a3144e4SHeiner Kallweit 	PHY_SETTING( 200000, FULL, 200000baseCR4_Full		),
1845a3144e4SHeiner Kallweit 	PHY_SETTING( 200000, FULL, 200000baseKR4_Full		),
1855a3144e4SHeiner Kallweit 	PHY_SETTING( 200000, FULL, 200000baseLR4_ER4_FR4_Full	),
1865a3144e4SHeiner Kallweit 	PHY_SETTING( 200000, FULL, 200000baseDR4_Full		),
1875a3144e4SHeiner Kallweit 	PHY_SETTING( 200000, FULL, 200000baseSR4_Full		),
188065e0d42SMeir Lichtinger 	PHY_SETTING( 200000, FULL, 200000baseCR2_Full		),
189065e0d42SMeir Lichtinger 	PHY_SETTING( 200000, FULL, 200000baseKR2_Full		),
190065e0d42SMeir Lichtinger 	PHY_SETTING( 200000, FULL, 200000baseLR2_ER2_FR2_Full	),
191065e0d42SMeir Lichtinger 	PHY_SETTING( 200000, FULL, 200000baseDR2_Full		),
192065e0d42SMeir Lichtinger 	PHY_SETTING( 200000, FULL, 200000baseSR2_Full		),
1933c6b59d6SAndrew Lunn 	/* 100G */
194f1538ecaSHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseCR4_Full		),
195f1538ecaSHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseKR4_Full		),
196f1538ecaSHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseLR4_ER4_Full	),
197f1538ecaSHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseSR4_Full		),
1985a3144e4SHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseCR2_Full		),
1995a3144e4SHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseKR2_Full		),
2005a3144e4SHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseLR2_ER2_FR2_Full	),
2015a3144e4SHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseDR2_Full		),
2025a3144e4SHeiner Kallweit 	PHY_SETTING( 100000, FULL, 100000baseSR2_Full		),
203065e0d42SMeir Lichtinger 	PHY_SETTING( 100000, FULL, 100000baseCR_Full		),
204065e0d42SMeir Lichtinger 	PHY_SETTING( 100000, FULL, 100000baseKR_Full		),
205065e0d42SMeir Lichtinger 	PHY_SETTING( 100000, FULL, 100000baseLR_ER_FR_Full	),
206065e0d42SMeir Lichtinger 	PHY_SETTING( 100000, FULL, 100000baseDR_Full		),
207065e0d42SMeir Lichtinger 	PHY_SETTING( 100000, FULL, 100000baseSR_Full		),
2083c6b59d6SAndrew Lunn 	/* 56G */
209f1538ecaSHeiner Kallweit 	PHY_SETTING(  56000, FULL,  56000baseCR4_Full	  	),
210f1538ecaSHeiner Kallweit 	PHY_SETTING(  56000, FULL,  56000baseKR4_Full	  	),
211f1538ecaSHeiner Kallweit 	PHY_SETTING(  56000, FULL,  56000baseLR4_Full	  	),
212f1538ecaSHeiner Kallweit 	PHY_SETTING(  56000, FULL,  56000baseSR4_Full	  	),
2133c6b59d6SAndrew Lunn 	/* 50G */
214f1538ecaSHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseCR2_Full		),
215f1538ecaSHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseKR2_Full		),
216f1538ecaSHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseSR2_Full		),
2175a3144e4SHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseCR_Full		),
2185a3144e4SHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseKR_Full		),
2195a3144e4SHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseLR_ER_FR_Full	),
2205a3144e4SHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseDR_Full		),
2215a3144e4SHeiner Kallweit 	PHY_SETTING(  50000, FULL,  50000baseSR_Full		),
2223c6b59d6SAndrew Lunn 	/* 40G */
223f1538ecaSHeiner Kallweit 	PHY_SETTING(  40000, FULL,  40000baseCR4_Full		),
224f1538ecaSHeiner Kallweit 	PHY_SETTING(  40000, FULL,  40000baseKR4_Full		),
225f1538ecaSHeiner Kallweit 	PHY_SETTING(  40000, FULL,  40000baseLR4_Full		),
226f1538ecaSHeiner Kallweit 	PHY_SETTING(  40000, FULL,  40000baseSR4_Full		),
2273c6b59d6SAndrew Lunn 	/* 25G */
228f1538ecaSHeiner Kallweit 	PHY_SETTING(  25000, FULL,  25000baseCR_Full		),
229f1538ecaSHeiner Kallweit 	PHY_SETTING(  25000, FULL,  25000baseKR_Full		),
230f1538ecaSHeiner Kallweit 	PHY_SETTING(  25000, FULL,  25000baseSR_Full		),
2313c6b59d6SAndrew Lunn 	/* 20G */
232f1538ecaSHeiner Kallweit 	PHY_SETTING(  20000, FULL,  20000baseKR2_Full		),
233f1538ecaSHeiner Kallweit 	PHY_SETTING(  20000, FULL,  20000baseMLD2_Full		),
2343c6b59d6SAndrew Lunn 	/* 10G */
235f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseCR_Full		),
236f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseER_Full		),
237f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseKR_Full		),
238f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseKX4_Full		),
239f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseLR_Full		),
240f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseLRM_Full		),
241f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseR_FEC		),
242f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseSR_Full		),
243f1538ecaSHeiner Kallweit 	PHY_SETTING(  10000, FULL,  10000baseT_Full		),
2443c6b59d6SAndrew Lunn 	/* 5G */
245f1538ecaSHeiner Kallweit 	PHY_SETTING(   5000, FULL,   5000baseT_Full		),
2463c6b59d6SAndrew Lunn 	/* 2.5G */
247f1538ecaSHeiner Kallweit 	PHY_SETTING(   2500, FULL,   2500baseT_Full		),
248f1538ecaSHeiner Kallweit 	PHY_SETTING(   2500, FULL,   2500baseX_Full		),
2493c6b59d6SAndrew Lunn 	/* 1G */
250f1538ecaSHeiner Kallweit 	PHY_SETTING(   1000, FULL,   1000baseT_Full		),
251f1538ecaSHeiner Kallweit 	PHY_SETTING(   1000, HALF,   1000baseT_Half		),
252b2557764SAndrew Lunn 	PHY_SETTING(   1000, FULL,   1000baseT1_Full		),
253f1538ecaSHeiner Kallweit 	PHY_SETTING(   1000, FULL,   1000baseX_Full		),
254f20f94f7SRussell King (Oracle) 	PHY_SETTING(   1000, FULL,   1000baseKX_Full		),
2553c6b59d6SAndrew Lunn 	/* 100M */
256f1538ecaSHeiner Kallweit 	PHY_SETTING(    100, FULL,    100baseT_Full		),
257b2557764SAndrew Lunn 	PHY_SETTING(    100, FULL,    100baseT1_Full		),
258f1538ecaSHeiner Kallweit 	PHY_SETTING(    100, HALF,    100baseT_Half		),
25955f13311SDan Murphy 	PHY_SETTING(    100, HALF,    100baseFX_Half		),
26055f13311SDan Murphy 	PHY_SETTING(    100, FULL,    100baseFX_Full		),
2613c6b59d6SAndrew Lunn 	/* 10M */
262f1538ecaSHeiner Kallweit 	PHY_SETTING(     10, FULL,     10baseT_Full		),
263f1538ecaSHeiner Kallweit 	PHY_SETTING(     10, HALF,     10baseT_Half		),
2643254e0b9SAlexandru Tachici 	PHY_SETTING(     10, FULL,     10baseT1L_Full		),
26516178c8eSPiergiorgio Beruto 	PHY_SETTING(     10, FULL,     10baseT1S_Full		),
26616178c8eSPiergiorgio Beruto 	PHY_SETTING(     10, HALF,     10baseT1S_Half		),
26716178c8eSPiergiorgio Beruto 	PHY_SETTING(     10, HALF,     10baseT1S_P2MP_Half	),
2680ccb4fc6SRussell King };
269f1538ecaSHeiner Kallweit #undef PHY_SETTING
2700ccb4fc6SRussell King 
2710ccb4fc6SRussell King /**
2720ccb4fc6SRussell King  * phy_lookup_setting - lookup a PHY setting
2730ccb4fc6SRussell King  * @speed: speed to match
2740ccb4fc6SRussell King  * @duplex: duplex to match
2750ccb4fc6SRussell King  * @mask: allowed link modes
2760ccb4fc6SRussell King  * @exact: an exact match is required
2770ccb4fc6SRussell King  *
2780ccb4fc6SRussell King  * Search the settings array for a setting that matches the speed and
2790ccb4fc6SRussell King  * duplex, and which is supported.
2800ccb4fc6SRussell King  *
2810ccb4fc6SRussell King  * If @exact is unset, either an exact match or %NULL for no match will
2820ccb4fc6SRussell King  * be returned.
2830ccb4fc6SRussell King  *
2840ccb4fc6SRussell King  * If @exact is set, an exact match, the fastest supported setting at
2850ccb4fc6SRussell King  * or below the specified speed, the slowest supported setting, or if
2860ccb4fc6SRussell King  * they all fail, %NULL will be returned.
2870ccb4fc6SRussell King  */
2880ccb4fc6SRussell King const struct phy_setting *
phy_lookup_setting(int speed,int duplex,const unsigned long * mask,bool exact)2893c1bcc86SAndrew Lunn phy_lookup_setting(int speed, int duplex, const unsigned long *mask, bool exact)
2900ccb4fc6SRussell King {
2910ccb4fc6SRussell King 	const struct phy_setting *p, *match = NULL, *last = NULL;
2920ccb4fc6SRussell King 	int i;
2930ccb4fc6SRussell King 
2940ccb4fc6SRussell King 	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
2953c1bcc86SAndrew Lunn 		if (p->bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
2963c1bcc86SAndrew Lunn 		    test_bit(p->bit, mask)) {
2970ccb4fc6SRussell King 			last = p;
2980ccb4fc6SRussell King 			if (p->speed == speed && p->duplex == duplex) {
2990ccb4fc6SRussell King 				/* Exact match for speed and duplex */
3000ccb4fc6SRussell King 				match = p;
3010ccb4fc6SRussell King 				break;
3020ccb4fc6SRussell King 			} else if (!exact) {
3030ccb4fc6SRussell King 				if (!match && p->speed <= speed)
3040ccb4fc6SRussell King 					/* Candidate */
3050ccb4fc6SRussell King 					match = p;
3060ccb4fc6SRussell King 
3070ccb4fc6SRussell King 				if (p->speed < speed)
3080ccb4fc6SRussell King 					break;
3090ccb4fc6SRussell King 			}
3100ccb4fc6SRussell King 		}
3110ccb4fc6SRussell King 	}
3120ccb4fc6SRussell King 
3130ccb4fc6SRussell King 	if (!match && !exact)
3140ccb4fc6SRussell King 		match = last;
3150ccb4fc6SRussell King 
3160ccb4fc6SRussell King 	return match;
3170ccb4fc6SRussell King }
3180ccb4fc6SRussell King EXPORT_SYMBOL_GPL(phy_lookup_setting);
3190ccb4fc6SRussell King 
phy_speeds(unsigned int * speeds,size_t size,unsigned long * mask)3200ccb4fc6SRussell King size_t phy_speeds(unsigned int *speeds, size_t size,
3213c1bcc86SAndrew Lunn 		  unsigned long *mask)
3220ccb4fc6SRussell King {
3230ccb4fc6SRussell King 	size_t count;
3240ccb4fc6SRussell King 	int i;
3250ccb4fc6SRussell King 
3260ccb4fc6SRussell King 	for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
3273c1bcc86SAndrew Lunn 		if (settings[i].bit < __ETHTOOL_LINK_MODE_MASK_NBITS &&
3280ccb4fc6SRussell King 		    test_bit(settings[i].bit, mask) &&
3290ccb4fc6SRussell King 		    (count == 0 || speeds[count - 1] != settings[i].speed))
3300ccb4fc6SRussell King 			speeds[count++] = settings[i].speed;
3310ccb4fc6SRussell King 
3320ccb4fc6SRussell King 	return count;
3330ccb4fc6SRussell King }
3340ccb4fc6SRussell King 
__set_linkmode_max_speed(u32 max_speed,unsigned long * addr)33573c105adSSergey Shtylyov static void __set_linkmode_max_speed(u32 max_speed, unsigned long *addr)
336a4eaed9fSMaxime Chevallier {
337a4eaed9fSMaxime Chevallier 	const struct phy_setting *p;
338a4eaed9fSMaxime Chevallier 	int i;
339a4eaed9fSMaxime Chevallier 
340a4eaed9fSMaxime Chevallier 	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
341a4eaed9fSMaxime Chevallier 		if (p->speed > max_speed)
3427b261e0eSHeiner Kallweit 			linkmode_clear_bit(p->bit, addr);
343a4eaed9fSMaxime Chevallier 		else
344a4eaed9fSMaxime Chevallier 			break;
345a4eaed9fSMaxime Chevallier 	}
346a4eaed9fSMaxime Chevallier }
347a4eaed9fSMaxime Chevallier 
__set_phy_supported(struct phy_device * phydev,u32 max_speed)34873c105adSSergey Shtylyov static void __set_phy_supported(struct phy_device *phydev, u32 max_speed)
3497b261e0eSHeiner Kallweit {
35073c105adSSergey Shtylyov 	__set_linkmode_max_speed(max_speed, phydev->supported);
3517b261e0eSHeiner Kallweit }
3527b261e0eSHeiner Kallweit 
3534069a572SAndrew Lunn /**
3544069a572SAndrew Lunn  * phy_set_max_speed - Set the maximum speed the PHY should support
3554069a572SAndrew Lunn  *
3564069a572SAndrew Lunn  * @phydev: The phy_device struct
3574069a572SAndrew Lunn  * @max_speed: Maximum speed
3584069a572SAndrew Lunn  *
3594069a572SAndrew Lunn  * The PHY might be more capable than the MAC. For example a Fast Ethernet
3604069a572SAndrew Lunn  * is connected to a 1G PHY. This function allows the MAC to indicate its
3614069a572SAndrew Lunn  * maximum speed, and so limit what the PHY will advertise.
3624069a572SAndrew Lunn  */
phy_set_max_speed(struct phy_device * phydev,u32 max_speed)36373c105adSSergey Shtylyov void phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
364a4eaed9fSMaxime Chevallier {
36573c105adSSergey Shtylyov 	__set_phy_supported(phydev, max_speed);
366a4eaed9fSMaxime Chevallier 
36722c0ef6bSHeiner Kallweit 	phy_advertise_supported(phydev);
368a4eaed9fSMaxime Chevallier }
369a4eaed9fSMaxime Chevallier EXPORT_SYMBOL(phy_set_max_speed);
370a4eaed9fSMaxime Chevallier 
of_set_phy_supported(struct phy_device * phydev)371a4eaed9fSMaxime Chevallier void of_set_phy_supported(struct phy_device *phydev)
372a4eaed9fSMaxime Chevallier {
373a4eaed9fSMaxime Chevallier 	struct device_node *node = phydev->mdio.dev.of_node;
374a4eaed9fSMaxime Chevallier 	u32 max_speed;
375a4eaed9fSMaxime Chevallier 
376a4eaed9fSMaxime Chevallier 	if (!IS_ENABLED(CONFIG_OF_MDIO))
377a4eaed9fSMaxime Chevallier 		return;
378a4eaed9fSMaxime Chevallier 
379a4eaed9fSMaxime Chevallier 	if (!node)
380a4eaed9fSMaxime Chevallier 		return;
381a4eaed9fSMaxime Chevallier 
382a4eaed9fSMaxime Chevallier 	if (!of_property_read_u32(node, "max-speed", &max_speed))
383a4eaed9fSMaxime Chevallier 		__set_phy_supported(phydev, max_speed);
384a4eaed9fSMaxime Chevallier }
385a4eaed9fSMaxime Chevallier 
of_set_phy_eee_broken(struct phy_device * phydev)3863feb9b23SMaxime Chevallier void of_set_phy_eee_broken(struct phy_device *phydev)
3873feb9b23SMaxime Chevallier {
3883feb9b23SMaxime Chevallier 	struct device_node *node = phydev->mdio.dev.of_node;
3893feb9b23SMaxime Chevallier 	u32 broken = 0;
3903feb9b23SMaxime Chevallier 
3913feb9b23SMaxime Chevallier 	if (!IS_ENABLED(CONFIG_OF_MDIO))
3923feb9b23SMaxime Chevallier 		return;
3933feb9b23SMaxime Chevallier 
3943feb9b23SMaxime Chevallier 	if (!node)
3953feb9b23SMaxime Chevallier 		return;
3963feb9b23SMaxime Chevallier 
3973feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-100tx"))
3983feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_100TX;
3993feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-1000t"))
4003feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_1000T;
4013feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-10gt"))
4023feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_10GT;
4033feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-1000kx"))
4043feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_1000KX;
4053feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-10gkx4"))
4063feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_10GKX4;
4073feb9b23SMaxime Chevallier 	if (of_property_read_bool(node, "eee-broken-10gkr"))
4083feb9b23SMaxime Chevallier 		broken |= MDIO_EEE_10GKR;
4093feb9b23SMaxime Chevallier 
4103feb9b23SMaxime Chevallier 	phydev->eee_broken_modes = broken;
4113feb9b23SMaxime Chevallier }
4123feb9b23SMaxime Chevallier 
4134069a572SAndrew Lunn /**
4144069a572SAndrew Lunn  * phy_resolve_aneg_pause - Determine pause autoneg results
4154069a572SAndrew Lunn  *
4164069a572SAndrew Lunn  * @phydev: The phy_device struct
4174069a572SAndrew Lunn  *
4184069a572SAndrew Lunn  * Once autoneg has completed the local pause settings can be
4194069a572SAndrew Lunn  * resolved.  Determine if pause and asymmetric pause should be used
4204069a572SAndrew Lunn  * by the MAC.
4214069a572SAndrew Lunn  */
4224069a572SAndrew Lunn 
phy_resolve_aneg_pause(struct phy_device * phydev)4232d880b87SRussell King void phy_resolve_aneg_pause(struct phy_device *phydev)
4242d880b87SRussell King {
4252d880b87SRussell King 	if (phydev->duplex == DUPLEX_FULL) {
4262d880b87SRussell King 		phydev->pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
4272d880b87SRussell King 						  phydev->lp_advertising);
4282d880b87SRussell King 		phydev->asym_pause = linkmode_test_bit(
4292d880b87SRussell King 			ETHTOOL_LINK_MODE_Asym_Pause_BIT,
4302d880b87SRussell King 			phydev->lp_advertising);
4312d880b87SRussell King 	}
4322d880b87SRussell King }
4332d880b87SRussell King EXPORT_SYMBOL_GPL(phy_resolve_aneg_pause);
4342d880b87SRussell King 
4358c5e850cSRussell King /**
4364069a572SAndrew Lunn  * phy_resolve_aneg_linkmode - resolve the advertisements into PHY settings
4378c5e850cSRussell King  * @phydev: The phy_device struct
4388c5e850cSRussell King  *
439cc1122b0SColin Ian King  * Resolve our and the link partner advertisements into their corresponding
4408c5e850cSRussell King  * speed and duplex. If full duplex was negotiated, extract the pause mode
4418c5e850cSRussell King  * from the link partner mask.
4428c5e850cSRussell King  */
phy_resolve_aneg_linkmode(struct phy_device * phydev)4438c5e850cSRussell King void phy_resolve_aneg_linkmode(struct phy_device *phydev)
4448c5e850cSRussell King {
4453c1bcc86SAndrew Lunn 	__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
446a2703de7SHeiner Kallweit 	int i;
4478c5e850cSRussell King 
448c0ec3c27SAndrew Lunn 	linkmode_and(common, phydev->lp_advertising, phydev->advertising);
4493c1bcc86SAndrew Lunn 
450a2703de7SHeiner Kallweit 	for (i = 0; i < ARRAY_SIZE(settings); i++)
451a2703de7SHeiner Kallweit 		if (test_bit(settings[i].bit, common)) {
452a2703de7SHeiner Kallweit 			phydev->speed = settings[i].speed;
453a2703de7SHeiner Kallweit 			phydev->duplex = settings[i].duplex;
454a2703de7SHeiner Kallweit 			break;
4558c5e850cSRussell King 		}
4568c5e850cSRussell King 
4572d880b87SRussell King 	phy_resolve_aneg_pause(phydev);
4588c5e850cSRussell King }
4598c5e850cSRussell King EXPORT_SYMBOL_GPL(phy_resolve_aneg_linkmode);
4608c5e850cSRussell King 
4615eee3bb7SHeiner Kallweit /**
4625eee3bb7SHeiner Kallweit  * phy_check_downshift - check whether downshift occurred
4635eee3bb7SHeiner Kallweit  * @phydev: The phy_device struct
4645eee3bb7SHeiner Kallweit  *
4655eee3bb7SHeiner Kallweit  * Check whether a downshift to a lower speed occurred. If this should be the
4665eee3bb7SHeiner Kallweit  * case warn the user.
4675eee3bb7SHeiner Kallweit  * Prerequisite for detecting downshift is that PHY driver implements the
4685eee3bb7SHeiner Kallweit  * read_status callback and sets phydev->speed to the actual link speed.
4695eee3bb7SHeiner Kallweit  */
phy_check_downshift(struct phy_device * phydev)4705eee3bb7SHeiner Kallweit void phy_check_downshift(struct phy_device *phydev)
4715eee3bb7SHeiner Kallweit {
4725eee3bb7SHeiner Kallweit 	__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
4735eee3bb7SHeiner Kallweit 	int i, speed = SPEED_UNKNOWN;
4745eee3bb7SHeiner Kallweit 
4755eee3bb7SHeiner Kallweit 	phydev->downshifted_rate = 0;
4765eee3bb7SHeiner Kallweit 
4775eee3bb7SHeiner Kallweit 	if (phydev->autoneg == AUTONEG_DISABLE ||
4785eee3bb7SHeiner Kallweit 	    phydev->speed == SPEED_UNKNOWN)
4795eee3bb7SHeiner Kallweit 		return;
4805eee3bb7SHeiner Kallweit 
4815eee3bb7SHeiner Kallweit 	linkmode_and(common, phydev->lp_advertising, phydev->advertising);
4825eee3bb7SHeiner Kallweit 
4835eee3bb7SHeiner Kallweit 	for (i = 0; i < ARRAY_SIZE(settings); i++)
4845eee3bb7SHeiner Kallweit 		if (test_bit(settings[i].bit, common)) {
4855eee3bb7SHeiner Kallweit 			speed = settings[i].speed;
4865eee3bb7SHeiner Kallweit 			break;
4875eee3bb7SHeiner Kallweit 		}
4885eee3bb7SHeiner Kallweit 
4895eee3bb7SHeiner Kallweit 	if (speed == SPEED_UNKNOWN || phydev->speed >= speed)
4905eee3bb7SHeiner Kallweit 		return;
4915eee3bb7SHeiner Kallweit 
4925eee3bb7SHeiner Kallweit 	phydev_warn(phydev, "Downshift occurred from negotiated speed %s to actual speed %s, check cabling!\n",
4935eee3bb7SHeiner Kallweit 		    phy_speed_to_str(speed), phy_speed_to_str(phydev->speed));
4945eee3bb7SHeiner Kallweit 
4955eee3bb7SHeiner Kallweit 	phydev->downshifted_rate = 1;
4965eee3bb7SHeiner Kallweit }
4975eee3bb7SHeiner Kallweit EXPORT_SYMBOL_GPL(phy_check_downshift);
4985eee3bb7SHeiner Kallweit 
phy_resolve_min_speed(struct phy_device * phydev,bool fdx_only)499331c56acSHeiner Kallweit static int phy_resolve_min_speed(struct phy_device *phydev, bool fdx_only)
500331c56acSHeiner Kallweit {
501331c56acSHeiner Kallweit 	__ETHTOOL_DECLARE_LINK_MODE_MASK(common);
502331c56acSHeiner Kallweit 	int i = ARRAY_SIZE(settings);
503331c56acSHeiner Kallweit 
504331c56acSHeiner Kallweit 	linkmode_and(common, phydev->lp_advertising, phydev->advertising);
505331c56acSHeiner Kallweit 
506331c56acSHeiner Kallweit 	while (--i >= 0) {
507331c56acSHeiner Kallweit 		if (test_bit(settings[i].bit, common)) {
508331c56acSHeiner Kallweit 			if (fdx_only && settings[i].duplex != DUPLEX_FULL)
509331c56acSHeiner Kallweit 				continue;
510331c56acSHeiner Kallweit 			return settings[i].speed;
511331c56acSHeiner Kallweit 		}
512331c56acSHeiner Kallweit 	}
513331c56acSHeiner Kallweit 
514331c56acSHeiner Kallweit 	return SPEED_UNKNOWN;
515331c56acSHeiner Kallweit }
516331c56acSHeiner Kallweit 
phy_speed_down_core(struct phy_device * phydev)517331c56acSHeiner Kallweit int phy_speed_down_core(struct phy_device *phydev)
518331c56acSHeiner Kallweit {
519331c56acSHeiner Kallweit 	int min_common_speed = phy_resolve_min_speed(phydev, true);
520331c56acSHeiner Kallweit 
521331c56acSHeiner Kallweit 	if (min_common_speed == SPEED_UNKNOWN)
522331c56acSHeiner Kallweit 		return -EINVAL;
523331c56acSHeiner Kallweit 
52473c105adSSergey Shtylyov 	__set_linkmode_max_speed(min_common_speed, phydev->advertising);
52573c105adSSergey Shtylyov 
52673c105adSSergey Shtylyov 	return 0;
527331c56acSHeiner Kallweit }
528331c56acSHeiner Kallweit 
mmd_phy_indirect(struct mii_bus * bus,int phy_addr,int devad,u16 regnum)529060fbc89SRussell King static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
530060fbc89SRussell King 			     u16 regnum)
5319860118bSRussell King {
5329860118bSRussell King 	/* Write the desired MMD Devad */
5331b2dea2eSRussell King 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
5349860118bSRussell King 
5359860118bSRussell King 	/* Write the desired MMD register address */
5361b2dea2eSRussell King 	__mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
5379860118bSRussell King 
5389860118bSRussell King 	/* Select the Function : DATA with no post increment */
5391b2dea2eSRussell King 	__mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
5401b2dea2eSRussell King 			devad | MII_MMD_CTRL_NOINCR);
5419860118bSRussell King }
5429860118bSRussell King 
5439860118bSRussell King /**
5441878f0dcSNikita Yushchenko  * __phy_read_mmd - Convenience function for reading a register
5459860118bSRussell King  * from an MMD on a given PHY.
5469860118bSRussell King  * @phydev: The phy_device struct
5473b85d8dfSRussell King  * @devad: The MMD to read from (0..31)
5483b85d8dfSRussell King  * @regnum: The register on the MMD to read (0..65535)
5499860118bSRussell King  *
5501878f0dcSNikita Yushchenko  * Same rules as for __phy_read();
5519860118bSRussell King  */
__phy_read_mmd(struct phy_device * phydev,int devad,u32 regnum)5521878f0dcSNikita Yushchenko int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
5539860118bSRussell King {
5543b85d8dfSRussell King 	int val;
5553b85d8dfSRussell King 
5561ee6b9bcSRussell King 	if (regnum > (u16)~0 || devad > 32)
5571ee6b9bcSRussell King 		return -EINVAL;
5589860118bSRussell King 
5593e41d04eSAlex Marginean 	if (phydev->drv && phydev->drv->read_mmd) {
5603b85d8dfSRussell King 		val = phydev->drv->read_mmd(phydev, devad, regnum);
5613b85d8dfSRussell King 	} else if (phydev->is_c45) {
56290ce665cSRussell King 		val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
56390ce665cSRussell King 					 devad, regnum);
5643b85d8dfSRussell King 	} else {
5659860118bSRussell King 		struct mii_bus *bus = phydev->mdio.bus;
5663b85d8dfSRussell King 		int phy_addr = phydev->mdio.addr;
5679860118bSRussell King 
568060fbc89SRussell King 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
5699860118bSRussell King 
5703b85d8dfSRussell King 		/* Read the content of the MMD's selected register */
5711b2dea2eSRussell King 		val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
5729860118bSRussell King 	}
5733b85d8dfSRussell King 	return val;
5749860118bSRussell King }
5751878f0dcSNikita Yushchenko EXPORT_SYMBOL(__phy_read_mmd);
5761878f0dcSNikita Yushchenko 
5771878f0dcSNikita Yushchenko /**
5781878f0dcSNikita Yushchenko  * phy_read_mmd - Convenience function for reading a register
5791878f0dcSNikita Yushchenko  * from an MMD on a given PHY.
5801878f0dcSNikita Yushchenko  * @phydev: The phy_device struct
5811878f0dcSNikita Yushchenko  * @devad: The MMD to read from
5821878f0dcSNikita Yushchenko  * @regnum: The register on the MMD to read
5831878f0dcSNikita Yushchenko  *
5841878f0dcSNikita Yushchenko  * Same rules as for phy_read();
5851878f0dcSNikita Yushchenko  */
phy_read_mmd(struct phy_device * phydev,int devad,u32 regnum)5861878f0dcSNikita Yushchenko int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
5871878f0dcSNikita Yushchenko {
5881878f0dcSNikita Yushchenko 	int ret;
5891878f0dcSNikita Yushchenko 
590bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
5911878f0dcSNikita Yushchenko 	ret = __phy_read_mmd(phydev, devad, regnum);
592bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
5931878f0dcSNikita Yushchenko 
5941878f0dcSNikita Yushchenko 	return ret;
5951878f0dcSNikita Yushchenko }
5963b85d8dfSRussell King EXPORT_SYMBOL(phy_read_mmd);
5979860118bSRussell King 
5989860118bSRussell King /**
5991878f0dcSNikita Yushchenko  * __phy_write_mmd - Convenience function for writing a register
6001878f0dcSNikita Yushchenko  * on an MMD on a given PHY.
6011878f0dcSNikita Yushchenko  * @phydev: The phy_device struct
6021878f0dcSNikita Yushchenko  * @devad: The MMD to read from
6031878f0dcSNikita Yushchenko  * @regnum: The register on the MMD to read
6041878f0dcSNikita Yushchenko  * @val: value to write to @regnum
6051878f0dcSNikita Yushchenko  *
6061878f0dcSNikita Yushchenko  * Same rules as for __phy_write();
6071878f0dcSNikita Yushchenko  */
__phy_write_mmd(struct phy_device * phydev,int devad,u32 regnum,u16 val)6081878f0dcSNikita Yushchenko int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
6091878f0dcSNikita Yushchenko {
6101878f0dcSNikita Yushchenko 	int ret;
6111878f0dcSNikita Yushchenko 
6121878f0dcSNikita Yushchenko 	if (regnum > (u16)~0 || devad > 32)
6131878f0dcSNikita Yushchenko 		return -EINVAL;
6141878f0dcSNikita Yushchenko 
6153e41d04eSAlex Marginean 	if (phydev->drv && phydev->drv->write_mmd) {
6161878f0dcSNikita Yushchenko 		ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
6171878f0dcSNikita Yushchenko 	} else if (phydev->is_c45) {
61890ce665cSRussell King 		ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
61990ce665cSRussell King 					  devad, regnum, val);
6201878f0dcSNikita Yushchenko 	} else {
6211878f0dcSNikita Yushchenko 		struct mii_bus *bus = phydev->mdio.bus;
6221878f0dcSNikita Yushchenko 		int phy_addr = phydev->mdio.addr;
6231878f0dcSNikita Yushchenko 
6241878f0dcSNikita Yushchenko 		mmd_phy_indirect(bus, phy_addr, devad, regnum);
6251878f0dcSNikita Yushchenko 
6261878f0dcSNikita Yushchenko 		/* Write the data into MMD's selected register */
6271878f0dcSNikita Yushchenko 		__mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
6281878f0dcSNikita Yushchenko 
6291878f0dcSNikita Yushchenko 		ret = 0;
6301878f0dcSNikita Yushchenko 	}
6311878f0dcSNikita Yushchenko 	return ret;
6321878f0dcSNikita Yushchenko }
6331878f0dcSNikita Yushchenko EXPORT_SYMBOL(__phy_write_mmd);
6341878f0dcSNikita Yushchenko 
6351878f0dcSNikita Yushchenko /**
6369860118bSRussell King  * phy_write_mmd - Convenience function for writing a register
6379860118bSRussell King  * on an MMD on a given PHY.
6389860118bSRussell King  * @phydev: The phy_device struct
6399860118bSRussell King  * @devad: The MMD to read from
6409860118bSRussell King  * @regnum: The register on the MMD to read
6419860118bSRussell King  * @val: value to write to @regnum
6429860118bSRussell King  *
6439860118bSRussell King  * Same rules as for phy_write();
6449860118bSRussell King  */
phy_write_mmd(struct phy_device * phydev,int devad,u32 regnum,u16 val)6459860118bSRussell King int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
6469860118bSRussell King {
6473b85d8dfSRussell King 	int ret;
6483b85d8dfSRussell King 
649bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
6501878f0dcSNikita Yushchenko 	ret = __phy_write_mmd(phydev, devad, regnum, val);
651bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
6529860118bSRussell King 
6533b85d8dfSRussell King 	return ret;
6549860118bSRussell King }
6559860118bSRussell King EXPORT_SYMBOL(phy_write_mmd);
656788f9933SRussell King 
657788f9933SRussell King /**
658b8554d4fSHeiner Kallweit  * phy_modify_changed - Function for modifying a PHY register
659b8554d4fSHeiner Kallweit  * @phydev: the phy_device struct
660b8554d4fSHeiner Kallweit  * @regnum: register number to modify
661b8554d4fSHeiner Kallweit  * @mask: bit mask of bits to clear
662b8554d4fSHeiner Kallweit  * @set: new value of bits set in mask to write to @regnum
663b8554d4fSHeiner Kallweit  *
664b8554d4fSHeiner Kallweit  * NOTE: MUST NOT be called from interrupt context,
665b8554d4fSHeiner Kallweit  * because the bus read/write functions may wait for an interrupt
666b8554d4fSHeiner Kallweit  * to conclude the operation.
667b8554d4fSHeiner Kallweit  *
668b8554d4fSHeiner Kallweit  * Returns negative errno, 0 if there was no change, and 1 in case of change
669b8554d4fSHeiner Kallweit  */
phy_modify_changed(struct phy_device * phydev,u32 regnum,u16 mask,u16 set)670b8554d4fSHeiner Kallweit int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
671b8554d4fSHeiner Kallweit {
672b8554d4fSHeiner Kallweit 	int ret;
673b8554d4fSHeiner Kallweit 
674bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
675b8554d4fSHeiner Kallweit 	ret = __phy_modify_changed(phydev, regnum, mask, set);
676bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
677b8554d4fSHeiner Kallweit 
678b8554d4fSHeiner Kallweit 	return ret;
679b8554d4fSHeiner Kallweit }
680b8554d4fSHeiner Kallweit EXPORT_SYMBOL_GPL(phy_modify_changed);
681b8554d4fSHeiner Kallweit 
682b8554d4fSHeiner Kallweit /**
683b8554d4fSHeiner Kallweit  * __phy_modify - Convenience function for modifying a PHY register
684b8554d4fSHeiner Kallweit  * @phydev: the phy_device struct
685b8554d4fSHeiner Kallweit  * @regnum: register number to modify
686b8554d4fSHeiner Kallweit  * @mask: bit mask of bits to clear
687b8554d4fSHeiner Kallweit  * @set: new value of bits set in mask to write to @regnum
688b8554d4fSHeiner Kallweit  *
689b8554d4fSHeiner Kallweit  * NOTE: MUST NOT be called from interrupt context,
690b8554d4fSHeiner Kallweit  * because the bus read/write functions may wait for an interrupt
691b8554d4fSHeiner Kallweit  * to conclude the operation.
692b8554d4fSHeiner Kallweit  */
__phy_modify(struct phy_device * phydev,u32 regnum,u16 mask,u16 set)693b8554d4fSHeiner Kallweit int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
694b8554d4fSHeiner Kallweit {
695b8554d4fSHeiner Kallweit 	int ret;
696b8554d4fSHeiner Kallweit 
697b8554d4fSHeiner Kallweit 	ret = __phy_modify_changed(phydev, regnum, mask, set);
6989f239fe6SAndrew Lunn 
6999f239fe6SAndrew Lunn 	return ret < 0 ? ret : 0;
700788f9933SRussell King }
701788f9933SRussell King EXPORT_SYMBOL_GPL(__phy_modify);
70278ffc4acSRussell King 
7032b74e5beSRussell King /**
7042b74e5beSRussell King  * phy_modify - Convenience function for modifying a given PHY register
7052b74e5beSRussell King  * @phydev: the phy_device struct
7062b74e5beSRussell King  * @regnum: register number to write
7072b74e5beSRussell King  * @mask: bit mask of bits to clear
7082b74e5beSRussell King  * @set: new value of bits set in mask to write to @regnum
7092b74e5beSRussell King  *
7102b74e5beSRussell King  * NOTE: MUST NOT be called from interrupt context,
7112b74e5beSRussell King  * because the bus read/write functions may wait for an interrupt
7122b74e5beSRussell King  * to conclude the operation.
7132b74e5beSRussell King  */
phy_modify(struct phy_device * phydev,u32 regnum,u16 mask,u16 set)7142b74e5beSRussell King int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
7152b74e5beSRussell King {
7162b74e5beSRussell King 	int ret;
7172b74e5beSRussell King 
718bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
7192b74e5beSRussell King 	ret = __phy_modify(phydev, regnum, mask, set);
720bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
7212b74e5beSRussell King 
7222b74e5beSRussell King 	return ret;
7232b74e5beSRussell King }
7242b74e5beSRussell King EXPORT_SYMBOL_GPL(phy_modify);
7252b74e5beSRussell King 
7261878f0dcSNikita Yushchenko /**
727b8554d4fSHeiner Kallweit  * __phy_modify_mmd_changed - Function for modifying a register on MMD
7281878f0dcSNikita Yushchenko  * @phydev: the phy_device struct
7291878f0dcSNikita Yushchenko  * @devad: the MMD containing register to modify
7301878f0dcSNikita Yushchenko  * @regnum: register number to modify
7311878f0dcSNikita Yushchenko  * @mask: bit mask of bits to clear
7321878f0dcSNikita Yushchenko  * @set: new value of bits set in mask to write to @regnum
7331878f0dcSNikita Yushchenko  *
7341878f0dcSNikita Yushchenko  * Unlocked helper function which allows a MMD register to be modified as
7351878f0dcSNikita Yushchenko  * new register value = (old register value & ~mask) | set
736b8554d4fSHeiner Kallweit  *
737b8554d4fSHeiner Kallweit  * Returns negative errno, 0 if there was no change, and 1 in case of change
738b8554d4fSHeiner Kallweit  */
__phy_modify_mmd_changed(struct phy_device * phydev,int devad,u32 regnum,u16 mask,u16 set)739b8554d4fSHeiner Kallweit int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
740b8554d4fSHeiner Kallweit 			     u16 mask, u16 set)
741b8554d4fSHeiner Kallweit {
742b8554d4fSHeiner Kallweit 	int new, ret;
743b8554d4fSHeiner Kallweit 
744b8554d4fSHeiner Kallweit 	ret = __phy_read_mmd(phydev, devad, regnum);
745b8554d4fSHeiner Kallweit 	if (ret < 0)
746b8554d4fSHeiner Kallweit 		return ret;
747b8554d4fSHeiner Kallweit 
748b8554d4fSHeiner Kallweit 	new = (ret & ~mask) | set;
749b8554d4fSHeiner Kallweit 	if (new == ret)
750b8554d4fSHeiner Kallweit 		return 0;
751b8554d4fSHeiner Kallweit 
752b8554d4fSHeiner Kallweit 	ret = __phy_write_mmd(phydev, devad, regnum, new);
753b8554d4fSHeiner Kallweit 
754b8554d4fSHeiner Kallweit 	return ret < 0 ? ret : 1;
755b8554d4fSHeiner Kallweit }
756b8554d4fSHeiner Kallweit EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed);
757b8554d4fSHeiner Kallweit 
758b8554d4fSHeiner Kallweit /**
759b8554d4fSHeiner Kallweit  * phy_modify_mmd_changed - Function for modifying a register on MMD
760b8554d4fSHeiner Kallweit  * @phydev: the phy_device struct
761b8554d4fSHeiner Kallweit  * @devad: the MMD containing register to modify
762b8554d4fSHeiner Kallweit  * @regnum: register number to modify
763b8554d4fSHeiner Kallweit  * @mask: bit mask of bits to clear
764b8554d4fSHeiner Kallweit  * @set: new value of bits set in mask to write to @regnum
765b8554d4fSHeiner Kallweit  *
766b8554d4fSHeiner Kallweit  * NOTE: MUST NOT be called from interrupt context,
767b8554d4fSHeiner Kallweit  * because the bus read/write functions may wait for an interrupt
768b8554d4fSHeiner Kallweit  * to conclude the operation.
769b8554d4fSHeiner Kallweit  *
770b8554d4fSHeiner Kallweit  * Returns negative errno, 0 if there was no change, and 1 in case of change
771b8554d4fSHeiner Kallweit  */
phy_modify_mmd_changed(struct phy_device * phydev,int devad,u32 regnum,u16 mask,u16 set)772b8554d4fSHeiner Kallweit int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
773b8554d4fSHeiner Kallweit 			   u16 mask, u16 set)
774b8554d4fSHeiner Kallweit {
775b8554d4fSHeiner Kallweit 	int ret;
776b8554d4fSHeiner Kallweit 
777bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
778b8554d4fSHeiner Kallweit 	ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
779bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
780b8554d4fSHeiner Kallweit 
781b8554d4fSHeiner Kallweit 	return ret;
782b8554d4fSHeiner Kallweit }
783b8554d4fSHeiner Kallweit EXPORT_SYMBOL_GPL(phy_modify_mmd_changed);
784b8554d4fSHeiner Kallweit 
785b8554d4fSHeiner Kallweit /**
786b8554d4fSHeiner Kallweit  * __phy_modify_mmd - Convenience function for modifying a register on MMD
787b8554d4fSHeiner Kallweit  * @phydev: the phy_device struct
788b8554d4fSHeiner Kallweit  * @devad: the MMD containing register to modify
789b8554d4fSHeiner Kallweit  * @regnum: register number to modify
790b8554d4fSHeiner Kallweit  * @mask: bit mask of bits to clear
791b8554d4fSHeiner Kallweit  * @set: new value of bits set in mask to write to @regnum
792b8554d4fSHeiner Kallweit  *
793b8554d4fSHeiner Kallweit  * NOTE: MUST NOT be called from interrupt context,
794b8554d4fSHeiner Kallweit  * because the bus read/write functions may wait for an interrupt
795b8554d4fSHeiner Kallweit  * to conclude the operation.
7961878f0dcSNikita Yushchenko  */
__phy_modify_mmd(struct phy_device * phydev,int devad,u32 regnum,u16 mask,u16 set)7971878f0dcSNikita Yushchenko int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
7981878f0dcSNikita Yushchenko 		     u16 mask, u16 set)
7991878f0dcSNikita Yushchenko {
8001878f0dcSNikita Yushchenko 	int ret;
8011878f0dcSNikita Yushchenko 
802b8554d4fSHeiner Kallweit 	ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
8031878f0dcSNikita Yushchenko 
8041878f0dcSNikita Yushchenko 	return ret < 0 ? ret : 0;
8051878f0dcSNikita Yushchenko }
8061878f0dcSNikita Yushchenko EXPORT_SYMBOL_GPL(__phy_modify_mmd);
8071878f0dcSNikita Yushchenko 
8081878f0dcSNikita Yushchenko /**
8091878f0dcSNikita Yushchenko  * phy_modify_mmd - Convenience function for modifying a register on MMD
8101878f0dcSNikita Yushchenko  * @phydev: the phy_device struct
8111878f0dcSNikita Yushchenko  * @devad: the MMD containing register to modify
8121878f0dcSNikita Yushchenko  * @regnum: register number to modify
8131878f0dcSNikita Yushchenko  * @mask: bit mask of bits to clear
8141878f0dcSNikita Yushchenko  * @set: new value of bits set in mask to write to @regnum
8151878f0dcSNikita Yushchenko  *
8161878f0dcSNikita Yushchenko  * NOTE: MUST NOT be called from interrupt context,
8171878f0dcSNikita Yushchenko  * because the bus read/write functions may wait for an interrupt
8181878f0dcSNikita Yushchenko  * to conclude the operation.
8191878f0dcSNikita Yushchenko  */
phy_modify_mmd(struct phy_device * phydev,int devad,u32 regnum,u16 mask,u16 set)8201878f0dcSNikita Yushchenko int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
8211878f0dcSNikita Yushchenko 		   u16 mask, u16 set)
8221878f0dcSNikita Yushchenko {
8231878f0dcSNikita Yushchenko 	int ret;
8241878f0dcSNikita Yushchenko 
825bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
8261878f0dcSNikita Yushchenko 	ret = __phy_modify_mmd(phydev, devad, regnum, mask, set);
827bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
8281878f0dcSNikita Yushchenko 
8291878f0dcSNikita Yushchenko 	return ret;
8301878f0dcSNikita Yushchenko }
8311878f0dcSNikita Yushchenko EXPORT_SYMBOL_GPL(phy_modify_mmd);
8321878f0dcSNikita Yushchenko 
__phy_read_page(struct phy_device * phydev)83378ffc4acSRussell King static int __phy_read_page(struct phy_device *phydev)
83478ffc4acSRussell King {
835f86854a2SHeiner Kallweit 	if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n"))
836f86854a2SHeiner Kallweit 		return -EOPNOTSUPP;
837f86854a2SHeiner Kallweit 
83878ffc4acSRussell King 	return phydev->drv->read_page(phydev);
83978ffc4acSRussell King }
84078ffc4acSRussell King 
__phy_write_page(struct phy_device * phydev,int page)84178ffc4acSRussell King static int __phy_write_page(struct phy_device *phydev, int page)
84278ffc4acSRussell King {
843f86854a2SHeiner Kallweit 	if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n"))
844f86854a2SHeiner Kallweit 		return -EOPNOTSUPP;
845f86854a2SHeiner Kallweit 
84678ffc4acSRussell King 	return phydev->drv->write_page(phydev, page);
84778ffc4acSRussell King }
84878ffc4acSRussell King 
84978ffc4acSRussell King /**
85078ffc4acSRussell King  * phy_save_page() - take the bus lock and save the current page
85178ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
85278ffc4acSRussell King  *
85378ffc4acSRussell King  * Take the MDIO bus lock, and return the current page number. On error,
85478ffc4acSRussell King  * returns a negative errno. phy_restore_page() must always be called
85578ffc4acSRussell King  * after this, irrespective of success or failure of this call.
85678ffc4acSRussell King  */
phy_save_page(struct phy_device * phydev)85778ffc4acSRussell King int phy_save_page(struct phy_device *phydev)
85878ffc4acSRussell King {
859bec170e5SHeiner Kallweit 	phy_lock_mdio_bus(phydev);
86078ffc4acSRussell King 	return __phy_read_page(phydev);
86178ffc4acSRussell King }
86278ffc4acSRussell King EXPORT_SYMBOL_GPL(phy_save_page);
86378ffc4acSRussell King 
86478ffc4acSRussell King /**
86578ffc4acSRussell King  * phy_select_page() - take the bus lock, save the current page, and set a page
86678ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
86778ffc4acSRussell King  * @page: desired page
86878ffc4acSRussell King  *
86978ffc4acSRussell King  * Take the MDIO bus lock to protect against concurrent access, save the
87078ffc4acSRussell King  * current PHY page, and set the current page.  On error, returns a
87178ffc4acSRussell King  * negative errno, otherwise returns the previous page number.
87278ffc4acSRussell King  * phy_restore_page() must always be called after this, irrespective
87378ffc4acSRussell King  * of success or failure of this call.
87478ffc4acSRussell King  */
phy_select_page(struct phy_device * phydev,int page)87578ffc4acSRussell King int phy_select_page(struct phy_device *phydev, int page)
87678ffc4acSRussell King {
87778ffc4acSRussell King 	int ret, oldpage;
87878ffc4acSRussell King 
87978ffc4acSRussell King 	oldpage = ret = phy_save_page(phydev);
88078ffc4acSRussell King 	if (ret < 0)
88178ffc4acSRussell King 		return ret;
88278ffc4acSRussell King 
88378ffc4acSRussell King 	if (oldpage != page) {
88478ffc4acSRussell King 		ret = __phy_write_page(phydev, page);
88578ffc4acSRussell King 		if (ret < 0)
88678ffc4acSRussell King 			return ret;
88778ffc4acSRussell King 	}
88878ffc4acSRussell King 
88978ffc4acSRussell King 	return oldpage;
89078ffc4acSRussell King }
89178ffc4acSRussell King EXPORT_SYMBOL_GPL(phy_select_page);
89278ffc4acSRussell King 
89378ffc4acSRussell King /**
89478ffc4acSRussell King  * phy_restore_page() - restore the page register and release the bus lock
89578ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
89678ffc4acSRussell King  * @oldpage: the old page, return value from phy_save_page() or phy_select_page()
89778ffc4acSRussell King  * @ret: operation's return code
89878ffc4acSRussell King  *
89978ffc4acSRussell King  * Release the MDIO bus lock, restoring @oldpage if it is a valid page.
90078ffc4acSRussell King  * This function propagates the earliest error code from the group of
90178ffc4acSRussell King  * operations.
90278ffc4acSRussell King  *
90378ffc4acSRussell King  * Returns:
90478ffc4acSRussell King  *   @oldpage if it was a negative value, otherwise
90578ffc4acSRussell King  *   @ret if it was a negative errno value, otherwise
90678ffc4acSRussell King  *   phy_write_page()'s negative value if it were in error, otherwise
90778ffc4acSRussell King  *   @ret.
90878ffc4acSRussell King  */
phy_restore_page(struct phy_device * phydev,int oldpage,int ret)90978ffc4acSRussell King int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
91078ffc4acSRussell King {
91178ffc4acSRussell King 	int r;
91278ffc4acSRussell King 
91378ffc4acSRussell King 	if (oldpage >= 0) {
91478ffc4acSRussell King 		r = __phy_write_page(phydev, oldpage);
91578ffc4acSRussell King 
91678ffc4acSRussell King 		/* Propagate the operation return code if the page write
91778ffc4acSRussell King 		 * was successful.
91878ffc4acSRussell King 		 */
91978ffc4acSRussell King 		if (ret >= 0 && r < 0)
92078ffc4acSRussell King 			ret = r;
92178ffc4acSRussell King 	} else {
92278ffc4acSRussell King 		/* Propagate the phy page selection error code */
92378ffc4acSRussell King 		ret = oldpage;
92478ffc4acSRussell King 	}
92578ffc4acSRussell King 
926bec170e5SHeiner Kallweit 	phy_unlock_mdio_bus(phydev);
92778ffc4acSRussell King 
92878ffc4acSRussell King 	return ret;
92978ffc4acSRussell King }
93078ffc4acSRussell King EXPORT_SYMBOL_GPL(phy_restore_page);
93178ffc4acSRussell King 
93278ffc4acSRussell King /**
93378ffc4acSRussell King  * phy_read_paged() - Convenience function for reading a paged register
93478ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
93578ffc4acSRussell King  * @page: the page for the phy
93678ffc4acSRussell King  * @regnum: register number
93778ffc4acSRussell King  *
93878ffc4acSRussell King  * Same rules as for phy_read().
93978ffc4acSRussell King  */
phy_read_paged(struct phy_device * phydev,int page,u32 regnum)94078ffc4acSRussell King int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
94178ffc4acSRussell King {
94278ffc4acSRussell King 	int ret = 0, oldpage;
94378ffc4acSRussell King 
94478ffc4acSRussell King 	oldpage = phy_select_page(phydev, page);
94578ffc4acSRussell King 	if (oldpage >= 0)
94678ffc4acSRussell King 		ret = __phy_read(phydev, regnum);
94778ffc4acSRussell King 
94878ffc4acSRussell King 	return phy_restore_page(phydev, oldpage, ret);
94978ffc4acSRussell King }
95078ffc4acSRussell King EXPORT_SYMBOL(phy_read_paged);
95178ffc4acSRussell King 
95278ffc4acSRussell King /**
95378ffc4acSRussell King  * phy_write_paged() - Convenience function for writing a paged register
95478ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
95578ffc4acSRussell King  * @page: the page for the phy
95678ffc4acSRussell King  * @regnum: register number
95778ffc4acSRussell King  * @val: value to write
95878ffc4acSRussell King  *
95978ffc4acSRussell King  * Same rules as for phy_write().
96078ffc4acSRussell King  */
phy_write_paged(struct phy_device * phydev,int page,u32 regnum,u16 val)96178ffc4acSRussell King int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
96278ffc4acSRussell King {
96378ffc4acSRussell King 	int ret = 0, oldpage;
96478ffc4acSRussell King 
96578ffc4acSRussell King 	oldpage = phy_select_page(phydev, page);
96678ffc4acSRussell King 	if (oldpage >= 0)
96778ffc4acSRussell King 		ret = __phy_write(phydev, regnum, val);
96878ffc4acSRussell King 
96978ffc4acSRussell King 	return phy_restore_page(phydev, oldpage, ret);
97078ffc4acSRussell King }
97178ffc4acSRussell King EXPORT_SYMBOL(phy_write_paged);
97278ffc4acSRussell King 
97378ffc4acSRussell King /**
974bf22b343SHeiner Kallweit  * phy_modify_paged_changed() - Function for modifying a paged register
975bf22b343SHeiner Kallweit  * @phydev: a pointer to a &struct phy_device
976bf22b343SHeiner Kallweit  * @page: the page for the phy
977bf22b343SHeiner Kallweit  * @regnum: register number
978bf22b343SHeiner Kallweit  * @mask: bit mask of bits to clear
979bf22b343SHeiner Kallweit  * @set: bit mask of bits to set
980bf22b343SHeiner Kallweit  *
981bf22b343SHeiner Kallweit  * Returns negative errno, 0 if there was no change, and 1 in case of change
982bf22b343SHeiner Kallweit  */
phy_modify_paged_changed(struct phy_device * phydev,int page,u32 regnum,u16 mask,u16 set)983bf22b343SHeiner Kallweit int phy_modify_paged_changed(struct phy_device *phydev, int page, u32 regnum,
984bf22b343SHeiner Kallweit 			     u16 mask, u16 set)
985bf22b343SHeiner Kallweit {
986bf22b343SHeiner Kallweit 	int ret = 0, oldpage;
987bf22b343SHeiner Kallweit 
988bf22b343SHeiner Kallweit 	oldpage = phy_select_page(phydev, page);
989bf22b343SHeiner Kallweit 	if (oldpage >= 0)
990bf22b343SHeiner Kallweit 		ret = __phy_modify_changed(phydev, regnum, mask, set);
991bf22b343SHeiner Kallweit 
992bf22b343SHeiner Kallweit 	return phy_restore_page(phydev, oldpage, ret);
993bf22b343SHeiner Kallweit }
994bf22b343SHeiner Kallweit EXPORT_SYMBOL(phy_modify_paged_changed);
995bf22b343SHeiner Kallweit 
996bf22b343SHeiner Kallweit /**
99778ffc4acSRussell King  * phy_modify_paged() - Convenience function for modifying a paged register
99878ffc4acSRussell King  * @phydev: a pointer to a &struct phy_device
99978ffc4acSRussell King  * @page: the page for the phy
100078ffc4acSRussell King  * @regnum: register number
100178ffc4acSRussell King  * @mask: bit mask of bits to clear
100278ffc4acSRussell King  * @set: bit mask of bits to set
100378ffc4acSRussell King  *
100478ffc4acSRussell King  * Same rules as for phy_read() and phy_write().
100578ffc4acSRussell King  */
phy_modify_paged(struct phy_device * phydev,int page,u32 regnum,u16 mask,u16 set)100678ffc4acSRussell King int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
100778ffc4acSRussell King 		     u16 mask, u16 set)
100878ffc4acSRussell King {
1009bf22b343SHeiner Kallweit 	int ret = phy_modify_paged_changed(phydev, page, regnum, mask, set);
101078ffc4acSRussell King 
1011bf22b343SHeiner Kallweit 	return ret < 0 ? ret : 0;
101278ffc4acSRussell King }
101378ffc4acSRussell King EXPORT_SYMBOL(phy_modify_paged);
1014