diff options
Diffstat (limited to 'drivers/net/phy/icplus.c')
| -rw-r--r-- | drivers/net/phy/icplus.c | 167 |
1 files changed, 127 insertions, 40 deletions
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index 9a09e24c30b..97bf58bf493 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -30,48 +30,59 @@ #include <asm/irq.h> #include <asm/uaccess.h> -MODULE_DESCRIPTION("ICPlus IP175C/IC1001 PHY drivers"); +MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers"); MODULE_AUTHOR("Michael Barkowski"); MODULE_LICENSE("GPL"); +/* IP101A/G - IP1001 */ +#define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ +#define IP1001_RXPHASE_SEL (1<<0) /* Add delay on RX_CLK */ +#define IP1001_TXPHASE_SEL (1<<1) /* Add delay on TX_CLK */ +#define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ +#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ +#define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ +#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ +#define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */ +#define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED + static int ip175c_config_init(struct phy_device *phydev) { int err, i; - static int full_reset_performed = 0; + static int full_reset_performed; if (full_reset_performed == 0) { /* master reset */ - err = phydev->bus->write(phydev->bus, 30, 0, 0x175c); + err = mdiobus_write(phydev->bus, 30, 0, 0x175c); if (err < 0) return err; /* ensure no bus delays overlap reset period */ - err = phydev->bus->read(phydev->bus, 30, 0); + err = mdiobus_read(phydev->bus, 30, 0); /* data sheet specifies reset period is 2 msec */ mdelay(2); /* enable IP175C mode */ - err = phydev->bus->write(phydev->bus, 29, 31, 0x175c); + err = mdiobus_write(phydev->bus, 29, 31, 0x175c); if (err < 0) return err; /* Set MII0 speed and duplex (in PHY mode) */ - err = phydev->bus->write(phydev->bus, 29, 22, 0x420); + err = mdiobus_write(phydev->bus, 29, 22, 0x420); if (err < 0) return err; /* reset switch ports */ for (i = 0; i < 5; i++) { - err = phydev->bus->write(phydev->bus, i, - MII_BMCR, BMCR_RESET); + err = mdiobus_write(phydev->bus, i, + MII_BMCR, BMCR_RESET); if (err < 0) return err; } for (i = 0; i < 5; i++) - err = phydev->bus->read(phydev->bus, i, MII_BMCR); + err = mdiobus_read(phydev->bus, i, MII_BMCR); mdelay(2); @@ -89,31 +100,89 @@ static int ip175c_config_init(struct phy_device *phydev) return 0; } -static int ip1001_config_init(struct phy_device *phydev) +static int ip1xx_reset(struct phy_device *phydev) { - int err, value; + int bmcr; /* Software Reset PHY */ - value = phy_read(phydev, MII_BMCR); - value |= BMCR_RESET; - err = phy_write(phydev, MII_BMCR, value); - if (err < 0) - return err; + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + bmcr |= BMCR_RESET; + bmcr = phy_write(phydev, MII_BMCR, bmcr); + if (bmcr < 0) + return bmcr; do { - value = phy_read(phydev, MII_BMCR); - } while (value & BMCR_RESET); + bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + } while (bmcr & BMCR_RESET); - /* Additional delay (2ns) used to adjust RX clock phase - * at GMII/ RGMII interface */ - value = phy_read(phydev, 16); - value |= 0x3; + return 0; +} - err = phy_write(phydev, 16, value); - if (err < 0) - return err; +static int ip1001_config_init(struct phy_device *phydev) +{ + int c; + + c = ip1xx_reset(phydev); + if (c < 0) + return c; + + /* Enable Auto Power Saving mode */ + c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2); + if (c < 0) + return c; + c |= IP1001_APS_ON; + c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c); + if (c < 0) + return c; + + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { + + c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); + if (c < 0) + return c; + + c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + c |= IP1001_RXPHASE_SEL; + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + c |= IP1001_TXPHASE_SEL; + + c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); + if (c < 0) + return c; + } + + return 0; +} + +static int ip101a_g_config_init(struct phy_device *phydev) +{ + int c; + + c = ip1xx_reset(phydev); + if (c < 0) + return c; + + /* INTR pin used: speed/link/duplex will cause an interrupt */ + c = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, IP101A_G_IRQ_DEFAULT); + if (c < 0) + return c; - return err; + /* Enable Auto Power Saving mode */ + c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); + c |= IP101A_G_APS_ON; + + return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); } static int ip175c_read_status(struct phy_device *phydev) @@ -135,7 +204,17 @@ static int ip175c_config_aneg(struct phy_device *phydev) return 0; } -static struct phy_driver ip175c_driver = { +static int ip101a_g_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); + if (err < 0) + return err; + + return 0; +} + +static struct phy_driver icplus_driver[] = { +{ .phy_id = 0x02430d80, .name = "ICPlus IP175C", .phy_id_mask = 0x0ffffff0, @@ -146,9 +225,7 @@ static struct phy_driver ip175c_driver = { .suspend = genphy_suspend, .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, -}; - -static struct phy_driver ip1001_driver = { +}, { .phy_id = 0x02430d90, .name = "ICPlus IP1001", .phy_id_mask = 0x0ffffff0, @@ -160,23 +237,32 @@ static struct phy_driver ip1001_driver = { .suspend = genphy_suspend, .resume = genphy_resume, .driver = { .owner = THIS_MODULE,}, -}; +}, { + .phy_id = 0x02430c54, + .name = "ICPlus IP101A/G", + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause, + .flags = PHY_HAS_INTERRUPT, + .ack_interrupt = ip101a_g_ack_interrupt, + .config_init = &ip101a_g_config_init, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = { .owner = THIS_MODULE,}, +} }; static int __init icplus_init(void) { - int ret = 0; - - ret = phy_driver_register(&ip1001_driver); - if (ret < 0) - return -ENODEV; - - return phy_driver_register(&ip175c_driver); + return phy_drivers_register(icplus_driver, + ARRAY_SIZE(icplus_driver)); } static void __exit icplus_exit(void) { - phy_driver_unregister(&ip1001_driver); - phy_driver_unregister(&ip175c_driver); + phy_drivers_unregister(icplus_driver, + ARRAY_SIZE(icplus_driver)); } module_init(icplus_init); @@ -185,6 +271,7 @@ module_exit(icplus_exit); static struct mdio_device_id __maybe_unused icplus_tbl[] = { { 0x02430d80, 0x0ffffff0 }, { 0x02430d90, 0x0ffffff0 }, + { 0x02430c54, 0x0ffffff0 }, { } }; |
