Commit c3892e8c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'reuse-smsc-phy-functionality'



Heiner Kallweit says:

====================
net: phy: reuse SMSC PHY driver functionality in the meson-gxl PHY driver

The Amlogic Meson internal PHY's have the same register layout as
certain SMSC PHY's (also for non-c22-standard registers). This seems
to be more than just coincidence. Apparently they also need the same
workaround for EDPD mode (energy detect power down). Therefore let's
reuse SMSC PHY driver functionality in the meson-gxl PHY driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 26271394 be66fcc1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ config AMD_PHY
config MESON_GXL_PHY
	tristate "Amlogic Meson GXL Internal PHY"
	depends on ARCH_MESON || COMPILE_TEST
	select SMSC_PHY
	help
	  Currently has a driver for the Amlogic Meson GXL Internal PHY

+8 −69
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/bitfield.h>
#include <linux/smscphy.h>

#define TSTCNTL		20
#define  TSTCNTL_READ		BIT(15)
@@ -23,18 +24,6 @@
#define  TSTCNTL_WRITE_ADDRESS	GENMASK(4, 0)
#define TSTREAD1	21
#define TSTWRITE	23
#define INTSRC_FLAG	29
#define  INTSRC_ANEG_PR		BIT(1)
#define  INTSRC_PARALLEL_FAULT	BIT(2)
#define  INTSRC_ANEG_LP_ACK	BIT(3)
#define  INTSRC_LINK_DOWN	BIT(4)
#define  INTSRC_REMOTE_FAULT	BIT(5)
#define  INTSRC_ANEG_COMPLETE	BIT(6)
#define  INTSRC_ENERGY_DETECT	BIT(7)
#define INTSRC_MASK	30

#define INT_SOURCES (INTSRC_LINK_DOWN | INTSRC_ANEG_COMPLETE | \
		     INTSRC_ENERGY_DETECT)

#define BANK_ANALOG_DSP		0
#define BANK_WOL		1
@@ -195,59 +184,6 @@ static int meson_gxl_read_status(struct phy_device *phydev)
	return genphy_read_status(phydev);
}

static int meson_gxl_ack_interrupt(struct phy_device *phydev)
{
	int ret = phy_read(phydev, INTSRC_FLAG);

	return ret < 0 ? ret : 0;
}

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

	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
		/* Ack any pending IRQ */
		ret = meson_gxl_ack_interrupt(phydev);
		if (ret)
			return ret;

		ret = phy_write(phydev, INTSRC_MASK, INT_SOURCES);
	} else {
		ret = phy_write(phydev, INTSRC_MASK, 0);

		/* Ack any pending IRQ */
		ret = meson_gxl_ack_interrupt(phydev);
	}

	return ret;
}

static irqreturn_t meson_gxl_handle_interrupt(struct phy_device *phydev)
{
	int irq_status;

	irq_status = phy_read(phydev, INTSRC_FLAG);
	if (irq_status < 0) {
		phy_error(phydev);
		return IRQ_NONE;
	}

	irq_status &= INT_SOURCES;

	if (irq_status == 0)
		return IRQ_NONE;

	/* Aneg-complete interrupt is used for link-up detection */
	if (phydev->autoneg == AUTONEG_ENABLE &&
	    irq_status == INTSRC_ENERGY_DETECT)
		return IRQ_HANDLED;

	phy_trigger_machine(phydev);

	return IRQ_HANDLED;
}

