1108118Smike// SPDX-License-Identifier: ISC 21573Srgrimes/* 31573Srgrimes * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 41573Srgrimes */ 51573Srgrimes 61573Srgrimes#include <linux/kernel.h> 71573Srgrimes#include <linux/module.h> 81573Srgrimes 91573Srgrimes#include "../mt76x02_usb.h" 101573Srgrimes#include "mt76x2u.h" 111573Srgrimes 121573Srgrimesstatic const struct usb_device_id mt76x2u_device_table[] = { 131573Srgrimes { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ 141573Srgrimes { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ 151573Srgrimes { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ 161573Srgrimes { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ 171573Srgrimes { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ 181573Srgrimes { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ 191573Srgrimes { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ 201573Srgrimes { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ 211573Srgrimes { USB_DEVICE(0x0846, 0x9014) }, /* Netgear WNDA3100v3 */ 221573Srgrimes { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ 231573Srgrimes { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ 241573Srgrimes { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ 251573Srgrimes { }, 261573Srgrimes}; 271573Srgrimes 281573Srgrimesstatic int mt76x2u_probe(struct usb_interface *intf, 291573Srgrimes const struct usb_device_id *id) 301573Srgrimes{ 311573Srgrimes static const struct mt76_driver_ops drv_ops = { 321573Srgrimes .drv_flags = MT_DRV_SW_RX_AIRTIME, 3386170Sobrien .survey_flags = SURVEY_INFO_TIME_TX, 3486170Sobrien .update_survey = mt76x02_update_channel, 351573Srgrimes .tx_prepare_skb = mt76x02u_tx_prepare_skb, 36142667Sphantom .tx_complete_skb = mt76x02u_tx_complete_skb, 37142667Sphantom .tx_status_data = mt76x02_tx_status_data, 38142667Sphantom .rx_skb = mt76x02_queue_rx_skb, 39142667Sphantom .sta_ps = mt76x02_sta_ps, 40142693Sphantom .sta_add = mt76x02_sta_add, 41108044Smike .sta_remove = mt76x02_sta_remove, 42142667Sphantom }; 432505Sbde struct usb_device *udev = interface_to_usbdev(intf); 441573Srgrimes struct mt76x02_dev *dev; 45142667Sphantom struct mt76_dev *mdev; 46108118Smike int err; 47108044Smike 48108044Smike mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, 49108044Smike &drv_ops); 50142667Sphantom if (!mdev) 51142667Sphantom return -ENOMEM; 52108044Smike 53142667Sphantom dev = container_of(mdev, struct mt76x02_dev, mt76); 541573Srgrimes 55108118Smike udev = usb_get_dev(udev); 56108118Smike usb_reset_device(udev); 57108118Smike 58108118Smike usb_set_intfdata(intf, dev); 59108044Smike 60142667Sphantom mt76x02u_init_mcu(mdev); 6187434Swes err = mt76u_init(mdev, intf); 62108603Smike if (err < 0) 63108044Smike goto err; 64108044Smike 6587434Swes mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 66108603Smike dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 67108603Smike if (!is_mt76x2(dev)) { 68108044Smike err = -ENODEV; 691573Srgrimes goto err; 70108603Smike } 7186944Swes 7287434Swes err = mt76x2u_register_device(dev); 73108603Smike if (err < 0) 74142667Sphantom goto err; 75142667Sphantom 76142667Sphantom return 0; 77114443Snectar 781573Srgrimeserr: 7986944Swes mt76u_queues_deinit(&dev->mt76); 80108044Smike mt76_free_device(&dev->mt76); 81108044Smike usb_set_intfdata(intf, NULL); 82108044Smike usb_put_dev(udev); 83142667Sphantom 84142667Sphantom return err; 85142667Sphantom} 86142667Sphantom 87142667Sphantomstatic void mt76x2u_disconnect(struct usb_interface *intf) 88142667Sphantom{ 8986944Swes struct usb_device *udev = interface_to_usbdev(intf); 90220376Sjilles struct mt76x02_dev *dev = usb_get_intfdata(intf); 91142667Sphantom struct ieee80211_hw *hw = mt76_hw(dev); 92142667Sphantom 93142667Sphantom set_bit(MT76_REMOVED, &dev->mphy.state); 94142667Sphantom ieee80211_unregister_hw(hw); 95142667Sphantom mt76x2u_cleanup(dev); 96142667Sphantom mt76_free_device(&dev->mt76); 97142667Sphantom usb_set_intfdata(intf, NULL); 98142667Sphantom usb_put_dev(udev); 99142667Sphantom} 100142667Sphantom 101142667Sphantomstatic int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, 102142667Sphantom pm_message_t state) 103142667Sphantom{ 104142667Sphantom struct mt76x02_dev *dev = usb_get_intfdata(intf); 105142667Sphantom 106142667Sphantom mt76u_stop_rx(&dev->mt76); 107142667Sphantom 108108118Smike return 0; 109142667Sphantom} 110142667Sphantom 111142667Sphantomstatic int __maybe_unused mt76x2u_resume(struct usb_interface *intf) 112142667Sphantom{ 113142667Sphantom struct mt76x02_dev *dev = usb_get_intfdata(intf); 114142667Sphantom int err; 115142667Sphantom 116108044Smike err = mt76u_resume_rx(&dev->mt76); 11786944Swes if (err < 0) 118108044Smike goto err; 119108044Smike 12086944Swes err = mt76x2u_init_hardware(dev); 121142667Sphantom if (err < 0) 12286944Swes goto err; 123142667Sphantom 124233062Skib return 0; 125108044Smike 12686944Sweserr: 127 mt76x2u_cleanup(dev); 128 return err; 129} 130 131MODULE_DEVICE_TABLE(usb, mt76x2u_device_table); 132MODULE_FIRMWARE(MT7662_FIRMWARE); 133MODULE_FIRMWARE(MT7662_ROM_PATCH); 134 135static struct usb_driver mt76x2u_driver = { 136 .name = KBUILD_MODNAME, 137 .id_table = mt76x2u_device_table, 138 .probe = mt76x2u_probe, 139 .disconnect = mt76x2u_disconnect, 140#ifdef CONFIG_PM 141 .suspend = mt76x2u_suspend, 142 .resume = mt76x2u_resume, 143 .reset_resume = mt76x2u_resume, 144#endif /* CONFIG_PM */ 145 .soft_unbind = 1, 146 .disable_hub_initiated_lpm = 1, 147}; 148module_usb_driver(mt76x2u_driver); 149 150MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); 151MODULE_DESCRIPTION("MediaTek MT76x2U (USB) wireless driver"); 152MODULE_LICENSE("Dual BSD/GPL"); 153