Commit dde25846 authored by Oleksij Rempel's avatar Oleksij Rempel Committed by David S. Miller
Browse files

net: usb/phy: asix: add support for ax88772A/C PHYs



Add support for build-in x88772A/C PHYs

Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7e88b11a
Loading
Loading
Loading
Loading
+73 −1
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@
#include <linux/mii.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/phy.h>


#define PHY_ID_ASIX_AX88772A		0x003b1861
#define PHY_ID_ASIX_AX88772C		0x003b1881
#define PHY_ID_ASIX_AX88796B		0x003b1841
#define PHY_ID_ASIX_AX88796B		0x003b1841


MODULE_DESCRIPTION("Asix PHY driver");
MODULE_DESCRIPTION("Asix PHY driver");
@@ -39,7 +41,75 @@ static int asix_soft_reset(struct phy_device *phydev)
	return genphy_soft_reset(phydev);
	return genphy_soft_reset(phydev);
}
}


static struct phy_driver asix_driver[] = { {
/* AX88772A is not working properly with some old switches (NETGEAR EN 108TP):
 * after autoneg is done and the link status is reported as active, the MII_LPA
 * register is 0. This issue is not reproducible on AX88772C.
 */
static int asix_ax88772a_read_status(struct phy_device *phydev)
{
	int ret, val;

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

	if (!phydev->link)
		return 0;

	/* If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
	 * linkmode so use MII_BMCR as default values.
	 */
	val = phy_read(phydev, MII_BMCR);
	if (val < 0)
		return val;

	if (val & BMCR_SPEED100)
		phydev->speed = SPEED_100;
	else
		phydev->speed = SPEED_10;

	if (val & BMCR_FULLDPLX)
		phydev->duplex = DUPLEX_FULL;
	else
		phydev->duplex = DUPLEX_HALF;

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

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

	return 0;
}

static void asix_ax88772a_link_change_notify(struct phy_device *phydev)
{
	/* Reset PHY, otherwise MII_LPA will provide outdated information.
	 * This issue is reproducible only with some link partner PHYs
	 */
	if (phydev->state == PHY_NOLINK && phydev->drv->soft_reset)
		phydev->drv->soft_reset(phydev);
}

static struct phy_driver asix_driver[] = {
{
	PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A),
	.name		= "Asix Electronics AX88772A",
	.flags		= PHY_IS_INTERNAL,
	.read_status	= asix_ax88772a_read_status,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
	.soft_reset	= asix_soft_reset,
	.link_change_notify	= asix_ax88772a_link_change_notify,
}, {
	PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C),
	.name		= "Asix Electronics AX88772C",
	.flags		= PHY_IS_INTERNAL,
	.suspend	= genphy_suspend,
	.resume		= genphy_resume,
	.soft_reset	= asix_soft_reset,
}, {
	.phy_id		= PHY_ID_ASIX_AX88796B,
	.phy_id		= PHY_ID_ASIX_AX88796B,
	.name		= "Asix Electronics AX88796B",
	.name		= "Asix Electronics AX88796B",
	.phy_id_mask	= 0xfffffff0,
	.phy_id_mask	= 0xfffffff0,
@@ -50,6 +120,8 @@ static struct phy_driver asix_driver[] = { {
module_phy_driver(asix_driver);
module_phy_driver(asix_driver);


static struct mdio_device_id __maybe_unused asix_tbl[] = {
static struct mdio_device_id __maybe_unused asix_tbl[] = {
	{ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772A) },
	{ PHY_ID_MATCH_EXACT(PHY_ID_ASIX_AX88772C) },
	{ PHY_ID_ASIX_AX88796B, 0xfffffff0 },
	{ PHY_ID_ASIX_AX88796B, 0xfffffff0 },
	{ }
	{ }
};
};
+1 −0
Original line number Original line Diff line number Diff line
@@ -164,6 +164,7 @@ config USB_NET_AX8817X
	depends on USB_USBNET
	depends on USB_USBNET
	select CRC32
	select CRC32
	select PHYLIB
	select PHYLIB
	select AX88796B_PHY
	default y
	default y
	help
	help
	  This option adds support for ASIX AX88xxx based USB 2.0
	  This option adds support for ASIX AX88xxx based USB 2.0