summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabrelite.c10
-rw-r--r--drivers/net/fec.c12
-rw-r--r--drivers/net/phy/micrel.c43
-rw-r--r--include/linux/fec.h1
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