117364b80SDmitry Bezrukov // SPDX-License-Identifier: GPL-2.0-or-later 217364b80SDmitry Bezrukov /* Aquantia Corp. Aquantia AQtion USB to 5GbE Controller 317364b80SDmitry Bezrukov * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> 417364b80SDmitry Bezrukov * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 517364b80SDmitry Bezrukov * Copyright (C) 2002-2003 TiVo Inc. 617364b80SDmitry Bezrukov * Copyright (C) 2017-2018 ASIX 717364b80SDmitry Bezrukov * Copyright (C) 2018 Aquantia Corp. 817364b80SDmitry Bezrukov */ 917364b80SDmitry Bezrukov 1017364b80SDmitry Bezrukov #include <linux/module.h> 1117364b80SDmitry Bezrukov #include <linux/netdevice.h> 1217364b80SDmitry Bezrukov #include <linux/mii.h> 1317364b80SDmitry Bezrukov #include <linux/usb.h> 1417364b80SDmitry Bezrukov #include <linux/usb/cdc.h> 1517364b80SDmitry Bezrukov #include <linux/usb/usbnet.h> 1617364b80SDmitry Bezrukov 17619fcb44SDmitry Bezrukov #include "aqc111.h" 18619fcb44SDmitry Bezrukov 19619fcb44SDmitry Bezrukov static int aqc111_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 20619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 21619fcb44SDmitry Bezrukov { 22619fcb44SDmitry Bezrukov int ret; 23619fcb44SDmitry Bezrukov 24619fcb44SDmitry Bezrukov ret = usbnet_read_cmd_nopm(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 25619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 26619fcb44SDmitry Bezrukov 27619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 28619fcb44SDmitry Bezrukov netdev_warn(dev->net, 29619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 30619fcb44SDmitry Bezrukov cmd, index, ret); 31619fcb44SDmitry Bezrukov 32619fcb44SDmitry Bezrukov return ret; 33619fcb44SDmitry Bezrukov } 34619fcb44SDmitry Bezrukov 35619fcb44SDmitry Bezrukov static int aqc111_read_cmd(struct usbnet *dev, u8 cmd, u16 value, 36619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 37619fcb44SDmitry Bezrukov { 38619fcb44SDmitry Bezrukov int ret; 39619fcb44SDmitry Bezrukov 40619fcb44SDmitry Bezrukov ret = usbnet_read_cmd(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | 41619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, data, size); 42619fcb44SDmitry Bezrukov 43619fcb44SDmitry Bezrukov if (unlikely(ret < 0)) 44619fcb44SDmitry Bezrukov netdev_warn(dev->net, 45619fcb44SDmitry Bezrukov "Failed to read(0x%x) reg index 0x%04x: %d\n", 46619fcb44SDmitry Bezrukov cmd, index, ret); 47619fcb44SDmitry Bezrukov 48619fcb44SDmitry Bezrukov return ret; 49619fcb44SDmitry Bezrukov } 50619fcb44SDmitry Bezrukov 51f3aa095aSDmitry Bezrukov static int aqc111_read16_cmd(struct usbnet *dev, u8 cmd, u16 value, 52f3aa095aSDmitry Bezrukov u16 index, u16 *data) 53f3aa095aSDmitry Bezrukov { 54f3aa095aSDmitry Bezrukov int ret = 0; 55f3aa095aSDmitry Bezrukov 56f3aa095aSDmitry Bezrukov ret = aqc111_read_cmd(dev, cmd, value, index, sizeof(*data), data); 57f3aa095aSDmitry Bezrukov le16_to_cpus(data); 58f3aa095aSDmitry Bezrukov 59f3aa095aSDmitry Bezrukov return ret; 60f3aa095aSDmitry Bezrukov } 61f3aa095aSDmitry Bezrukov 62619fcb44SDmitry Bezrukov static int __aqc111_write_cmd(struct usbnet *dev, u8 cmd, u8 reqtype, 63619fcb44SDmitry Bezrukov u16 value, u16 index, u16 size, const void *data) 64619fcb44SDmitry Bezrukov { 65619fcb44SDmitry Bezrukov int err = -ENOMEM; 66619fcb44SDmitry Bezrukov void *buf = NULL; 67619fcb44SDmitry Bezrukov 68619fcb44SDmitry Bezrukov netdev_dbg(dev->net, 69619fcb44SDmitry Bezrukov "%s cmd=%#x reqtype=%#x value=%#x index=%#x size=%d\n", 70619fcb44SDmitry Bezrukov __func__, cmd, reqtype, value, index, size); 71619fcb44SDmitry Bezrukov 72619fcb44SDmitry Bezrukov if (data) { 73619fcb44SDmitry Bezrukov buf = kmemdup(data, size, GFP_KERNEL); 74619fcb44SDmitry Bezrukov if (!buf) 75619fcb44SDmitry Bezrukov goto out; 76619fcb44SDmitry Bezrukov } 77619fcb44SDmitry Bezrukov 78619fcb44SDmitry Bezrukov err = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), 79619fcb44SDmitry Bezrukov cmd, reqtype, value, index, buf, size, 80619fcb44SDmitry Bezrukov (cmd == AQ_PHY_POWER) ? AQ_USB_PHY_SET_TIMEOUT : 81619fcb44SDmitry Bezrukov AQ_USB_SET_TIMEOUT); 82619fcb44SDmitry Bezrukov 83619fcb44SDmitry Bezrukov if (unlikely(err < 0)) 84619fcb44SDmitry Bezrukov netdev_warn(dev->net, 85619fcb44SDmitry Bezrukov "Failed to write(0x%x) reg index 0x%04x: %d\n", 86619fcb44SDmitry Bezrukov cmd, index, err); 87619fcb44SDmitry Bezrukov kfree(buf); 88619fcb44SDmitry Bezrukov 89619fcb44SDmitry Bezrukov out: 90619fcb44SDmitry Bezrukov return err; 91619fcb44SDmitry Bezrukov } 92619fcb44SDmitry Bezrukov 93619fcb44SDmitry Bezrukov static int aqc111_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 94619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 95619fcb44SDmitry Bezrukov { 96619fcb44SDmitry Bezrukov int ret; 97619fcb44SDmitry Bezrukov 98619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 99619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 100619fcb44SDmitry Bezrukov 101619fcb44SDmitry Bezrukov return ret; 102619fcb44SDmitry Bezrukov } 103619fcb44SDmitry Bezrukov 104619fcb44SDmitry Bezrukov static int aqc111_write_cmd(struct usbnet *dev, u8 cmd, u16 value, 105619fcb44SDmitry Bezrukov u16 index, u16 size, void *data) 106619fcb44SDmitry Bezrukov { 107619fcb44SDmitry Bezrukov int ret; 108619fcb44SDmitry Bezrukov 109619fcb44SDmitry Bezrukov if (usb_autopm_get_interface(dev->intf) < 0) 110619fcb44SDmitry Bezrukov return -ENODEV; 111619fcb44SDmitry Bezrukov 112619fcb44SDmitry Bezrukov ret = __aqc111_write_cmd(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | 113619fcb44SDmitry Bezrukov USB_RECIP_DEVICE, value, index, size, data); 114619fcb44SDmitry Bezrukov 115619fcb44SDmitry Bezrukov usb_autopm_put_interface(dev->intf); 116619fcb44SDmitry Bezrukov 117619fcb44SDmitry Bezrukov return ret; 118619fcb44SDmitry Bezrukov } 119619fcb44SDmitry Bezrukov 120f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 121f3aa095aSDmitry Bezrukov u16 index, u16 *data) 122f3aa095aSDmitry Bezrukov { 123f3aa095aSDmitry Bezrukov u16 tmp = *data; 124f3aa095aSDmitry Bezrukov 125f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 126f3aa095aSDmitry Bezrukov 127f3aa095aSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 128f3aa095aSDmitry Bezrukov } 129f3aa095aSDmitry Bezrukov 130f3aa095aSDmitry Bezrukov static int aqc111_write16_cmd(struct usbnet *dev, u8 cmd, u16 value, 131f3aa095aSDmitry Bezrukov u16 index, u16 *data) 132f3aa095aSDmitry Bezrukov { 133f3aa095aSDmitry Bezrukov u16 tmp = *data; 134f3aa095aSDmitry Bezrukov 135f3aa095aSDmitry Bezrukov cpu_to_le16s(&tmp); 136f3aa095aSDmitry Bezrukov 137f3aa095aSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 138f3aa095aSDmitry Bezrukov } 139f3aa095aSDmitry Bezrukov 140*33cd597fSDmitry Bezrukov static int aqc111_write32_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value, 141*33cd597fSDmitry Bezrukov u16 index, u32 *data) 142*33cd597fSDmitry Bezrukov { 143*33cd597fSDmitry Bezrukov u32 tmp = *data; 144*33cd597fSDmitry Bezrukov 145*33cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 146*33cd597fSDmitry Bezrukov 147*33cd597fSDmitry Bezrukov return aqc111_write_cmd_nopm(dev, cmd, value, index, sizeof(tmp), &tmp); 148*33cd597fSDmitry Bezrukov } 149*33cd597fSDmitry Bezrukov 150*33cd597fSDmitry Bezrukov static int aqc111_write32_cmd(struct usbnet *dev, u8 cmd, u16 value, 151*33cd597fSDmitry Bezrukov u16 index, u32 *data) 152*33cd597fSDmitry Bezrukov { 153*33cd597fSDmitry Bezrukov u32 tmp = *data; 154*33cd597fSDmitry Bezrukov 155*33cd597fSDmitry Bezrukov cpu_to_le32s(&tmp); 156*33cd597fSDmitry Bezrukov 157*33cd597fSDmitry Bezrukov return aqc111_write_cmd(dev, cmd, value, index, sizeof(tmp), &tmp); 158*33cd597fSDmitry Bezrukov } 159*33cd597fSDmitry Bezrukov 1607cea2d40SDmitry Bezrukov static const struct net_device_ops aqc111_netdev_ops = { 1617cea2d40SDmitry Bezrukov .ndo_open = usbnet_open, 1627cea2d40SDmitry Bezrukov .ndo_stop = usbnet_stop, 1637cea2d40SDmitry Bezrukov }; 1647cea2d40SDmitry Bezrukov 165*33cd597fSDmitry Bezrukov static void aqc111_read_fw_version(struct usbnet *dev, 166*33cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data) 167*33cd597fSDmitry Bezrukov { 168*33cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MAJOR, 169*33cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.major); 170*33cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_MINOR, 171*33cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.minor); 172*33cd597fSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, AQ_FW_VER_REV, 173*33cd597fSDmitry Bezrukov 1, 1, &aqc111_data->fw_ver.rev); 174*33cd597fSDmitry Bezrukov 175*33cd597fSDmitry Bezrukov if (aqc111_data->fw_ver.major & 0x80) 176*33cd597fSDmitry Bezrukov aqc111_data->fw_ver.major &= ~0x80; 177*33cd597fSDmitry Bezrukov } 178*33cd597fSDmitry Bezrukov 1797cea2d40SDmitry Bezrukov static int aqc111_bind(struct usbnet *dev, struct usb_interface *intf) 1807cea2d40SDmitry Bezrukov { 1817cea2d40SDmitry Bezrukov struct usb_device *udev = interface_to_usbdev(intf); 182*33cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data; 1837cea2d40SDmitry Bezrukov int ret; 1847cea2d40SDmitry Bezrukov 1857cea2d40SDmitry Bezrukov /* Check if vendor configuration */ 1867cea2d40SDmitry Bezrukov if (udev->actconfig->desc.bConfigurationValue != 1) { 1877cea2d40SDmitry Bezrukov usb_driver_set_configuration(udev, 1); 1887cea2d40SDmitry Bezrukov return -ENODEV; 1897cea2d40SDmitry Bezrukov } 1907cea2d40SDmitry Bezrukov 1917cea2d40SDmitry Bezrukov usb_reset_configuration(dev->udev); 1927cea2d40SDmitry Bezrukov 1937cea2d40SDmitry Bezrukov ret = usbnet_get_endpoints(dev, intf); 1947cea2d40SDmitry Bezrukov if (ret < 0) { 1957cea2d40SDmitry Bezrukov netdev_dbg(dev->net, "usbnet_get_endpoints failed"); 1967cea2d40SDmitry Bezrukov return ret; 1977cea2d40SDmitry Bezrukov } 1987cea2d40SDmitry Bezrukov 199*33cd597fSDmitry Bezrukov aqc111_data = kzalloc(sizeof(*aqc111_data), GFP_KERNEL); 200*33cd597fSDmitry Bezrukov if (!aqc111_data) 201*33cd597fSDmitry Bezrukov return -ENOMEM; 202*33cd597fSDmitry Bezrukov 203*33cd597fSDmitry Bezrukov /* store aqc111_data pointer in device data field */ 204*33cd597fSDmitry Bezrukov dev->driver_priv = aqc111_data; 205*33cd597fSDmitry Bezrukov 2067cea2d40SDmitry Bezrukov dev->net->netdev_ops = &aqc111_netdev_ops; 2077cea2d40SDmitry Bezrukov 208*33cd597fSDmitry Bezrukov aqc111_read_fw_version(dev, aqc111_data); 209*33cd597fSDmitry Bezrukov 2107cea2d40SDmitry Bezrukov return 0; 2117cea2d40SDmitry Bezrukov } 2127cea2d40SDmitry Bezrukov 2137cea2d40SDmitry Bezrukov static void aqc111_unbind(struct usbnet *dev, struct usb_interface *intf) 2147cea2d40SDmitry Bezrukov { 215*33cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 216f3aa095aSDmitry Bezrukov u16 reg16; 217f3aa095aSDmitry Bezrukov 218f3aa095aSDmitry Bezrukov /* Force bz */ 219f3aa095aSDmitry Bezrukov reg16 = SFR_PHYPWR_RSTCTL_BZ; 220f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 221f3aa095aSDmitry Bezrukov 2, ®16); 222f3aa095aSDmitry Bezrukov reg16 = 0; 223f3aa095aSDmitry Bezrukov aqc111_write16_cmd_nopm(dev, AQ_ACCESS_MAC, SFR_PHYPWR_RSTCTL, 224f3aa095aSDmitry Bezrukov 2, ®16); 225*33cd597fSDmitry Bezrukov 226*33cd597fSDmitry Bezrukov /* Power down ethernet PHY */ 227*33cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 228*33cd597fSDmitry Bezrukov aqc111_data->phy_cfg &= ~AQ_PHY_POWER_EN; 229*33cd597fSDmitry Bezrukov aqc111_write32_cmd_nopm(dev, AQ_PHY_OPS, 0, 0, 230*33cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 231*33cd597fSDmitry Bezrukov 232*33cd597fSDmitry Bezrukov kfree(aqc111_data); 233f3aa095aSDmitry Bezrukov } 234f3aa095aSDmitry Bezrukov 235f3aa095aSDmitry Bezrukov static int aqc111_reset(struct usbnet *dev) 236f3aa095aSDmitry Bezrukov { 237*33cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 238f3aa095aSDmitry Bezrukov u8 reg8 = 0; 239f3aa095aSDmitry Bezrukov 240*33cd597fSDmitry Bezrukov /* Power up ethernet PHY */ 241*33cd597fSDmitry Bezrukov aqc111_data->phy_cfg = AQ_PHY_POWER_EN; 242*33cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 243*33cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 244*33cd597fSDmitry Bezrukov 245f3aa095aSDmitry Bezrukov reg8 = 0xFF; 246f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_BM_INT_MASK, 1, 1, ®8); 247f3aa095aSDmitry Bezrukov 248f3aa095aSDmitry Bezrukov reg8 = 0x0; 249f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_SWP_CTRL, 1, 1, ®8); 250f3aa095aSDmitry Bezrukov 251f3aa095aSDmitry Bezrukov aqc111_read_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 252f3aa095aSDmitry Bezrukov reg8 &= ~(SFR_MONITOR_MODE_EPHYRW | SFR_MONITOR_MODE_RWLC | 253f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RWMP | SFR_MONITOR_MODE_RWWF | 254f3aa095aSDmitry Bezrukov SFR_MONITOR_MODE_RW_FLAG); 255f3aa095aSDmitry Bezrukov aqc111_write_cmd(dev, AQ_ACCESS_MAC, SFR_MONITOR_MODE, 1, 1, ®8); 256f3aa095aSDmitry Bezrukov 257f3aa095aSDmitry Bezrukov return 0; 258f3aa095aSDmitry Bezrukov } 259f3aa095aSDmitry Bezrukov 260f3aa095aSDmitry Bezrukov static int aqc111_stop(struct usbnet *dev) 261f3aa095aSDmitry Bezrukov { 262*33cd597fSDmitry Bezrukov struct aqc111_data *aqc111_data = dev->driver_priv; 263f3aa095aSDmitry Bezrukov u16 reg16 = 0; 264f3aa095aSDmitry Bezrukov 265f3aa095aSDmitry Bezrukov aqc111_read16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 266f3aa095aSDmitry Bezrukov 2, ®16); 267f3aa095aSDmitry Bezrukov reg16 &= ~SFR_MEDIUM_RECEIVE_EN; 268f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_MEDIUM_STATUS_MODE, 269f3aa095aSDmitry Bezrukov 2, ®16); 270f3aa095aSDmitry Bezrukov reg16 = 0; 271f3aa095aSDmitry Bezrukov aqc111_write16_cmd(dev, AQ_ACCESS_MAC, SFR_RX_CTL, 2, ®16); 272f3aa095aSDmitry Bezrukov 273*33cd597fSDmitry Bezrukov /* Put PHY to low power*/ 274*33cd597fSDmitry Bezrukov aqc111_data->phy_cfg |= AQ_LOW_POWER; 275*33cd597fSDmitry Bezrukov aqc111_write32_cmd(dev, AQ_PHY_OPS, 0, 0, 276*33cd597fSDmitry Bezrukov &aqc111_data->phy_cfg); 277*33cd597fSDmitry Bezrukov 278f3aa095aSDmitry Bezrukov return 0; 2797cea2d40SDmitry Bezrukov } 2807cea2d40SDmitry Bezrukov 28117364b80SDmitry Bezrukov static const struct driver_info aqc111_info = { 28217364b80SDmitry Bezrukov .description = "Aquantia AQtion USB to 5GbE Controller", 2837cea2d40SDmitry Bezrukov .bind = aqc111_bind, 2847cea2d40SDmitry Bezrukov .unbind = aqc111_unbind, 285f3aa095aSDmitry Bezrukov .reset = aqc111_reset, 286f3aa095aSDmitry Bezrukov .stop = aqc111_stop, 28717364b80SDmitry Bezrukov }; 28817364b80SDmitry Bezrukov 28917364b80SDmitry Bezrukov #define AQC111_USB_ETH_DEV(vid, pid, table) \ 29017364b80SDmitry Bezrukov USB_DEVICE_INTERFACE_CLASS((vid), (pid), USB_CLASS_VENDOR_SPEC), \ 29117364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table) \ 29217364b80SDmitry Bezrukov }, \ 29317364b80SDmitry Bezrukov { \ 29417364b80SDmitry Bezrukov USB_DEVICE_AND_INTERFACE_INFO((vid), (pid), \ 29517364b80SDmitry Bezrukov USB_CLASS_COMM, \ 29617364b80SDmitry Bezrukov USB_CDC_SUBCLASS_ETHERNET, \ 29717364b80SDmitry Bezrukov USB_CDC_PROTO_NONE), \ 29817364b80SDmitry Bezrukov .driver_info = (unsigned long)&(table), 29917364b80SDmitry Bezrukov 30017364b80SDmitry Bezrukov static const struct usb_device_id products[] = { 30117364b80SDmitry Bezrukov {AQC111_USB_ETH_DEV(0x2eca, 0xc101, aqc111_info)}, 30217364b80SDmitry Bezrukov { },/* END */ 30317364b80SDmitry Bezrukov }; 30417364b80SDmitry Bezrukov MODULE_DEVICE_TABLE(usb, products); 30517364b80SDmitry Bezrukov 30617364b80SDmitry Bezrukov static struct usb_driver aq_driver = { 30717364b80SDmitry Bezrukov .name = "aqc111", 30817364b80SDmitry Bezrukov .id_table = products, 30917364b80SDmitry Bezrukov .probe = usbnet_probe, 31017364b80SDmitry Bezrukov .disconnect = usbnet_disconnect, 31117364b80SDmitry Bezrukov }; 31217364b80SDmitry Bezrukov 31317364b80SDmitry Bezrukov module_usb_driver(aq_driver); 31417364b80SDmitry Bezrukov 31517364b80SDmitry Bezrukov MODULE_DESCRIPTION("Aquantia AQtion USB to 5/2.5GbE Controllers"); 31617364b80SDmitry Bezrukov MODULE_LICENSE("GPL"); 317