static struct phy_driver meson_gxl_phy[] = {
	{
		PHY_ID_MATCH_EXACT(0x01814400),
@@ -257,8 +193,8 @@ static struct phy_driver meson_gxl_phy[] = {
		.soft_reset     = genphy_soft_reset,
		.config_init	= meson_gxl_config_init,
		.read_status	= meson_gxl_read_status,
		.config_intr	= meson_gxl_config_intr,
		.handle_interrupt = meson_gxl_handle_interrupt,
		.config_intr	= smsc_phy_config_intr,
		.handle_interrupt = smsc_phy_handle_interrupt,
		.suspend        = genphy_suspend,
		.resume         = genphy_resume,
		.read_mmd	= genphy_read_mmd_unsupported,
@@ -268,9 +204,12 @@ static struct phy_driver meson_gxl_phy[] = {
		.name		= "Meson G12A Internal PHY",
		/* PHY_BASIC_FEATURES */
		.flags		= PHY_IS_INTERNAL,
		.probe		= smsc_phy_probe,
		.config_init	= smsc_phy_config_init,
		.soft_reset     = genphy_soft_reset,
		.config_intr	= meson_gxl_config_intr,
		.handle_interrupt = meson_gxl_handle_interrupt,
		.read_status	= lan87xx_read_status,
		.config_intr	= smsc_phy_config_intr,
		.handle_interrupt = smsc_phy_handle_interrupt,
		.suspend        = genphy_suspend,
		.resume         = genphy_resume,
		.read_mmd	= genphy_read_mmd_unsupported,
+13 −7
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ static int smsc_phy_ack_interrupt(struct phy_device *phydev)
	return rc < 0 ? rc : 0;
}

static int smsc_phy_config_intr(struct phy_device *phydev)
int smsc_phy_config_intr(struct phy_device *phydev)
{
	int rc;

@@ -75,8 +75,9 @@ static int smsc_phy_config_intr(struct phy_device *phydev)

	return rc < 0 ? rc : 0;
}
EXPORT_SYMBOL_GPL(smsc_phy_config_intr);

static irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)
irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)
{
	int irq_status;

@@ -95,18 +96,20 @@ static irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)

	return IRQ_HANDLED;
}
EXPORT_SYMBOL_GPL(smsc_phy_handle_interrupt);

static int smsc_phy_config_init(struct phy_device *phydev)
int smsc_phy_config_init(struct phy_device *phydev)
{
	struct smsc_phy_priv *priv = phydev->priv;

	if (!priv->energy_enable || phydev->irq != PHY_POLL)
	if (!priv || !priv->energy_enable || phydev->irq != PHY_POLL)
		return 0;

	/* Enable energy detect power down mode */
	return phy_set_bits(phydev, MII_LAN83C185_CTRL_STATUS,
			    MII_LAN83C185_EDPWRDOWN);
}
EXPORT_SYMBOL_GPL(smsc_phy_config_init);

static int smsc_phy_reset(struct phy_device *phydev)
{
@@ -186,7 +189,7 @@ static int lan95xx_config_aneg_ext(struct phy_device *phydev)
 * The workaround is only applicable to poll mode. Energy Detect Power-Down may
 * not be used in interrupt mode lest link change detection becomes unreliable.
 */
static int lan87xx_read_status(struct phy_device *phydev)
int lan87xx_read_status(struct phy_device *phydev)
{
	struct smsc_phy_priv *priv = phydev->priv;
	int err;
@@ -195,7 +198,8 @@ static int lan87xx_read_status(struct phy_device *phydev)
	if (err)
		return err;

	if (!phydev->link && priv->energy_enable && phydev->irq == PHY_POLL) {
	if (!phydev->link && priv && priv->energy_enable &&
	    phydev->irq == PHY_POLL) {
		/* Disable EDPD to wake up PHY */
		int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
		if (rc < 0)
@@ -229,6 +233,7 @@ static int lan87xx_read_status(struct phy_device *phydev)

	return err;
}
EXPORT_SYMBOL_GPL(lan87xx_read_status);

static int smsc_get_sset_count(struct phy_device *phydev)
{
@@ -269,7 +274,7 @@ static void smsc_get_stats(struct phy_device *phydev,
		data[i] = smsc_get_stat(phydev, i);
}

static int smsc_phy_probe(struct phy_device *phydev)
int smsc_phy_probe(struct phy_device *phydev)
{
	struct device *dev = &phydev->mdio.dev;
	struct smsc_phy_priv *priv;
@@ -294,6 +299,7 @@ static int smsc_phy_probe(struct phy_device *phydev)

	return clk_set_rate(refclk, 50 * 1000 * 1000);
}
EXPORT_SYMBOL_GPL(smsc_phy_probe);

static struct phy_driver smsc_phy_driver[] = {
{
+6 −0
Original line number Diff line number Diff line
@@ -28,4 +28,10 @@
#define MII_LAN83C185_MODE_POWERDOWN 0xC0 /* Power Down mode */
#define MII_LAN83C185_MODE_ALL       0xE0 /* All capable mode */

int smsc_phy_config_intr(struct phy_device *phydev);
irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev);
int smsc_phy_config_init(struct phy_device *phydev);
int lan87xx_read_status(struct phy_device *phydev);
int smsc_phy_probe(struct phy_device *phydev);

#endif /* __LINUX_SMSCPHY_H__ */