10ca7111aSMatus Ujhelyi /* 20ca7111aSMatus Ujhelyi * drivers/net/phy/at803x.c 30ca7111aSMatus Ujhelyi * 40ca7111aSMatus Ujhelyi * Driver for Atheros 803x PHY 50ca7111aSMatus Ujhelyi * 60ca7111aSMatus Ujhelyi * Author: Matus Ujhelyi <ujhelyi.m@gmail.com> 70ca7111aSMatus Ujhelyi * 80ca7111aSMatus Ujhelyi * This program is free software; you can redistribute it and/or modify it 90ca7111aSMatus Ujhelyi * under the terms of the GNU General Public License as published by the 100ca7111aSMatus Ujhelyi * Free Software Foundation; either version 2 of the License, or (at your 110ca7111aSMatus Ujhelyi * option) any later version. 120ca7111aSMatus Ujhelyi */ 130ca7111aSMatus Ujhelyi 140ca7111aSMatus Ujhelyi #include <linux/phy.h> 150ca7111aSMatus Ujhelyi #include <linux/module.h> 160ca7111aSMatus Ujhelyi #include <linux/string.h> 170ca7111aSMatus Ujhelyi #include <linux/netdevice.h> 180ca7111aSMatus Ujhelyi #include <linux/etherdevice.h> 1913a56b44SDaniel Mack #include <linux/of_gpio.h> 2013a56b44SDaniel Mack #include <linux/gpio/consumer.h> 210ca7111aSMatus Ujhelyi 220ca7111aSMatus Ujhelyi #define AT803X_INTR_ENABLE 0x12 23a46bd63bSMartin Blumenstingl #define AT803X_INTR_ENABLE_INIT 0xec00 240ca7111aSMatus Ujhelyi #define AT803X_INTR_STATUS 0x13 25a46bd63bSMartin Blumenstingl 2613a56b44SDaniel Mack #define AT803X_SMART_SPEED 0x14 2713a56b44SDaniel Mack #define AT803X_LED_CONTROL 0x18 28a46bd63bSMartin Blumenstingl 290ca7111aSMatus Ujhelyi #define AT803X_WOL_ENABLE 0x01 300ca7111aSMatus Ujhelyi #define AT803X_DEVICE_ADDR 0x03 310ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C 320ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B 330ca7111aSMatus Ujhelyi #define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A 340ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL 0x0D 350ca7111aSMatus Ujhelyi #define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E 360ca7111aSMatus Ujhelyi #define AT803X_FUNC_DATA 0x4003 37a46bd63bSMartin Blumenstingl 381ca6d1b1SMugunthan V N #define AT803X_DEBUG_ADDR 0x1D 391ca6d1b1SMugunthan V N #define AT803X_DEBUG_DATA 0x1E 40a46bd63bSMartin Blumenstingl 412e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_0 0x00 422e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) 43a46bd63bSMartin Blumenstingl 442e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_REG_5 0x05 452e5f9f28SMartin Blumenstingl #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) 460ca7111aSMatus Ujhelyi 47bd8ca17fSDaniel Mack #define ATH8030_PHY_ID 0x004dd076 48bd8ca17fSDaniel Mack #define ATH8031_PHY_ID 0x004dd074 49bd8ca17fSDaniel Mack #define ATH8035_PHY_ID 0x004dd072 50bd8ca17fSDaniel Mack 510ca7111aSMatus Ujhelyi MODULE_DESCRIPTION("Atheros 803x PHY driver"); 520ca7111aSMatus Ujhelyi MODULE_AUTHOR("Matus Ujhelyi"); 530ca7111aSMatus Ujhelyi MODULE_LICENSE("GPL"); 540ca7111aSMatus Ujhelyi 5513a56b44SDaniel Mack struct at803x_priv { 5613a56b44SDaniel Mack bool phy_reset:1; 5713a56b44SDaniel Mack struct gpio_desc *gpiod_reset; 5813a56b44SDaniel Mack }; 5913a56b44SDaniel Mack 6013a56b44SDaniel Mack struct at803x_context { 6113a56b44SDaniel Mack u16 bmcr; 6213a56b44SDaniel Mack u16 advertise; 6313a56b44SDaniel Mack u16 control1000; 6413a56b44SDaniel Mack u16 int_enable; 6513a56b44SDaniel Mack u16 smart_speed; 6613a56b44SDaniel Mack u16 led_control; 6713a56b44SDaniel Mack }; 6813a56b44SDaniel Mack 692e5f9f28SMartin Blumenstingl static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) 702e5f9f28SMartin Blumenstingl { 712e5f9f28SMartin Blumenstingl int ret; 722e5f9f28SMartin Blumenstingl 732e5f9f28SMartin Blumenstingl ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); 742e5f9f28SMartin Blumenstingl if (ret < 0) 752e5f9f28SMartin Blumenstingl return ret; 762e5f9f28SMartin Blumenstingl 772e5f9f28SMartin Blumenstingl return phy_read(phydev, AT803X_DEBUG_DATA); 782e5f9f28SMartin Blumenstingl } 792e5f9f28SMartin Blumenstingl 802e5f9f28SMartin Blumenstingl static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, 812e5f9f28SMartin Blumenstingl u16 clear, u16 set) 822e5f9f28SMartin Blumenstingl { 832e5f9f28SMartin Blumenstingl u16 val; 842e5f9f28SMartin Blumenstingl int ret; 852e5f9f28SMartin Blumenstingl 862e5f9f28SMartin Blumenstingl ret = at803x_debug_reg_read(phydev, reg); 872e5f9f28SMartin Blumenstingl if (ret < 0) 882e5f9f28SMartin Blumenstingl return ret; 892e5f9f28SMartin Blumenstingl 902e5f9f28SMartin Blumenstingl val = ret & 0xffff; 912e5f9f28SMartin Blumenstingl val &= ~clear; 922e5f9f28SMartin Blumenstingl val |= set; 932e5f9f28SMartin Blumenstingl 942e5f9f28SMartin Blumenstingl return phy_write(phydev, AT803X_DEBUG_DATA, val); 952e5f9f28SMartin Blumenstingl } 962e5f9f28SMartin Blumenstingl 972e5f9f28SMartin Blumenstingl static inline int at803x_enable_rx_delay(struct phy_device *phydev) 982e5f9f28SMartin Blumenstingl { 992e5f9f28SMartin Blumenstingl return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0, 1002e5f9f28SMartin Blumenstingl AT803X_DEBUG_RX_CLK_DLY_EN); 1012e5f9f28SMartin Blumenstingl } 1022e5f9f28SMartin Blumenstingl 1032e5f9f28SMartin Blumenstingl static inline int at803x_enable_tx_delay(struct phy_device *phydev) 1042e5f9f28SMartin Blumenstingl { 1052e5f9f28SMartin Blumenstingl return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0, 1062e5f9f28SMartin Blumenstingl AT803X_DEBUG_TX_CLK_DLY_EN); 1072e5f9f28SMartin Blumenstingl } 1082e5f9f28SMartin Blumenstingl 10913a56b44SDaniel Mack /* save relevant PHY registers to private copy */ 11013a56b44SDaniel Mack static void at803x_context_save(struct phy_device *phydev, 11113a56b44SDaniel Mack struct at803x_context *context) 11213a56b44SDaniel Mack { 11313a56b44SDaniel Mack context->bmcr = phy_read(phydev, MII_BMCR); 11413a56b44SDaniel Mack context->advertise = phy_read(phydev, MII_ADVERTISE); 11513a56b44SDaniel Mack context->control1000 = phy_read(phydev, MII_CTRL1000); 11613a56b44SDaniel Mack context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); 11713a56b44SDaniel Mack context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); 11813a56b44SDaniel Mack context->led_control = phy_read(phydev, AT803X_LED_CONTROL); 11913a56b44SDaniel Mack } 12013a56b44SDaniel Mack 12113a56b44SDaniel Mack /* restore relevant PHY registers from private copy */ 12213a56b44SDaniel Mack static void at803x_context_restore(struct phy_device *phydev, 12313a56b44SDaniel Mack const struct at803x_context *context) 12413a56b44SDaniel Mack { 12513a56b44SDaniel Mack phy_write(phydev, MII_BMCR, context->bmcr); 12613a56b44SDaniel Mack phy_write(phydev, MII_ADVERTISE, context->advertise); 12713a56b44SDaniel Mack phy_write(phydev, MII_CTRL1000, context->control1000); 12813a56b44SDaniel Mack phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); 12913a56b44SDaniel Mack phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); 13013a56b44SDaniel Mack phy_write(phydev, AT803X_LED_CONTROL, context->led_control); 13113a56b44SDaniel Mack } 13213a56b44SDaniel Mack 133ea13c9eeSMugunthan V N static int at803x_set_wol(struct phy_device *phydev, 134ea13c9eeSMugunthan V N struct ethtool_wolinfo *wol) 1350ca7111aSMatus Ujhelyi { 1360ca7111aSMatus Ujhelyi struct net_device *ndev = phydev->attached_dev; 1370ca7111aSMatus Ujhelyi const u8 *mac; 138ea13c9eeSMugunthan V N int ret; 139ea13c9eeSMugunthan V N u32 value; 1400ca7111aSMatus Ujhelyi unsigned int i, offsets[] = { 1410ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_32_47_OFFSET, 1420ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_16_31_OFFSET, 1430ca7111aSMatus Ujhelyi AT803X_LOC_MAC_ADDR_0_15_OFFSET, 1440ca7111aSMatus Ujhelyi }; 1450ca7111aSMatus Ujhelyi 1460ca7111aSMatus Ujhelyi if (!ndev) 147ea13c9eeSMugunthan V N return -ENODEV; 1480ca7111aSMatus Ujhelyi 149ea13c9eeSMugunthan V N if (wol->wolopts & WAKE_MAGIC) { 1500ca7111aSMatus Ujhelyi mac = (const u8 *) ndev->dev_addr; 1510ca7111aSMatus Ujhelyi 1520ca7111aSMatus Ujhelyi if (!is_valid_ether_addr(mac)) 153ea13c9eeSMugunthan V N return -EFAULT; 1540ca7111aSMatus Ujhelyi 1550ca7111aSMatus Ujhelyi for (i = 0; i < 3; i++) { 1560ca7111aSMatus Ujhelyi phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, 1570ca7111aSMatus Ujhelyi AT803X_DEVICE_ADDR); 1580ca7111aSMatus Ujhelyi phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA, 1590ca7111aSMatus Ujhelyi offsets[i]); 1600ca7111aSMatus Ujhelyi phy_write(phydev, AT803X_MMD_ACCESS_CONTROL, 1610ca7111aSMatus Ujhelyi AT803X_FUNC_DATA); 1620ca7111aSMatus Ujhelyi phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA, 1630ca7111aSMatus Ujhelyi mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); 1640ca7111aSMatus Ujhelyi } 165ea13c9eeSMugunthan V N 166ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 167ea13c9eeSMugunthan V N value |= AT803X_WOL_ENABLE; 168ea13c9eeSMugunthan V N ret = phy_write(phydev, AT803X_INTR_ENABLE, value); 169ea13c9eeSMugunthan V N if (ret) 170ea13c9eeSMugunthan V N return ret; 171ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_STATUS); 172ea13c9eeSMugunthan V N } else { 173ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 174ea13c9eeSMugunthan V N value &= (~AT803X_WOL_ENABLE); 175ea13c9eeSMugunthan V N ret = phy_write(phydev, AT803X_INTR_ENABLE, value); 176ea13c9eeSMugunthan V N if (ret) 177ea13c9eeSMugunthan V N return ret; 178ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_STATUS); 179ea13c9eeSMugunthan V N } 180ea13c9eeSMugunthan V N 181ea13c9eeSMugunthan V N return ret; 182ea13c9eeSMugunthan V N } 183ea13c9eeSMugunthan V N 184ea13c9eeSMugunthan V N static void at803x_get_wol(struct phy_device *phydev, 185ea13c9eeSMugunthan V N struct ethtool_wolinfo *wol) 186ea13c9eeSMugunthan V N { 187ea13c9eeSMugunthan V N u32 value; 188ea13c9eeSMugunthan V N 189ea13c9eeSMugunthan V N wol->supported = WAKE_MAGIC; 190ea13c9eeSMugunthan V N wol->wolopts = 0; 191ea13c9eeSMugunthan V N 192ea13c9eeSMugunthan V N value = phy_read(phydev, AT803X_INTR_ENABLE); 193ea13c9eeSMugunthan V N if (value & AT803X_WOL_ENABLE) 194ea13c9eeSMugunthan V N wol->wolopts |= WAKE_MAGIC; 1950ca7111aSMatus Ujhelyi } 1960ca7111aSMatus Ujhelyi 1976229ed1fSDaniel Mack static int at803x_suspend(struct phy_device *phydev) 1986229ed1fSDaniel Mack { 1996229ed1fSDaniel Mack int value; 2006229ed1fSDaniel Mack int wol_enabled; 2016229ed1fSDaniel Mack 2026229ed1fSDaniel Mack mutex_lock(&phydev->lock); 2036229ed1fSDaniel Mack 2046229ed1fSDaniel Mack value = phy_read(phydev, AT803X_INTR_ENABLE); 2056229ed1fSDaniel Mack wol_enabled = value & AT803X_WOL_ENABLE; 2066229ed1fSDaniel Mack 2076229ed1fSDaniel Mack value = phy_read(phydev, MII_BMCR); 2086229ed1fSDaniel Mack 2096229ed1fSDaniel Mack if (wol_enabled) 2106229ed1fSDaniel Mack value |= BMCR_ISOLATE; 2116229ed1fSDaniel Mack else 2126229ed1fSDaniel Mack value |= BMCR_PDOWN; 2136229ed1fSDaniel Mack 2146229ed1fSDaniel Mack phy_write(phydev, MII_BMCR, value); 2156229ed1fSDaniel Mack 2166229ed1fSDaniel Mack mutex_unlock(&phydev->lock); 2176229ed1fSDaniel Mack 2186229ed1fSDaniel Mack return 0; 2196229ed1fSDaniel Mack } 2206229ed1fSDaniel Mack 2216229ed1fSDaniel Mack static int at803x_resume(struct phy_device *phydev) 2226229ed1fSDaniel Mack { 2236229ed1fSDaniel Mack int value; 2246229ed1fSDaniel Mack 2256229ed1fSDaniel Mack mutex_lock(&phydev->lock); 2266229ed1fSDaniel Mack 2276229ed1fSDaniel Mack value = phy_read(phydev, MII_BMCR); 2286229ed1fSDaniel Mack value &= ~(BMCR_PDOWN | BMCR_ISOLATE); 2296229ed1fSDaniel Mack phy_write(phydev, MII_BMCR, value); 2306229ed1fSDaniel Mack 2316229ed1fSDaniel Mack mutex_unlock(&phydev->lock); 2326229ed1fSDaniel Mack 2336229ed1fSDaniel Mack return 0; 2346229ed1fSDaniel Mack } 2356229ed1fSDaniel Mack 23613a56b44SDaniel Mack static int at803x_probe(struct phy_device *phydev) 23713a56b44SDaniel Mack { 238e5a03bfdSAndrew Lunn struct device *dev = &phydev->mdio.dev; 23913a56b44SDaniel Mack struct at803x_priv *priv; 240687908c2SUwe Kleine-König struct gpio_desc *gpiod_reset; 24113a56b44SDaniel Mack 2428f2877caSFengguang Wu priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 24313a56b44SDaniel Mack if (!priv) 24413a56b44SDaniel Mack return -ENOMEM; 24513a56b44SDaniel Mack 246687908c2SUwe Kleine-König gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 247687908c2SUwe Kleine-König if (IS_ERR(gpiod_reset)) 248687908c2SUwe Kleine-König return PTR_ERR(gpiod_reset); 249687908c2SUwe Kleine-König 250687908c2SUwe Kleine-König priv->gpiod_reset = gpiod_reset; 25113a56b44SDaniel Mack 25213a56b44SDaniel Mack phydev->priv = priv; 25313a56b44SDaniel Mack 25413a56b44SDaniel Mack return 0; 25513a56b44SDaniel Mack } 25613a56b44SDaniel Mack 2570ca7111aSMatus Ujhelyi static int at803x_config_init(struct phy_device *phydev) 2580ca7111aSMatus Ujhelyi { 2591ca6d1b1SMugunthan V N int ret; 2600ca7111aSMatus Ujhelyi 2616ff01dbbSDaniel Mack ret = genphy_config_init(phydev); 2626ff01dbbSDaniel Mack if (ret < 0) 2636ff01dbbSDaniel Mack return ret; 2640ca7111aSMatus Ujhelyi 2652e5f9f28SMartin Blumenstingl if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID || 2662e5f9f28SMartin Blumenstingl phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 2672e5f9f28SMartin Blumenstingl ret = at803x_enable_rx_delay(phydev); 2682e5f9f28SMartin Blumenstingl if (ret < 0) 2691ca6d1b1SMugunthan V N return ret; 2702e5f9f28SMartin Blumenstingl } 2712e5f9f28SMartin Blumenstingl 2722e5f9f28SMartin Blumenstingl if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID || 2732e5f9f28SMartin Blumenstingl phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) { 2742e5f9f28SMartin Blumenstingl ret = at803x_enable_tx_delay(phydev); 2752e5f9f28SMartin Blumenstingl if (ret < 0) 2761ca6d1b1SMugunthan V N return ret; 2771ca6d1b1SMugunthan V N } 2781ca6d1b1SMugunthan V N 2790ca7111aSMatus Ujhelyi return 0; 2800ca7111aSMatus Ujhelyi } 2810ca7111aSMatus Ujhelyi 28277a99394SZhao Qiang static int at803x_ack_interrupt(struct phy_device *phydev) 28377a99394SZhao Qiang { 28477a99394SZhao Qiang int err; 28577a99394SZhao Qiang 286a46bd63bSMartin Blumenstingl err = phy_read(phydev, AT803X_INTR_STATUS); 28777a99394SZhao Qiang 28877a99394SZhao Qiang return (err < 0) ? err : 0; 28977a99394SZhao Qiang } 29077a99394SZhao Qiang 29177a99394SZhao Qiang static int at803x_config_intr(struct phy_device *phydev) 29277a99394SZhao Qiang { 29377a99394SZhao Qiang int err; 29477a99394SZhao Qiang int value; 29577a99394SZhao Qiang 296a46bd63bSMartin Blumenstingl value = phy_read(phydev, AT803X_INTR_ENABLE); 29777a99394SZhao Qiang 29877a99394SZhao Qiang if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 299a46bd63bSMartin Blumenstingl err = phy_write(phydev, AT803X_INTR_ENABLE, 300a46bd63bSMartin Blumenstingl value | AT803X_INTR_ENABLE_INIT); 30177a99394SZhao Qiang else 302a46bd63bSMartin Blumenstingl err = phy_write(phydev, AT803X_INTR_ENABLE, 0); 30377a99394SZhao Qiang 30477a99394SZhao Qiang return err; 30577a99394SZhao Qiang } 30677a99394SZhao Qiang 30713a56b44SDaniel Mack static void at803x_link_change_notify(struct phy_device *phydev) 30813a56b44SDaniel Mack { 30913a56b44SDaniel Mack struct at803x_priv *priv = phydev->priv; 31013a56b44SDaniel Mack 31113a56b44SDaniel Mack /* 31213a56b44SDaniel Mack * Conduct a hardware reset for AT8030 every time a link loss is 31313a56b44SDaniel Mack * signalled. This is necessary to circumvent a hardware bug that 31413a56b44SDaniel Mack * occurs when the cable is unplugged while TX packets are pending 31513a56b44SDaniel Mack * in the FIFO. In such cases, the FIFO enters an error mode it 31613a56b44SDaniel Mack * cannot recover from by software. 31713a56b44SDaniel Mack */ 31813a56b44SDaniel Mack if (phydev->drv->phy_id == ATH8030_PHY_ID) { 31913a56b44SDaniel Mack if (phydev->state == PHY_NOLINK) { 32013a56b44SDaniel Mack if (priv->gpiod_reset && !priv->phy_reset) { 32113a56b44SDaniel Mack struct at803x_context context; 32213a56b44SDaniel Mack 32313a56b44SDaniel Mack at803x_context_save(phydev, &context); 32413a56b44SDaniel Mack 32513a56b44SDaniel Mack gpiod_set_value(priv->gpiod_reset, 0); 32613a56b44SDaniel Mack msleep(1); 32713a56b44SDaniel Mack gpiod_set_value(priv->gpiod_reset, 1); 32813a56b44SDaniel Mack msleep(1); 32913a56b44SDaniel Mack 33013a56b44SDaniel Mack at803x_context_restore(phydev, &context); 33113a56b44SDaniel Mack 33272ba48beSAndrew Lunn phydev_dbg(phydev, "%s(): phy was reset\n", 33313a56b44SDaniel Mack __func__); 33413a56b44SDaniel Mack priv->phy_reset = true; 33513a56b44SDaniel Mack } 33613a56b44SDaniel Mack } else { 33713a56b44SDaniel Mack priv->phy_reset = false; 33813a56b44SDaniel Mack } 33913a56b44SDaniel Mack } 34013a56b44SDaniel Mack } 34113a56b44SDaniel Mack 342317420abSMugunthan V N static struct phy_driver at803x_driver[] = { 343317420abSMugunthan V N { 3440ca7111aSMatus Ujhelyi /* ATHEROS 8035 */ 345bd8ca17fSDaniel Mack .phy_id = ATH8035_PHY_ID, 3460ca7111aSMatus Ujhelyi .name = "Atheros 8035 ethernet", 3470ca7111aSMatus Ujhelyi .phy_id_mask = 0xffffffef, 34813a56b44SDaniel Mack .probe = at803x_probe, 3490ca7111aSMatus Ujhelyi .config_init = at803x_config_init, 35013a56b44SDaniel Mack .link_change_notify = at803x_link_change_notify, 351ea13c9eeSMugunthan V N .set_wol = at803x_set_wol, 352ea13c9eeSMugunthan V N .get_wol = at803x_get_wol, 3536229ed1fSDaniel Mack .suspend = at803x_suspend, 3546229ed1fSDaniel Mack .resume = at803x_resume, 3550ca7111aSMatus Ujhelyi .features = PHY_GBIT_FEATURES, 3560ca7111aSMatus Ujhelyi .flags = PHY_HAS_INTERRUPT, 3570197ffedSDaniel Mack .config_aneg = genphy_config_aneg, 3580197ffedSDaniel Mack .read_status = genphy_read_status, 3590eae5982SMåns Rullgård .ack_interrupt = at803x_ack_interrupt, 3600eae5982SMåns Rullgård .config_intr = at803x_config_intr, 361317420abSMugunthan V N }, { 3620ca7111aSMatus Ujhelyi /* ATHEROS 8030 */ 363bd8ca17fSDaniel Mack .phy_id = ATH8030_PHY_ID, 3640ca7111aSMatus Ujhelyi .name = "Atheros 8030 ethernet", 3650ca7111aSMatus Ujhelyi .phy_id_mask = 0xffffffef, 36613a56b44SDaniel Mack .probe = at803x_probe, 3670ca7111aSMatus Ujhelyi .config_init = at803x_config_init, 36813a56b44SDaniel Mack .link_change_notify = at803x_link_change_notify, 369ea13c9eeSMugunthan V N .set_wol = at803x_set_wol, 370ea13c9eeSMugunthan V N .get_wol = at803x_get_wol, 3716229ed1fSDaniel Mack .suspend = at803x_suspend, 3726229ed1fSDaniel Mack .resume = at803x_resume, 373e15bb4c6SMartin Blumenstingl .features = PHY_BASIC_FEATURES, 3740ca7111aSMatus Ujhelyi .flags = PHY_HAS_INTERRUPT, 3750197ffedSDaniel Mack .config_aneg = genphy_config_aneg, 3760197ffedSDaniel Mack .read_status = genphy_read_status, 3770eae5982SMåns Rullgård .ack_interrupt = at803x_ack_interrupt, 3780eae5982SMåns Rullgård .config_intr = at803x_config_intr, 37905d7cce8SMugunthan V N }, { 38005d7cce8SMugunthan V N /* ATHEROS 8031 */ 381bd8ca17fSDaniel Mack .phy_id = ATH8031_PHY_ID, 38205d7cce8SMugunthan V N .name = "Atheros 8031 ethernet", 38305d7cce8SMugunthan V N .phy_id_mask = 0xffffffef, 38413a56b44SDaniel Mack .probe = at803x_probe, 38505d7cce8SMugunthan V N .config_init = at803x_config_init, 38613a56b44SDaniel Mack .link_change_notify = at803x_link_change_notify, 38705d7cce8SMugunthan V N .set_wol = at803x_set_wol, 38805d7cce8SMugunthan V N .get_wol = at803x_get_wol, 3896229ed1fSDaniel Mack .suspend = at803x_suspend, 3906229ed1fSDaniel Mack .resume = at803x_resume, 39105d7cce8SMugunthan V N .features = PHY_GBIT_FEATURES, 39205d7cce8SMugunthan V N .flags = PHY_HAS_INTERRUPT, 3930197ffedSDaniel Mack .config_aneg = genphy_config_aneg, 3940197ffedSDaniel Mack .read_status = genphy_read_status, 39577a99394SZhao Qiang .ack_interrupt = &at803x_ack_interrupt, 39677a99394SZhao Qiang .config_intr = &at803x_config_intr, 397317420abSMugunthan V N } }; 3980ca7111aSMatus Ujhelyi 39950fd7150SJohan Hovold module_phy_driver(at803x_driver); 4000ca7111aSMatus Ujhelyi 4010ca7111aSMatus Ujhelyi static struct mdio_device_id __maybe_unused atheros_tbl[] = { 402bd8ca17fSDaniel Mack { ATH8030_PHY_ID, 0xffffffef }, 403bd8ca17fSDaniel Mack { ATH8031_PHY_ID, 0xffffffef }, 404bd8ca17fSDaniel Mack { ATH8035_PHY_ID, 0xffffffef }, 4050ca7111aSMatus Ujhelyi { } 4060ca7111aSMatus Ujhelyi }; 4070ca7111aSMatus Ujhelyi 4080ca7111aSMatus Ujhelyi MODULE_DEVICE_TABLE(mdio, atheros_tbl); 409