Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d23f028a authored by Steve Glendinning's avatar Steve Glendinning Committed by David S. Miller
Browse files

smsc911x: add external phy detection overrides



On LAN9115/LAN9117/LAN9215/LAN9217, external phys are supported.  These
are usually indicated by a hardware strap which sets an "external PHY
detected" bit in the HW_CFG register.

In some cases it is desirable to override this hardware strap and force
use of either the internal phy or an external PHY.  This patch adds
SMSC911X_FORCE_INTERNAL_PHY and SMSC911X_FORCE_EXTERNAL_PHY flags so a
platform can indicate this preference via its platform_data.

Signed-off-by: default avatarSteve Glendinning <steve.glendinning@smsc.com>
Acked-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Tested-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e81259b4
Loading
Loading
Loading
Loading
+38 −37
Original line number Diff line number Diff line
@@ -368,20 +368,11 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
	return reg;
}

/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors.
 * If something goes wrong, returns -ENODEV to revert back to internal phy.
 * Performed at initialisation only, so interrupts are enabled */
static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
/* Switch to external phy. Assumes tx and rx are stopped. */
static void smsc911x_phy_enable_external(struct smsc911x_data *pdata)
{
	unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);

	/* External phy is requested, supported, and detected */
	if (hwcfg & HW_CFG_EXT_PHY_DET_) {

		/* Switch to external phy. Assuming tx and rx are stopped
		 * because smsc911x_phy_initialise is called before
		 * smsc911x_rx_initialise and tx_initialise. */

	/* Disable phy clocks to the MAC */
	hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
	hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
@@ -400,16 +391,30 @@ static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)

	hwcfg |= HW_CFG_SMI_SEL_;
	smsc911x_reg_write(pdata, HW_CFG, hwcfg);
}

/* Autodetects and enables external phy if present on supported chips.
 * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY
 * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */
static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
{
	unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);

		SMSC_TRACE(HW, "Successfully switched to external PHY");
	if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) {
		SMSC_TRACE(HW, "Forcing internal PHY");
		pdata->using_extphy = 0;
	} else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) {
		SMSC_TRACE(HW, "Forcing external PHY");
		smsc911x_phy_enable_external(pdata);
		pdata->using_extphy = 1;
	} else if (hwcfg & HW_CFG_EXT_PHY_DET_) {
		SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY");
		smsc911x_phy_enable_external(pdata);
		pdata->using_extphy = 1;
	} else {
		SMSC_WARNING(HW, "No external PHY detected, "
			"Using internal PHY instead.");
		/* Use internal phy */
		return -ENODEV;
		SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY");
		pdata->using_extphy = 0;
	}
	return 0;
}

/* Fetches a tx status out of the status fifo */
@@ -825,22 +830,18 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,

	pdata->mii_bus->parent = &pdev->dev;

	pdata->using_extphy = 0;

	switch (pdata->idrev & 0xFFFF0000) {
	case 0x01170000:
	case 0x01150000:
	case 0x117A0000:
	case 0x115A0000:
		/* External PHY supported, try to autodetect */
		if (smsc911x_phy_initialise_external(pdata) < 0) {
			SMSC_TRACE(HW, "No external PHY detected, "
				"using internal PHY");
		}
		smsc911x_phy_initialise_external(pdata);
		break;
	default:
		SMSC_TRACE(HW, "External PHY is not supported, "
			"using internal PHY");
		pdata->using_extphy = 0;
		break;
	}

+2 −0
Original line number Diff line number Diff line
@@ -43,5 +43,7 @@ struct smsc911x_platform_config {
/* Constants for flags */
#define SMSC911X_USE_16BIT 			(BIT(0))
#define SMSC911X_USE_32BIT 			(BIT(1))
#define SMSC911X_FORCE_INTERNAL_PHY		(BIT(2))
#define SMSC911X_FORCE_EXTERNAL_PHY 		(BIT(3))

#endif /* __LINUX_SMSC911X_H__ */