diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/broadcom.c | 46 | ||||
-rw-r--r-- | drivers/net/phy/icplus.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 77 | ||||
-rw-r--r-- | drivers/net/phy/mdio-octeon.c | 6 | ||||
-rw-r--r-- | drivers/net/phy/micrel.c | 167 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 8 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 2 |
7 files changed, 270 insertions, 38 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index cecdbbd549ec..4accd83d3dfe 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -685,7 +685,7 @@ static int brcm_fet_config_intr(struct phy_device *phydev) } static struct phy_driver bcm5411_driver = { - .phy_id = 0x00206070, + .phy_id = PHY_ID_BCM5411, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5411", .features = PHY_GBIT_FEATURES | @@ -700,7 +700,7 @@ static struct phy_driver bcm5411_driver = { }; static struct phy_driver bcm5421_driver = { - .phy_id = 0x002060e0, + .phy_id = PHY_ID_BCM5421, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5421", .features = PHY_GBIT_FEATURES | @@ -715,7 +715,7 @@ static struct phy_driver bcm5421_driver = { }; static struct phy_driver bcm5461_driver = { - .phy_id = 0x002060c0, + .phy_id = PHY_ID_BCM5461, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5461", .features = PHY_GBIT_FEATURES | @@ -730,7 +730,7 @@ static struct phy_driver bcm5461_driver = { }; static struct phy_driver bcm5464_driver = { - .phy_id = 0x002060b0, + .phy_id = PHY_ID_BCM5464, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5464", .features = PHY_GBIT_FEATURES | @@ -745,7 +745,7 @@ static struct phy_driver bcm5464_driver = { }; static struct phy_driver bcm5481_driver = { - .phy_id = 0x0143bca0, + .phy_id = PHY_ID_BCM5481, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5481", .features = PHY_GBIT_FEATURES | @@ -760,7 +760,7 @@ static struct phy_driver bcm5481_driver = { }; static struct phy_driver bcm5482_driver = { - .phy_id = 0x0143bcb0, + .phy_id = PHY_ID_BCM5482, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", .features = PHY_GBIT_FEATURES | @@ -834,6 +834,21 @@ static struct phy_driver bcmac131_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcm5241_driver = { + .phy_id = PHY_ID_BCM5241, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM5241", + .features = PHY_BASIC_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = brcm_fet_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = brcm_fet_ack_interrupt, + .config_intr = brcm_fet_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -868,8 +883,13 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcmac131_driver); if (ret) goto out_ac131; + ret = phy_driver_register(&bcm5241_driver); + if (ret) + goto out_5241; return ret; +out_5241: + phy_driver_unregister(&bcmac131_driver); out_ac131: phy_driver_unregister(&bcm57780_driver); out_57780: @@ -894,6 +914,7 @@ out_5411: static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcm5241_driver); phy_driver_unregister(&bcmac131_driver); phy_driver_unregister(&bcm57780_driver); phy_driver_unregister(&bcm50610m_driver); @@ -910,16 +931,17 @@ module_init(broadcom_init); module_exit(broadcom_exit); static struct mdio_device_id broadcom_tbl[] = { - { 0x00206070, 0xfffffff0 }, - { 0x002060e0, 0xfffffff0 }, - { 0x002060c0, 0xfffffff0 }, - { 0x002060b0, 0xfffffff0 }, - { 0x0143bca0, 0xfffffff0 }, - { 0x0143bcb0, 0xfffffff0 }, + { PHY_ID_BCM5411, 0xfffffff0 }, + { PHY_ID_BCM5421, 0xfffffff0 }, + { PHY_ID_BCM5461, 0xfffffff0 }, + { PHY_ID_BCM5464, 0xfffffff0 }, + { PHY_ID_BCM5482, 0xfffffff0 }, + { PHY_ID_BCM5482, 0xfffffff0 }, { PHY_ID_BCM50610, 0xfffffff0 }, { PHY_ID_BCM50610M, 0xfffffff0 }, { PHY_ID_BCM57780, 0xfffffff0 }, { PHY_ID_BCMAC131, 0xfffffff0 }, + { PHY_ID_BCM5241, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index 439adafeacb1..3f2583f18a39 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -116,6 +116,8 @@ static struct phy_driver ip175c_driver = { .config_init = &ip175c_config_init, .config_aneg = &ip175c_config_aneg, .read_status = &ip175c_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 5a1bd5db2a93..0101f2bdf400 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -68,6 +68,15 @@ #define MII_M1111_COPPER 0 #define MII_M1111_FIBER 1 +#define MII_88E1121_PHY_MSCR_PAGE 2 +#define MII_88E1121_PHY_MSCR_REG 21 +#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5) +#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4) +#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4)) + +#define MII_88EC048_PHY_MSCR1_REG 16 +#define MII_88EC048_PHY_MSCR1_PAD_ODD BIT(6) + #define MII_88E1121_PHY_LED_CTRL 16 #define MII_88E1121_PHY_LED_PAGE 3 #define MII_88E1121_PHY_LED_DEF 0x0030 @@ -179,7 +188,30 @@ static int marvell_config_aneg(struct phy_device *phydev) static int m88e1121_config_aneg(struct phy_device *phydev) { - int err, temp; + int err, oldpage, mscr; + + oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + + err = phy_write(phydev, MII_88E1121_PHY_PAGE, + MII_88E1121_PHY_MSCR_PAGE); + if (err < 0) + return err; + mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & + MII_88E1121_PHY_MSCR_DELAY_MASK; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | + MII_88E1121_PHY_MSCR_TX_DELAY); + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; + + err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); + if (err < 0) + return err; + + phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); err = phy_write(phydev, MII_BMCR, BMCR_RESET); if (err < 0) @@ -190,17 +222,42 @@ static int m88e1121_config_aneg(struct phy_device *phydev) if (err < 0) return err; - temp = phy_read(phydev, MII_88E1121_PHY_PAGE); + oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE); phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF); - phy_write(phydev, MII_88E1121_PHY_PAGE, temp); + phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); err = genphy_config_aneg(phydev); return err; } +static int m88ec048_config_aneg(struct phy_device *phydev) +{ + int err, oldpage, mscr; + + oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE); + + err = phy_write(phydev, MII_88E1121_PHY_PAGE, + MII_88E1121_PHY_MSCR_PAGE); + if (err < 0) + return err; + + mscr = phy_read(phydev, MII_88EC048_PHY_MSCR1_REG); + mscr |= MII_88EC048_PHY_MSCR1_PAD_ODD; + + err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); + if (err < 0) + return err; + + err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); + if (err < 0) + return err; + + return m88e1121_config_aneg(phydev); +} + static int m88e1111_config_init(struct phy_device *phydev) { int err; @@ -595,6 +652,19 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { + .phy_id = MARVELL_PHY_ID_88EC048, + .phy_id_mask = MARVELL_PHY_ID_MASK, + .name = "Marvell 88EC048", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &m88ec048_config_aneg, + .read_status = &marvell_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .did_interrupt = &m88e1121_did_interrupt, + .driver = { .owner = THIS_MODULE }, + }, + { .phy_id = MARVELL_PHY_ID_88E1145, .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1145", @@ -659,6 +729,7 @@ static struct mdio_device_id marvell_tbl[] = { { 0x01410cb0, 0xfffffff0 }, { 0x01410cd0, 0xfffffff0 }, { 0x01410e30, 0xfffffff0 }, + { 0x01410e90, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index f443d43edd80..bd12ba941be5 100644 --- a/drivers/net/phy/mdio-octeon.c +++ b/drivers/net/phy/mdio-octeon.c @@ -85,7 +85,7 @@ static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, return 0; } -static int __init octeon_mdiobus_probe(struct platform_device *pdev) +static int __devinit octeon_mdiobus_probe(struct platform_device *pdev) { struct octeon_mdiobus *bus; union cvmx_smix_en smi_en; @@ -143,7 +143,7 @@ err: return err; } -static int __exit octeon_mdiobus_remove(struct platform_device *pdev) +static int __devexit octeon_mdiobus_remove(struct platform_device *pdev) { struct octeon_mdiobus *bus; union cvmx_smix_en smi_en; @@ -163,7 +163,7 @@ static struct platform_driver octeon_mdiobus_driver = { .owner = THIS_MODULE, }, .probe = octeon_mdiobus_probe, - .remove = __exit_p(octeon_mdiobus_remove), + .remove = __devexit_p(octeon_mdiobus_remove), }; void octeon_mdiobus_force_mod_depencency(void) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 0692f750c404..8bb7db676a5c 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -12,7 +12,8 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * - * Support : ksz9021 , vsc8201, ks8001 + * Support : ksz9021 1000/100/10 phy from Micrel + * ks8001, ks8737, ks8721, ks8041, ks8051 100/10 phy */ #include <linux/kernel.h> @@ -20,37 +21,146 @@ #include <linux/phy.h> #define PHY_ID_KSZ9021 0x00221611 -#define PHY_ID_VSC8201 0x000FC413 +#define PHY_ID_KS8737 0x00221720 +#define PHY_ID_KS8041 0x00221510 +#define PHY_ID_KS8051 0x00221550 +/* both for ks8001 Rev. A/B, and for ks8721 Rev 3. */ #define PHY_ID_KS8001 0x0022161A +/* general Interrupt control/status reg in vendor specific block. */ +#define MII_KSZPHY_INTCS 0x1B +#define KSZPHY_INTCS_JABBER (1 << 15) +#define KSZPHY_INTCS_RECEIVE_ERR (1 << 14) +#define KSZPHY_INTCS_PAGE_RECEIVE (1 << 13) +#define KSZPHY_INTCS_PARELLEL (1 << 12) +#define KSZPHY_INTCS_LINK_PARTNER_ACK (1 << 11) +#define KSZPHY_INTCS_LINK_DOWN (1 << 10) +#define KSZPHY_INTCS_REMOTE_FAULT (1 << 9) +#define KSZPHY_INTCS_LINK_UP (1 << 8) +#define KSZPHY_INTCS_ALL (KSZPHY_INTCS_LINK_UP |\ + KSZPHY_INTCS_LINK_DOWN) + +/* general PHY control reg in vendor specific block. */ +#define MII_KSZPHY_CTRL 0x1F +/* bitmap of PHY register to set interrupt mode */ +#define KSZPHY_CTRL_INT_ACTIVE_HIGH (1 << 9) +#define KSZ9021_CTRL_INT_ACTIVE_HIGH (1 << 14) +#define KS8737_CTRL_INT_ACTIVE_HIGH (1 << 14) + +static int kszphy_ack_interrupt(struct phy_device *phydev) +{ + /* bit[7..0] int status, which is a read and clear register. */ + 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); +} + +static int kszphy_config_intr(struct phy_device *phydev) +{ + int temp, rc; + + /* 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); + rc = kszphy_set_interrupt(phydev); + return rc < 0 ? rc : 0; +} + +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); + rc = kszphy_set_interrupt(phydev); + return rc < 0 ? rc : 0; +} + +static int ks8737_config_intr(struct phy_device *phydev) +{ + int temp, rc; + + /* set the interrupt pin active low */ + temp = phy_read(phydev, MII_KSZPHY_CTRL); + temp &= ~KS8737_CTRL_INT_ACTIVE_HIGH; + phy_write(phydev, MII_KSZPHY_CTRL, temp); + rc = kszphy_set_interrupt(phydev); + return rc < 0 ? rc : 0; +} static int kszphy_config_init(struct phy_device *phydev) { return 0; } +static struct phy_driver ks8737_driver = { + .phy_id = PHY_ID_KS8737, + .phy_id_mask = 0x00fffff0, + .name = "Micrel KS8737", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = kszphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = ks8737_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static struct phy_driver ks8041_driver = { + .phy_id = PHY_ID_KS8041, + .phy_id_mask = 0x00fffff0, + .name = "Micrel KS8041", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = kszphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = kszphy_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; -static struct phy_driver ks8001_driver = { - .phy_id = PHY_ID_KS8001, - .name = "Micrel KS8001", +static struct phy_driver ks8051_driver = { + .phy_id = PHY_ID_KS8051, .phy_id_mask = 0x00fffff0, - .features = PHY_BASIC_FEATURES, - .flags = PHY_POLL, + .name = "Micrel KS8051", + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = kszphy_config_intr, .driver = { .owner = THIS_MODULE,}, }; -static struct phy_driver vsc8201_driver = { - .phy_id = PHY_ID_VSC8201, - .name = "Micrel VSC8201", +static struct phy_driver ks8001_driver = { + .phy_id = PHY_ID_KS8001, + .name = "Micrel KS8001 or KS8721", .phy_id_mask = 0x00fffff0, - .features = PHY_BASIC_FEATURES, - .flags = PHY_POLL, + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = kszphy_config_intr, .driver = { .owner = THIS_MODULE,}, }; @@ -58,11 +168,14 @@ static struct phy_driver ksz9021_driver = { .phy_id = PHY_ID_KSZ9021, .phy_id_mask = 0x000fff10, .name = "Micrel KSZ9021 Gigabit PHY", - .features = PHY_GBIT_FEATURES | SUPPORTED_Pause, - .flags = PHY_POLL, + .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .ack_interrupt = kszphy_ack_interrupt, + .config_intr = ksz9021_config_intr, .driver = { .owner = THIS_MODULE, }, }; @@ -73,17 +186,29 @@ static int __init ksphy_init(void) ret = phy_driver_register(&ks8001_driver); if (ret) goto err1; - ret = phy_driver_register(&vsc8201_driver); + + ret = phy_driver_register(&ksz9021_driver); if (ret) goto err2; - ret = phy_driver_register(&ksz9021_driver); + ret = phy_driver_register(&ks8737_driver); if (ret) goto err3; + ret = phy_driver_register(&ks8041_driver); + if (ret) + goto err4; + ret = phy_driver_register(&ks8051_driver); + if (ret) + goto err5; + return 0; +err5: + phy_driver_unregister(&ks8041_driver); +err4: + phy_driver_unregister(&ks8737_driver); err3: - phy_driver_unregister(&vsc8201_driver); + phy_driver_unregister(&ksz9021_driver); err2: phy_driver_unregister(&ks8001_driver); err1: @@ -93,8 +218,10 @@ err1: static void __exit ksphy_exit(void) { phy_driver_unregister(&ks8001_driver); - phy_driver_unregister(&vsc8201_driver); + phy_driver_unregister(&ks8737_driver); phy_driver_unregister(&ksz9021_driver); + phy_driver_unregister(&ks8041_driver); + phy_driver_unregister(&ks8051_driver); } module_init(ksphy_init); @@ -106,8 +233,10 @@ MODULE_LICENSE("GPL"); static struct mdio_device_id micrel_tbl[] = { { PHY_ID_KSZ9021, 0x000fff10 }, - { PHY_ID_VSC8201, 0x00fffff0 }, { PHY_ID_KS8001, 0x00fffff0 }, + { PHY_ID_KS8737, 0x00fffff0 }, + { PHY_ID_KS8041, 0x00fffff0 }, + { PHY_ID_KS8051, 0x00fffff0 }, { } }; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 64be4664ccab..5130db8f5c4e 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -309,8 +309,9 @@ EXPORT_SYMBOL(phy_ethtool_gset); * current state. Use at own risk. */ int phy_mii_ioctl(struct phy_device *phydev, - struct mii_ioctl_data *mii_data, int cmd) + struct ifreq *ifr, int cmd) { + struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; switch (cmd) { @@ -360,6 +361,11 @@ int phy_mii_ioctl(struct phy_device *phydev, } break; + case SIOCSHWTSTAMP: + if (phydev->drv->hwtstamp) + return phydev->drv->hwtstamp(phydev, ifr); + /* fall through */ + default: return -EOPNOTSUPP; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 1a99bb244106..c0761197c07e 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -460,6 +460,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, } phydev->attached_dev = dev; + dev->phydev = phydev; phydev->dev_flags = flags; @@ -513,6 +514,7 @@ EXPORT_SYMBOL(phy_attach); */ void phy_detach(struct phy_device *phydev) { + phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; /* If the device had no specific driver before (i.e. - it |