18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "../mt76x02_usb.h" 108c2ecf20Sopenharmony_ci#include "mt76x2u.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistatic const struct usb_device_id mt76x2u_device_table[] = { 138c2ecf20Sopenharmony_ci { USB_DEVICE(0x0b05, 0x1833) }, /* Asus USB-AC54 */ 148c2ecf20Sopenharmony_ci { USB_DEVICE(0x0b05, 0x17eb) }, /* Asus USB-AC55 */ 158c2ecf20Sopenharmony_ci { USB_DEVICE(0x0b05, 0x180b) }, /* Asus USB-N53 B1 */ 168c2ecf20Sopenharmony_ci { USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */ 178c2ecf20Sopenharmony_ci { USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */ 188c2ecf20Sopenharmony_ci { USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */ 198c2ecf20Sopenharmony_ci { USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */ 208c2ecf20Sopenharmony_ci { USB_DEVICE(0x2c4e, 0x0103) }, /* Mercury UD13 */ 218c2ecf20Sopenharmony_ci { USB_DEVICE(0x0846, 0x9053) }, /* Netgear A6210 */ 228c2ecf20Sopenharmony_ci { USB_DEVICE(0x045e, 0x02e6) }, /* XBox One Wireless Adapter */ 238c2ecf20Sopenharmony_ci { USB_DEVICE(0x045e, 0x02fe) }, /* XBox One Wireless Adapter */ 248c2ecf20Sopenharmony_ci { }, 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int mt76x2u_probe(struct usb_interface *intf, 288c2ecf20Sopenharmony_ci const struct usb_device_id *id) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci static const struct mt76_driver_ops drv_ops = { 318c2ecf20Sopenharmony_ci .drv_flags = MT_DRV_SW_RX_AIRTIME, 328c2ecf20Sopenharmony_ci .survey_flags = SURVEY_INFO_TIME_TX, 338c2ecf20Sopenharmony_ci .update_survey = mt76x02_update_channel, 348c2ecf20Sopenharmony_ci .tx_prepare_skb = mt76x02u_tx_prepare_skb, 358c2ecf20Sopenharmony_ci .tx_complete_skb = mt76x02u_tx_complete_skb, 368c2ecf20Sopenharmony_ci .tx_status_data = mt76x02_tx_status_data, 378c2ecf20Sopenharmony_ci .rx_skb = mt76x02_queue_rx_skb, 388c2ecf20Sopenharmony_ci .sta_ps = mt76x02_sta_ps, 398c2ecf20Sopenharmony_ci .sta_add = mt76x02_sta_add, 408c2ecf20Sopenharmony_ci .sta_remove = mt76x02_sta_remove, 418c2ecf20Sopenharmony_ci }; 428c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 438c2ecf20Sopenharmony_ci struct mt76x02_dev *dev; 448c2ecf20Sopenharmony_ci struct mt76_dev *mdev; 458c2ecf20Sopenharmony_ci int err; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, 488c2ecf20Sopenharmony_ci &drv_ops); 498c2ecf20Sopenharmony_ci if (!mdev) 508c2ecf20Sopenharmony_ci return -ENOMEM; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci dev = container_of(mdev, struct mt76x02_dev, mt76); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci udev = usb_get_dev(udev); 558c2ecf20Sopenharmony_ci usb_reset_device(udev); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci usb_set_intfdata(intf, dev); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci mt76x02u_init_mcu(mdev); 608c2ecf20Sopenharmony_ci err = mt76u_init(mdev, intf, false); 618c2ecf20Sopenharmony_ci if (err < 0) 628c2ecf20Sopenharmony_ci goto err; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci mdev->rev = mt76_rr(dev, MT_ASIC_VERSION); 658c2ecf20Sopenharmony_ci dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev); 668c2ecf20Sopenharmony_ci if (!is_mt76x2(dev)) { 678c2ecf20Sopenharmony_ci err = -ENODEV; 688c2ecf20Sopenharmony_ci goto err; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci err = mt76x2u_register_device(dev); 728c2ecf20Sopenharmony_ci if (err < 0) 738c2ecf20Sopenharmony_ci goto err; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cierr: 788c2ecf20Sopenharmony_ci mt76_free_device(&dev->mt76); 798c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 808c2ecf20Sopenharmony_ci usb_put_dev(udev); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return err; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic void mt76x2u_disconnect(struct usb_interface *intf) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 888c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = usb_get_intfdata(intf); 898c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = mt76_hw(dev); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci set_bit(MT76_REMOVED, &dev->mphy.state); 928c2ecf20Sopenharmony_ci ieee80211_unregister_hw(hw); 938c2ecf20Sopenharmony_ci mt76x2u_cleanup(dev); 948c2ecf20Sopenharmony_ci mt76_free_device(&dev->mt76); 958c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 968c2ecf20Sopenharmony_ci usb_put_dev(udev); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int __maybe_unused mt76x2u_suspend(struct usb_interface *intf, 1008c2ecf20Sopenharmony_ci pm_message_t state) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = usb_get_intfdata(intf); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci mt76u_stop_rx(&dev->mt76); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int __maybe_unused mt76x2u_resume(struct usb_interface *intf) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct mt76x02_dev *dev = usb_get_intfdata(intf); 1128c2ecf20Sopenharmony_ci int err; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci err = mt76u_resume_rx(&dev->mt76); 1158c2ecf20Sopenharmony_ci if (err < 0) 1168c2ecf20Sopenharmony_ci goto err; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci err = mt76x2u_init_hardware(dev); 1198c2ecf20Sopenharmony_ci if (err < 0) 1208c2ecf20Sopenharmony_ci goto err; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cierr: 1258c2ecf20Sopenharmony_ci mt76x2u_cleanup(dev); 1268c2ecf20Sopenharmony_ci return err; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, mt76x2u_device_table); 1308c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7662_FIRMWARE); 1318c2ecf20Sopenharmony_ciMODULE_FIRMWARE(MT7662_ROM_PATCH); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic struct usb_driver mt76x2u_driver = { 1348c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 1358c2ecf20Sopenharmony_ci .id_table = mt76x2u_device_table, 1368c2ecf20Sopenharmony_ci .probe = mt76x2u_probe, 1378c2ecf20Sopenharmony_ci .disconnect = mt76x2u_disconnect, 1388c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1398c2ecf20Sopenharmony_ci .suspend = mt76x2u_suspend, 1408c2ecf20Sopenharmony_ci .resume = mt76x2u_resume, 1418c2ecf20Sopenharmony_ci .reset_resume = mt76x2u_resume, 1428c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 1438c2ecf20Sopenharmony_ci .soft_unbind = 1, 1448c2ecf20Sopenharmony_ci .disable_hub_initiated_lpm = 1, 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_cimodule_usb_driver(mt76x2u_driver); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>"); 1498c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 150