Commit 79c7bc05 authored by Luo Jie's avatar Luo Jie Committed by David S. Miller
Browse files

net: phy: add qca8081 read_status



1. Separate the function at803x_read_specific_status from
the at803x_read_status, since it can be reused by the
read_status of qca8081 phy driver excepting adding the
2500M speed.

2. Add the qca8081 read_status function qca808x_read_status.

Signed-off-by: default avatarLuo Jie <luoj@codeaurora.org>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent daf61732
Loading
Loading
Loading
Loading
+73 −22
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
#define AT803X_SS_SPEED_DUPLEX_RESOLVED		BIT(11)
#define AT803X_SS_MDIX				BIT(6)

#define QCA808X_SS_SPEED_MASK			GENMASK(9, 7)
#define QCA808X_SS_SPEED_2500			4

#define AT803X_INTR_ENABLE			0x12
#define AT803X_INTR_ENABLE_AUTONEG_ERR		BIT(15)
#define AT803X_INTR_ENABLE_SPEED_CHANGED	BIT(14)
@@ -959,27 +962,9 @@ static void at803x_link_change_notify(struct phy_device *phydev)
	}
}

static int at803x_read_status(struct phy_device *phydev)
static int at803x_read_specific_status(struct phy_device *phydev)
{
	int ss, err, old_link = phydev->link;

	/* Update the link, but return if there was an error */
	err = genphy_update_link(phydev);
	if (err)
		return err;

	/* why bother the PHY if nothing can have changed */
	if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
		return 0;

	phydev->speed = SPEED_UNKNOWN;
	phydev->duplex = DUPLEX_UNKNOWN;
	phydev->pause = 0;
	phydev->asym_pause = 0;

	err = genphy_read_lpa(phydev);
	if (err < 0)
		return err;
	int ss;

	/* Read the AT8035 PHY-Specific Status register, which indicates the
	 * speed and duplex that the PHY is actually using, irrespective of
@@ -990,13 +975,19 @@ static int at803x_read_status(struct phy_device *phydev)
		return ss;

	if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
		int sfc;
		int sfc, speed;

		sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
		if (sfc < 0)
			return sfc;

		switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) {
		/* qca8081 takes the different bits for speed value from at803x */
		if (phydev->drv->phy_id == QCA8081_PHY_ID)
			speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
		else
			speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);

		switch (speed) {
		case AT803X_SS_SPEED_10:
			phydev->speed = SPEED_10;
			break;
@@ -1006,6 +997,9 @@ static int at803x_read_status(struct phy_device *phydev)
		case AT803X_SS_SPEED_1000:
			phydev->speed = SPEED_1000;
			break;
		case QCA808X_SS_SPEED_2500:
			phydev->speed = SPEED_2500;
			break;
		}
		if (ss & AT803X_SS_DUPLEX)
			phydev->duplex = DUPLEX_FULL;
@@ -1030,6 +1024,35 @@ static int at803x_read_status(struct phy_device *phydev)
		}
	}

	return 0;
}

static int at803x_read_status(struct phy_device *phydev)
{
	int err, old_link = phydev->link;

	/* Update the link, but return if there was an error */
	err = genphy_update_link(phydev);
	if (err)
		return err;

	/* why bother the PHY if nothing can have changed */
	if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
		return 0;

	phydev->speed = SPEED_UNKNOWN;
	phydev->duplex = DUPLEX_UNKNOWN;
	phydev->pause = 0;
	phydev->asym_pause = 0;

	err = genphy_read_lpa(phydev);
	if (err < 0)
		return err;

	err = at803x_read_specific_status(phydev);
	if (err < 0)
		return err;

	if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
		phy_resolve_aneg_pause(phydev);

@@ -1434,6 +1457,33 @@ static int qca83xx_suspend(struct phy_device *phydev)
	return 0;
}

static int qca808x_read_status(struct phy_device *phydev)
{
	int ret;

	ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
	if (ret < 0)
		return ret;

	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
			ret & MDIO_AN_10GBT_STAT_LP2_5G);

	ret = genphy_read_status(phydev);
	if (ret)
		return ret;

	ret = at803x_read_specific_status(phydev);
	if (ret < 0)
		return ret;

	if (phydev->link && phydev->speed == SPEED_2500)
		phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
	else
		phydev->interface = PHY_INTERFACE_MODE_SMII;

	return 0;
}

static struct phy_driver at803x_driver[] = {
{
	/* Qualcomm Atheros AR8035 */
@@ -1605,6 +1655,7 @@ static struct phy_driver at803x_driver[] = {
	.get_wol		= at803x_get_wol,
	.suspend		= genphy_suspend,
	.resume			= genphy_resume,
	.read_status		= qca808x_read_status,
}, };

module_phy_driver(at803x_driver);