aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/at803x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/at803x.c')
-rw-r--r--drivers/net/phy/at803x.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index f279a897a5c7..a52b560e428b 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -42,19 +42,24 @@
42#define AT803X_MMD_ACCESS_CONTROL 0x0D 42#define AT803X_MMD_ACCESS_CONTROL 0x0D
43#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E 43#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
44#define AT803X_FUNC_DATA 0x4003 44#define AT803X_FUNC_DATA 0x4003
45#define AT803X_REG_CHIP_CONFIG 0x1f
46#define AT803X_BT_BX_REG_SEL 0x8000
45 47
46#define AT803X_DEBUG_ADDR 0x1D 48#define AT803X_DEBUG_ADDR 0x1D
47#define AT803X_DEBUG_DATA 0x1E 49#define AT803X_DEBUG_DATA 0x1E
48 50
51#define AT803X_MODE_CFG_MASK 0x0F
52#define AT803X_MODE_CFG_SGMII 0x01
53
54#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
55#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
56
49#define AT803X_DEBUG_REG_0 0x00 57#define AT803X_DEBUG_REG_0 0x00
50#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) 58#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
51 59
52#define AT803X_DEBUG_REG_5 0x05 60#define AT803X_DEBUG_REG_5 0x05
53#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) 61#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8)
54 62
55#define AT803X_REG_CHIP_CONFIG 0x1f
56#define AT803X_BT_BX_REG_SEL 0x8000
57
58#define ATH8030_PHY_ID 0x004dd076 63#define ATH8030_PHY_ID 0x004dd076
59#define ATH8031_PHY_ID 0x004dd074 64#define ATH8031_PHY_ID 0x004dd074
60#define ATH8035_PHY_ID 0x004dd072 65#define ATH8035_PHY_ID 0x004dd072
@@ -209,7 +214,6 @@ static int at803x_suspend(struct phy_device *phydev)
209{ 214{
210 int value; 215 int value;
211 int wol_enabled; 216 int wol_enabled;
212 int ccr;
213 217
214 mutex_lock(&phydev->lock); 218 mutex_lock(&phydev->lock);
215 219
@@ -225,16 +229,6 @@ static int at803x_suspend(struct phy_device *phydev)
225 229
226 phy_write(phydev, MII_BMCR, value); 230 phy_write(phydev, MII_BMCR, value);
227 231
228 if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
229 goto done;
230
231 /* also power-down SGMII interface */
232 ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
233 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
234 phy_write(phydev, MII_BMCR, phy_read(phydev, MII_BMCR) | BMCR_PDOWN);
235 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
236
237done:
238 mutex_unlock(&phydev->lock); 232 mutex_unlock(&phydev->lock);
239 233
240 return 0; 234 return 0;
@@ -243,7 +237,6 @@ done:
243static int at803x_resume(struct phy_device *phydev) 237static int at803x_resume(struct phy_device *phydev)
244{ 238{
245 int value; 239 int value;
246 int ccr;
247 240
248 mutex_lock(&phydev->lock); 241 mutex_lock(&phydev->lock);
249 242
@@ -251,17 +244,6 @@ static int at803x_resume(struct phy_device *phydev)
251 value &= ~(BMCR_PDOWN | BMCR_ISOLATE); 244 value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
252 phy_write(phydev, MII_BMCR, value); 245 phy_write(phydev, MII_BMCR, value);
253 246
254 if (phydev->interface != PHY_INTERFACE_MODE_SGMII)
255 goto done;
256
257 /* also power-up SGMII interface */
258 ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
259 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
260 value = phy_read(phydev, MII_BMCR) & ~(BMCR_PDOWN | BMCR_ISOLATE);
261 phy_write(phydev, MII_BMCR, value);
262 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
263
264done:
265 mutex_unlock(&phydev->lock); 247 mutex_unlock(&phydev->lock);
266 248
267 return 0; 249 return 0;
@@ -381,6 +363,36 @@ static void at803x_link_change_notify(struct phy_device *phydev)
381 } 363 }
382} 364}
383 365
366static int at803x_aneg_done(struct phy_device *phydev)
367{
368 int ccr;
369
370 int aneg_done = genphy_aneg_done(phydev);
371 if (aneg_done != BMSR_ANEGCOMPLETE)
372 return aneg_done;
373
374 /*
375 * in SGMII mode, if copper side autoneg is successful,
376 * also check SGMII side autoneg result
377 */
378 ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
379 if ((ccr & AT803X_MODE_CFG_MASK) != AT803X_MODE_CFG_SGMII)
380 return aneg_done;
381
382 /* switch to SGMII/fiber page */
383 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr & ~AT803X_BT_BX_REG_SEL);
384
385 /* check if the SGMII link is OK. */
386 if (!(phy_read(phydev, AT803X_PSSR) & AT803X_PSSR_MR_AN_COMPLETE)) {
387 pr_warn("803x_aneg_done: SGMII link is not ok\n");
388 aneg_done = 0;
389 }
390 /* switch back to copper page */
391 phy_write(phydev, AT803X_REG_CHIP_CONFIG, ccr | AT803X_BT_BX_REG_SEL);
392
393 return aneg_done;
394}
395
384static struct phy_driver at803x_driver[] = { 396static struct phy_driver at803x_driver[] = {
385{ 397{
386 /* ATHEROS 8035 */ 398 /* ATHEROS 8035 */
@@ -432,6 +444,7 @@ static struct phy_driver at803x_driver[] = {
432 .flags = PHY_HAS_INTERRUPT, 444 .flags = PHY_HAS_INTERRUPT,
433 .config_aneg = genphy_config_aneg, 445 .config_aneg = genphy_config_aneg,
434 .read_status = genphy_read_status, 446 .read_status = genphy_read_status,
447 .aneg_done = at803x_aneg_done,
435 .ack_interrupt = &at803x_ack_interrupt, 448 .ack_interrupt = &at803x_ack_interrupt,
436 .config_intr = &at803x_config_intr, 449 .config_intr = &at803x_config_intr,
437} }; 450} };