diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 46 | ||||
-rw-r--r-- | drivers/net/phy/icplus.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/lxt.c | 52 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 115 | ||||
-rw-r--r-- | drivers/net/phy/mdio-gpio.c | 4 | ||||
-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 | 10 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 2 |
10 files changed, 345 insertions, 61 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index a527e37728c..eb799b36c86 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -5,7 +5,7 @@ menuconfig PHYLIB tristate "PHY Device support and infrastructure" depends on !S390 - depends on NET_ETHERNET + depends on NETDEVICES help Ethernet controllers are usually attached to PHY devices. This option provides infrastructure for diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index cecdbbd549e..4accd83d3df 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 439adafeacb..3f2583f18a3 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/lxt.c b/drivers/net/phy/lxt.c index 8ee929b796d..29c39ff85de 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -53,6 +53,9 @@ #define MII_LXT971_ISR 19 /* Interrupt Status Register */ +/* register definitions for the 973 */ +#define MII_LXT973_PCR 16 /* Port Configuration Register */ +#define PCR_FIBER_SELECT 1 MODULE_DESCRIPTION("Intel LXT PHY driver"); MODULE_AUTHOR("Andy Fleming"); @@ -119,6 +122,33 @@ static int lxt971_config_intr(struct phy_device *phydev) return err; } +static int lxt973_probe(struct phy_device *phydev) +{ + int val = phy_read(phydev, MII_LXT973_PCR); + + if (val & PCR_FIBER_SELECT) { + /* + * If fiber is selected, then the only correct setting + * is 100Mbps, full duplex, and auto negotiation off. + */ + val = phy_read(phydev, MII_BMCR); + val |= (BMCR_SPEED100 | BMCR_FULLDPLX); + val &= ~BMCR_ANENABLE; + phy_write(phydev, MII_BMCR, val); + /* Remember that the port is in fiber mode. */ + phydev->priv = lxt973_probe; + } else { + phydev->priv = NULL; + } + return 0; +} + +static int lxt973_config_aneg(struct phy_device *phydev) +{ + /* Do nothing if port is in fiber mode. */ + return phydev->priv ? 0 : genphy_config_aneg(phydev); +} + static struct phy_driver lxt970_driver = { .phy_id = 0x78100000, .name = "LXT970", @@ -146,6 +176,18 @@ static struct phy_driver lxt971_driver = { .driver = { .owner = THIS_MODULE,}, }; +static struct phy_driver lxt973_driver = { + .phy_id = 0x00137a10, + .name = "LXT973", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .flags = 0, + .probe = lxt973_probe, + .config_aneg = lxt973_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + static int __init lxt_init(void) { int ret; @@ -157,9 +199,15 @@ static int __init lxt_init(void) ret = phy_driver_register(&lxt971_driver); if (ret) goto err2; + + ret = phy_driver_register(&lxt973_driver); + if (ret) + goto err3; return 0; - err2: + err3: + phy_driver_unregister(&lxt971_driver); + err2: phy_driver_unregister(&lxt970_driver); err1: return ret; @@ -169,6 +217,7 @@ static void __exit lxt_exit(void) { phy_driver_unregister(&lxt970_driver); phy_driver_unregister(&lxt971_driver); + phy_driver_unregister(&lxt973_driver); } module_init(lxt_init); @@ -177,6 +226,7 @@ module_exit(lxt_exit); static struct mdio_device_id lxt_tbl[] = { { 0x78100000, 0xfffffff0 }, { 0x001378e0, 0xfffffff0 }, + { 0x00137a10, 0xfffffff0 }, { } }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 78b74e83ce5..0101f2bdf40 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -29,6 +29,7 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/marvell_phy.h> #include <asm/io.h> #include <asm/irq.h> @@ -48,8 +49,6 @@ #define MII_M1145_RGMII_RX_DELAY 0x0080 #define MII_M1145_RGMII_TX_DELAY 0x0002 -#define M1145_DEV_FLAGS_RESISTANCE 0x00000001 - #define MII_M1111_PHY_LED_CONTROL 0x18 #define MII_M1111_PHY_LED_DIRECT 0x4100 #define MII_M1111_PHY_LED_COMBINE 0x411c @@ -69,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 @@ -180,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) @@ -191,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; @@ -350,7 +406,10 @@ static int m88e1118_config_init(struct phy_device *phydev) return err; /* Adjust LED Control */ - err = phy_write(phydev, 0x10, 0x021e); + if (phydev->dev_flags & MARVELL_PHY_M1118_DNS323_LEDS) + err = phy_write(phydev, 0x10, 0x1100); + else + err = phy_write(phydev, 0x10, 0x021e); if (err < 0) return err; @@ -398,7 +457,7 @@ static int m88e1145_config_init(struct phy_device *phydev) if (err < 0) return err; - if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) { + if (phydev->dev_flags & MARVELL_PHY_M1145_FLAGS_RESISTANCE) { err = phy_write(phydev, 0x1d, 0x0012); if (err < 0) return err; @@ -529,8 +588,8 @@ static int m88e1121_did_interrupt(struct phy_device *phydev) static struct phy_driver marvell_drivers[] = { { - .phy_id = 0x01410c60, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1101, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1101", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -541,8 +600,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410c90, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1112, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1112", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -554,8 +613,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410cc0, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1111, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1111", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -567,8 +626,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410e10, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1118, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1118", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -580,8 +639,8 @@ static struct phy_driver marvell_drivers[] = { .driver = {.owner = THIS_MODULE,}, }, { - .phy_id = 0x01410cb0, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1121R, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1121R", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -593,8 +652,21 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410cd0, - .phy_id_mask = 0xfffffff0, + .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", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -606,8 +678,8 @@ static struct phy_driver marvell_drivers[] = { .driver = { .owner = THIS_MODULE }, }, { - .phy_id = 0x01410e30, - .phy_id_mask = 0xfffffff0, + .phy_id = MARVELL_PHY_ID_88E1240, + .phy_id_mask = MARVELL_PHY_ID_MASK, .name = "Marvell 88E1240", .features = PHY_GBIT_FEATURES, .flags = PHY_HAS_INTERRUPT, @@ -657,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-gpio.c b/drivers/net/phy/mdio-gpio.c index fc5fef2a817..f62c7b717bc 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -188,7 +188,7 @@ static int __devexit mdio_gpio_remove(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO -static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, +static int __devinit mdio_ofgpio_probe(struct platform_device *ofdev, const struct of_device_id *match) { struct mdio_gpio_platform_data *pdata; @@ -224,7 +224,7 @@ out_free: return -ENODEV; } -static int __devexit mdio_ofgpio_remove(struct of_device *ofdev) +static int __devexit mdio_ofgpio_remove(struct platform_device *ofdev) { mdio_gpio_bus_destroy(&ofdev->dev); kfree(ofdev->dev.platform_data); diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c index f443d43edd8..bd12ba941be 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 0692f750c40..8bb7db676a5 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 64be4664cca..1bb16cb7943 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -301,7 +301,7 @@ EXPORT_SYMBOL(phy_ethtool_gset); /** * phy_mii_ioctl - generic PHY MII ioctl interface * @phydev: the phy_device struct - * @mii_data: MII ioctl data + * @ifr: &struct ifreq for socket ioctl's * @cmd: ioctl cmd to execute * * Note that this function is currently incompatible with the @@ -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 1a99bb24410..c0761197c07 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 |