1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+ 20cefeebaSMichael Barkowski /* 30cefeebaSMichael Barkowski * Driver for ICPlus PHYs 40cefeebaSMichael Barkowski * 50cefeebaSMichael Barkowski * Copyright (c) 2007 Freescale Semiconductor, Inc. 60cefeebaSMichael Barkowski */ 70cefeebaSMichael Barkowski #include <linux/kernel.h> 80cefeebaSMichael Barkowski #include <linux/string.h> 90cefeebaSMichael Barkowski #include <linux/errno.h> 100cefeebaSMichael Barkowski #include <linux/unistd.h> 110cefeebaSMichael Barkowski #include <linux/interrupt.h> 120cefeebaSMichael Barkowski #include <linux/init.h> 130cefeebaSMichael Barkowski #include <linux/delay.h> 140cefeebaSMichael Barkowski #include <linux/netdevice.h> 150cefeebaSMichael Barkowski #include <linux/etherdevice.h> 160cefeebaSMichael Barkowski #include <linux/skbuff.h> 170cefeebaSMichael Barkowski #include <linux/spinlock.h> 180cefeebaSMichael Barkowski #include <linux/mm.h> 190cefeebaSMichael Barkowski #include <linux/module.h> 200cefeebaSMichael Barkowski #include <linux/mii.h> 210cefeebaSMichael Barkowski #include <linux/ethtool.h> 220cefeebaSMichael Barkowski #include <linux/phy.h> 23f2f1a847SMartin Blumenstingl #include <linux/property.h> 240cefeebaSMichael Barkowski 250cefeebaSMichael Barkowski #include <asm/io.h> 260cefeebaSMichael Barkowski #include <asm/irq.h> 277c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 280cefeebaSMichael Barkowski 29e3e09f26SGiuseppe CAVALLARO MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers"); 300cefeebaSMichael Barkowski MODULE_AUTHOR("Michael Barkowski"); 310cefeebaSMichael Barkowski MODULE_LICENSE("GPL"); 320cefeebaSMichael Barkowski 33e3e09f26SGiuseppe CAVALLARO /* IP101A/G - IP1001 */ 349c9b1f24SGiuseppe CAVALLARO #define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ 35ee336140SMartin Blumenstingl #define IP1001_RXPHASE_SEL BIT(0) /* Add delay on RX_CLK */ 36ee336140SMartin Blumenstingl #define IP1001_TXPHASE_SEL BIT(1) /* Add delay on TX_CLK */ 379c9b1f24SGiuseppe CAVALLARO #define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ 389c9b1f24SGiuseppe CAVALLARO #define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ 39ee336140SMartin Blumenstingl #define IP101A_G_APS_ON BIT(1) /* IP101A/G APS Mode bit */ 40996f7393SGiuseppe CAVALLARO #define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ 41ba2f55b0SHeiner Kallweit #define IP101A_G_IRQ_PIN_USED BIT(15) /* INTR pin used */ 42a872c388SMartin Blumenstingl #define IP101A_G_IRQ_ALL_MASK BIT(11) /* IRQ's inactive */ 43f7e290fbSMartin Blumenstingl #define IP101A_G_IRQ_SPEED_CHANGE BIT(2) 44f7e290fbSMartin Blumenstingl #define IP101A_G_IRQ_DUPLEX_CHANGE BIT(1) 45f7e290fbSMartin Blumenstingl #define IP101A_G_IRQ_LINK_CHANGE BIT(0) 469c9b1f24SGiuseppe CAVALLARO 47f2f1a847SMartin Blumenstingl #define IP101G_DIGITAL_IO_SPEC_CTRL 0x1d 48f2f1a847SMartin Blumenstingl #define IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32 BIT(2) 49f2f1a847SMartin Blumenstingl 502ad4758cSMichael Walle #define IP175C_PHY_ID 0x02430d80 512ad4758cSMichael Walle #define IP1001_PHY_ID 0x02430d90 522ad4758cSMichael Walle #define IP101A_PHY_ID 0x02430c54 532ad4758cSMichael Walle 54f2f1a847SMartin Blumenstingl /* The 32-pin IP101GR package can re-configure the mode of the RXER/INTR_32 pin 55f2f1a847SMartin Blumenstingl * (pin number 21). The hardware default is RXER (receive error) mode. But it 56f2f1a847SMartin Blumenstingl * can be configured to interrupt mode manually. 57f2f1a847SMartin Blumenstingl */ 58f2f1a847SMartin Blumenstingl enum ip101gr_sel_intr32 { 59f2f1a847SMartin Blumenstingl IP101GR_SEL_INTR32_KEEP, 60f2f1a847SMartin Blumenstingl IP101GR_SEL_INTR32_INTR, 61f2f1a847SMartin Blumenstingl IP101GR_SEL_INTR32_RXER, 62f2f1a847SMartin Blumenstingl }; 63f2f1a847SMartin Blumenstingl 64f2f1a847SMartin Blumenstingl struct ip101a_g_phy_priv { 65f2f1a847SMartin Blumenstingl enum ip101gr_sel_intr32 sel_intr32; 66f2f1a847SMartin Blumenstingl }; 67f2f1a847SMartin Blumenstingl 680cefeebaSMichael Barkowski static int ip175c_config_init(struct phy_device *phydev) 690cefeebaSMichael Barkowski { 700cefeebaSMichael Barkowski int err, i; 719ed66cb5SFlorian Fainelli static int full_reset_performed; 720cefeebaSMichael Barkowski 730cefeebaSMichael Barkowski if (full_reset_performed == 0) { 740cefeebaSMichael Barkowski 750cefeebaSMichael Barkowski /* master reset */ 76e5a03bfdSAndrew Lunn err = mdiobus_write(phydev->mdio.bus, 30, 0, 0x175c); 770cefeebaSMichael Barkowski if (err < 0) 780cefeebaSMichael Barkowski return err; 790cefeebaSMichael Barkowski 800cefeebaSMichael Barkowski /* ensure no bus delays overlap reset period */ 81e5a03bfdSAndrew Lunn err = mdiobus_read(phydev->mdio.bus, 30, 0); 820cefeebaSMichael Barkowski 830cefeebaSMichael Barkowski /* data sheet specifies reset period is 2 msec */ 840cefeebaSMichael Barkowski mdelay(2); 850cefeebaSMichael Barkowski 860cefeebaSMichael Barkowski /* enable IP175C mode */ 87e5a03bfdSAndrew Lunn err = mdiobus_write(phydev->mdio.bus, 29, 31, 0x175c); 880cefeebaSMichael Barkowski if (err < 0) 890cefeebaSMichael Barkowski return err; 900cefeebaSMichael Barkowski 910cefeebaSMichael Barkowski /* Set MII0 speed and duplex (in PHY mode) */ 92e5a03bfdSAndrew Lunn err = mdiobus_write(phydev->mdio.bus, 29, 22, 0x420); 930cefeebaSMichael Barkowski if (err < 0) 940cefeebaSMichael Barkowski return err; 950cefeebaSMichael Barkowski 960cefeebaSMichael Barkowski /* reset switch ports */ 970cefeebaSMichael Barkowski for (i = 0; i < 5; i++) { 98e5a03bfdSAndrew Lunn err = mdiobus_write(phydev->mdio.bus, i, 990cefeebaSMichael Barkowski MII_BMCR, BMCR_RESET); 1000cefeebaSMichael Barkowski if (err < 0) 1010cefeebaSMichael Barkowski return err; 1020cefeebaSMichael Barkowski } 1030cefeebaSMichael Barkowski 1040cefeebaSMichael Barkowski for (i = 0; i < 5; i++) 105e5a03bfdSAndrew Lunn err = mdiobus_read(phydev->mdio.bus, i, MII_BMCR); 1060cefeebaSMichael Barkowski 1070cefeebaSMichael Barkowski mdelay(2); 1080cefeebaSMichael Barkowski 1090cefeebaSMichael Barkowski full_reset_performed = 1; 1100cefeebaSMichael Barkowski } 1110cefeebaSMichael Barkowski 112e5a03bfdSAndrew Lunn if (phydev->mdio.addr != 4) { 1130cefeebaSMichael Barkowski phydev->state = PHY_RUNNING; 1140cefeebaSMichael Barkowski phydev->speed = SPEED_100; 1150cefeebaSMichael Barkowski phydev->duplex = DUPLEX_FULL; 1160cefeebaSMichael Barkowski phydev->link = 1; 1170cefeebaSMichael Barkowski netif_carrier_on(phydev->attached_dev); 1180cefeebaSMichael Barkowski } 1190cefeebaSMichael Barkowski 1200cefeebaSMichael Barkowski return 0; 1210cefeebaSMichael Barkowski } 1220cefeebaSMichael Barkowski 1239c9b1f24SGiuseppe CAVALLARO static int ip1xx_reset(struct phy_device *phydev) 124377ecca9SGiuseppe CAVALLARO { 125b8e3995aSDavid McKay int bmcr; 126377ecca9SGiuseppe CAVALLARO 127377ecca9SGiuseppe CAVALLARO /* Software Reset PHY */ 1289c9b1f24SGiuseppe CAVALLARO bmcr = phy_read(phydev, MII_BMCR); 129b8e3995aSDavid McKay if (bmcr < 0) 130b8e3995aSDavid McKay return bmcr; 1319c9b1f24SGiuseppe CAVALLARO bmcr |= BMCR_RESET; 132b8e3995aSDavid McKay bmcr = phy_write(phydev, MII_BMCR, bmcr); 133b8e3995aSDavid McKay if (bmcr < 0) 134b8e3995aSDavid McKay return bmcr; 135377ecca9SGiuseppe CAVALLARO 136377ecca9SGiuseppe CAVALLARO do { 1379c9b1f24SGiuseppe CAVALLARO bmcr = phy_read(phydev, MII_BMCR); 138b8e3995aSDavid McKay if (bmcr < 0) 139b8e3995aSDavid McKay return bmcr; 1409c9b1f24SGiuseppe CAVALLARO } while (bmcr & BMCR_RESET); 1419c9b1f24SGiuseppe CAVALLARO 142b8e3995aSDavid McKay return 0; 1439c9b1f24SGiuseppe CAVALLARO } 1449c9b1f24SGiuseppe CAVALLARO 1459c9b1f24SGiuseppe CAVALLARO static int ip1001_config_init(struct phy_device *phydev) 1469c9b1f24SGiuseppe CAVALLARO { 1479c9b1f24SGiuseppe CAVALLARO int c; 1489c9b1f24SGiuseppe CAVALLARO 1499c9b1f24SGiuseppe CAVALLARO c = ip1xx_reset(phydev); 1509c9b1f24SGiuseppe CAVALLARO if (c < 0) 1519c9b1f24SGiuseppe CAVALLARO return c; 1529c9b1f24SGiuseppe CAVALLARO 1539c9b1f24SGiuseppe CAVALLARO /* Enable Auto Power Saving mode */ 1549c9b1f24SGiuseppe CAVALLARO c = phy_read(phydev, IP1001_SPEC_CTRL_STATUS_2); 155b8e3995aSDavid McKay if (c < 0) 156b8e3995aSDavid McKay return c; 1579c9b1f24SGiuseppe CAVALLARO c |= IP1001_APS_ON; 158b8e3995aSDavid McKay c = phy_write(phydev, IP1001_SPEC_CTRL_STATUS_2, c); 1599c9b1f24SGiuseppe CAVALLARO if (c < 0) 1609c9b1f24SGiuseppe CAVALLARO return c; 161377ecca9SGiuseppe CAVALLARO 16232a64161SFlorian Fainelli if (phy_interface_is_rgmii(phydev)) { 163b4a49631SStuart Menefy 1649c9b1f24SGiuseppe CAVALLARO c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); 165b8e3995aSDavid McKay if (c < 0) 166b8e3995aSDavid McKay return c; 167b8e3995aSDavid McKay 168b4a49631SStuart Menefy c &= ~(IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); 169b4a49631SStuart Menefy 170b4a49631SStuart Menefy if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) 171b4a49631SStuart Menefy c |= (IP1001_RXPHASE_SEL | IP1001_TXPHASE_SEL); 172b4a49631SStuart Menefy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) 173b4a49631SStuart Menefy c |= IP1001_RXPHASE_SEL; 174b4a49631SStuart Menefy else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) 175b4a49631SStuart Menefy c |= IP1001_TXPHASE_SEL; 176b4a49631SStuart Menefy 177a4886d52SGiuseppe CAVALLARO c = phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); 178b8e3995aSDavid McKay if (c < 0) 179b8e3995aSDavid McKay return c; 180a4886d52SGiuseppe CAVALLARO } 181377ecca9SGiuseppe CAVALLARO 182b8e3995aSDavid McKay return 0; 1839c9b1f24SGiuseppe CAVALLARO } 1849c9b1f24SGiuseppe CAVALLARO 1850cefeebaSMichael Barkowski static int ip175c_read_status(struct phy_device *phydev) 1860cefeebaSMichael Barkowski { 187e5a03bfdSAndrew Lunn if (phydev->mdio.addr == 4) /* WAN port */ 1880cefeebaSMichael Barkowski genphy_read_status(phydev); 1890cefeebaSMichael Barkowski else 1900cefeebaSMichael Barkowski /* Don't need to read status for switch ports */ 1910cefeebaSMichael Barkowski phydev->irq = PHY_IGNORE_INTERRUPT; 1920cefeebaSMichael Barkowski 1930cefeebaSMichael Barkowski return 0; 1940cefeebaSMichael Barkowski } 1950cefeebaSMichael Barkowski 1960cefeebaSMichael Barkowski static int ip175c_config_aneg(struct phy_device *phydev) 1970cefeebaSMichael Barkowski { 198e5a03bfdSAndrew Lunn if (phydev->mdio.addr == 4) /* WAN port */ 1990cefeebaSMichael Barkowski genphy_config_aneg(phydev); 2000cefeebaSMichael Barkowski 2010cefeebaSMichael Barkowski return 0; 2020cefeebaSMichael Barkowski } 2030cefeebaSMichael Barkowski 204f2f1a847SMartin Blumenstingl static int ip101a_g_probe(struct phy_device *phydev) 205f2f1a847SMartin Blumenstingl { 206f2f1a847SMartin Blumenstingl struct device *dev = &phydev->mdio.dev; 207f2f1a847SMartin Blumenstingl struct ip101a_g_phy_priv *priv; 208f2f1a847SMartin Blumenstingl 209f2f1a847SMartin Blumenstingl priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 210f2f1a847SMartin Blumenstingl if (!priv) 211f2f1a847SMartin Blumenstingl return -ENOMEM; 212f2f1a847SMartin Blumenstingl 213f2f1a847SMartin Blumenstingl /* Both functions (RX error and interrupt status) are sharing the same 214f2f1a847SMartin Blumenstingl * pin on the 32-pin IP101GR, so this is an exclusive choice. 215f2f1a847SMartin Blumenstingl */ 216f2f1a847SMartin Blumenstingl if (device_property_read_bool(dev, "icplus,select-rx-error") && 217f2f1a847SMartin Blumenstingl device_property_read_bool(dev, "icplus,select-interrupt")) { 218f2f1a847SMartin Blumenstingl dev_err(dev, 219f2f1a847SMartin Blumenstingl "RXER and INTR mode cannot be selected together\n"); 220f2f1a847SMartin Blumenstingl return -EINVAL; 221f2f1a847SMartin Blumenstingl } 222f2f1a847SMartin Blumenstingl 223f2f1a847SMartin Blumenstingl if (device_property_read_bool(dev, "icplus,select-rx-error")) 224f2f1a847SMartin Blumenstingl priv->sel_intr32 = IP101GR_SEL_INTR32_RXER; 225f2f1a847SMartin Blumenstingl else if (device_property_read_bool(dev, "icplus,select-interrupt")) 226f2f1a847SMartin Blumenstingl priv->sel_intr32 = IP101GR_SEL_INTR32_INTR; 227f2f1a847SMartin Blumenstingl else 228f2f1a847SMartin Blumenstingl priv->sel_intr32 = IP101GR_SEL_INTR32_KEEP; 229f2f1a847SMartin Blumenstingl 230f2f1a847SMartin Blumenstingl phydev->priv = priv; 231f2f1a847SMartin Blumenstingl 232f2f1a847SMartin Blumenstingl return 0; 233f2f1a847SMartin Blumenstingl } 234f2f1a847SMartin Blumenstingl 235034289b2SMartin Blumenstingl static int ip101a_g_config_init(struct phy_device *phydev) 236034289b2SMartin Blumenstingl { 237f2f1a847SMartin Blumenstingl struct ip101a_g_phy_priv *priv = phydev->priv; 238f2f1a847SMartin Blumenstingl int err, c; 239034289b2SMartin Blumenstingl 240034289b2SMartin Blumenstingl c = ip1xx_reset(phydev); 241034289b2SMartin Blumenstingl if (c < 0) 242034289b2SMartin Blumenstingl return c; 243034289b2SMartin Blumenstingl 244f2f1a847SMartin Blumenstingl /* configure the RXER/INTR_32 pin of the 32-pin IP101GR if needed: */ 245f2f1a847SMartin Blumenstingl switch (priv->sel_intr32) { 246f2f1a847SMartin Blumenstingl case IP101GR_SEL_INTR32_RXER: 247f2f1a847SMartin Blumenstingl err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL, 248f2f1a847SMartin Blumenstingl IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32, 0); 249f2f1a847SMartin Blumenstingl if (err < 0) 250f2f1a847SMartin Blumenstingl return err; 251f2f1a847SMartin Blumenstingl break; 252f2f1a847SMartin Blumenstingl 253f2f1a847SMartin Blumenstingl case IP101GR_SEL_INTR32_INTR: 254f2f1a847SMartin Blumenstingl err = phy_modify(phydev, IP101G_DIGITAL_IO_SPEC_CTRL, 255f2f1a847SMartin Blumenstingl IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32, 256f2f1a847SMartin Blumenstingl IP101G_DIGITAL_IO_SPEC_CTRL_SEL_INTR32); 257f2f1a847SMartin Blumenstingl if (err < 0) 258f2f1a847SMartin Blumenstingl return err; 259f2f1a847SMartin Blumenstingl break; 260f2f1a847SMartin Blumenstingl 261f2f1a847SMartin Blumenstingl default: 262f2f1a847SMartin Blumenstingl /* Don't touch IP101G_DIGITAL_IO_SPEC_CTRL because it's not 263f2f1a847SMartin Blumenstingl * documented on IP101A and it's not clear whether this would 264f2f1a847SMartin Blumenstingl * cause problems. 265f2f1a847SMartin Blumenstingl * For the 32-pin IP101GR we simply keep the SEL_INTR32 266f2f1a847SMartin Blumenstingl * configuration as set by the bootloader when not configured 267f2f1a847SMartin Blumenstingl * to one of the special functions. 268f2f1a847SMartin Blumenstingl */ 269f2f1a847SMartin Blumenstingl break; 270f2f1a847SMartin Blumenstingl } 271f2f1a847SMartin Blumenstingl 272034289b2SMartin Blumenstingl /* Enable Auto Power Saving mode */ 273034289b2SMartin Blumenstingl c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS); 274034289b2SMartin Blumenstingl c |= IP101A_G_APS_ON; 275034289b2SMartin Blumenstingl 276034289b2SMartin Blumenstingl return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c); 277034289b2SMartin Blumenstingl } 278034289b2SMartin Blumenstingl 27912ae7ba3SIoana Ciornei static int ip101a_g_ack_interrupt(struct phy_device *phydev) 28012ae7ba3SIoana Ciornei { 28112ae7ba3SIoana Ciornei int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); 28212ae7ba3SIoana Ciornei 28312ae7ba3SIoana Ciornei if (err < 0) 28412ae7ba3SIoana Ciornei return err; 28512ae7ba3SIoana Ciornei 28612ae7ba3SIoana Ciornei return 0; 28712ae7ba3SIoana Ciornei } 28812ae7ba3SIoana Ciornei 289ba2f55b0SHeiner Kallweit static int ip101a_g_config_intr(struct phy_device *phydev) 290ba2f55b0SHeiner Kallweit { 291ba2f55b0SHeiner Kallweit u16 val; 29212ae7ba3SIoana Ciornei int err; 293ba2f55b0SHeiner Kallweit 29412ae7ba3SIoana Ciornei if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 29512ae7ba3SIoana Ciornei err = ip101a_g_ack_interrupt(phydev); 29612ae7ba3SIoana Ciornei if (err) 29712ae7ba3SIoana Ciornei return err; 29812ae7ba3SIoana Ciornei 299ba2f55b0SHeiner Kallweit /* INTR pin used: Speed/link/duplex will cause an interrupt */ 300ba2f55b0SHeiner Kallweit val = IP101A_G_IRQ_PIN_USED; 30112ae7ba3SIoana Ciornei err = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); 30212ae7ba3SIoana Ciornei } else { 303a872c388SMartin Blumenstingl val = IP101A_G_IRQ_ALL_MASK; 30412ae7ba3SIoana Ciornei err = phy_write(phydev, IP101A_G_IRQ_CONF_STATUS, val); 30512ae7ba3SIoana Ciornei if (err) 30612ae7ba3SIoana Ciornei return err; 307ba2f55b0SHeiner Kallweit 30812ae7ba3SIoana Ciornei err = ip101a_g_ack_interrupt(phydev); 30912ae7ba3SIoana Ciornei } 31012ae7ba3SIoana Ciornei 31112ae7ba3SIoana Ciornei return err; 312ba2f55b0SHeiner Kallweit } 313ba2f55b0SHeiner Kallweit 31425497b7fSIoana Ciornei static irqreturn_t ip101a_g_handle_interrupt(struct phy_device *phydev) 315f7e290fbSMartin Blumenstingl { 31625497b7fSIoana Ciornei int irq_status; 317f7e290fbSMartin Blumenstingl 31825497b7fSIoana Ciornei irq_status = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS); 31925497b7fSIoana Ciornei if (irq_status < 0) { 32025497b7fSIoana Ciornei phy_error(phydev); 32125497b7fSIoana Ciornei return IRQ_NONE; 32225497b7fSIoana Ciornei } 323f7e290fbSMartin Blumenstingl 32425497b7fSIoana Ciornei if (!(irq_status & (IP101A_G_IRQ_SPEED_CHANGE | 325f7e290fbSMartin Blumenstingl IP101A_G_IRQ_DUPLEX_CHANGE | 32625497b7fSIoana Ciornei IP101A_G_IRQ_LINK_CHANGE))) 32725497b7fSIoana Ciornei return IRQ_NONE; 32825497b7fSIoana Ciornei 32925497b7fSIoana Ciornei phy_trigger_machine(phydev); 33025497b7fSIoana Ciornei 33125497b7fSIoana Ciornei return IRQ_HANDLED; 332f7e290fbSMartin Blumenstingl } 333f7e290fbSMartin Blumenstingl 334d5bf9071SChristian Hohnstaedt static struct phy_driver icplus_driver[] = { 335d5bf9071SChristian Hohnstaedt { 3362ad4758cSMichael Walle PHY_ID_MATCH_MODEL(IP175C_PHY_ID), 3370cefeebaSMichael Barkowski .name = "ICPlus IP175C", 338dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 3390cefeebaSMichael Barkowski .config_init = &ip175c_config_init, 3400cefeebaSMichael Barkowski .config_aneg = &ip175c_config_aneg, 3410cefeebaSMichael Barkowski .read_status = &ip175c_read_status, 342dab10863SGiuseppe Cavallaro .suspend = genphy_suspend, 343dab10863SGiuseppe Cavallaro .resume = genphy_resume, 344d5bf9071SChristian Hohnstaedt }, { 3452ad4758cSMichael Walle PHY_ID_MATCH_MODEL(IP1001_PHY_ID), 346377ecca9SGiuseppe CAVALLARO .name = "ICPlus IP1001", 347dcdecdcfSHeiner Kallweit /* PHY_GBIT_FEATURES */ 348377ecca9SGiuseppe CAVALLARO .config_init = &ip1001_config_init, 349377ecca9SGiuseppe CAVALLARO .suspend = genphy_suspend, 350377ecca9SGiuseppe CAVALLARO .resume = genphy_resume, 351d5bf9071SChristian Hohnstaedt }, { 352*7360a4deSMichael Walle PHY_ID_MATCH_EXACT(IP101A_PHY_ID), 353e3e09f26SGiuseppe CAVALLARO .name = "ICPlus IP101A/G", 354dcdecdcfSHeiner Kallweit /* PHY_BASIC_FEATURES */ 355f2f1a847SMartin Blumenstingl .probe = ip101a_g_probe, 356ba2f55b0SHeiner Kallweit .config_intr = ip101a_g_config_intr, 35725497b7fSIoana Ciornei .handle_interrupt = ip101a_g_handle_interrupt, 358e3e09f26SGiuseppe CAVALLARO .config_init = &ip101a_g_config_init, 3599c9b1f24SGiuseppe CAVALLARO .suspend = genphy_suspend, 3609c9b1f24SGiuseppe CAVALLARO .resume = genphy_resume, 361d5bf9071SChristian Hohnstaedt } }; 3629c9b1f24SGiuseppe CAVALLARO 36350fd7150SJohan Hovold module_phy_driver(icplus_driver); 3644e4f10f6SDavid Woodhouse 365cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused icplus_tbl[] = { 3662ad4758cSMichael Walle { PHY_ID_MATCH_MODEL(IP175C_PHY_ID) }, 3672ad4758cSMichael Walle { PHY_ID_MATCH_MODEL(IP1001_PHY_ID) }, 368*7360a4deSMichael Walle { PHY_ID_MATCH_EXACT(IP101A_PHY_ID) }, 3694e4f10f6SDavid Woodhouse { } 3704e4f10f6SDavid Woodhouse }; 3714e4f10f6SDavid Woodhouse 3724e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, icplus_tbl); 373