提交 d23f028a 编写于 作者: S Steve Glendinning 提交者: David S. Miller

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: NSteve Glendinning <steve.glendinning@smsc.com>
Acked-by: NSascha Hauer <s.hauer@pengutronix.de>
Tested-by: NSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 e81259b4
...@@ -368,48 +368,53 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, ...@@ -368,48 +368,53 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
return reg; return reg;
} }
/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors. /* Switch to external phy. Assumes tx and rx are stopped. */
* If something goes wrong, returns -ENODEV to revert back to internal phy. static void smsc911x_phy_enable_external(struct smsc911x_data *pdata)
* Performed at initialisation only, so interrupts are enabled */
static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
{ {
unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
/* External phy is requested, supported, and detected */ /* Disable phy clocks to the MAC */
if (hwcfg & HW_CFG_EXT_PHY_DET_) { hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
smsc911x_reg_write(pdata, HW_CFG, hwcfg);
udelay(10); /* Enough time for clocks to stop */
/* Switch to external phy. Assuming tx and rx are stopped /* Switch to external phy */
* because smsc911x_phy_initialise is called before hwcfg |= HW_CFG_EXT_PHY_EN_;
* smsc911x_rx_initialise and tx_initialise. */ smsc911x_reg_write(pdata, HW_CFG, hwcfg);
/* Disable phy clocks to the MAC */ /* Enable phy clocks to the MAC */
hwcfg &= (~HW_CFG_PHY_CLK_SEL_); hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
smsc911x_reg_write(pdata, HW_CFG, hwcfg); smsc911x_reg_write(pdata, HW_CFG, hwcfg);
udelay(10); /* Enough time for clocks to stop */ udelay(10); /* Enough time for clocks to restart */
/* Switch to external phy */ hwcfg |= HW_CFG_SMI_SEL_;
hwcfg |= HW_CFG_EXT_PHY_EN_; smsc911x_reg_write(pdata, HW_CFG, hwcfg);
smsc911x_reg_write(pdata, HW_CFG, hwcfg); }
/* Enable phy clocks to the MAC */
hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
smsc911x_reg_write(pdata, HW_CFG, hwcfg);
udelay(10); /* Enough time for clocks to restart */
hwcfg |= HW_CFG_SMI_SEL_; /* Autodetects and enables external phy if present on supported chips.
smsc911x_reg_write(pdata, HW_CFG, hwcfg); * 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; pdata->using_extphy = 1;
} else { } else {
SMSC_WARNING(HW, "No external PHY detected, " SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY");
"Using internal PHY instead."); pdata->using_extphy = 0;
/* Use internal phy */
return -ENODEV;
} }
return 0;
} }
/* Fetches a tx status out of the status fifo */ /* Fetches a tx status out of the status fifo */
...@@ -825,22 +830,18 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev, ...@@ -825,22 +830,18 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
pdata->mii_bus->parent = &pdev->dev; pdata->mii_bus->parent = &pdev->dev;
pdata->using_extphy = 0;
switch (pdata->idrev & 0xFFFF0000) { switch (pdata->idrev & 0xFFFF0000) {
case 0x01170000: case 0x01170000:
case 0x01150000: case 0x01150000:
case 0x117A0000: case 0x117A0000:
case 0x115A0000: case 0x115A0000:
/* External PHY supported, try to autodetect */ /* External PHY supported, try to autodetect */
if (smsc911x_phy_initialise_external(pdata) < 0) { smsc911x_phy_initialise_external(pdata);
SMSC_TRACE(HW, "No external PHY detected, "
"using internal PHY");
}
break; break;
default: default:
SMSC_TRACE(HW, "External PHY is not supported, " SMSC_TRACE(HW, "External PHY is not supported, "
"using internal PHY"); "using internal PHY");
pdata->using_extphy = 0;
break; break;
} }
......
...@@ -43,5 +43,7 @@ struct smsc911x_platform_config { ...@@ -43,5 +43,7 @@ struct smsc911x_platform_config {
/* Constants for flags */ /* Constants for flags */
#define SMSC911X_USE_16BIT (BIT(0)) #define SMSC911X_USE_16BIT (BIT(0))
#define SMSC911X_USE_32BIT (BIT(1)) #define SMSC911X_USE_32BIT (BIT(1))
#define SMSC911X_FORCE_INTERNAL_PHY (BIT(2))
#define SMSC911X_FORCE_EXTERNAL_PHY (BIT(3))
#endif /* __LINUX_SMSC911X_H__ */ #endif /* __LINUX_SMSC911X_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册