cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

marvell-88x2222.c (15780B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Marvell 88x2222 dual-port multi-speed ethernet transceiver.
      4 *
      5 * Supports:
      6 *	XAUI on the host side.
      7 *	1000Base-X or 10GBase-R on the line side.
      8 *	SGMII over 1000Base-X.
      9 */
     10#include <linux/module.h>
     11#include <linux/phy.h>
     12#include <linux/gpio.h>
     13#include <linux/delay.h>
     14#include <linux/mdio.h>
     15#include <linux/marvell_phy.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18#include <linux/of_gpio.h>
     19#include <linux/sfp.h>
     20#include <linux/netdevice.h>
     21
     22/* Port PCS Configuration */
     23#define	MV_PCS_CONFIG		0xF002
     24#define	MV_PCS_HOST_XAUI	0x73
     25#define	MV_PCS_LINE_10GBR	(0x71 << 8)
     26#define	MV_PCS_LINE_1GBX_AN	(0x7B << 8)
     27#define	MV_PCS_LINE_SGMII_AN	(0x7F << 8)
     28
     29/* Port Reset and Power Down */
     30#define	MV_PORT_RST	0xF003
     31#define	MV_LINE_RST_SW	BIT(15)
     32#define	MV_HOST_RST_SW	BIT(7)
     33#define	MV_PORT_RST_SW	(MV_LINE_RST_SW | MV_HOST_RST_SW)
     34
     35/* PMD Receive Signal Detect */
     36#define	MV_RX_SIGNAL_DETECT		0x000A
     37#define	MV_RX_SIGNAL_DETECT_GLOBAL	BIT(0)
     38
     39/* 1000Base-X/SGMII Control Register */
     40#define	MV_1GBX_CTRL		(0x2000 + MII_BMCR)
     41
     42/* 1000BASE-X/SGMII Status Register */
     43#define	MV_1GBX_STAT		(0x2000 + MII_BMSR)
     44
     45/* 1000Base-X Auto-Negotiation Advertisement Register */
     46#define	MV_1GBX_ADVERTISE	(0x2000 + MII_ADVERTISE)
     47
     48/* 1000Base-X PHY Specific Status Register */
     49#define	MV_1GBX_PHY_STAT		0xA003
     50#define	MV_1GBX_PHY_STAT_AN_RESOLVED	BIT(11)
     51#define	MV_1GBX_PHY_STAT_DUPLEX		BIT(13)
     52#define	MV_1GBX_PHY_STAT_SPEED100	BIT(14)
     53#define	MV_1GBX_PHY_STAT_SPEED1000	BIT(15)
     54
     55#define	AUTONEG_TIMEOUT	3
     56
     57struct mv2222_data {
     58	phy_interface_t line_interface;
     59	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
     60	bool sfp_link;
     61};
     62
     63/* SFI PMA transmit enable */
     64static int mv2222_tx_enable(struct phy_device *phydev)
     65{
     66	return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
     67				  MDIO_PMD_TXDIS_GLOBAL);
     68}
     69
     70/* SFI PMA transmit disable */
     71static int mv2222_tx_disable(struct phy_device *phydev)
     72{
     73	return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
     74				MDIO_PMD_TXDIS_GLOBAL);
     75}
     76
     77static int mv2222_soft_reset(struct phy_device *phydev)
     78{
     79	int val, ret;
     80
     81	ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
     82			    MV_PORT_RST_SW);
     83	if (ret < 0)
     84		return ret;
     85
     86	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
     87					 val, !(val & MV_PORT_RST_SW),
     88					 5000, 1000000, true);
     89}
     90
     91static int mv2222_disable_aneg(struct phy_device *phydev)
     92{
     93	int ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
     94				     BMCR_ANENABLE | BMCR_ANRESTART);
     95	if (ret < 0)
     96		return ret;
     97
     98	return mv2222_soft_reset(phydev);
     99}
    100
    101static int mv2222_enable_aneg(struct phy_device *phydev)
    102{
    103	int ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
    104				   BMCR_ANENABLE | BMCR_RESET);
    105	if (ret < 0)
    106		return ret;
    107
    108	return mv2222_soft_reset(phydev);
    109}
    110
    111static int mv2222_set_sgmii_speed(struct phy_device *phydev)
    112{
    113	struct mv2222_data *priv = phydev->priv;
    114
    115	switch (phydev->speed) {
    116	default:
    117	case SPEED_1000:
    118		if ((linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
    119				       priv->supported) ||
    120		     linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
    121				       priv->supported)))
    122			return phy_modify_mmd(phydev, MDIO_MMD_PCS,
    123					      MV_1GBX_CTRL,
    124					      BMCR_SPEED1000 | BMCR_SPEED100,
    125					      BMCR_SPEED1000);
    126
    127		fallthrough;
    128	case SPEED_100:
    129		if ((linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
    130				       priv->supported) ||
    131		     linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
    132				       priv->supported)))
    133			return phy_modify_mmd(phydev, MDIO_MMD_PCS,
    134					      MV_1GBX_CTRL,
    135					      BMCR_SPEED1000 | BMCR_SPEED100,
    136					      BMCR_SPEED100);
    137		fallthrough;
    138	case SPEED_10:
    139		if ((linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
    140				       priv->supported) ||
    141		     linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
    142				       priv->supported)))
    143			return phy_modify_mmd(phydev, MDIO_MMD_PCS,
    144					      MV_1GBX_CTRL,
    145					      BMCR_SPEED1000 | BMCR_SPEED100,
    146					      BMCR_SPEED10);
    147
    148		return -EINVAL;
    149	}
    150}
    151
    152static bool mv2222_is_10g_capable(struct phy_device *phydev)
    153{
    154	struct mv2222_data *priv = phydev->priv;
    155
    156	return (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
    157				  priv->supported) ||
    158		linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
    159				  priv->supported) ||
    160		linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
    161				  priv->supported) ||
    162		linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
    163				  priv->supported) ||
    164		linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
    165				  priv->supported) ||
    166		linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
    167				  priv->supported));
    168}
    169
    170static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
    171{
    172	struct mv2222_data *priv = phydev->priv;
    173
    174	return linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
    175				 priv->supported);
    176}
    177
    178static bool mv2222_is_sgmii_capable(struct phy_device *phydev)
    179{
    180	struct mv2222_data *priv = phydev->priv;
    181
    182	return (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
    183				  priv->supported) ||
    184		linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
    185				  priv->supported) ||
    186		linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
    187				  priv->supported) ||
    188		linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
    189				  priv->supported) ||
    190		linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
    191				  priv->supported) ||
    192		linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
    193				  priv->supported));
    194}
    195
    196static int mv2222_config_line(struct phy_device *phydev)
    197{
    198	struct mv2222_data *priv = phydev->priv;
    199
    200	switch (priv->line_interface) {
    201	case PHY_INTERFACE_MODE_10GBASER:
    202		return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
    203				     MV_PCS_HOST_XAUI | MV_PCS_LINE_10GBR);
    204	case PHY_INTERFACE_MODE_1000BASEX:
    205		return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
    206				     MV_PCS_HOST_XAUI | MV_PCS_LINE_1GBX_AN);
    207	case PHY_INTERFACE_MODE_SGMII:
    208		return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
    209				     MV_PCS_HOST_XAUI | MV_PCS_LINE_SGMII_AN);
    210	default:
    211		return -EINVAL;
    212	}
    213}
    214
    215/* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
    216static int mv2222_swap_line_type(struct phy_device *phydev)
    217{
    218	struct mv2222_data *priv = phydev->priv;
    219	bool changed = false;
    220	int ret;
    221
    222	switch (priv->line_interface) {
    223	case PHY_INTERFACE_MODE_10GBASER:
    224		if (mv2222_is_1gbx_capable(phydev)) {
    225			priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
    226			changed = true;
    227		}
    228
    229		if (mv2222_is_sgmii_capable(phydev)) {
    230			priv->line_interface = PHY_INTERFACE_MODE_SGMII;
    231			changed = true;
    232		}
    233
    234		break;
    235	case PHY_INTERFACE_MODE_1000BASEX:
    236	case PHY_INTERFACE_MODE_SGMII:
    237		if (mv2222_is_10g_capable(phydev)) {
    238			priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
    239			changed = true;
    240		}
    241
    242		break;
    243	default:
    244		return -EINVAL;
    245	}
    246
    247	if (changed) {
    248		ret = mv2222_config_line(phydev);
    249		if (ret < 0)
    250			return ret;
    251	}
    252
    253	return 0;
    254}
    255
    256static int mv2222_setup_forced(struct phy_device *phydev)
    257{
    258	struct mv2222_data *priv = phydev->priv;
    259	int ret;
    260
    261	if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) {
    262		if (phydev->speed < SPEED_10000 &&
    263		    phydev->speed != SPEED_UNKNOWN) {
    264			ret = mv2222_swap_line_type(phydev);
    265			if (ret < 0)
    266				return ret;
    267		}
    268	}
    269
    270	if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) {
    271		ret = mv2222_set_sgmii_speed(phydev);
    272		if (ret < 0)
    273			return ret;
    274	}
    275
    276	return mv2222_disable_aneg(phydev);
    277}
    278
    279static int mv2222_config_aneg(struct phy_device *phydev)
    280{
    281	struct mv2222_data *priv = phydev->priv;
    282	int ret, adv;
    283
    284	/* SFP is not present, do nothing */
    285	if (priv->line_interface == PHY_INTERFACE_MODE_NA)
    286		return 0;
    287
    288	if (phydev->autoneg == AUTONEG_DISABLE ||
    289	    priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
    290		return mv2222_setup_forced(phydev);
    291
    292	adv = linkmode_adv_to_mii_adv_x(priv->supported,
    293					ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
    294
    295	ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_ADVERTISE,
    296			     ADVERTISE_1000XFULL |
    297			     ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
    298			     adv);
    299	if (ret < 0)
    300		return ret;
    301
    302	return mv2222_enable_aneg(phydev);
    303}
    304
    305static int mv2222_aneg_done(struct phy_device *phydev)
    306{
    307	int ret;
    308
    309	if (mv2222_is_10g_capable(phydev)) {
    310		ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
    311		if (ret < 0)
    312			return ret;
    313
    314		if (ret & MDIO_STAT1_LSTATUS)
    315			return 1;
    316	}
    317
    318	ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
    319	if (ret < 0)
    320		return ret;
    321
    322	return (ret & BMSR_ANEGCOMPLETE);
    323}
    324
    325/* Returns negative on error, 0 if link is down, 1 if link is up */
    326static int mv2222_read_status_10g(struct phy_device *phydev)
    327{
    328	static int timeout;
    329	int val, link = 0;
    330
    331	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
    332	if (val < 0)
    333		return val;
    334
    335	if (val & MDIO_STAT1_LSTATUS) {
    336		link = 1;
    337
    338		/* 10GBASE-R do not support auto-negotiation */
    339		phydev->autoneg = AUTONEG_DISABLE;
    340		phydev->speed = SPEED_10000;
    341		phydev->duplex = DUPLEX_FULL;
    342	} else {
    343		if (phydev->autoneg == AUTONEG_ENABLE) {
    344			timeout++;
    345
    346			if (timeout > AUTONEG_TIMEOUT) {
    347				timeout = 0;
    348
    349				val = mv2222_swap_line_type(phydev);
    350				if (val < 0)
    351					return val;
    352
    353				return mv2222_config_aneg(phydev);
    354			}
    355		}
    356	}
    357
    358	return link;
    359}
    360
    361/* Returns negative on error, 0 if link is down, 1 if link is up */
    362static int mv2222_read_status_1g(struct phy_device *phydev)
    363{
    364	static int timeout;
    365	int val, link = 0;
    366
    367	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
    368	if (val < 0)
    369		return val;
    370
    371	if (phydev->autoneg == AUTONEG_ENABLE &&
    372	    !(val & BMSR_ANEGCOMPLETE)) {
    373		timeout++;
    374
    375		if (timeout > AUTONEG_TIMEOUT) {
    376			timeout = 0;
    377
    378			val = mv2222_swap_line_type(phydev);
    379			if (val < 0)
    380				return val;
    381
    382			return mv2222_config_aneg(phydev);
    383		}
    384
    385		return 0;
    386	}
    387
    388	if (!(val & BMSR_LSTATUS))
    389		return 0;
    390
    391	link = 1;
    392
    393	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT);
    394	if (val < 0)
    395		return val;
    396
    397	if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) {
    398		if (val & MV_1GBX_PHY_STAT_DUPLEX)
    399			phydev->duplex = DUPLEX_FULL;
    400		else
    401			phydev->duplex = DUPLEX_HALF;
    402
    403		if (val & MV_1GBX_PHY_STAT_SPEED1000)
    404			phydev->speed = SPEED_1000;
    405		else if (val & MV_1GBX_PHY_STAT_SPEED100)
    406			phydev->speed = SPEED_100;
    407		else
    408			phydev->speed = SPEED_10;
    409	}
    410
    411	return link;
    412}
    413
    414static bool mv2222_link_is_operational(struct phy_device *phydev)
    415{
    416	struct mv2222_data *priv = phydev->priv;
    417	int val;
    418
    419	val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_RX_SIGNAL_DETECT);
    420	if (val < 0 || !(val & MV_RX_SIGNAL_DETECT_GLOBAL))
    421		return false;
    422
    423	if (phydev->sfp_bus && !priv->sfp_link)
    424		return false;
    425
    426	return true;
    427}
    428
    429static int mv2222_read_status(struct phy_device *phydev)
    430{
    431	struct mv2222_data *priv = phydev->priv;
    432	int link;
    433
    434	phydev->link = 0;
    435	phydev->speed = SPEED_UNKNOWN;
    436	phydev->duplex = DUPLEX_UNKNOWN;
    437
    438	if (!mv2222_link_is_operational(phydev))
    439		return 0;
    440
    441	if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
    442		link = mv2222_read_status_10g(phydev);
    443	else
    444		link = mv2222_read_status_1g(phydev);
    445
    446	if (link < 0)
    447		return link;
    448
    449	phydev->link = link;
    450
    451	return 0;
    452}
    453
    454static int mv2222_resume(struct phy_device *phydev)
    455{
    456	return mv2222_tx_enable(phydev);
    457}
    458
    459static int mv2222_suspend(struct phy_device *phydev)
    460{
    461	return mv2222_tx_disable(phydev);
    462}
    463
    464static int mv2222_get_features(struct phy_device *phydev)
    465{
    466	/* All supported linkmodes are set at probe */
    467
    468	return 0;
    469}
    470
    471static int mv2222_config_init(struct phy_device *phydev)
    472{
    473	if (phydev->interface != PHY_INTERFACE_MODE_XAUI)
    474		return -EINVAL;
    475
    476	return 0;
    477}
    478
    479static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
    480{
    481	struct phy_device *phydev = upstream;
    482	phy_interface_t sfp_interface;
    483	struct mv2222_data *priv;
    484	struct device *dev;
    485	int ret;
    486
    487	__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, };
    488
    489	priv = (struct mv2222_data *)phydev->priv;
    490	dev = &phydev->mdio.dev;
    491
    492	sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
    493	sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
    494
    495	dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
    496
    497	if (sfp_interface != PHY_INTERFACE_MODE_10GBASER &&
    498	    sfp_interface != PHY_INTERFACE_MODE_1000BASEX &&
    499	    sfp_interface != PHY_INTERFACE_MODE_SGMII) {
    500		dev_err(dev, "Incompatible SFP module inserted\n");
    501
    502		return -EINVAL;
    503	}
    504
    505	priv->line_interface = sfp_interface;
    506	linkmode_and(priv->supported, phydev->supported, sfp_supported);
    507
    508	ret = mv2222_config_line(phydev);
    509	if (ret < 0)
    510		return ret;
    511
    512	if (mutex_trylock(&phydev->lock)) {
    513		ret = mv2222_config_aneg(phydev);
    514		mutex_unlock(&phydev->lock);
    515	}
    516
    517	return ret;
    518}
    519
    520static void mv2222_sfp_remove(void *upstream)
    521{
    522	struct phy_device *phydev = upstream;
    523	struct mv2222_data *priv;
    524
    525	priv = (struct mv2222_data *)phydev->priv;
    526
    527	priv->line_interface = PHY_INTERFACE_MODE_NA;
    528	linkmode_zero(priv->supported);
    529}
    530
    531static void mv2222_sfp_link_up(void *upstream)
    532{
    533	struct phy_device *phydev = upstream;
    534	struct mv2222_data *priv;
    535
    536	priv = phydev->priv;
    537	priv->sfp_link = true;
    538}
    539
    540static void mv2222_sfp_link_down(void *upstream)
    541{
    542	struct phy_device *phydev = upstream;
    543	struct mv2222_data *priv;
    544
    545	priv = phydev->priv;
    546	priv->sfp_link = false;
    547}
    548
    549static const struct sfp_upstream_ops sfp_phy_ops = {
    550	.module_insert = mv2222_sfp_insert,
    551	.module_remove = mv2222_sfp_remove,
    552	.link_up = mv2222_sfp_link_up,
    553	.link_down = mv2222_sfp_link_down,
    554	.attach = phy_sfp_attach,
    555	.detach = phy_sfp_detach,
    556};
    557
    558static int mv2222_probe(struct phy_device *phydev)
    559{
    560	struct device *dev = &phydev->mdio.dev;
    561	struct mv2222_data *priv = NULL;
    562
    563	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
    564
    565	linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
    566	linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
    567	linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
    568	linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
    569	linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
    570	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, supported);
    571	linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, supported);
    572	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, supported);
    573	linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, supported);
    574	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, supported);
    575	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, supported);
    576	linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, supported);
    577	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, supported);
    578	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, supported);
    579	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
    580	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
    581	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, supported);
    582	linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
    583
    584	linkmode_copy(phydev->supported, supported);
    585
    586	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    587	if (!priv)
    588		return -ENOMEM;
    589
    590	priv->line_interface = PHY_INTERFACE_MODE_NA;
    591	phydev->priv = priv;
    592
    593	return phy_sfp_probe(phydev, &sfp_phy_ops);
    594}
    595
    596static struct phy_driver mv2222_drivers[] = {
    597	{
    598		.phy_id = MARVELL_PHY_ID_88X2222,
    599		.phy_id_mask = MARVELL_PHY_ID_MASK,
    600		.name = "Marvell 88X2222",
    601		.get_features = mv2222_get_features,
    602		.soft_reset = mv2222_soft_reset,
    603		.config_init = mv2222_config_init,
    604		.config_aneg = mv2222_config_aneg,
    605		.aneg_done = mv2222_aneg_done,
    606		.probe = mv2222_probe,
    607		.suspend = mv2222_suspend,
    608		.resume = mv2222_resume,
    609		.read_status = mv2222_read_status,
    610	},
    611};
    612module_phy_driver(mv2222_drivers);
    613
    614static struct mdio_device_id __maybe_unused mv2222_tbl[] = {
    615	{ MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK },
    616	{ }
    617};
    618MODULE_DEVICE_TABLE(mdio, mv2222_tbl);
    619
    620MODULE_DESCRIPTION("Marvell 88x2222 ethernet transceiver driver");
    621MODULE_LICENSE("GPL");