diff options
author | Patrick Trantham <patrick.trantham@fuel7.com> | 2012-11-15 04:00:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-15 17:48:50 -0500 |
commit | 4223dbffed9f89596177ff2b256ef3258b20fa46 (patch) | |
tree | 6472e1dbeaca62e74929aa613afe98527b1086e5 | |
parent | f191a1d17f227032c159e5499809f545402b6dc6 (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>
-rw-r--r-- | drivers/net/phy/smsc.c | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 88e3991464e..16dceed29d8 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 | ||
59 | static int lan87xx_config_init(struct phy_device *phydev) | 59 | static 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 | ||
85 | static 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 | */ | ||
75 | static 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 | ||
90 | static struct phy_driver smsc_phy_driver[] = { | 107 | static 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, |