aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Glendinning <steve.glendinning@smsc.com>2009-01-27 01:51:11 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-01 03:37:21 -0500
commitd23f028a4ddce8b783c212bfe911d1d307ff3617 (patch)
tree95166b84758afba8fdbbf4ce2fdb4dd3b5a4ccac
parente81259b4f7c69a71d92216ba551731fb7027bcbe (diff)
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: Steve Glendinning <steve.glendinning@smsc.com> Acked-by: Sascha Hauer <s.hauer@pengutronix.de> Tested-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/smsc911x.c75
-rw-r--r--include/linux/smsc911x.h2
2 files changed, 40 insertions, 37 deletions
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 6aa2b165de6..27d2d7c4551 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -368,48 +368,53 @@ out:
368 return reg; 368 return reg;
369} 369}
370 370
371/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors. 371/* Switch to external phy. Assumes tx and rx are stopped. */
372 * If something goes wrong, returns -ENODEV to revert back to internal phy. 372static void smsc911x_phy_enable_external(struct smsc911x_data *pdata)
373 * Performed at initialisation only, so interrupts are enabled */
374static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
375{ 373{
376 unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); 374 unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
377 375
378 /* External phy is requested, supported, and detected */ 376 /* Disable phy clocks to the MAC */
379 if (hwcfg & HW_CFG_EXT_PHY_DET_) { 377 hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
378 hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
379 smsc911x_reg_write(pdata, HW_CFG, hwcfg);
380 udelay(10); /* Enough time for clocks to stop */
380 381
381 /* Switch to external phy. Assuming tx and rx are stopped 382 /* Switch to external phy */
382 * because smsc911x_phy_initialise is called before 383 hwcfg |= HW_CFG_EXT_PHY_EN_;
383 * smsc911x_rx_initialise and tx_initialise. */ 384 smsc911x_reg_write(pdata, HW_CFG, hwcfg);
384 385
385 /* Disable phy clocks to the MAC */ 386 /* Enable phy clocks to the MAC */
386 hwcfg &= (~HW_CFG_PHY_CLK_SEL_); 387 hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
387 hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; 388 hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
388 smsc911x_reg_write(pdata, HW_CFG, hwcfg); 389 smsc911x_reg_write(pdata, HW_CFG, hwcfg);
389 udelay(10); /* Enough time for clocks to stop */ 390 udelay(10); /* Enough time for clocks to restart */
390 391
391 /* Switch to external phy */ 392 hwcfg |= HW_CFG_SMI_SEL_;
392 hwcfg |= HW_CFG_EXT_PHY_EN_; 393 smsc911x_reg_write(pdata, HW_CFG, hwcfg);
393 smsc911x_reg_write(pdata, HW_CFG, hwcfg); 394}
394
395 /* Enable phy clocks to the MAC */
396 hwcfg &= (~HW_CFG_PHY_CLK_SEL_);
397 hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
398 smsc911x_reg_write(pdata, HW_CFG, hwcfg);
399 udelay(10); /* Enough time for clocks to restart */
400 395
401 hwcfg |= HW_CFG_SMI_SEL_; 396/* Autodetects and enables external phy if present on supported chips.
402 smsc911x_reg_write(pdata, HW_CFG, hwcfg); 397 * autodetection can be overridden by specifying SMSC911X_FORCE_INTERNAL_PHY
398 * or SMSC911X_FORCE_EXTERNAL_PHY in the platform_data flags. */
399static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
400{
401 unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
403 402
404 SMSC_TRACE(HW, "Successfully switched to external PHY"); 403 if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) {
404 SMSC_TRACE(HW, "Forcing internal PHY");
405 pdata->using_extphy = 0;
406 } else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) {
407 SMSC_TRACE(HW, "Forcing external PHY");
408 smsc911x_phy_enable_external(pdata);
409 pdata->using_extphy = 1;
410 } else if (hwcfg & HW_CFG_EXT_PHY_DET_) {
411 SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY");
412 smsc911x_phy_enable_external(pdata);
405 pdata->using_extphy = 1; 413 pdata->using_extphy = 1;
406 } else { 414 } else {
407 SMSC_WARNING(HW, "No external PHY detected, " 415 SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY");
408 "Using internal PHY instead."); 416 pdata->using_extphy = 0;
409 /* Use internal phy */
410 return -ENODEV;
411 } 417 }
412 return 0;
413} 418}
414 419
415/* Fetches a tx status out of the status fifo */ 420/* Fetches a tx status out of the status fifo */
@@ -825,22 +830,18 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
825 830
826 pdata->mii_bus->parent = &pdev->dev; 831 pdata->mii_bus->parent = &pdev->dev;
827 832
828 pdata->using_extphy = 0;
829
830 switch (pdata->idrev & 0xFFFF0000) { 833 switch (pdata->idrev & 0xFFFF0000) {
831 case 0x01170000: 834 case 0x01170000:
832 case 0x01150000: 835 case 0x01150000:
833 case 0x117A0000: 836 case 0x117A0000:
834 case 0x115A0000: 837 case 0x115A0000:
835 /* External PHY supported, try to autodetect */ 838 /* External PHY supported, try to autodetect */
836 if (smsc911x_phy_initialise_external(pdata) < 0) { 839 smsc911x_phy_initialise_external(pdata);
837 SMSC_TRACE(HW, "No external PHY detected, "
838 "using internal PHY");
839 }
840 break; 840 break;
841 default: 841 default:
842 SMSC_TRACE(HW, "External PHY is not supported, " 842 SMSC_TRACE(HW, "External PHY is not supported, "
843 "using internal PHY"); 843 "using internal PHY");
844 pdata->using_extphy = 0;
844 break; 845 break;
845 } 846 }
846 847
diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h
index 1cbf0313add..170c76b8f7a 100644
--- a/include/linux/smsc911x.h
+++ b/include/linux/smsc911x.h
@@ -43,5 +43,7 @@ struct smsc911x_platform_config {
43/* Constants for flags */ 43/* Constants for flags */
44#define SMSC911X_USE_16BIT (BIT(0)) 44#define SMSC911X_USE_16BIT (BIT(0))
45#define SMSC911X_USE_32BIT (BIT(1)) 45#define SMSC911X_USE_32BIT (BIT(1))
46#define SMSC911X_FORCE_INTERNAL_PHY (BIT(2))
47#define SMSC911X_FORCE_EXTERNAL_PHY (BIT(3))
46 48
47#endif /* __LINUX_SMSC911X_H__ */ 49#endif /* __LINUX_SMSC911X_H__ */