1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *	drivers/net/phy/broadcom.c
4 *
5 *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
6 *	transceivers.
7 *
8 *	Copyright (c) 2006  Maciej W. Rozycki
9 *
10 *	Inspired by code written by Amy Fong.
11 */
12
13#include "bcm-phy-lib.h"
14#include <linux/delay.h>
15#include <linux/module.h>
16#include <linux/phy.h>
17#include <linux/pm_wakeup.h>
18#include <linux/brcmphy.h>
19#include <linux/of.h>
20#include <linux/interrupt.h>
21#include <linux/irq.h>
22#include <linux/gpio/consumer.h>
23
24#define BRCM_PHY_MODEL(phydev) \
25	((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
26
27#define BRCM_PHY_REV(phydev) \
28	((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
29
30MODULE_DESCRIPTION("Broadcom PHY driver");
31MODULE_AUTHOR("Maciej W. Rozycki");
32MODULE_LICENSE("GPL");
33
34struct bcm54xx_phy_priv {
35	u64	*stats;
36	struct bcm_ptp_private *ptp;
37	int	wake_irq;
38	bool	wake_irq_enabled;
39};
40
41static bool bcm54xx_phy_can_wakeup(struct phy_device *phydev)
42{
43	struct bcm54xx_phy_priv *priv = phydev->priv;
44
45	return phy_interrupt_is_valid(phydev) || priv->wake_irq >= 0;
46}
47
48static int bcm54xx_config_clock_delay(struct phy_device *phydev)
49{
50	int rc, val;
51
52	/* handling PHY's internal RX clock delay */
53	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
54	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
55	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
56	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
57		/* Disable RGMII RXC-RXD skew */
58		val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
59	}
60	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
61	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
62		/* Enable RGMII RXC-RXD skew */
63		val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
64	}
65	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
66				  val);
67	if (rc < 0)
68		return rc;
69
70	/* handling PHY's internal TX clock delay */
71	val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
72	if (phydev->interface == PHY_INTERFACE_MODE_RGMII ||
73	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
74		/* Disable internal TX clock delay */
75		val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
76	}
77	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
78	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
79		/* Enable internal TX clock delay */
80		val |= BCM54810_SHD_CLK_CTL_GTXCLK_EN;
81	}
82	rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
83	if (rc < 0)
84		return rc;
85
86	return 0;
87}
88
89static int bcm54210e_config_init(struct phy_device *phydev)
90{
91	int val;
92
93	bcm54xx_config_clock_delay(phydev);
94
95	if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) {
96		val = phy_read(phydev, MII_CTRL1000);
97		val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER;
98		phy_write(phydev, MII_CTRL1000, val);
99	}
100
101	return 0;
102}
103
104static int bcm54612e_config_init(struct phy_device *phydev)
105{
106	int reg;
107
108	bcm54xx_config_clock_delay(phydev);
109
110	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
111	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
112		int err;
113
114		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
115		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
116					BCM54612E_LED4_CLK125OUT_EN | reg);
117
118		if (err < 0)
119			return err;
120	}
121
122	return 0;
123}
124
125static int bcm54616s_config_init(struct phy_device *phydev)
126{
127	int rc, val;
128
129	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
130	    phydev->interface != PHY_INTERFACE_MODE_1000BASEX)
131		return 0;
132
133	/* Ensure proper interface mode is selected. */
134	/* Disable RGMII mode */
135	val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
136	if (val < 0)
137		return val;
138	val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_EN;
139	val |= MII_BCM54XX_AUXCTL_MISC_WREN;
140	rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
141				  val);
142	if (rc < 0)
143		return rc;
144
145	/* Select 1000BASE-X register set (primary SerDes) */
146	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
147	if (val < 0)
148		return val;
149	val |= BCM54XX_SHD_MODE_1000BX;
150	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
151	if (rc < 0)
152		return rc;
153
154	/* Power down SerDes interface */
155	rc = phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
156	if (rc < 0)
157		return rc;
158
159	/* Select proper interface mode */
160	val &= ~BCM54XX_SHD_INTF_SEL_MASK;
161	val |= phydev->interface == PHY_INTERFACE_MODE_SGMII ?
162		BCM54XX_SHD_INTF_SEL_SGMII :
163		BCM54XX_SHD_INTF_SEL_GBIC;
164	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
165	if (rc < 0)
166		return rc;
167
168	/* Power up SerDes interface */
169	rc = phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
170	if (rc < 0)
171		return rc;
172
173	/* Select copper register set */
174	val &= ~BCM54XX_SHD_MODE_1000BX;
175	rc = bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, val);
176	if (rc < 0)
177		return rc;
178
179	/* Power up copper interface */
180	return phy_clear_bits(phydev, MII_BMCR, BMCR_PDOWN);
181}
182
183/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
184static int bcm50610_a0_workaround(struct phy_device *phydev)
185{
186	int err;
187
188	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH0,
189				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
190				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
191	if (err < 0)
192		return err;
193
194	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_AADJ1CH3,
195				MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
196	if (err < 0)
197		return err;
198
199	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75,
200				MII_BCM54XX_EXP_EXP75_VDACCTRL);
201	if (err < 0)
202		return err;
203
204	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP96,
205				MII_BCM54XX_EXP_EXP96_MYST);
206	if (err < 0)
207		return err;
208
209	err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP97,
210				MII_BCM54XX_EXP_EXP97_MYST);
211
212	return err;
213}
214
215static int bcm54xx_phydsp_config(struct phy_device *phydev)
216{
217	int err, err2;
218
219	/* Enable the SMDSP clock */
220	err = bcm54xx_auxctl_write(phydev,
221				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
222				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
223				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
224	if (err < 0)
225		return err;
226
227	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
228	    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
229		/* Clear bit 9 to fix a phy interop issue. */
230		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08,
231					MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
232		if (err < 0)
233			goto error;
234
235		if (phydev->drv->phy_id == PHY_ID_BCM50610) {
236			err = bcm50610_a0_workaround(phydev);
237			if (err < 0)
238				goto error;
239		}
240	}
241
242	if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
243		int val;
244
245		val = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP75);
246		if (val < 0)
247			goto error;
248
249		val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
250		err = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP75, val);
251	}
252
253error:
254	/* Disable the SMDSP clock */
255	err2 = bcm54xx_auxctl_write(phydev,
256				    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
257				    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
258
259	/* Return the first error reported. */
260	return err ? err : err2;
261}
262
263static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
264{
265	u32 orig;
266	int val;
267	bool clk125en = true;
268
269	/* Abort if we are using an untested phy. */
270	if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
271	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
272	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M &&
273	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E &&
274	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 &&
275	    BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811)
276		return;
277
278	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
279	if (val < 0)
280		return;
281
282	orig = val;
283
284	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
285	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
286	    BRCM_PHY_REV(phydev) >= 0x3) {
287		/*
288		 * Here, bit 0 _disables_ CLK125 when set.
289		 * This bit is set by default.
290		 */
291		clk125en = false;
292	} else {
293		if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
294			if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) {
295				/* Here, bit 0 _enables_ CLK125 when set */
296				val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
297			}
298			clk125en = false;
299		}
300	}
301
302	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
303		val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
304	else
305		val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
306
307	if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) {
308		if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E ||
309		    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 ||
310		    BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811)
311			val |= BCM54XX_SHD_SCR3_RXCTXC_DIS;
312		else
313			val |= BCM54XX_SHD_SCR3_TRDDAPD;
314	}
315
316	if (orig != val)
317		bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val);
318
319	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD);
320	if (val < 0)
321		return;
322
323	orig = val;
324
325	if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
326		val |= BCM54XX_SHD_APD_EN;
327	else
328		val &= ~BCM54XX_SHD_APD_EN;
329
330	if (orig != val)
331		bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
332}
333
334static void bcm54xx_ptp_stop(struct phy_device *phydev)
335{
336	struct bcm54xx_phy_priv *priv = phydev->priv;
337
338	if (priv->ptp)
339		bcm_ptp_stop(priv->ptp);
340}
341
342static void bcm54xx_ptp_config_init(struct phy_device *phydev)
343{
344	struct bcm54xx_phy_priv *priv = phydev->priv;
345
346	if (priv->ptp)
347		bcm_ptp_config_init(phydev);
348}
349
350static int bcm54xx_config_init(struct phy_device *phydev)
351{
352	int reg, err, val;
353
354	reg = phy_read(phydev, MII_BCM54XX_ECR);
355	if (reg < 0)
356		return reg;
357
358	/* Mask interrupts globally.  */
359	reg |= MII_BCM54XX_ECR_IM;
360	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
361	if (err < 0)
362		return err;
363
364	/* Unmask events we are interested in.  */
365	reg = ~(MII_BCM54XX_INT_DUPLEX |
366		MII_BCM54XX_INT_SPEED |
367		MII_BCM54XX_INT_LINK);
368	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
369	if (err < 0)
370		return err;
371
372	if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
373	     BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
374	    (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
375		bcm_phy_write_shadow(phydev, BCM54XX_SHD_RGMII_MODE, 0);
376
377	bcm54xx_adjust_rxrefclk(phydev);
378
379	switch (BRCM_PHY_MODEL(phydev)) {
380	case PHY_ID_BCM50610:
381	case PHY_ID_BCM50610M:
382		err = bcm54xx_config_clock_delay(phydev);
383		break;
384	case PHY_ID_BCM54210E:
385		err = bcm54210e_config_init(phydev);
386		break;
387	case PHY_ID_BCM54612E:
388		err = bcm54612e_config_init(phydev);
389		break;
390	case PHY_ID_BCM54616S:
391		err = bcm54616s_config_init(phydev);
392		break;
393	case PHY_ID_BCM54810:
394		/* For BCM54810, we need to disable BroadR-Reach function */
395		val = bcm_phy_read_exp(phydev,
396				       BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
397		val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
398		err = bcm_phy_write_exp(phydev,
399					BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
400					val);
401		break;
402	}
403	if (err)
404		return err;
405
406	bcm54xx_phydsp_config(phydev);
407
408	/* For non-SFP setups, encode link speed into LED1 and LED3 pair
409	 * (green/amber).
410	 * Also flash these two LEDs on activity. This means configuring
411	 * them for MULTICOLOR and encoding link/activity into them.
412	 * Don't do this for devices on an SFP module, since some of these
413	 * use the LED outputs to control the SFP LOS signal, and changing
414	 * these settings will cause LOS to malfunction.
415	 */
416	if (!phy_on_sfp(phydev)) {
417		val = BCM54XX_SHD_LEDS1_LED1(BCM_LED_SRC_MULTICOLOR1) |
418			BCM54XX_SHD_LEDS1_LED3(BCM_LED_SRC_MULTICOLOR1);
419		bcm_phy_write_shadow(phydev, BCM54XX_SHD_LEDS1, val);
420
421		val = BCM_LED_MULTICOLOR_IN_PHASE |
422			BCM54XX_SHD_LEDS1_LED1(BCM_LED_MULTICOLOR_LINK_ACT) |
423			BCM54XX_SHD_LEDS1_LED3(BCM_LED_MULTICOLOR_LINK_ACT);
424		bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
425	}
426
427	bcm54xx_ptp_config_init(phydev);
428
429	/* Acknowledge any left over interrupt and charge the device for
430	 * wake-up.
431	 */
432	err = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS);
433	if (err < 0)
434		return err;
435
436	if (err)
437		pm_wakeup_event(&phydev->mdio.dev, 0);
438
439	return 0;
440}
441
442static int bcm54xx_iddq_set(struct phy_device *phydev, bool enable)
443{
444	int ret = 0;
445
446	if (!(phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND))
447		return ret;
448
449	ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL);
450	if (ret < 0)
451		goto out;
452
453	if (enable)
454		ret |= BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP;
455	else
456		ret &= ~(BCM54XX_TOP_MISC_IDDQ_SR | BCM54XX_TOP_MISC_IDDQ_LP);
457
458	ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_IDDQ_CTRL, ret);
459out:
460	return ret;
461}
462
463static int bcm54xx_set_wakeup_irq(struct phy_device *phydev, bool state)
464{
465	struct bcm54xx_phy_priv *priv = phydev->priv;
466	int ret = 0;
467
468	if (!bcm54xx_phy_can_wakeup(phydev))
469		return ret;
470
471	if (priv->wake_irq_enabled != state) {
472		if (state)
473			ret = enable_irq_wake(priv->wake_irq);
474		else
475			ret = disable_irq_wake(priv->wake_irq);
476		priv->wake_irq_enabled = state;
477	}
478
479	return ret;
480}
481
482static int bcm54xx_suspend(struct phy_device *phydev)
483{
484	int ret = 0;
485
486	bcm54xx_ptp_stop(phydev);
487
488	/* Acknowledge any Wake-on-LAN interrupt prior to suspend */
489	ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS);
490	if (ret < 0)
491		return ret;
492
493	if (phydev->wol_enabled)
494		return bcm54xx_set_wakeup_irq(phydev, true);
495
496	/* We cannot use a read/modify/write here otherwise the PHY gets into
497	 * a bad state where its LEDs keep flashing, thus defeating the purpose
498	 * of low power mode.
499	 */
500	ret = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
501	if (ret < 0)
502		return ret;
503
504	return bcm54xx_iddq_set(phydev, true);
505}
506
507static int bcm54xx_resume(struct phy_device *phydev)
508{
509	int ret = 0;
510
511	if (phydev->wol_enabled) {
512		ret = bcm54xx_set_wakeup_irq(phydev, false);
513		if (ret)
514			return ret;
515	}
516
517	ret = bcm54xx_iddq_set(phydev, false);
518	if (ret < 0)
519		return ret;
520
521	/* Writes to register other than BMCR would be ignored
522	 * unless we clear the PDOWN bit first
523	 */
524	ret = genphy_resume(phydev);
525	if (ret < 0)
526		return ret;
527
528	/* Upon exiting power down, the PHY remains in an internal reset state
529	 * for 40us
530	 */
531	fsleep(40);
532
533	/* Issue a soft reset after clearing the power down bit
534	 * and before doing any other configuration.
535	 */
536	if (phydev->dev_flags & PHY_BRCM_IDDQ_SUSPEND) {
537		ret = genphy_soft_reset(phydev);
538		if (ret < 0)
539			return ret;
540	}
541
542	return bcm54xx_config_init(phydev);
543}
544
545static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
546{
547	return -EOPNOTSUPP;
548}
549
550static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
551			      u16 val)
552{
553	return -EOPNOTSUPP;
554}
555
556static int bcm54811_config_init(struct phy_device *phydev)
557{
558	int err, reg;
559
560	/* Disable BroadR-Reach function. */
561	reg = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
562	reg &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
563	err = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
564				reg);
565	if (err < 0)
566		return err;
567
568	err = bcm54xx_config_init(phydev);
569
570	/* Enable CLK125 MUX on LED4 if ref clock is enabled. */
571	if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) {
572		reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0);
573		err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0,
574					BCM54612E_LED4_CLK125OUT_EN | reg);
575		if (err < 0)
576			return err;
577	}
578
579	return err;
580}
581
582static int bcm5481_config_aneg(struct phy_device *phydev)
583{
584	struct device_node *np = phydev->mdio.dev.of_node;
585	int ret;
586
587	/* Aneg firstly. */
588	ret = genphy_config_aneg(phydev);
589
590	/* Then we can set up the delay. */
591	bcm54xx_config_clock_delay(phydev);
592
593	if (of_property_read_bool(np, "enet-phy-lane-swap")) {
594		/* Lane Swap - Undocumented register...magic! */
595		ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
596					0x11B);
597		if (ret < 0)
598			return ret;
599	}
600
601	return ret;
602}
603
604struct bcm54616s_phy_priv {
605	bool mode_1000bx_en;
606};
607
608static int bcm54616s_probe(struct phy_device *phydev)
609{
610	struct bcm54616s_phy_priv *priv;
611	int val;
612
613	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
614	if (!priv)
615		return -ENOMEM;
616
617	phydev->priv = priv;
618
619	val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE);
620	if (val < 0)
621		return val;
622
623	/* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0]
624	 * is 01b, and the link between PHY and its link partner can be
625	 * either 1000Base-X or 100Base-FX.
626	 * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX
627	 * support is still missing as of now.
628	 */
629	if ((val & BCM54XX_SHD_INTF_SEL_MASK) == BCM54XX_SHD_INTF_SEL_RGMII) {
630		val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL);
631		if (val < 0)
632			return val;
633
634		/* Bit 0 of the SerDes 100-FX Control register, when set
635		 * to 1, sets the MII/RGMII -> 100BASE-FX configuration.
636		 * When this bit is set to 0, it sets the GMII/RGMII ->
637		 * 1000BASE-X configuration.
638		 */
639		if (!(val & BCM54616S_100FX_MODE))
640			priv->mode_1000bx_en = true;
641
642		phydev->port = PORT_FIBRE;
643	}
644
645	return 0;
646}
647
648static int bcm54616s_config_aneg(struct phy_device *phydev)
649{
650	struct bcm54616s_phy_priv *priv = phydev->priv;
651	int ret;
652
653	/* Aneg firstly. */
654	if (priv->mode_1000bx_en)
655		ret = genphy_c37_config_aneg(phydev);
656	else
657		ret = genphy_config_aneg(phydev);
658
659	/* Then we can set up the delay. */
660	bcm54xx_config_clock_delay(phydev);
661
662	return ret;
663}
664
665static int bcm54616s_read_status(struct phy_device *phydev)
666{
667	struct bcm54616s_phy_priv *priv = phydev->priv;
668	int err;
669
670	if (priv->mode_1000bx_en)
671		err = genphy_c37_read_status(phydev);
672	else
673		err = genphy_read_status(phydev);
674
675	return err;
676}
677
678static int brcm_fet_config_init(struct phy_device *phydev)
679{
680	int reg, err, err2, brcmtest;
681
682	/* Reset the PHY to bring it to a known state. */
683	err = phy_write(phydev, MII_BMCR, BMCR_RESET);
684	if (err < 0)
685		return err;
686
687	/* The datasheet indicates the PHY needs up to 1us to complete a reset,
688	 * build some slack here.
689	 */
690	usleep_range(1000, 2000);
691
692	/* The PHY requires 65 MDC clock cycles to complete a write operation
693	 * and turnaround the line properly.
694	 *
695	 * We ignore -EIO here as the MDIO controller (e.g.: mdio-bcm-unimac)
696	 * may flag the lack of turn-around as a read failure. This is
697	 * particularly true with this combination since the MDIO controller
698	 * only used 64 MDC cycles. This is not a critical failure in this
699	 * specific case and it has no functional impact otherwise, so we let
700	 * that one go through. If there is a genuine bus error, the next read
701	 * of MII_BRCM_FET_INTREG will error out.
702	 */
703	err = phy_read(phydev, MII_BMCR);
704	if (err < 0 && err != -EIO)
705		return err;
706
707	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
708	if (reg < 0)
709		return reg;
710
711	/* Unmask events we are interested in and mask interrupts globally. */
712	reg = MII_BRCM_FET_IR_DUPLEX_EN |
713	      MII_BRCM_FET_IR_SPEED_EN |
714	      MII_BRCM_FET_IR_LINK_EN |
715	      MII_BRCM_FET_IR_ENABLE |
716	      MII_BRCM_FET_IR_MASK;
717
718	err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
719	if (err < 0)
720		return err;
721
722	/* Enable shadow register access */
723	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
724	if (brcmtest < 0)
725		return brcmtest;
726
727	reg = brcmtest | MII_BRCM_FET_BT_SRE;
728
729	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
730	if (err < 0)
731		return err;
732
733	/* Set the LED mode */
734	reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
735	if (reg < 0) {
736		err = reg;
737		goto done;
738	}
739
740	reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
741	reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
742
743	err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
744	if (err < 0)
745		goto done;
746
747	/* Enable auto MDIX */
748	err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
749			   MII_BRCM_FET_SHDW_MC_FAME);
750	if (err < 0)
751		goto done;
752
753	if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
754		/* Enable auto power down */
755		err = phy_set_bits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
756				   MII_BRCM_FET_SHDW_AS2_APDE);
757	}
758
759done:
760	/* Disable shadow register access */
761	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
762	if (!err)
763		err = err2;
764
765	return err;
766}
767
768static int brcm_fet_ack_interrupt(struct phy_device *phydev)
769{
770	int reg;
771
772	/* Clear pending interrupts.  */
773	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
774	if (reg < 0)
775		return reg;
776
777	return 0;
778}
779
780static int brcm_fet_config_intr(struct phy_device *phydev)
781{
782	int reg, err;
783
784	reg = phy_read(phydev, MII_BRCM_FET_INTREG);
785	if (reg < 0)
786		return reg;
787
788	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
789		err = brcm_fet_ack_interrupt(phydev);
790		if (err)
791			return err;
792
793		reg &= ~MII_BRCM_FET_IR_MASK;
794		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
795	} else {
796		reg |= MII_BRCM_FET_IR_MASK;
797		err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
798		if (err)
799			return err;
800
801		err = brcm_fet_ack_interrupt(phydev);
802	}
803
804	return err;
805}
806
807static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
808{
809	int irq_status;
810
811	irq_status = phy_read(phydev, MII_BRCM_FET_INTREG);
812	if (irq_status < 0) {
813		phy_error(phydev);
814		return IRQ_NONE;
815	}
816
817	if (irq_status == 0)
818		return IRQ_NONE;
819
820	phy_trigger_machine(phydev);
821
822	return IRQ_HANDLED;
823}
824
825static int brcm_fet_suspend(struct phy_device *phydev)
826{
827	int reg, err, err2, brcmtest;
828
829	/* We cannot use a read/modify/write here otherwise the PHY continues
830	 * to drive LEDs which defeats the purpose of low power mode.
831	 */
832	err = phy_write(phydev, MII_BMCR, BMCR_PDOWN);
833	if (err < 0)
834		return err;
835
836	/* Enable shadow register access */
837	brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
838	if (brcmtest < 0)
839		return brcmtest;
840
841	reg = brcmtest | MII_BRCM_FET_BT_SRE;
842
843	err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
844	if (err < 0)
845		return err;
846
847	/* Set standby mode */
848	err = phy_modify(phydev, MII_BRCM_FET_SHDW_AUXMODE4,
849			 MII_BRCM_FET_SHDW_AM4_STANDBY,
850			 MII_BRCM_FET_SHDW_AM4_STANDBY);
851
852	/* Disable shadow register access */
853	err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
854	if (!err)
855		err = err2;
856
857	return err;
858}
859
860static void bcm54xx_phy_get_wol(struct phy_device *phydev,
861				struct ethtool_wolinfo *wol)
862{
863	/* We cannot wake-up if we do not have a dedicated PHY interrupt line
864	 * or an out of band GPIO descriptor for wake-up. Zeroing
865	 * wol->supported allows the caller (MAC driver) to play through and
866	 * offer its own Wake-on-LAN scheme if available.
867	 */
868	if (!bcm54xx_phy_can_wakeup(phydev)) {
869		wol->supported = 0;
870		return;
871	}
872
873	bcm_phy_get_wol(phydev, wol);
874}
875
876static int bcm54xx_phy_set_wol(struct phy_device *phydev,
877			       struct ethtool_wolinfo *wol)
878{
879	int ret;
880
881	/* We cannot wake-up if we do not have a dedicated PHY interrupt line
882	 * or an out of band GPIO descriptor for wake-up. Returning -EOPNOTSUPP
883	 * allows the caller (MAC driver) to play through and offer its own
884	 * Wake-on-LAN scheme if available.
885	 */
886	if (!bcm54xx_phy_can_wakeup(phydev))
887		return -EOPNOTSUPP;
888
889	ret = bcm_phy_set_wol(phydev, wol);
890	if (ret < 0)
891		return ret;
892
893	return 0;
894}
895
896static int bcm54xx_phy_probe(struct phy_device *phydev)
897{
898	struct bcm54xx_phy_priv *priv;
899	struct gpio_desc *wakeup_gpio;
900	int ret = 0;
901
902	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
903	if (!priv)
904		return -ENOMEM;
905
906	priv->wake_irq = -ENXIO;
907
908	phydev->priv = priv;
909
910	priv->stats = devm_kcalloc(&phydev->mdio.dev,
911				   bcm_phy_get_sset_count(phydev), sizeof(u64),
912				   GFP_KERNEL);
913	if (!priv->stats)
914		return -ENOMEM;
915
916	priv->ptp = bcm_ptp_probe(phydev);
917	if (IS_ERR(priv->ptp))
918		return PTR_ERR(priv->ptp);
919
920	/* We cannot utilize the _optional variant here since we want to know
921	 * whether the GPIO descriptor exists or not to advertise Wake-on-LAN
922	 * support or not.
923	 */
924	wakeup_gpio = devm_gpiod_get(&phydev->mdio.dev, "wakeup", GPIOD_IN);
925	if (PTR_ERR(wakeup_gpio) == -EPROBE_DEFER)
926		return PTR_ERR(wakeup_gpio);
927
928	if (!IS_ERR(wakeup_gpio)) {
929		priv->wake_irq = gpiod_to_irq(wakeup_gpio);
930
931		/* Dummy interrupt handler which is not enabled but is provided
932		 * in order for the interrupt descriptor to be fully set-up.
933		 */
934		ret = devm_request_irq(&phydev->mdio.dev, priv->wake_irq,
935				       bcm_phy_wol_isr,
936				       IRQF_TRIGGER_LOW | IRQF_NO_AUTOEN,
937				       dev_name(&phydev->mdio.dev), phydev);
938		if (ret)
939			return ret;
940	}
941
942	/* If we do not have a main interrupt or a side-band wake-up interrupt,
943	 * then the device cannot be marked as wake-up capable.
944	 */
945	if (!bcm54xx_phy_can_wakeup(phydev))
946		return 0;
947
948	return device_init_wakeup(&phydev->mdio.dev, true);
949}
950
951static void bcm54xx_get_stats(struct phy_device *phydev,
952			      struct ethtool_stats *stats, u64 *data)
953{
954	struct bcm54xx_phy_priv *priv = phydev->priv;
955
956	bcm_phy_get_stats(phydev, priv->stats, stats, data);
957}
958
959static void bcm54xx_link_change_notify(struct phy_device *phydev)
960{
961	u16 mask = MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE |
962		   MII_BCM54XX_EXP_EXP08_FORCE_DAC_WAKE;
963	int ret;
964
965	if (phydev->state != PHY_RUNNING)
966		return;
967
968	/* Don't change the DAC wake settings if auto power down
969	 * is not requested.
970	 */
971	if (!(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
972		return;
973
974	ret = bcm_phy_read_exp(phydev, MII_BCM54XX_EXP_EXP08);
975	if (ret < 0)
976		return;
977
978	/* Enable/disable 10BaseT auto and forced early DAC wake depending
979	 * on the negotiated speed, those settings should only be done
980	 * for 10Mbits/sec.
981	 */
982	if (phydev->speed == SPEED_10)
983		ret |= mask;
984	else
985		ret &= ~mask;
986	bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_EXP08, ret);
987}
988
989static struct phy_driver broadcom_drivers[] = {
990{
991	.phy_id		= PHY_ID_BCM5411,
992	.phy_id_mask	= 0xfffffff0,
993	.name		= "Broadcom BCM5411",
994	/* PHY_GBIT_FEATURES */
995	.get_sset_count	= bcm_phy_get_sset_count,
996	.get_strings	= bcm_phy_get_strings,
997	.get_stats	= bcm54xx_get_stats,
998	.probe		= bcm54xx_phy_probe,
999	.config_init	= bcm54xx_config_init,
1000	.config_intr	= bcm_phy_config_intr,
1001	.handle_interrupt = bcm_phy_handle_interrupt,
1002	.link_change_notify	= bcm54xx_link_change_notify,
1003}, {
1004	.phy_id		= PHY_ID_BCM5421,
1005	.phy_id_mask	= 0xfffffff0,
1006	.name		= "Broadcom BCM5421",
1007	/* PHY_GBIT_FEATURES */
1008	.get_sset_count	= bcm_phy_get_sset_count,
1009	.get_strings	= bcm_phy_get_strings,
1010	.get_stats	= bcm54xx_get_stats,
1011	.probe		= bcm54xx_phy_probe,
1012	.config_init	= bcm54xx_config_init,
1013	.config_intr	= bcm_phy_config_intr,
1014	.handle_interrupt = bcm_phy_handle_interrupt,
1015	.link_change_notify	= bcm54xx_link_change_notify,
1016}, {
1017	.phy_id		= PHY_ID_BCM54210E,
1018	.phy_id_mask	= 0xfffffff0,
1019	.name		= "Broadcom BCM54210E",
1020	/* PHY_GBIT_FEATURES */
1021	.flags		= PHY_ALWAYS_CALL_SUSPEND,
1022	.get_sset_count	= bcm_phy_get_sset_count,
1023	.get_strings	= bcm_phy_get_strings,
1024	.get_stats	= bcm54xx_get_stats,
1025	.probe		= bcm54xx_phy_probe,
1026	.config_init	= bcm54xx_config_init,
1027	.config_intr	= bcm_phy_config_intr,
1028	.handle_interrupt = bcm_phy_handle_interrupt,
1029	.link_change_notify	= bcm54xx_link_change_notify,
1030	.suspend	= bcm54xx_suspend,
1031	.resume		= bcm54xx_resume,
1032	.get_wol	= bcm54xx_phy_get_wol,
1033	.set_wol	= bcm54xx_phy_set_wol,
1034	.led_brightness_set	= bcm_phy_led_brightness_set,
1035}, {
1036	.phy_id		= PHY_ID_BCM5461,
1037	.phy_id_mask	= 0xfffffff0,
1038	.name		= "Broadcom BCM5461",
1039	/* PHY_GBIT_FEATURES */
1040	.get_sset_count	= bcm_phy_get_sset_count,
1041	.get_strings	= bcm_phy_get_strings,
1042	.get_stats	= bcm54xx_get_stats,
1043	.probe		= bcm54xx_phy_probe,
1044	.config_init	= bcm54xx_config_init,
1045	.config_intr	= bcm_phy_config_intr,
1046	.handle_interrupt = bcm_phy_handle_interrupt,
1047	.link_change_notify	= bcm54xx_link_change_notify,
1048	.led_brightness_set	= bcm_phy_led_brightness_set,
1049}, {
1050	.phy_id		= PHY_ID_BCM54612E,
1051	.phy_id_mask	= 0xfffffff0,
1052	.name		= "Broadcom BCM54612E",
1053	/* PHY_GBIT_FEATURES */
1054	.get_sset_count	= bcm_phy_get_sset_count,
1055	.get_strings	= bcm_phy_get_strings,
1056	.get_stats	= bcm54xx_get_stats,
1057	.probe		= bcm54xx_phy_probe,
1058	.config_init	= bcm54xx_config_init,
1059	.config_intr	= bcm_phy_config_intr,
1060	.handle_interrupt = bcm_phy_handle_interrupt,
1061	.link_change_notify	= bcm54xx_link_change_notify,
1062	.led_brightness_set	= bcm_phy_led_brightness_set,
1063}, {
1064	.phy_id		= PHY_ID_BCM54616S,
1065	.phy_id_mask	= 0xfffffff0,
1066	.name		= "Broadcom BCM54616S",
1067	/* PHY_GBIT_FEATURES */
1068	.soft_reset     = genphy_soft_reset,
1069	.config_init	= bcm54xx_config_init,
1070	.config_aneg	= bcm54616s_config_aneg,
1071	.config_intr	= bcm_phy_config_intr,
1072	.handle_interrupt = bcm_phy_handle_interrupt,
1073	.read_status	= bcm54616s_read_status,
1074	.probe		= bcm54616s_probe,
1075	.link_change_notify	= bcm54xx_link_change_notify,
1076	.led_brightness_set	= bcm_phy_led_brightness_set,
1077}, {
1078	.phy_id		= PHY_ID_BCM5464,
1079	.phy_id_mask	= 0xfffffff0,
1080	.name		= "Broadcom BCM5464",
1081	/* PHY_GBIT_FEATURES */
1082	.get_sset_count	= bcm_phy_get_sset_count,
1083	.get_strings	= bcm_phy_get_strings,
1084	.get_stats	= bcm54xx_get_stats,
1085	.probe		= bcm54xx_phy_probe,
1086	.config_init	= bcm54xx_config_init,
1087	.config_intr	= bcm_phy_config_intr,
1088	.handle_interrupt = bcm_phy_handle_interrupt,
1089	.suspend	= genphy_suspend,
1090	.resume		= genphy_resume,
1091	.link_change_notify	= bcm54xx_link_change_notify,
1092	.led_brightness_set	= bcm_phy_led_brightness_set,
1093}, {
1094	.phy_id		= PHY_ID_BCM5481,
1095	.phy_id_mask	= 0xfffffff0,
1096	.name		= "Broadcom BCM5481",
1097	/* PHY_GBIT_FEATURES */
1098	.get_sset_count	= bcm_phy_get_sset_count,
1099	.get_strings	= bcm_phy_get_strings,
1100	.get_stats	= bcm54xx_get_stats,
1101	.probe		= bcm54xx_phy_probe,
1102	.config_init	= bcm54xx_config_init,
1103	.config_aneg	= bcm5481_config_aneg,
1104	.config_intr	= bcm_phy_config_intr,
1105	.handle_interrupt = bcm_phy_handle_interrupt,
1106	.link_change_notify	= bcm54xx_link_change_notify,
1107	.led_brightness_set	= bcm_phy_led_brightness_set,
1108}, {
1109	.phy_id         = PHY_ID_BCM54810,
1110	.phy_id_mask    = 0xfffffff0,
1111	.name           = "Broadcom BCM54810",
1112	/* PHY_GBIT_FEATURES */
1113	.get_sset_count	= bcm_phy_get_sset_count,
1114	.get_strings	= bcm_phy_get_strings,
1115	.get_stats	= bcm54xx_get_stats,
1116	.probe		= bcm54xx_phy_probe,
1117	.read_mmd	= bcm54810_read_mmd,
1118	.write_mmd	= bcm54810_write_mmd,
1119	.config_init    = bcm54xx_config_init,
1120	.config_aneg    = bcm5481_config_aneg,
1121	.config_intr    = bcm_phy_config_intr,
1122	.handle_interrupt = bcm_phy_handle_interrupt,
1123	.suspend	= bcm54xx_suspend,
1124	.resume		= bcm54xx_resume,
1125	.link_change_notify	= bcm54xx_link_change_notify,
1126	.led_brightness_set	= bcm_phy_led_brightness_set,
1127}, {
1128	.phy_id         = PHY_ID_BCM54811,
1129	.phy_id_mask    = 0xfffffff0,
1130	.name           = "Broadcom BCM54811",
1131	/* PHY_GBIT_FEATURES */
1132	.get_sset_count	= bcm_phy_get_sset_count,
1133	.get_strings	= bcm_phy_get_strings,
1134	.get_stats	= bcm54xx_get_stats,
1135	.probe		= bcm54xx_phy_probe,
1136	.config_init    = bcm54811_config_init,
1137	.config_aneg    = bcm5481_config_aneg,
1138	.config_intr    = bcm_phy_config_intr,
1139	.handle_interrupt = bcm_phy_handle_interrupt,
1140	.suspend	= bcm54xx_suspend,
1141	.resume		= bcm54xx_resume,
1142	.link_change_notify	= bcm54xx_link_change_notify,
1143	.led_brightness_set	= bcm_phy_led_brightness_set,
1144}, {
1145	.phy_id		= PHY_ID_BCM5482,
1146	.phy_id_mask	= 0xfffffff0,
1147	.name		= "Broadcom BCM5482",
1148	/* PHY_GBIT_FEATURES */
1149	.get_sset_count	= bcm_phy_get_sset_count,
1150	.get_strings	= bcm_phy_get_strings,
1151	.get_stats	= bcm54xx_get_stats,
1152	.probe		= bcm54xx_phy_probe,
1153	.config_init	= bcm54xx_config_init,
1154	.config_intr	= bcm_phy_config_intr,
1155	.handle_interrupt = bcm_phy_handle_interrupt,
1156	.link_change_notify	= bcm54xx_link_change_notify,
1157	.led_brightness_set	= bcm_phy_led_brightness_set,
1158}, {
1159	.phy_id		= PHY_ID_BCM50610,
1160	.phy_id_mask	= 0xfffffff0,
1161	.name		= "Broadcom BCM50610",
1162	/* PHY_GBIT_FEATURES */
1163	.get_sset_count	= bcm_phy_get_sset_count,
1164	.get_strings	= bcm_phy_get_strings,
1165	.get_stats	= bcm54xx_get_stats,
1166	.probe		= bcm54xx_phy_probe,
1167	.config_init	= bcm54xx_config_init,
1168	.config_intr	= bcm_phy_config_intr,
1169	.handle_interrupt = bcm_phy_handle_interrupt,
1170	.link_change_notify	= bcm54xx_link_change_notify,
1171	.suspend	= bcm54xx_suspend,
1172	.resume		= bcm54xx_resume,
1173	.led_brightness_set	= bcm_phy_led_brightness_set,
1174}, {
1175	.phy_id		= PHY_ID_BCM50610M,
1176	.phy_id_mask	= 0xfffffff0,
1177	.name		= "Broadcom BCM50610M",
1178	/* PHY_GBIT_FEATURES */
1179	.get_sset_count	= bcm_phy_get_sset_count,
1180	.get_strings	= bcm_phy_get_strings,
1181	.get_stats	= bcm54xx_get_stats,
1182	.probe		= bcm54xx_phy_probe,
1183	.config_init	= bcm54xx_config_init,
1184	.config_intr	= bcm_phy_config_intr,
1185	.handle_interrupt = bcm_phy_handle_interrupt,
1186	.link_change_notify	= bcm54xx_link_change_notify,
1187	.suspend	= bcm54xx_suspend,
1188	.resume		= bcm54xx_resume,
1189	.led_brightness_set	= bcm_phy_led_brightness_set,
1190}, {
1191	.phy_id		= PHY_ID_BCM57780,
1192	.phy_id_mask	= 0xfffffff0,
1193	.name		= "Broadcom BCM57780",
1194	/* PHY_GBIT_FEATURES */
1195	.get_sset_count	= bcm_phy_get_sset_count,
1196	.get_strings	= bcm_phy_get_strings,
1197	.get_stats	= bcm54xx_get_stats,
1198	.probe		= bcm54xx_phy_probe,
1199	.config_init	= bcm54xx_config_init,
1200	.config_intr	= bcm_phy_config_intr,
1201	.handle_interrupt = bcm_phy_handle_interrupt,
1202	.link_change_notify	= bcm54xx_link_change_notify,
1203	.led_brightness_set	= bcm_phy_led_brightness_set,
1204}, {
1205	.phy_id		= PHY_ID_BCMAC131,
1206	.phy_id_mask	= 0xfffffff0,
1207	.name		= "Broadcom BCMAC131",
1208	/* PHY_BASIC_FEATURES */
1209	.config_init	= brcm_fet_config_init,
1210	.config_intr	= brcm_fet_config_intr,
1211	.handle_interrupt = brcm_fet_handle_interrupt,
1212	.suspend	= brcm_fet_suspend,
1213	.resume		= brcm_fet_config_init,
1214}, {
1215	.phy_id		= PHY_ID_BCM5241,
1216	.phy_id_mask	= 0xfffffff0,
1217	.name		= "Broadcom BCM5241",
1218	/* PHY_BASIC_FEATURES */
1219	.config_init	= brcm_fet_config_init,
1220	.config_intr	= brcm_fet_config_intr,
1221	.handle_interrupt = brcm_fet_handle_interrupt,
1222	.suspend	= brcm_fet_suspend,
1223	.resume		= brcm_fet_config_init,
1224}, {
1225	.phy_id		= PHY_ID_BCM5395,
1226	.phy_id_mask	= 0xfffffff0,
1227	.name		= "Broadcom BCM5395",
1228	.flags		= PHY_IS_INTERNAL,
1229	/* PHY_GBIT_FEATURES */
1230	.get_sset_count	= bcm_phy_get_sset_count,
1231	.get_strings	= bcm_phy_get_strings,
1232	.get_stats	= bcm54xx_get_stats,
1233	.probe		= bcm54xx_phy_probe,
1234	.link_change_notify	= bcm54xx_link_change_notify,
1235	.led_brightness_set	= bcm_phy_led_brightness_set,
1236}, {
1237	.phy_id		= PHY_ID_BCM53125,
1238	.phy_id_mask	= 0xfffffff0,
1239	.name		= "Broadcom BCM53125",
1240	.flags		= PHY_IS_INTERNAL,
1241	/* PHY_GBIT_FEATURES */
1242	.get_sset_count	= bcm_phy_get_sset_count,
1243	.get_strings	= bcm_phy_get_strings,
1244	.get_stats	= bcm54xx_get_stats,
1245	.probe		= bcm54xx_phy_probe,
1246	.config_init	= bcm54xx_config_init,
1247	.config_intr	= bcm_phy_config_intr,
1248	.handle_interrupt = bcm_phy_handle_interrupt,
1249	.link_change_notify	= bcm54xx_link_change_notify,
1250	.led_brightness_set	= bcm_phy_led_brightness_set,
1251}, {
1252	.phy_id		= PHY_ID_BCM53128,
1253	.phy_id_mask	= 0xfffffff0,
1254	.name		= "Broadcom BCM53128",
1255	.flags		= PHY_IS_INTERNAL,
1256	/* PHY_GBIT_FEATURES */
1257	.get_sset_count	= bcm_phy_get_sset_count,
1258	.get_strings	= bcm_phy_get_strings,
1259	.get_stats	= bcm54xx_get_stats,
1260	.probe		= bcm54xx_phy_probe,
1261	.config_init	= bcm54xx_config_init,
1262	.config_intr	= bcm_phy_config_intr,
1263	.handle_interrupt = bcm_phy_handle_interrupt,
1264	.link_change_notify	= bcm54xx_link_change_notify,
1265	.led_brightness_set	= bcm_phy_led_brightness_set,
1266}, {
1267	.phy_id         = PHY_ID_BCM89610,
1268	.phy_id_mask    = 0xfffffff0,
1269	.name           = "Broadcom BCM89610",
1270	/* PHY_GBIT_FEATURES */
1271	.get_sset_count	= bcm_phy_get_sset_count,
1272	.get_strings	= bcm_phy_get_strings,
1273	.get_stats	= bcm54xx_get_stats,
1274	.probe		= bcm54xx_phy_probe,
1275	.config_init    = bcm54xx_config_init,
1276	.config_intr    = bcm_phy_config_intr,
1277	.handle_interrupt = bcm_phy_handle_interrupt,
1278	.link_change_notify	= bcm54xx_link_change_notify,
1279} };
1280
1281module_phy_driver(broadcom_drivers);
1282
1283static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
1284	{ PHY_ID_BCM5411, 0xfffffff0 },
1285	{ PHY_ID_BCM5421, 0xfffffff0 },
1286	{ PHY_ID_BCM54210E, 0xfffffff0 },
1287	{ PHY_ID_BCM5461, 0xfffffff0 },
1288	{ PHY_ID_BCM54612E, 0xfffffff0 },
1289	{ PHY_ID_BCM54616S, 0xfffffff0 },
1290	{ PHY_ID_BCM5464, 0xfffffff0 },
1291	{ PHY_ID_BCM5481, 0xfffffff0 },
1292	{ PHY_ID_BCM54810, 0xfffffff0 },
1293	{ PHY_ID_BCM54811, 0xfffffff0 },
1294	{ PHY_ID_BCM5482, 0xfffffff0 },
1295	{ PHY_ID_BCM50610, 0xfffffff0 },
1296	{ PHY_ID_BCM50610M, 0xfffffff0 },
1297	{ PHY_ID_BCM57780, 0xfffffff0 },
1298	{ PHY_ID_BCMAC131, 0xfffffff0 },
1299	{ PHY_ID_BCM5241, 0xfffffff0 },
1300	{ PHY_ID_BCM5395, 0xfffffff0 },
1301	{ PHY_ID_BCM53125, 0xfffffff0 },
1302	{ PHY_ID_BCM53128, 0xfffffff0 },
1303	{ PHY_ID_BCM89610, 0xfffffff0 },
1304	{ }
1305};
1306
1307MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
1308