18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ASIX AX8817X based USB 2.0 Ethernet Devices 48c2ecf20Sopenharmony_ci * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 68c2ecf20Sopenharmony_ci * Copyright (C) 2006 James Painter <jamie.painter@iname.com> 78c2ecf20Sopenharmony_ci * Copyright (c) 2002-2003 TiVo Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "asix.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define PHY_MODE_MARVELL 0x0000 138c2ecf20Sopenharmony_ci#define MII_MARVELL_LED_CTRL 0x0018 148c2ecf20Sopenharmony_ci#define MII_MARVELL_STATUS 0x001b 158c2ecf20Sopenharmony_ci#define MII_MARVELL_CTRL 0x0014 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define MARVELL_LED_MANUAL 0x0019 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define MARVELL_STATUS_HWCFG 0x0004 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define MARVELL_CTRL_TXDELAY 0x0002 228c2ecf20Sopenharmony_ci#define MARVELL_CTRL_RXDELAY 0x0080 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define PHY_MODE_RTL8211CL 0x000C 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define AX88772A_PHY14H 0x14 278c2ecf20Sopenharmony_ci#define AX88772A_PHY14H_DEFAULT 0x442C 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define AX88772A_PHY15H 0x15 308c2ecf20Sopenharmony_ci#define AX88772A_PHY15H_DEFAULT 0x03C8 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define AX88772A_PHY16H 0x16 338c2ecf20Sopenharmony_ci#define AX88772A_PHY16H_DEFAULT 0x4044 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct ax88172_int_data { 368c2ecf20Sopenharmony_ci __le16 res1; 378c2ecf20Sopenharmony_ci u8 link; 388c2ecf20Sopenharmony_ci __le16 res2; 398c2ecf20Sopenharmony_ci u8 status; 408c2ecf20Sopenharmony_ci __le16 res3; 418c2ecf20Sopenharmony_ci} __packed; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void asix_status(struct usbnet *dev, struct urb *urb) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct ax88172_int_data *event; 468c2ecf20Sopenharmony_ci int link; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (urb->actual_length < 8) 498c2ecf20Sopenharmony_ci return; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci event = urb->transfer_buffer; 528c2ecf20Sopenharmony_ci link = event->link & 0x01; 538c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev->net) != link) { 548c2ecf20Sopenharmony_ci usbnet_link_change(dev, link, 1); 558c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Link Status is: %d\n", link); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void asix_set_netdev_dev_addr(struct usbnet *dev, u8 *addr) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci if (is_valid_ether_addr(addr)) { 628c2ecf20Sopenharmony_ci memcpy(dev->net->dev_addr, addr, ETH_ALEN); 638c2ecf20Sopenharmony_ci } else { 648c2ecf20Sopenharmony_ci netdev_info(dev->net, "invalid hw address, using random\n"); 658c2ecf20Sopenharmony_ci eth_hw_addr_random(dev->net); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ 708c2ecf20Sopenharmony_cistatic u32 asix_get_phyid(struct usbnet *dev) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int phy_reg; 738c2ecf20Sopenharmony_ci u32 phy_id; 748c2ecf20Sopenharmony_ci int i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* Poll for the rare case the FW or phy isn't ready yet. */ 778c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 788c2ecf20Sopenharmony_ci phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); 798c2ecf20Sopenharmony_ci if (phy_reg < 0) 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci if (phy_reg != 0 && phy_reg != 0xFFFF) 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci mdelay(1); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (phy_reg <= 0 || phy_reg == 0xFFFF) 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci phy_id = (phy_reg & 0xffff) << 16; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); 928c2ecf20Sopenharmony_ci if (phy_reg < 0) 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci phy_id |= (phy_reg & 0xffff); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci return phy_id; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic u32 asix_get_link(struct net_device *net) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return mii_link_ok(&dev->mii); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* We need to override some ethtool_ops so we require our 1158c2ecf20Sopenharmony_ci own structure so we don't interfere with other usbnet 1168c2ecf20Sopenharmony_ci devices that may be connected at the same time. */ 1178c2ecf20Sopenharmony_cistatic const struct ethtool_ops ax88172_ethtool_ops = { 1188c2ecf20Sopenharmony_ci .get_drvinfo = asix_get_drvinfo, 1198c2ecf20Sopenharmony_ci .get_link = asix_get_link, 1208c2ecf20Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 1218c2ecf20Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 1228c2ecf20Sopenharmony_ci .get_wol = asix_get_wol, 1238c2ecf20Sopenharmony_ci .set_wol = asix_set_wol, 1248c2ecf20Sopenharmony_ci .get_eeprom_len = asix_get_eeprom_len, 1258c2ecf20Sopenharmony_ci .get_eeprom = asix_get_eeprom, 1268c2ecf20Sopenharmony_ci .set_eeprom = asix_set_eeprom, 1278c2ecf20Sopenharmony_ci .nway_reset = usbnet_nway_reset, 1288c2ecf20Sopenharmony_ci .get_link_ksettings = usbnet_get_link_ksettings, 1298c2ecf20Sopenharmony_ci .set_link_ksettings = usbnet_set_link_ksettings, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic void ax88172_set_multicast(struct net_device *net) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 1358c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 1368c2ecf20Sopenharmony_ci u8 rx_ctl = 0x8c; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (net->flags & IFF_PROMISC) { 1398c2ecf20Sopenharmony_ci rx_ctl |= 0x01; 1408c2ecf20Sopenharmony_ci } else if (net->flags & IFF_ALLMULTI || 1418c2ecf20Sopenharmony_ci netdev_mc_count(net) > AX_MAX_MCAST) { 1428c2ecf20Sopenharmony_ci rx_ctl |= 0x02; 1438c2ecf20Sopenharmony_ci } else if (netdev_mc_empty(net)) { 1448c2ecf20Sopenharmony_ci /* just broadcast and directed */ 1458c2ecf20Sopenharmony_ci } else { 1468c2ecf20Sopenharmony_ci /* We use the 20 byte dev->data 1478c2ecf20Sopenharmony_ci * for our 8 byte filter buffer 1488c2ecf20Sopenharmony_ci * to avoid allocating memory that 1498c2ecf20Sopenharmony_ci * is tricky to free later */ 1508c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 1518c2ecf20Sopenharmony_ci u32 crc_bits; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Build the multicast hash filter. */ 1568c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, net) { 1578c2ecf20Sopenharmony_ci crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 1588c2ecf20Sopenharmony_ci data->multi_filter[crc_bits >> 3] |= 1598c2ecf20Sopenharmony_ci 1 << (crc_bits & 7); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, 1638c2ecf20Sopenharmony_ci AX_MCAST_FILTER_SIZE, data->multi_filter); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci rx_ctl |= 0x10; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int ax88172_link_reset(struct usbnet *dev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci u8 mode; 1748c2ecf20Sopenharmony_ci struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci mii_check_media(&dev->mii, 1, 1); 1778c2ecf20Sopenharmony_ci mii_ethtool_gset(&dev->mii, &ecmd); 1788c2ecf20Sopenharmony_ci mode = AX88172_MEDIUM_DEFAULT; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (ecmd.duplex != DUPLEX_FULL) 1818c2ecf20Sopenharmony_ci mode |= ~AX88172_MEDIUM_FD; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 1848c2ecf20Sopenharmony_ci ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, mode, 0); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic const struct net_device_ops ax88172_netdev_ops = { 1928c2ecf20Sopenharmony_ci .ndo_open = usbnet_open, 1938c2ecf20Sopenharmony_ci .ndo_stop = usbnet_stop, 1948c2ecf20Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 1958c2ecf20Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 1968c2ecf20Sopenharmony_ci .ndo_change_mtu = usbnet_change_mtu, 1978c2ecf20Sopenharmony_ci .ndo_get_stats64 = usbnet_get_stats64, 1988c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 1998c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 2008c2ecf20Sopenharmony_ci .ndo_do_ioctl = asix_ioctl, 2018c2ecf20Sopenharmony_ci .ndo_set_rx_mode = ax88172_set_multicast, 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci unsigned int timeout = 5000; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, reset_bits); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* give phy_id a chance to process reset */ 2118c2ecf20Sopenharmony_ci udelay(500); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* See IEEE 802.3 "22.2.4.1.1 Reset": 500ms max */ 2148c2ecf20Sopenharmony_ci while (timeout--) { 2158c2ecf20Sopenharmony_ci if (asix_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR) 2168c2ecf20Sopenharmony_ci & BMCR_RESET) 2178c2ecf20Sopenharmony_ci udelay(100); 2188c2ecf20Sopenharmony_ci else 2198c2ecf20Sopenharmony_ci return; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci netdev_err(dev->net, "BMCR_RESET timeout on phy_id %d\n", 2238c2ecf20Sopenharmony_ci dev->mii.phy_id); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int ret = 0; 2298c2ecf20Sopenharmony_ci u8 buf[ETH_ALEN] = {0}; 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci unsigned long gpio_bits = dev->driver_info->data; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci usbnet_get_endpoints(dev,intf); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Toggle the GPIOs in a manufacturer/model specific way */ 2368c2ecf20Sopenharmony_ci for (i = 2; i >= 0; i--) { 2378c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, 2388c2ecf20Sopenharmony_ci (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL, 0); 2398c2ecf20Sopenharmony_ci if (ret < 0) 2408c2ecf20Sopenharmony_ci goto out; 2418c2ecf20Sopenharmony_ci msleep(5); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, 0x80, 0); 2458c2ecf20Sopenharmony_ci if (ret < 0) 2468c2ecf20Sopenharmony_ci goto out; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Get the MAC address */ 2498c2ecf20Sopenharmony_ci ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 2508c2ecf20Sopenharmony_ci 0, 0, ETH_ALEN, buf, 0); 2518c2ecf20Sopenharmony_ci if (ret < 0) { 2528c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "read AX_CMD_READ_NODE_ID failed: %d\n", 2538c2ecf20Sopenharmony_ci ret); 2548c2ecf20Sopenharmony_ci goto out; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci asix_set_netdev_dev_addr(dev, buf); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* Initialize MII structure */ 2608c2ecf20Sopenharmony_ci dev->mii.dev = dev->net; 2618c2ecf20Sopenharmony_ci dev->mii.mdio_read = asix_mdio_read; 2628c2ecf20Sopenharmony_ci dev->mii.mdio_write = asix_mdio_write; 2638c2ecf20Sopenharmony_ci dev->mii.phy_id_mask = 0x3f; 2648c2ecf20Sopenharmony_ci dev->mii.reg_num_mask = 0x1f; 2658c2ecf20Sopenharmony_ci dev->mii.phy_id = asix_get_phy_addr(dev); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dev->net->netdev_ops = &ax88172_netdev_ops; 2688c2ecf20Sopenharmony_ci dev->net->ethtool_ops = &ax88172_ethtool_ops; 2698c2ecf20Sopenharmony_ci dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ 2708c2ecf20Sopenharmony_ci dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci asix_phy_reset(dev, BMCR_RESET); 2738c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 2748c2ecf20Sopenharmony_ci ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 2758c2ecf20Sopenharmony_ci mii_nway_restart(&dev->mii); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ciout: 2808c2ecf20Sopenharmony_ci return ret; 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic const struct ethtool_ops ax88772_ethtool_ops = { 2848c2ecf20Sopenharmony_ci .get_drvinfo = asix_get_drvinfo, 2858c2ecf20Sopenharmony_ci .get_link = asix_get_link, 2868c2ecf20Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 2878c2ecf20Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 2888c2ecf20Sopenharmony_ci .get_wol = asix_get_wol, 2898c2ecf20Sopenharmony_ci .set_wol = asix_set_wol, 2908c2ecf20Sopenharmony_ci .get_eeprom_len = asix_get_eeprom_len, 2918c2ecf20Sopenharmony_ci .get_eeprom = asix_get_eeprom, 2928c2ecf20Sopenharmony_ci .set_eeprom = asix_set_eeprom, 2938c2ecf20Sopenharmony_ci .nway_reset = usbnet_nway_reset, 2948c2ecf20Sopenharmony_ci .get_link_ksettings = usbnet_get_link_ksettings, 2958c2ecf20Sopenharmony_ci .set_link_ksettings = usbnet_set_link_ksettings, 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int ax88772_link_reset(struct usbnet *dev) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci u16 mode; 3018c2ecf20Sopenharmony_ci struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mii_check_media(&dev->mii, 1, 1); 3048c2ecf20Sopenharmony_ci mii_ethtool_gset(&dev->mii, &ecmd); 3058c2ecf20Sopenharmony_ci mode = AX88772_MEDIUM_DEFAULT; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (ethtool_cmd_speed(&ecmd) != SPEED_100) 3088c2ecf20Sopenharmony_ci mode &= ~AX_MEDIUM_PS; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (ecmd.duplex != DUPLEX_FULL) 3118c2ecf20Sopenharmony_ci mode &= ~AX_MEDIUM_FD; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 3148c2ecf20Sopenharmony_ci ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, mode, 0); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int ax88772_reset(struct usbnet *dev) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Rewrite MAC address */ 3278c2ecf20Sopenharmony_ci ether_addr_copy(data->mac_addr, dev->net->dev_addr); 3288c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, 3298c2ecf20Sopenharmony_ci ETH_ALEN, data->mac_addr, 0); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci goto out; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 3348c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0); 3358c2ecf20Sopenharmony_ci if (ret < 0) 3368c2ecf20Sopenharmony_ci goto out; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, 0); 3398c2ecf20Sopenharmony_ci if (ret < 0) 3408c2ecf20Sopenharmony_ci goto out; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciout: 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int ax88772_hw_reset(struct usbnet *dev, int in_pm) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 3518c2ecf20Sopenharmony_ci int ret, embd_phy; 3528c2ecf20Sopenharmony_ci u16 rx_ctl; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | 3558c2ecf20Sopenharmony_ci AX_GPIO_GPO2EN, 5, in_pm); 3568c2ecf20Sopenharmony_ci if (ret < 0) 3578c2ecf20Sopenharmony_ci goto out; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 3628c2ecf20Sopenharmony_ci 0, 0, NULL, in_pm); 3638c2ecf20Sopenharmony_ci if (ret < 0) { 3648c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (embd_phy) { 3698c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPPD, in_pm); 3708c2ecf20Sopenharmony_ci if (ret < 0) 3718c2ecf20Sopenharmony_ci goto out; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, in_pm); 3768c2ecf20Sopenharmony_ci if (ret < 0) 3778c2ecf20Sopenharmony_ci goto out; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci msleep(60); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL, 3828c2ecf20Sopenharmony_ci in_pm); 3838c2ecf20Sopenharmony_ci if (ret < 0) 3848c2ecf20Sopenharmony_ci goto out; 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL, 3878c2ecf20Sopenharmony_ci in_pm); 3888c2ecf20Sopenharmony_ci if (ret < 0) 3898c2ecf20Sopenharmony_ci goto out; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci msleep(150); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (in_pm && (!asix_mdio_read_nopm(dev->net, dev->mii.phy_id, 3958c2ecf20Sopenharmony_ci MII_PHYSID1))){ 3968c2ecf20Sopenharmony_ci ret = -EIO; 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm); 4018c2ecf20Sopenharmony_ci if (ret < 0) 4028c2ecf20Sopenharmony_ci goto out; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, in_pm); 4058c2ecf20Sopenharmony_ci if (ret < 0) 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, 4098c2ecf20Sopenharmony_ci AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, 4108c2ecf20Sopenharmony_ci AX88772_IPG2_DEFAULT, 0, NULL, in_pm); 4118c2ecf20Sopenharmony_ci if (ret < 0) { 4128c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Rewrite MAC address */ 4178c2ecf20Sopenharmony_ci ether_addr_copy(data->mac_addr, dev->net->dev_addr); 4188c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, 4198c2ecf20Sopenharmony_ci ETH_ALEN, data->mac_addr, in_pm); 4208c2ecf20Sopenharmony_ci if (ret < 0) 4218c2ecf20Sopenharmony_ci goto out; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 4248c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm); 4258c2ecf20Sopenharmony_ci if (ret < 0) 4268c2ecf20Sopenharmony_ci goto out; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci rx_ctl = asix_read_rx_ctl(dev, in_pm); 4298c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", 4308c2ecf20Sopenharmony_ci rx_ctl); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci rx_ctl = asix_read_medium_status(dev, in_pm); 4338c2ecf20Sopenharmony_ci netdev_dbg(dev->net, 4348c2ecf20Sopenharmony_ci "Medium Status is 0x%04x after all initializations\n", 4358c2ecf20Sopenharmony_ci rx_ctl); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ciout: 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int ax88772a_hw_reset(struct usbnet *dev, int in_pm) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 4468c2ecf20Sopenharmony_ci int ret, embd_phy; 4478c2ecf20Sopenharmony_ci u16 rx_ctl, phy14h, phy15h, phy16h; 4488c2ecf20Sopenharmony_ci u8 chipcode = 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci ret = asix_write_gpio(dev, AX_GPIO_RSE, 5, in_pm); 4518c2ecf20Sopenharmony_ci if (ret < 0) 4528c2ecf20Sopenharmony_ci goto out; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy | 4578c2ecf20Sopenharmony_ci AX_PHYSEL_SSEN, 0, 0, NULL, in_pm); 4588c2ecf20Sopenharmony_ci if (ret < 0) { 4598c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); 4608c2ecf20Sopenharmony_ci goto out; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_IPRL, in_pm); 4658c2ecf20Sopenharmony_ci if (ret < 0) 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPRL, in_pm); 4718c2ecf20Sopenharmony_ci if (ret < 0) 4728c2ecf20Sopenharmony_ci goto out; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci msleep(160); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_CLEAR, in_pm); 4778c2ecf20Sopenharmony_ci if (ret < 0) 4788c2ecf20Sopenharmony_ci goto out; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci ret = asix_sw_reset(dev, AX_SWRESET_IPRL, in_pm); 4818c2ecf20Sopenharmony_ci if (ret < 0) 4828c2ecf20Sopenharmony_ci goto out; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci msleep(200); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (in_pm && (!asix_mdio_read_nopm(dev->net, dev->mii.phy_id, 4878c2ecf20Sopenharmony_ci MII_PHYSID1))) { 4888c2ecf20Sopenharmony_ci ret = -1; 4898c2ecf20Sopenharmony_ci goto out; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 4938c2ecf20Sopenharmony_ci 0, 1, &chipcode, in_pm); 4948c2ecf20Sopenharmony_ci if (ret < 0) 4958c2ecf20Sopenharmony_ci goto out; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if ((chipcode & AX_CHIPCODE_MASK) == AX_AX88772B_CHIPCODE) { 4988c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_QCTCTRL, 0x8000, 0x8001, 4998c2ecf20Sopenharmony_ci 0, NULL, in_pm); 5008c2ecf20Sopenharmony_ci if (ret < 0) { 5018c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Write BQ setting failed: %d\n", 5028c2ecf20Sopenharmony_ci ret); 5038c2ecf20Sopenharmony_ci goto out; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci } else if ((chipcode & AX_CHIPCODE_MASK) == AX_AX88772A_CHIPCODE) { 5068c2ecf20Sopenharmony_ci /* Check if the PHY registers have default settings */ 5078c2ecf20Sopenharmony_ci phy14h = asix_mdio_read_nopm(dev->net, dev->mii.phy_id, 5088c2ecf20Sopenharmony_ci AX88772A_PHY14H); 5098c2ecf20Sopenharmony_ci phy15h = asix_mdio_read_nopm(dev->net, dev->mii.phy_id, 5108c2ecf20Sopenharmony_ci AX88772A_PHY15H); 5118c2ecf20Sopenharmony_ci phy16h = asix_mdio_read_nopm(dev->net, dev->mii.phy_id, 5128c2ecf20Sopenharmony_ci AX88772A_PHY16H); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci netdev_dbg(dev->net, 5158c2ecf20Sopenharmony_ci "772a_hw_reset: MR20=0x%x MR21=0x%x MR22=0x%x\n", 5168c2ecf20Sopenharmony_ci phy14h, phy15h, phy16h); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Restore PHY registers default setting if not */ 5198c2ecf20Sopenharmony_ci if (phy14h != AX88772A_PHY14H_DEFAULT) 5208c2ecf20Sopenharmony_ci asix_mdio_write_nopm(dev->net, dev->mii.phy_id, 5218c2ecf20Sopenharmony_ci AX88772A_PHY14H, 5228c2ecf20Sopenharmony_ci AX88772A_PHY14H_DEFAULT); 5238c2ecf20Sopenharmony_ci if (phy15h != AX88772A_PHY15H_DEFAULT) 5248c2ecf20Sopenharmony_ci asix_mdio_write_nopm(dev->net, dev->mii.phy_id, 5258c2ecf20Sopenharmony_ci AX88772A_PHY15H, 5268c2ecf20Sopenharmony_ci AX88772A_PHY15H_DEFAULT); 5278c2ecf20Sopenharmony_ci if (phy16h != AX88772A_PHY16H_DEFAULT) 5288c2ecf20Sopenharmony_ci asix_mdio_write_nopm(dev->net, dev->mii.phy_id, 5298c2ecf20Sopenharmony_ci AX88772A_PHY16H, 5308c2ecf20Sopenharmony_ci AX88772A_PHY16H_DEFAULT); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, 5348c2ecf20Sopenharmony_ci AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, 5358c2ecf20Sopenharmony_ci AX88772_IPG2_DEFAULT, 0, NULL, in_pm); 5368c2ecf20Sopenharmony_ci if (ret < 0) { 5378c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); 5388c2ecf20Sopenharmony_ci goto out; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Rewrite MAC address */ 5428c2ecf20Sopenharmony_ci memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 5438c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 5448c2ecf20Sopenharmony_ci data->mac_addr, in_pm); 5458c2ecf20Sopenharmony_ci if (ret < 0) 5468c2ecf20Sopenharmony_ci goto out; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 5498c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm); 5508c2ecf20Sopenharmony_ci if (ret < 0) 5518c2ecf20Sopenharmony_ci goto out; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT, in_pm); 5548c2ecf20Sopenharmony_ci if (ret < 0) 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 5588c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, in_pm); 5598c2ecf20Sopenharmony_ci if (ret < 0) 5608c2ecf20Sopenharmony_ci goto out; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci rx_ctl = asix_read_rx_ctl(dev, in_pm); 5638c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", 5648c2ecf20Sopenharmony_ci rx_ctl); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci rx_ctl = asix_read_medium_status(dev, in_pm); 5678c2ecf20Sopenharmony_ci netdev_dbg(dev->net, 5688c2ecf20Sopenharmony_ci "Medium Status is 0x%04x after all initializations\n", 5698c2ecf20Sopenharmony_ci rx_ctl); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciout: 5748c2ecf20Sopenharmony_ci return ret; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic const struct net_device_ops ax88772_netdev_ops = { 5788c2ecf20Sopenharmony_ci .ndo_open = usbnet_open, 5798c2ecf20Sopenharmony_ci .ndo_stop = usbnet_stop, 5808c2ecf20Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 5818c2ecf20Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 5828c2ecf20Sopenharmony_ci .ndo_change_mtu = usbnet_change_mtu, 5838c2ecf20Sopenharmony_ci .ndo_get_stats64 = usbnet_get_stats64, 5848c2ecf20Sopenharmony_ci .ndo_set_mac_address = asix_set_mac_address, 5858c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 5868c2ecf20Sopenharmony_ci .ndo_do_ioctl = asix_ioctl, 5878c2ecf20Sopenharmony_ci .ndo_set_rx_mode = asix_set_multicast, 5888c2ecf20Sopenharmony_ci}; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void ax88772_suspend(struct usbnet *dev) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct asix_common_private *priv = dev->driver_priv; 5938c2ecf20Sopenharmony_ci u16 medium; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Stop MAC operation */ 5968c2ecf20Sopenharmony_ci medium = asix_read_medium_status(dev, 1); 5978c2ecf20Sopenharmony_ci medium &= ~AX_MEDIUM_RE; 5988c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, medium, 1); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88772_suspend: medium=0x%04x\n", 6018c2ecf20Sopenharmony_ci asix_read_medium_status(dev, 1)); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Preserve BMCR for restoring */ 6048c2ecf20Sopenharmony_ci priv->presvd_phy_bmcr = 6058c2ecf20Sopenharmony_ci asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_BMCR); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Preserve ANAR for restoring */ 6088c2ecf20Sopenharmony_ci priv->presvd_phy_advertise = 6098c2ecf20Sopenharmony_ci asix_mdio_read_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic int asix_suspend(struct usb_interface *intf, pm_message_t message) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 6158c2ecf20Sopenharmony_ci struct asix_common_private *priv = dev->driver_priv; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (priv && priv->suspend) 6188c2ecf20Sopenharmony_ci priv->suspend(dev); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return usbnet_suspend(intf, message); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void ax88772_restore_phy(struct usbnet *dev) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct asix_common_private *priv = dev->driver_priv; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (priv->presvd_phy_advertise) { 6288c2ecf20Sopenharmony_ci /* Restore Advertisement control reg */ 6298c2ecf20Sopenharmony_ci asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_ADVERTISE, 6308c2ecf20Sopenharmony_ci priv->presvd_phy_advertise); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* Restore BMCR */ 6338c2ecf20Sopenharmony_ci if (priv->presvd_phy_bmcr & BMCR_ANENABLE) 6348c2ecf20Sopenharmony_ci priv->presvd_phy_bmcr |= BMCR_ANRESTART; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci asix_mdio_write_nopm(dev->net, dev->mii.phy_id, MII_BMCR, 6378c2ecf20Sopenharmony_ci priv->presvd_phy_bmcr); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci priv->presvd_phy_advertise = 0; 6408c2ecf20Sopenharmony_ci priv->presvd_phy_bmcr = 0; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic void ax88772_resume(struct usbnet *dev) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci int i; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 6498c2ecf20Sopenharmony_ci if (!ax88772_hw_reset(dev, 1)) 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci ax88772_restore_phy(dev); 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic void ax88772a_resume(struct usbnet *dev) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci int i; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 6598c2ecf20Sopenharmony_ci if (!ax88772a_hw_reset(dev, 1)) 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci ax88772_restore_phy(dev); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic int asix_resume(struct usb_interface *intf) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct usbnet *dev = usb_get_intfdata(intf); 6698c2ecf20Sopenharmony_ci struct asix_common_private *priv = dev->driver_priv; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (priv && priv->resume) 6728c2ecf20Sopenharmony_ci priv->resume(dev); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return usbnet_resume(intf); 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci int ret, i; 6808c2ecf20Sopenharmony_ci u8 buf[ETH_ALEN] = {0}, chipcode = 0; 6818c2ecf20Sopenharmony_ci u32 phyid; 6828c2ecf20Sopenharmony_ci struct asix_common_private *priv; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci usbnet_get_endpoints(dev, intf); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Maybe the boot loader passed the MAC address via device tree */ 6878c2ecf20Sopenharmony_ci if (!eth_platform_get_mac_address(&dev->udev->dev, buf)) { 6888c2ecf20Sopenharmony_ci netif_dbg(dev, ifup, dev->net, 6898c2ecf20Sopenharmony_ci "MAC address read from device tree"); 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci /* Try getting the MAC address from EEPROM */ 6928c2ecf20Sopenharmony_ci if (dev->driver_info->data & FLAG_EEPROM_MAC) { 6938c2ecf20Sopenharmony_ci for (i = 0; i < (ETH_ALEN >> 1); i++) { 6948c2ecf20Sopenharmony_ci ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, 6958c2ecf20Sopenharmony_ci 0x04 + i, 0, 2, buf + i * 2, 6968c2ecf20Sopenharmony_ci 0); 6978c2ecf20Sopenharmony_ci if (ret < 0) 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci } else { 7018c2ecf20Sopenharmony_ci ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 7028c2ecf20Sopenharmony_ci 0, 0, ETH_ALEN, buf, 0); 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (ret < 0) { 7068c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Failed to read MAC address: %d\n", 7078c2ecf20Sopenharmony_ci ret); 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci asix_set_netdev_dev_addr(dev, buf); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Initialize MII structure */ 7158c2ecf20Sopenharmony_ci dev->mii.dev = dev->net; 7168c2ecf20Sopenharmony_ci dev->mii.mdio_read = asix_mdio_read; 7178c2ecf20Sopenharmony_ci dev->mii.mdio_write = asix_mdio_write; 7188c2ecf20Sopenharmony_ci dev->mii.phy_id_mask = 0x1f; 7198c2ecf20Sopenharmony_ci dev->mii.reg_num_mask = 0x1f; 7208c2ecf20Sopenharmony_ci dev->mii.phy_id = asix_get_phy_addr(dev); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci dev->net->netdev_ops = &ax88772_netdev_ops; 7238c2ecf20Sopenharmony_ci dev->net->ethtool_ops = &ax88772_ethtool_ops; 7248c2ecf20Sopenharmony_ci dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ 7258c2ecf20Sopenharmony_ci dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0); 7288c2ecf20Sopenharmony_ci chipcode &= AX_CHIPCODE_MASK; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci ret = (chipcode == AX_AX88772_CHIPCODE) ? ax88772_hw_reset(dev, 0) : 7318c2ecf20Sopenharmony_ci ax88772a_hw_reset(dev, 0); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (ret < 0) { 7348c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Failed to reset AX88772: %d\n", ret); 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* Read PHYID register *AFTER* the PHY was reset properly */ 7398c2ecf20Sopenharmony_ci phyid = asix_get_phyid(dev); 7408c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 7438c2ecf20Sopenharmony_ci if (dev->driver_info->flags & FLAG_FRAMING_AX) { 7448c2ecf20Sopenharmony_ci /* hard_mtu is still the default - the device does not support 7458c2ecf20Sopenharmony_ci jumbo eth frames */ 7468c2ecf20Sopenharmony_ci dev->rx_urb_size = 2048; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); 7508c2ecf20Sopenharmony_ci if (!dev->driver_priv) 7518c2ecf20Sopenharmony_ci return -ENOMEM; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci priv = dev->driver_priv; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci priv->presvd_phy_bmcr = 0; 7568c2ecf20Sopenharmony_ci priv->presvd_phy_advertise = 0; 7578c2ecf20Sopenharmony_ci if (chipcode == AX_AX88772_CHIPCODE) { 7588c2ecf20Sopenharmony_ci priv->resume = ax88772_resume; 7598c2ecf20Sopenharmony_ci priv->suspend = ax88772_suspend; 7608c2ecf20Sopenharmony_ci } else { 7618c2ecf20Sopenharmony_ci priv->resume = ax88772a_resume; 7628c2ecf20Sopenharmony_ci priv->suspend = ax88772_suspend; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci asix_rx_fixup_common_free(dev->driver_priv); 7718c2ecf20Sopenharmony_ci kfree(dev->driver_priv); 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic const struct ethtool_ops ax88178_ethtool_ops = { 7758c2ecf20Sopenharmony_ci .get_drvinfo = asix_get_drvinfo, 7768c2ecf20Sopenharmony_ci .get_link = asix_get_link, 7778c2ecf20Sopenharmony_ci .get_msglevel = usbnet_get_msglevel, 7788c2ecf20Sopenharmony_ci .set_msglevel = usbnet_set_msglevel, 7798c2ecf20Sopenharmony_ci .get_wol = asix_get_wol, 7808c2ecf20Sopenharmony_ci .set_wol = asix_set_wol, 7818c2ecf20Sopenharmony_ci .get_eeprom_len = asix_get_eeprom_len, 7828c2ecf20Sopenharmony_ci .get_eeprom = asix_get_eeprom, 7838c2ecf20Sopenharmony_ci .set_eeprom = asix_set_eeprom, 7848c2ecf20Sopenharmony_ci .nway_reset = usbnet_nway_reset, 7858c2ecf20Sopenharmony_ci .get_link_ksettings = usbnet_get_link_ksettings, 7868c2ecf20Sopenharmony_ci .set_link_ksettings = usbnet_set_link_ksettings, 7878c2ecf20Sopenharmony_ci}; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int marvell_phy_init(struct usbnet *dev) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 7928c2ecf20Sopenharmony_ci u16 reg; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "marvell_phy_init()\n"); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); 7978c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, 8008c2ecf20Sopenharmony_ci MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (data->ledmode) { 8038c2ecf20Sopenharmony_ci reg = asix_mdio_read(dev->net, dev->mii.phy_id, 8048c2ecf20Sopenharmony_ci MII_MARVELL_LED_CTRL); 8058c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci reg &= 0xf8ff; 8088c2ecf20Sopenharmony_ci reg |= (1 + 0x0100); 8098c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, 8108c2ecf20Sopenharmony_ci MII_MARVELL_LED_CTRL, reg); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci reg = asix_mdio_read(dev->net, dev->mii.phy_id, 8138c2ecf20Sopenharmony_ci MII_MARVELL_LED_CTRL); 8148c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); 8158c2ecf20Sopenharmony_ci reg &= 0xfc0f; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int rtl8211cl_phy_init(struct usbnet *dev) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); 8288c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); 8298c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, 8308c2ecf20Sopenharmony_ci asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); 8318c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (data->ledmode == 12) { 8348c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); 8358c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); 8368c2ecf20Sopenharmony_ci asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int marvell_led_status(struct usbnet *dev, u16 speed) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* Clear out the center LED bits - 0x03F0 */ 8498c2ecf20Sopenharmony_ci reg &= 0xfc0f; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci switch (speed) { 8528c2ecf20Sopenharmony_ci case SPEED_1000: 8538c2ecf20Sopenharmony_ci reg |= 0x03e0; 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci case SPEED_100: 8568c2ecf20Sopenharmony_ci reg |= 0x03b0; 8578c2ecf20Sopenharmony_ci break; 8588c2ecf20Sopenharmony_ci default: 8598c2ecf20Sopenharmony_ci reg |= 0x02f0; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); 8638c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int ax88178_reset(struct usbnet *dev) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 8718c2ecf20Sopenharmony_ci int ret; 8728c2ecf20Sopenharmony_ci __le16 eeprom; 8738c2ecf20Sopenharmony_ci u8 status; 8748c2ecf20Sopenharmony_ci int gpio0 = 0; 8758c2ecf20Sopenharmony_ci u32 phyid; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status, 0); 8788c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "GPIO Status: 0x%04x\n", status); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL, 0); 8818c2ecf20Sopenharmony_ci asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom, 0); 8828c2ecf20Sopenharmony_ci asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL, 0); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "EEPROM index 0x17 is 0x%04x\n", eeprom); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (eeprom == cpu_to_le16(0xffff)) { 8878c2ecf20Sopenharmony_ci data->phymode = PHY_MODE_MARVELL; 8888c2ecf20Sopenharmony_ci data->ledmode = 0; 8898c2ecf20Sopenharmony_ci gpio0 = 1; 8908c2ecf20Sopenharmony_ci } else { 8918c2ecf20Sopenharmony_ci data->phymode = le16_to_cpu(eeprom) & 0x7F; 8928c2ecf20Sopenharmony_ci data->ledmode = le16_to_cpu(eeprom) >> 8; 8938c2ecf20Sopenharmony_ci gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "GPIO0: %d, PhyMode: %d\n", gpio0, data->phymode); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Power up external GigaPHY through AX88178 GPIO pin */ 8988c2ecf20Sopenharmony_ci asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | 8998c2ecf20Sopenharmony_ci AX_GPIO_GPO1EN, 40, 0); 9008c2ecf20Sopenharmony_ci if ((le16_to_cpu(eeprom) >> 8) != 1) { 9018c2ecf20Sopenharmony_ci asix_write_gpio(dev, 0x003c, 30, 0); 9028c2ecf20Sopenharmony_ci asix_write_gpio(dev, 0x001c, 300, 0); 9038c2ecf20Sopenharmony_ci asix_write_gpio(dev, 0x003c, 30, 0); 9048c2ecf20Sopenharmony_ci } else { 9058c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "gpio phymode == 1 path\n"); 9068c2ecf20Sopenharmony_ci asix_write_gpio(dev, AX_GPIO_GPO1EN, 30, 0); 9078c2ecf20Sopenharmony_ci asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30, 0); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* Read PHYID register *AFTER* powering up PHY */ 9118c2ecf20Sopenharmony_ci phyid = asix_get_phyid(dev); 9128c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ 9158c2ecf20Sopenharmony_ci asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL, 0); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci asix_sw_reset(dev, 0, 0); 9188c2ecf20Sopenharmony_ci msleep(150); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD, 0); 9218c2ecf20Sopenharmony_ci msleep(150); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci asix_write_rx_ctl(dev, 0, 0); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (data->phymode == PHY_MODE_MARVELL) { 9268c2ecf20Sopenharmony_ci marvell_phy_init(dev); 9278c2ecf20Sopenharmony_ci msleep(60); 9288c2ecf20Sopenharmony_ci } else if (data->phymode == PHY_MODE_RTL8211CL) 9298c2ecf20Sopenharmony_ci rtl8211cl_phy_init(dev); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci asix_phy_reset(dev, BMCR_RESET | BMCR_ANENABLE); 9328c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 9338c2ecf20Sopenharmony_ci ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 9348c2ecf20Sopenharmony_ci asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, 9358c2ecf20Sopenharmony_ci ADVERTISE_1000FULL); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT, 0); 9388c2ecf20Sopenharmony_ci mii_nway_restart(&dev->mii); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Rewrite MAC address */ 9418c2ecf20Sopenharmony_ci memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 9428c2ecf20Sopenharmony_ci ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 9438c2ecf20Sopenharmony_ci data->mac_addr, 0); 9448c2ecf20Sopenharmony_ci if (ret < 0) 9458c2ecf20Sopenharmony_ci return ret; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL, 0); 9488c2ecf20Sopenharmony_ci if (ret < 0) 9498c2ecf20Sopenharmony_ci return ret; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic int ax88178_link_reset(struct usbnet *dev) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci u16 mode; 9578c2ecf20Sopenharmony_ci struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 9588c2ecf20Sopenharmony_ci struct asix_data *data = (struct asix_data *)&dev->data; 9598c2ecf20Sopenharmony_ci u32 speed; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88178_link_reset()\n"); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci mii_check_media(&dev->mii, 1, 1); 9648c2ecf20Sopenharmony_ci mii_ethtool_gset(&dev->mii, &ecmd); 9658c2ecf20Sopenharmony_ci mode = AX88178_MEDIUM_DEFAULT; 9668c2ecf20Sopenharmony_ci speed = ethtool_cmd_speed(&ecmd); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (speed == SPEED_1000) 9698c2ecf20Sopenharmony_ci mode |= AX_MEDIUM_GM; 9708c2ecf20Sopenharmony_ci else if (speed == SPEED_100) 9718c2ecf20Sopenharmony_ci mode |= AX_MEDIUM_PS; 9728c2ecf20Sopenharmony_ci else 9738c2ecf20Sopenharmony_ci mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci mode |= AX_MEDIUM_ENCK; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (ecmd.duplex == DUPLEX_FULL) 9788c2ecf20Sopenharmony_ci mode |= AX_MEDIUM_FD; 9798c2ecf20Sopenharmony_ci else 9808c2ecf20Sopenharmony_ci mode &= ~AX_MEDIUM_FD; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 9838c2ecf20Sopenharmony_ci speed, ecmd.duplex, mode); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, mode, 0); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (data->phymode == PHY_MODE_MARVELL && data->ledmode) 9888c2ecf20Sopenharmony_ci marvell_led_status(dev, speed); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic void ax88178_set_mfb(struct usbnet *dev) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci u16 mfb = AX_RX_CTL_MFB_16384; 9968c2ecf20Sopenharmony_ci u16 rxctl; 9978c2ecf20Sopenharmony_ci u16 medium; 9988c2ecf20Sopenharmony_ci int old_rx_urb_size = dev->rx_urb_size; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (dev->hard_mtu < 2048) { 10018c2ecf20Sopenharmony_ci dev->rx_urb_size = 2048; 10028c2ecf20Sopenharmony_ci mfb = AX_RX_CTL_MFB_2048; 10038c2ecf20Sopenharmony_ci } else if (dev->hard_mtu < 4096) { 10048c2ecf20Sopenharmony_ci dev->rx_urb_size = 4096; 10058c2ecf20Sopenharmony_ci mfb = AX_RX_CTL_MFB_4096; 10068c2ecf20Sopenharmony_ci } else if (dev->hard_mtu < 8192) { 10078c2ecf20Sopenharmony_ci dev->rx_urb_size = 8192; 10088c2ecf20Sopenharmony_ci mfb = AX_RX_CTL_MFB_8192; 10098c2ecf20Sopenharmony_ci } else if (dev->hard_mtu < 16384) { 10108c2ecf20Sopenharmony_ci dev->rx_urb_size = 16384; 10118c2ecf20Sopenharmony_ci mfb = AX_RX_CTL_MFB_16384; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci rxctl = asix_read_rx_ctl(dev, 0); 10158c2ecf20Sopenharmony_ci asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb, 0); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci medium = asix_read_medium_status(dev, 0); 10188c2ecf20Sopenharmony_ci if (dev->net->mtu > 1500) 10198c2ecf20Sopenharmony_ci medium |= AX_MEDIUM_JFE; 10208c2ecf20Sopenharmony_ci else 10218c2ecf20Sopenharmony_ci medium &= ~AX_MEDIUM_JFE; 10228c2ecf20Sopenharmony_ci asix_write_medium_mode(dev, medium, 0); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (dev->rx_urb_size > old_rx_urb_size) 10258c2ecf20Sopenharmony_ci usbnet_unlink_rx_urbs(dev); 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cistatic int ax88178_change_mtu(struct net_device *net, int new_mtu) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci struct usbnet *dev = netdev_priv(net); 10318c2ecf20Sopenharmony_ci int ll_mtu = new_mtu + net->hard_header_len + 4; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if ((ll_mtu % dev->maxpacket) == 0) 10368c2ecf20Sopenharmony_ci return -EDOM; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci net->mtu = new_mtu; 10398c2ecf20Sopenharmony_ci dev->hard_mtu = net->mtu + net->hard_header_len; 10408c2ecf20Sopenharmony_ci ax88178_set_mfb(dev); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* max qlen depend on hard_mtu and rx_urb_size */ 10438c2ecf20Sopenharmony_ci usbnet_update_max_qlen(dev); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic const struct net_device_ops ax88178_netdev_ops = { 10498c2ecf20Sopenharmony_ci .ndo_open = usbnet_open, 10508c2ecf20Sopenharmony_ci .ndo_stop = usbnet_stop, 10518c2ecf20Sopenharmony_ci .ndo_start_xmit = usbnet_start_xmit, 10528c2ecf20Sopenharmony_ci .ndo_tx_timeout = usbnet_tx_timeout, 10538c2ecf20Sopenharmony_ci .ndo_get_stats64 = usbnet_get_stats64, 10548c2ecf20Sopenharmony_ci .ndo_set_mac_address = asix_set_mac_address, 10558c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 10568c2ecf20Sopenharmony_ci .ndo_set_rx_mode = asix_set_multicast, 10578c2ecf20Sopenharmony_ci .ndo_do_ioctl = asix_ioctl, 10588c2ecf20Sopenharmony_ci .ndo_change_mtu = ax88178_change_mtu, 10598c2ecf20Sopenharmony_ci}; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_cistatic int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci int ret; 10648c2ecf20Sopenharmony_ci u8 buf[ETH_ALEN] = {0}; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci usbnet_get_endpoints(dev,intf); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* Get the MAC address */ 10698c2ecf20Sopenharmony_ci ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf, 0); 10708c2ecf20Sopenharmony_ci if (ret < 0) { 10718c2ecf20Sopenharmony_ci netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); 10728c2ecf20Sopenharmony_ci return ret; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci asix_set_netdev_dev_addr(dev, buf); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Initialize MII structure */ 10788c2ecf20Sopenharmony_ci dev->mii.dev = dev->net; 10798c2ecf20Sopenharmony_ci dev->mii.mdio_read = asix_mdio_read; 10808c2ecf20Sopenharmony_ci dev->mii.mdio_write = asix_mdio_write; 10818c2ecf20Sopenharmony_ci dev->mii.phy_id_mask = 0x1f; 10828c2ecf20Sopenharmony_ci dev->mii.reg_num_mask = 0xff; 10838c2ecf20Sopenharmony_ci dev->mii.supports_gmii = 1; 10848c2ecf20Sopenharmony_ci dev->mii.phy_id = asix_get_phy_addr(dev); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci dev->net->netdev_ops = &ax88178_netdev_ops; 10878c2ecf20Sopenharmony_ci dev->net->ethtool_ops = &ax88178_ethtool_ops; 10888c2ecf20Sopenharmony_ci dev->net->max_mtu = 16384 - (dev->net->hard_header_len + 4); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* Blink LEDS so users know driver saw dongle */ 10918c2ecf20Sopenharmony_ci asix_sw_reset(dev, 0, 0); 10928c2ecf20Sopenharmony_ci msleep(150); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD, 0); 10958c2ecf20Sopenharmony_ci msleep(150); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 10988c2ecf20Sopenharmony_ci if (dev->driver_info->flags & FLAG_FRAMING_AX) { 10998c2ecf20Sopenharmony_ci /* hard_mtu is still the default - the device does not support 11008c2ecf20Sopenharmony_ci jumbo eth frames */ 11018c2ecf20Sopenharmony_ci dev->rx_urb_size = 2048; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci dev->driver_priv = kzalloc(sizeof(struct asix_common_private), GFP_KERNEL); 11058c2ecf20Sopenharmony_ci if (!dev->driver_priv) 11068c2ecf20Sopenharmony_ci return -ENOMEM; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic const struct driver_info ax8817x_info = { 11128c2ecf20Sopenharmony_ci .description = "ASIX AX8817x USB 2.0 Ethernet", 11138c2ecf20Sopenharmony_ci .bind = ax88172_bind, 11148c2ecf20Sopenharmony_ci .status = asix_status, 11158c2ecf20Sopenharmony_ci .link_reset = ax88172_link_reset, 11168c2ecf20Sopenharmony_ci .reset = ax88172_link_reset, 11178c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_LINK_INTR, 11188c2ecf20Sopenharmony_ci .data = 0x00130103, 11198c2ecf20Sopenharmony_ci}; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic const struct driver_info dlink_dub_e100_info = { 11228c2ecf20Sopenharmony_ci .description = "DLink DUB-E100 USB Ethernet", 11238c2ecf20Sopenharmony_ci .bind = ax88172_bind, 11248c2ecf20Sopenharmony_ci .status = asix_status, 11258c2ecf20Sopenharmony_ci .link_reset = ax88172_link_reset, 11268c2ecf20Sopenharmony_ci .reset = ax88172_link_reset, 11278c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_LINK_INTR, 11288c2ecf20Sopenharmony_ci .data = 0x009f9d9f, 11298c2ecf20Sopenharmony_ci}; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic const struct driver_info netgear_fa120_info = { 11328c2ecf20Sopenharmony_ci .description = "Netgear FA-120 USB Ethernet", 11338c2ecf20Sopenharmony_ci .bind = ax88172_bind, 11348c2ecf20Sopenharmony_ci .status = asix_status, 11358c2ecf20Sopenharmony_ci .link_reset = ax88172_link_reset, 11368c2ecf20Sopenharmony_ci .reset = ax88172_link_reset, 11378c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_LINK_INTR, 11388c2ecf20Sopenharmony_ci .data = 0x00130103, 11398c2ecf20Sopenharmony_ci}; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic const struct driver_info hawking_uf200_info = { 11428c2ecf20Sopenharmony_ci .description = "Hawking UF200 USB Ethernet", 11438c2ecf20Sopenharmony_ci .bind = ax88172_bind, 11448c2ecf20Sopenharmony_ci .status = asix_status, 11458c2ecf20Sopenharmony_ci .link_reset = ax88172_link_reset, 11468c2ecf20Sopenharmony_ci .reset = ax88172_link_reset, 11478c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_LINK_INTR, 11488c2ecf20Sopenharmony_ci .data = 0x001f1d1f, 11498c2ecf20Sopenharmony_ci}; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic const struct driver_info ax88772_info = { 11528c2ecf20Sopenharmony_ci .description = "ASIX AX88772 USB 2.0 Ethernet", 11538c2ecf20Sopenharmony_ci .bind = ax88772_bind, 11548c2ecf20Sopenharmony_ci .unbind = ax88772_unbind, 11558c2ecf20Sopenharmony_ci .status = asix_status, 11568c2ecf20Sopenharmony_ci .link_reset = ax88772_link_reset, 11578c2ecf20Sopenharmony_ci .reset = ax88772_reset, 11588c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, 11598c2ecf20Sopenharmony_ci .rx_fixup = asix_rx_fixup_common, 11608c2ecf20Sopenharmony_ci .tx_fixup = asix_tx_fixup, 11618c2ecf20Sopenharmony_ci}; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic const struct driver_info ax88772b_info = { 11648c2ecf20Sopenharmony_ci .description = "ASIX AX88772B USB 2.0 Ethernet", 11658c2ecf20Sopenharmony_ci .bind = ax88772_bind, 11668c2ecf20Sopenharmony_ci .unbind = ax88772_unbind, 11678c2ecf20Sopenharmony_ci .status = asix_status, 11688c2ecf20Sopenharmony_ci .link_reset = ax88772_link_reset, 11698c2ecf20Sopenharmony_ci .reset = ax88772_reset, 11708c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | 11718c2ecf20Sopenharmony_ci FLAG_MULTI_PACKET, 11728c2ecf20Sopenharmony_ci .rx_fixup = asix_rx_fixup_common, 11738c2ecf20Sopenharmony_ci .tx_fixup = asix_tx_fixup, 11748c2ecf20Sopenharmony_ci .data = FLAG_EEPROM_MAC, 11758c2ecf20Sopenharmony_ci}; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic const struct driver_info ax88178_info = { 11788c2ecf20Sopenharmony_ci .description = "ASIX AX88178 USB 2.0 Ethernet", 11798c2ecf20Sopenharmony_ci .bind = ax88178_bind, 11808c2ecf20Sopenharmony_ci .unbind = ax88772_unbind, 11818c2ecf20Sopenharmony_ci .status = asix_status, 11828c2ecf20Sopenharmony_ci .link_reset = ax88178_link_reset, 11838c2ecf20Sopenharmony_ci .reset = ax88178_reset, 11848c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | 11858c2ecf20Sopenharmony_ci FLAG_MULTI_PACKET, 11868c2ecf20Sopenharmony_ci .rx_fixup = asix_rx_fixup_common, 11878c2ecf20Sopenharmony_ci .tx_fixup = asix_tx_fixup, 11888c2ecf20Sopenharmony_ci}; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci/* 11918c2ecf20Sopenharmony_ci * USBLINK 20F9 "USB 2.0 LAN" USB ethernet adapter, typically found in 11928c2ecf20Sopenharmony_ci * no-name packaging. 11938c2ecf20Sopenharmony_ci * USB device strings are: 11948c2ecf20Sopenharmony_ci * 1: Manufacturer: USBLINK 11958c2ecf20Sopenharmony_ci * 2: Product: HG20F9 USB2.0 11968c2ecf20Sopenharmony_ci * 3: Serial: 000003 11978c2ecf20Sopenharmony_ci * Appears to be compatible with Asix 88772B. 11988c2ecf20Sopenharmony_ci */ 11998c2ecf20Sopenharmony_cistatic const struct driver_info hg20f9_info = { 12008c2ecf20Sopenharmony_ci .description = "HG20F9 USB 2.0 Ethernet", 12018c2ecf20Sopenharmony_ci .bind = ax88772_bind, 12028c2ecf20Sopenharmony_ci .unbind = ax88772_unbind, 12038c2ecf20Sopenharmony_ci .status = asix_status, 12048c2ecf20Sopenharmony_ci .link_reset = ax88772_link_reset, 12058c2ecf20Sopenharmony_ci .reset = ax88772_reset, 12068c2ecf20Sopenharmony_ci .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | 12078c2ecf20Sopenharmony_ci FLAG_MULTI_PACKET, 12088c2ecf20Sopenharmony_ci .rx_fixup = asix_rx_fixup_common, 12098c2ecf20Sopenharmony_ci .tx_fixup = asix_tx_fixup, 12108c2ecf20Sopenharmony_ci .data = FLAG_EEPROM_MAC, 12118c2ecf20Sopenharmony_ci}; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic const struct usb_device_id products [] = { 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci // Linksys USB200M 12168c2ecf20Sopenharmony_ci USB_DEVICE (0x077b, 0x2226), 12178c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12188c2ecf20Sopenharmony_ci}, { 12198c2ecf20Sopenharmony_ci // Netgear FA120 12208c2ecf20Sopenharmony_ci USB_DEVICE (0x0846, 0x1040), 12218c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &netgear_fa120_info, 12228c2ecf20Sopenharmony_ci}, { 12238c2ecf20Sopenharmony_ci // DLink DUB-E100 12248c2ecf20Sopenharmony_ci USB_DEVICE (0x2001, 0x1a00), 12258c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &dlink_dub_e100_info, 12268c2ecf20Sopenharmony_ci}, { 12278c2ecf20Sopenharmony_ci // Intellinet, ST Lab USB Ethernet 12288c2ecf20Sopenharmony_ci USB_DEVICE (0x0b95, 0x1720), 12298c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12308c2ecf20Sopenharmony_ci}, { 12318c2ecf20Sopenharmony_ci // Hawking UF200, TrendNet TU2-ET100 12328c2ecf20Sopenharmony_ci USB_DEVICE (0x07b8, 0x420a), 12338c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &hawking_uf200_info, 12348c2ecf20Sopenharmony_ci}, { 12358c2ecf20Sopenharmony_ci // Billionton Systems, USB2AR 12368c2ecf20Sopenharmony_ci USB_DEVICE (0x08dd, 0x90ff), 12378c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12388c2ecf20Sopenharmony_ci}, { 12398c2ecf20Sopenharmony_ci // Billionton Systems, GUSB2AM-1G-B 12408c2ecf20Sopenharmony_ci USB_DEVICE(0x08dd, 0x0114), 12418c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 12428c2ecf20Sopenharmony_ci}, { 12438c2ecf20Sopenharmony_ci // ATEN UC210T 12448c2ecf20Sopenharmony_ci USB_DEVICE (0x0557, 0x2009), 12458c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12468c2ecf20Sopenharmony_ci}, { 12478c2ecf20Sopenharmony_ci // Buffalo LUA-U2-KTX 12488c2ecf20Sopenharmony_ci USB_DEVICE (0x0411, 0x003d), 12498c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12508c2ecf20Sopenharmony_ci}, { 12518c2ecf20Sopenharmony_ci // Buffalo LUA-U2-GT 10/100/1000 12528c2ecf20Sopenharmony_ci USB_DEVICE (0x0411, 0x006e), 12538c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 12548c2ecf20Sopenharmony_ci}, { 12558c2ecf20Sopenharmony_ci // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" 12568c2ecf20Sopenharmony_ci USB_DEVICE (0x6189, 0x182d), 12578c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12588c2ecf20Sopenharmony_ci}, { 12598c2ecf20Sopenharmony_ci // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" 12608c2ecf20Sopenharmony_ci USB_DEVICE (0x0df6, 0x0056), 12618c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 12628c2ecf20Sopenharmony_ci}, { 12638c2ecf20Sopenharmony_ci // Sitecom LN-028 "USB 2.0 10/100/1000 Ethernet adapter" 12648c2ecf20Sopenharmony_ci USB_DEVICE (0x0df6, 0x061c), 12658c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 12668c2ecf20Sopenharmony_ci}, { 12678c2ecf20Sopenharmony_ci // corega FEther USB2-TX 12688c2ecf20Sopenharmony_ci USB_DEVICE (0x07aa, 0x0017), 12698c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12708c2ecf20Sopenharmony_ci}, { 12718c2ecf20Sopenharmony_ci // Surecom EP-1427X-2 12728c2ecf20Sopenharmony_ci USB_DEVICE (0x1189, 0x0893), 12738c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12748c2ecf20Sopenharmony_ci}, { 12758c2ecf20Sopenharmony_ci // goodway corp usb gwusb2e 12768c2ecf20Sopenharmony_ci USB_DEVICE (0x1631, 0x6200), 12778c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12788c2ecf20Sopenharmony_ci}, { 12798c2ecf20Sopenharmony_ci // JVC MP-PRX1 Port Replicator 12808c2ecf20Sopenharmony_ci USB_DEVICE (0x04f1, 0x3008), 12818c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax8817x_info, 12828c2ecf20Sopenharmony_ci}, { 12838c2ecf20Sopenharmony_ci // Lenovo U2L100P 10/100 12848c2ecf20Sopenharmony_ci USB_DEVICE (0x17ef, 0x7203), 12858c2ecf20Sopenharmony_ci .driver_info = (unsigned long)&ax88772b_info, 12868c2ecf20Sopenharmony_ci}, { 12878c2ecf20Sopenharmony_ci // ASIX AX88772B 10/100 12888c2ecf20Sopenharmony_ci USB_DEVICE (0x0b95, 0x772b), 12898c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772b_info, 12908c2ecf20Sopenharmony_ci}, { 12918c2ecf20Sopenharmony_ci // ASIX AX88772 10/100 12928c2ecf20Sopenharmony_ci USB_DEVICE (0x0b95, 0x7720), 12938c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 12948c2ecf20Sopenharmony_ci}, { 12958c2ecf20Sopenharmony_ci // ASIX AX88178 10/100/1000 12968c2ecf20Sopenharmony_ci USB_DEVICE (0x0b95, 0x1780), 12978c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 12988c2ecf20Sopenharmony_ci}, { 12998c2ecf20Sopenharmony_ci // Logitec LAN-GTJ/U2A 13008c2ecf20Sopenharmony_ci USB_DEVICE (0x0789, 0x0160), 13018c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 13028c2ecf20Sopenharmony_ci}, { 13038c2ecf20Sopenharmony_ci // Linksys USB200M Rev 2 13048c2ecf20Sopenharmony_ci USB_DEVICE (0x13b1, 0x0018), 13058c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13068c2ecf20Sopenharmony_ci}, { 13078c2ecf20Sopenharmony_ci // 0Q0 cable ethernet 13088c2ecf20Sopenharmony_ci USB_DEVICE (0x1557, 0x7720), 13098c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13108c2ecf20Sopenharmony_ci}, { 13118c2ecf20Sopenharmony_ci // DLink DUB-E100 H/W Ver B1 13128c2ecf20Sopenharmony_ci USB_DEVICE (0x07d1, 0x3c05), 13138c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13148c2ecf20Sopenharmony_ci}, { 13158c2ecf20Sopenharmony_ci // DLink DUB-E100 H/W Ver B1 Alternate 13168c2ecf20Sopenharmony_ci USB_DEVICE (0x2001, 0x3c05), 13178c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13188c2ecf20Sopenharmony_ci}, { 13198c2ecf20Sopenharmony_ci // DLink DUB-E100 H/W Ver C1 13208c2ecf20Sopenharmony_ci USB_DEVICE (0x2001, 0x1a02), 13218c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13228c2ecf20Sopenharmony_ci}, { 13238c2ecf20Sopenharmony_ci // Linksys USB1000 13248c2ecf20Sopenharmony_ci USB_DEVICE (0x1737, 0x0039), 13258c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 13268c2ecf20Sopenharmony_ci}, { 13278c2ecf20Sopenharmony_ci // IO-DATA ETG-US2 13288c2ecf20Sopenharmony_ci USB_DEVICE (0x04bb, 0x0930), 13298c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 13308c2ecf20Sopenharmony_ci}, { 13318c2ecf20Sopenharmony_ci // Belkin F5D5055 13328c2ecf20Sopenharmony_ci USB_DEVICE(0x050d, 0x5055), 13338c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 13348c2ecf20Sopenharmony_ci}, { 13358c2ecf20Sopenharmony_ci // Apple USB Ethernet Adapter 13368c2ecf20Sopenharmony_ci USB_DEVICE(0x05ac, 0x1402), 13378c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13388c2ecf20Sopenharmony_ci}, { 13398c2ecf20Sopenharmony_ci // Cables-to-Go USB Ethernet Adapter 13408c2ecf20Sopenharmony_ci USB_DEVICE(0x0b95, 0x772a), 13418c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13428c2ecf20Sopenharmony_ci}, { 13438c2ecf20Sopenharmony_ci // ABOCOM for pci 13448c2ecf20Sopenharmony_ci USB_DEVICE(0x14ea, 0xab11), 13458c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88178_info, 13468c2ecf20Sopenharmony_ci}, { 13478c2ecf20Sopenharmony_ci // ASIX 88772a 13488c2ecf20Sopenharmony_ci USB_DEVICE(0x0db0, 0xa877), 13498c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88772_info, 13508c2ecf20Sopenharmony_ci}, { 13518c2ecf20Sopenharmony_ci // Asus USB Ethernet Adapter 13528c2ecf20Sopenharmony_ci USB_DEVICE (0x0b95, 0x7e2b), 13538c2ecf20Sopenharmony_ci .driver_info = (unsigned long)&ax88772b_info, 13548c2ecf20Sopenharmony_ci}, { 13558c2ecf20Sopenharmony_ci /* ASIX 88172a demo board */ 13568c2ecf20Sopenharmony_ci USB_DEVICE(0x0b95, 0x172a), 13578c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &ax88172a_info, 13588c2ecf20Sopenharmony_ci}, { 13598c2ecf20Sopenharmony_ci /* 13608c2ecf20Sopenharmony_ci * USBLINK HG20F9 "USB 2.0 LAN" 13618c2ecf20Sopenharmony_ci * Appears to have gazumped Linksys's manufacturer ID but 13628c2ecf20Sopenharmony_ci * doesn't (yet) conflict with any known Linksys product. 13638c2ecf20Sopenharmony_ci */ 13648c2ecf20Sopenharmony_ci USB_DEVICE(0x066b, 0x20f9), 13658c2ecf20Sopenharmony_ci .driver_info = (unsigned long) &hg20f9_info, 13668c2ecf20Sopenharmony_ci}, 13678c2ecf20Sopenharmony_ci { }, // END 13688c2ecf20Sopenharmony_ci}; 13698c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, products); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic struct usb_driver asix_driver = { 13728c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 13738c2ecf20Sopenharmony_ci .id_table = products, 13748c2ecf20Sopenharmony_ci .probe = usbnet_probe, 13758c2ecf20Sopenharmony_ci .suspend = asix_suspend, 13768c2ecf20Sopenharmony_ci .resume = asix_resume, 13778c2ecf20Sopenharmony_ci .reset_resume = asix_resume, 13788c2ecf20Sopenharmony_ci .disconnect = usbnet_disconnect, 13798c2ecf20Sopenharmony_ci .supports_autosuspend = 1, 13808c2ecf20Sopenharmony_ci .disable_hub_initiated_lpm = 1, 13818c2ecf20Sopenharmony_ci}; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cimodule_usb_driver(asix_driver); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Hollis"); 13868c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 13878c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); 13888c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 13898c2ecf20Sopenharmony_ci 1390