diff options
-rw-r--r-- | arch/arm/mach-mx6/board-mx6q_sabrelite.c | 10 | ||||
-rw-r--r-- | drivers/net/fec.c | 12 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 43 | ||||
-rw-r--r-- | include/linux/fec.h | 1 |
4 files changed, 50 insertions, 16 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c index bb82ddec55a4..c0065bfc24d4 100644 --- a/arch/arm/mach-mx6/board-mx6q_sabrelite.c +++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c @@ -95,6 +95,7 @@ #define MX6Q_SABRELITE_VOL_DOWN_KEY IMX_GPIO_NR(4, 5) #define MX6Q_SABRELITE_CSI0_RST IMX_GPIO_NR(1, 8) #define MX6Q_SABRELITE_CSI0_PWN IMX_GPIO_NR(1, 6) +#define MX6Q_SABRELITE_ENET_PHY_INT IMX_GPIO_NR(1, 28) #define N6_WL1271_WL_IRQ IMX_GPIO_NR(6, 14) #define N6_WL1271_WL_EN IMX_GPIO_NR(6, 15) @@ -496,13 +497,17 @@ static const struct imxuart_platform_data mx6_arm2_uart2_data __initconst = { static int mx6q_sabrelite_fec_phy_init(struct phy_device *phydev) { - /* prefer master mode, disable 1000 Base-T capable */ - phy_write(phydev, 0x9, 0x1c00); + /* prefer master mode */ + phy_write(phydev, 0x9, 0x1f00); /* min rx data delay */ phy_write(phydev, 0x0b, 0x8105); phy_write(phydev, 0x0c, 0x0000); + /* min tx data delay */ + phy_write(phydev, 0x0b, 0x8106); + phy_write(phydev, 0x0c, 0x0000); + /* max rx/tx clock delay, min rx/tx control delay */ phy_write(phydev, 0x0b, 0x8104); phy_write(phydev, 0x0c, 0xf0f0); @@ -514,6 +519,7 @@ static int mx6q_sabrelite_fec_phy_init(struct phy_device *phydev) static struct fec_platform_data fec_data __initdata = { .init = mx6q_sabrelite_fec_phy_init, .phy = PHY_INTERFACE_MODE_RGMII, + .phy_irq = gpio_to_irq(MX6Q_SABRELITE_ENET_PHY_INT) }; static int mx6q_sabrelite_spi_cs[] = { diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2078ef8d25f0..08ab0db522e5 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -874,7 +874,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) return 0; } -static int fec_enet_mii_init(struct platform_device *pdev) +static int fec_enet_mii_init(struct platform_device *pdev, int phy_irq) { static struct mii_bus *fec0_mii_bus; struct net_device *ndev = platform_get_drvdata(pdev); @@ -940,7 +940,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) } for (i = 0; i < PHY_MAX_ADDR; i++) - fep->mii_bus->irq[i] = PHY_POLL; + fep->mii_bus->irq[i] = phy_irq; if (mdiobus_register(fep->mii_bus)) goto err_out_free_mdio_irq; @@ -1525,6 +1525,7 @@ fec_probe(struct platform_device *pdev) struct net_device *ndev; int i, irq, ret = 0; struct resource *r; + int phy_irq = PHY_POLL; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) @@ -1557,8 +1558,11 @@ fec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); pdata = pdev->dev.platform_data; - if (pdata) + if (pdata) { fep->phy_interface = pdata->phy; + if (pdata->phy_irq) + phy_irq = pdata->phy_irq; + } /* This device has up to three irqs on some platforms */ for (i = 0; i < 3; i++) { @@ -1586,7 +1590,7 @@ fec_probe(struct platform_device *pdev) if (ret) goto failed_init; - ret = fec_enet_mii_init(pdev); + ret = fec_enet_mii_init(pdev, phy_irq); if (ret) goto failed_mii_init; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 80747d2d1118..6eafb5cf4902 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -16,6 +16,7 @@ * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy */ +#include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/phy.h> @@ -48,16 +49,34 @@ static int kszphy_ack_interrupt(struct phy_device *phydev) int rc; rc = phy_read(phydev, MII_KSZPHY_INTCS); - return (rc < 0) ? rc : 0; } static int kszphy_set_interrupt(struct phy_device *phydev) { - int temp; - temp = (PHY_INTERRUPT_ENABLED == phydev->interrupts) ? - KSZPHY_INTCS_ALL : 0; - return phy_write(phydev, MII_KSZPHY_INTCS, temp); + int bmcr, new_bmcr; + bmcr = phy_read(phydev, MII_BMCR); + if (PHY_INTERRUPT_ENABLED == phydev->interrupts) { + new_bmcr = bmcr & ~BMCR_PDOWN; + if (bmcr != new_bmcr) { + unsigned intcs, temp; + phy_write(phydev, MII_BMCR, new_bmcr); + udelay(100); /* power up needs delay after */ + /* force master mode */ + phy_write(phydev, 0x9, 0x1f00); + } + return phy_write(phydev, MII_KSZPHY_INTCS, KSZPHY_INTCS_ALL); + } else { + phy_write(phydev, MII_KSZPHY_INTCS, 0); + new_bmcr = bmcr | BMCR_PDOWN; + if ((PHY_HALTED == phydev->state) && (bmcr != new_bmcr)) { + phy_write(phydev, MII_BMCR, bmcr | BMCR_ANRESTART); + /* let phy note link is down before poweroff */ + udelay(10); + phy_write(phydev, MII_BMCR, new_bmcr); + } + return 0; + } } static int kszphy_config_intr(struct phy_device *phydev) @@ -66,8 +85,10 @@ static int kszphy_config_intr(struct phy_device *phydev) /* set the interrupt pin active low */ temp = phy_read(phydev, MII_KSZPHY_CTRL); - temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; - phy_write(phydev, MII_KSZPHY_CTRL, temp); + if (temp & KSZPHY_CTRL_INT_ACTIVE_HIGH) { + temp &= ~KSZPHY_CTRL_INT_ACTIVE_HIGH; + phy_write(phydev, MII_KSZPHY_CTRL, temp); + } rc = kszphy_set_interrupt(phydev); return rc < 0 ? rc : 0; } @@ -76,10 +97,12 @@ static int ksz9021_config_intr(struct phy_device *phydev) { int temp, rc; - /* set the interrupt pin active low */ temp = phy_read(phydev, MII_KSZPHY_CTRL); - temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; - phy_write(phydev, MII_KSZPHY_CTRL, temp); + if (temp & KSZ9021_CTRL_INT_ACTIVE_HIGH) { + /* set the interrupt pin active low */ + temp &= ~KSZ9021_CTRL_INT_ACTIVE_HIGH; + phy_write(phydev, MII_KSZPHY_CTRL, temp); + } rc = kszphy_set_interrupt(phydev); return rc < 0 ? rc : 0; } diff --git a/include/linux/fec.h b/include/linux/fec.h index 8f69cb58d458..7a08261d5654 100644 --- a/include/linux/fec.h +++ b/include/linux/fec.h @@ -21,6 +21,7 @@ struct fec_platform_data { int (*power_hibernate) (struct phy_device *); phy_interface_t phy; unsigned char mac[ETH_ALEN]; + int phy_irq; }; #endif |