aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/smsc.c
diff options
context:
space:
mode:
authorPatrick Trantham <patrick.trantham@fuel7.com>2012-11-15 04:00:57 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-15 17:48:50 -0500
commit4223dbffed9f89596177ff2b256ef3258b20fa46 (patch)
tree6472e1dbeaca62e74929aa613afe98527b1086e5 /drivers/net/phy/smsc.c
parentf191a1d17f227032c159e5499809f545402b6dc6 (diff)
net: phy: smsc: Re-enable EDPD mode for LAN87xx
This patch re-enables Energy Detect Power Down (EDPD) mode for the LAN8710/LAN8720. EDPD mode was disabled in a previous commit, (b629820d18fa65cc598390e4b9712fd5f83ee693), because it was causing the PHY to not be able to detect a link when cold started without a cable connected. The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each other in order to set the ENERGYON bit and exit EDPD mode. If a link partner does send the pulses within this interval, the PHY will remained powered down. This workaround will manually toggle the PHY on/off upon calls to read_status in order to generate link test pulses if the link is down. If a link partner is present, it will respond to the pulses, which will cause the ENERGYON bit to be set and will cause the EDPD mode to be exited. Signed-off-by: Patrick Trantham <patrick.trantham@fuel7.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/smsc.c')
-rw-r--r--drivers/net/phy/smsc.c69
1 files changed, 43 insertions, 26 deletions
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 88e3991464e7..16dceed29d8c 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -56,35 +56,52 @@ static int smsc_phy_config_init(struct phy_device *phydev)
56 return smsc_phy_ack_interrupt (phydev); 56 return smsc_phy_ack_interrupt (phydev);
57} 57}
58 58
59static int lan87xx_config_init(struct phy_device *phydev) 59static int lan911x_config_init(struct phy_device *phydev)
60{ 60{
61 /*
62 * Make sure the EDPWRDOWN bit is NOT set. Setting this bit on
63 * LAN8710/LAN8720 PHY causes the PHY to misbehave, likely due
64 * to a bug on the chip.
65 *
66 * When the system is powered on with the network cable being
67 * disconnected all the way until after ifconfig ethX up is
68 * issued for the LAN port with this PHY, connecting the cable
69 * afterwards does not cause LINK change detection, while the
70 * expected behavior is the Link UP being detected.
71 */
72 int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
73 if (rc < 0)
74 return rc;
75
76 rc &= ~MII_LAN83C185_EDPWRDOWN;
77
78 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, rc);
79 if (rc < 0)
80 return rc;
81
82 return smsc_phy_ack_interrupt(phydev); 61 return smsc_phy_ack_interrupt(phydev);
83} 62}
84 63
85static int lan911x_config_init(struct phy_device *phydev) 64/*
65 * The LAN8710/LAN8720 requires a minimum of 2 link pulses within 64ms of each
66 * other in order to set the ENERGYON bit and exit EDPD mode. If a link partner
67 * does send the pulses within this interval, the PHY will remained powered
68 * down.
69 *
70 * This workaround will manually toggle the PHY on/off upon calls to read_status
71 * in order to generate link test pulses if the link is down. If a link partner
72 * is present, it will respond to the pulses, which will cause the ENERGYON bit
73 * to be set and will cause the EDPD mode to be exited.
74 */
75static int lan87xx_read_status(struct phy_device *phydev)
86{ 76{
87 return smsc_phy_ack_interrupt(phydev); 77 int err = genphy_read_status(phydev);
78
79 if (!phydev->link) {
80 /* Disable EDPD to wake up PHY */
81 int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
82 if (rc < 0)
83 return rc;
84
85 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
86 rc & ~MII_LAN83C185_EDPWRDOWN);
87 if (rc < 0)
88 return rc;
89
90 /* Sleep 64 ms to allow ~5 link test pulses to be sent */
91 msleep(64);
92
93 /* Re-enable EDPD */
94 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
95 if (rc < 0)
96 return rc;
97
98 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
99 rc | MII_LAN83C185_EDPWRDOWN);
100 if (rc < 0)
101 return rc;
102 }
103
104 return err;
88} 105}
89 106
90static struct phy_driver smsc_phy_driver[] = { 107static struct phy_driver smsc_phy_driver[] = {
@@ -187,8 +204,8 @@ static struct phy_driver smsc_phy_driver[] = {
187 204
188 /* basic functions */ 205 /* basic functions */
189 .config_aneg = genphy_config_aneg, 206 .config_aneg = genphy_config_aneg,
190 .read_status = genphy_read_status, 207 .read_status = lan87xx_read_status,
191 .config_init = lan87xx_config_init, 208 .config_intr = smsc_phy_config_intr,
192 209
193 /* IRQ related */ 210 /* IRQ related */
194 .ack_interrupt = smsc_phy_ack_interrupt, 211 .ack_interrupt = smsc_phy_ack_interrupt,