18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * (c) Copyright 2002-2010, Ralink Technology, Inc. 48c2ecf20Sopenharmony_ci * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "mt7601u.h" 98c2ecf20Sopenharmony_ci#include "eeprom.h" 108c2ecf20Sopenharmony_ci#include "trace.h" 118c2ecf20Sopenharmony_ci#include "mcu.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "initvals.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic void 168c2ecf20Sopenharmony_cimt7601u_set_wlan_state(struct mt7601u_dev *dev, u32 val, bool enable) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci int i; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci /* Note: we don't turn off WLAN_CLK because that makes the device 218c2ecf20Sopenharmony_ci * not respond properly on the probe path. 228c2ecf20Sopenharmony_ci * In case anyone (PSM?) wants to use this function we can 238c2ecf20Sopenharmony_ci * bring the clock stuff back and fixup the probe path. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (enable) 278c2ecf20Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_EN | 288c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_CLK_EN); 298c2ecf20Sopenharmony_ci else 308c2ecf20Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_EN); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 338c2ecf20Sopenharmony_ci udelay(20); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci if (enable) { 368c2ecf20Sopenharmony_ci set_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); 378c2ecf20Sopenharmony_ci } else { 388c2ecf20Sopenharmony_ci clear_bit(MT7601U_STATE_WLAN_RUNNING, &dev->state); 398c2ecf20Sopenharmony_ci return; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci for (i = 200; i; i--) { 438c2ecf20Sopenharmony_ci val = mt7601u_rr(dev, MT_CMB_CTRL); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (val & MT_CMB_CTRL_XTAL_RDY && val & MT_CMB_CTRL_PLL_LD) 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci udelay(20); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* Note: vendor driver tries to disable/enable wlan here and retry 528c2ecf20Sopenharmony_ci * but the code which does it is so buggy it must have never 538c2ecf20Sopenharmony_ci * triggered, so don't bother. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci if (!i) 568c2ecf20Sopenharmony_ci dev_err(dev->dev, "Error: PLL and XTAL check failed!\n"); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void mt7601u_chip_onoff(struct mt7601u_dev *dev, bool enable, bool reset) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci u32 val; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci mutex_lock(&dev->hw_atomic_mutex); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci val = mt7601u_rr(dev, MT_WLAN_FUN_CTRL); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (reset) { 688c2ecf20Sopenharmony_ci val |= MT_WLAN_FUN_CTRL_GPIO_OUT_EN; 698c2ecf20Sopenharmony_ci val &= ~MT_WLAN_FUN_CTRL_FRC_WL_ANT_SEL; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (val & MT_WLAN_FUN_CTRL_WLAN_EN) { 728c2ecf20Sopenharmony_ci val |= (MT_WLAN_FUN_CTRL_WLAN_RESET | 738c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 748c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 758c2ecf20Sopenharmony_ci udelay(20); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci val &= ~(MT_WLAN_FUN_CTRL_WLAN_RESET | 788c2ecf20Sopenharmony_ci MT_WLAN_FUN_CTRL_WLAN_RESET_RF); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_WLAN_FUN_CTRL, val); 838c2ecf20Sopenharmony_ci udelay(20); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci mt7601u_set_wlan_state(dev, val, enable); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci mutex_unlock(&dev->hw_atomic_mutex); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void mt7601u_reset_csr_bbp(struct mt7601u_dev *dev) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, (MT_MAC_SYS_CTRL_RESET_CSR | 938c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_RESET_BBP)); 948c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, 0); 958c2ecf20Sopenharmony_ci msleep(1); 968c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 0); 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void mt7601u_init_usb_dma(struct mt7601u_dev *dev) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci u32 val; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci val = FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_TOUT, MT_USB_AGGR_TIMEOUT) | 1048c2ecf20Sopenharmony_ci FIELD_PREP(MT_USB_DMA_CFG_RX_BULK_AGG_LMT, 1058c2ecf20Sopenharmony_ci MT_USB_AGGR_SIZE_LIMIT) | 1068c2ecf20Sopenharmony_ci MT_USB_DMA_CFG_RX_BULK_EN | 1078c2ecf20Sopenharmony_ci MT_USB_DMA_CFG_TX_BULK_EN; 1088c2ecf20Sopenharmony_ci if (dev->in_max_packet == 512) 1098c2ecf20Sopenharmony_ci val |= MT_USB_DMA_CFG_RX_BULK_AGG_EN; 1108c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci val |= MT_USB_DMA_CFG_UDMA_RX_WL_DROP; 1138c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 1148c2ecf20Sopenharmony_ci val &= ~MT_USB_DMA_CFG_UDMA_RX_WL_DROP; 1158c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_USB_DMA_CFG, val); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int mt7601u_init_bbp(struct mt7601u_dev *dev) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci int ret; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci ret = mt7601u_wait_bbp_ready(dev); 1238c2ecf20Sopenharmony_ci if (ret) 1248c2ecf20Sopenharmony_ci return ret; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_common_vals, 1278c2ecf20Sopenharmony_ci ARRAY_SIZE(bbp_common_vals)); 1288c2ecf20Sopenharmony_ci if (ret) 1298c2ecf20Sopenharmony_ci return ret; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_BBP, bbp_chip_vals, 1328c2ecf20Sopenharmony_ci ARRAY_SIZE(bbp_chip_vals)); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void 1368c2ecf20Sopenharmony_cimt76_init_beacon_offsets(struct mt7601u_dev *dev) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u16 base = MT_BEACON_BASE; 1398c2ecf20Sopenharmony_ci u32 regs[4] = {}; 1408c2ecf20Sopenharmony_ci int i; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 1438c2ecf20Sopenharmony_ci u16 addr = dev->beacon_offsets[i]; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci regs[i / 4] |= ((addr - base) / 64) << (8 * (i % 4)); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 1498c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_BCN_OFFSET(i), regs[i]); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int mt7601u_write_mac_initvals(struct mt7601u_dev *dev) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci int ret; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, mac_common_vals, 1578c2ecf20Sopenharmony_ci ARRAY_SIZE(mac_common_vals)); 1588c2ecf20Sopenharmony_ci if (ret) 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci ret = mt7601u_write_reg_pairs(dev, MT_MCU_MEMMAP_WLAN, 1618c2ecf20Sopenharmony_ci mac_chip_vals, ARRAY_SIZE(mac_chip_vals)); 1628c2ecf20Sopenharmony_ci if (ret) 1638c2ecf20Sopenharmony_ci return ret; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci mt76_init_beacon_offsets(dev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_AUX_CLK_CFG, 0); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int mt7601u_init_wcid_mem(struct mt7601u_dev *dev) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 *vals; 1758c2ecf20Sopenharmony_ci int i, ret; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); 1788c2ecf20Sopenharmony_ci if (!vals) 1798c2ecf20Sopenharmony_ci return -ENOMEM; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci for (i = 0; i < N_WCIDS; i++) { 1828c2ecf20Sopenharmony_ci vals[i * 2] = 0xffffffff; 1838c2ecf20Sopenharmony_ci vals[i * 2 + 1] = 0x00ffffff; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = mt7601u_burst_write_regs(dev, MT_WCID_ADDR_BASE, 1878c2ecf20Sopenharmony_ci vals, N_WCIDS * 2); 1888c2ecf20Sopenharmony_ci kfree(vals); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return ret; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int mt7601u_init_key_mem(struct mt7601u_dev *dev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 vals[4] = {}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return mt7601u_burst_write_regs(dev, MT_SKEY_MODE_BASE_0, 1988c2ecf20Sopenharmony_ci vals, ARRAY_SIZE(vals)); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int mt7601u_init_wcid_attr_mem(struct mt7601u_dev *dev) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u32 *vals; 2048c2ecf20Sopenharmony_ci int i, ret; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci vals = kmalloc(sizeof(*vals) * N_WCIDS * 2, GFP_KERNEL); 2078c2ecf20Sopenharmony_ci if (!vals) 2088c2ecf20Sopenharmony_ci return -ENOMEM; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci for (i = 0; i < N_WCIDS * 2; i++) 2118c2ecf20Sopenharmony_ci vals[i] = 1; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = mt7601u_burst_write_regs(dev, MT_WCID_ATTR_BASE, 2148c2ecf20Sopenharmony_ci vals, N_WCIDS * 2); 2158c2ecf20Sopenharmony_ci kfree(vals); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic void mt7601u_reset_counters(struct mt7601u_dev *dev) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT0); 2238c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT1); 2248c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_RX_STA_CNT2); 2258c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT0); 2268c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT1); 2278c2ecf20Sopenharmony_ci mt7601u_rr(dev, MT_TX_STA_CNT2); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ciint mt7601u_mac_start(struct mt7601u_dev *dev) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 2358c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 200000)) 2368c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci dev->rxfilter = MT_RX_FILTR_CFG_CRC_ERR | 2398c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_PHY_ERR | MT_RX_FILTR_CFG_PROMISC | 2408c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_VER_ERR | MT_RX_FILTR_CFG_DUP | 2418c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_CFACK | MT_RX_FILTR_CFG_CFEND | 2428c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_ACK | MT_RX_FILTR_CFG_CTS | 2438c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_RTS | MT_RX_FILTR_CFG_PSPOLL | 2448c2ecf20Sopenharmony_ci MT_RX_FILTR_CFG_BA | MT_RX_FILTR_CFG_CTRL_RSV; 2458c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_RX_FILTR_CFG, dev->rxfilter); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_MAC_SYS_CTRL, 2488c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 2518c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 50)) 2528c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void mt7601u_mac_stop_hw(struct mt7601u_dev *dev) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci int i, ok; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (test_bit(MT7601U_STATE_REMOVED, &dev->state)) 2628c2ecf20Sopenharmony_ci return; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci mt76_clear(dev, MT_BEACON_TIME_CFG, MT_BEACON_TIME_CFG_TIMER_EN | 2658c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | MT_BEACON_TIME_CFG_TBTT_EN | 2668c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_TX_BUSY, 0, 1000)) 2698c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Warning: TX DMA did not stop!\n"); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Page count on TxQ */ 2728c2ecf20Sopenharmony_ci i = 200; 2738c2ecf20Sopenharmony_ci while (i-- && ((mt76_rr(dev, 0x0438) & 0xffffffff) || 2748c2ecf20Sopenharmony_ci (mt76_rr(dev, 0x0a30) & 0x000000ff) || 2758c2ecf20Sopenharmony_ci (mt76_rr(dev, 0x0a34) & 0x00ff00ff))) 2768c2ecf20Sopenharmony_ci msleep(10); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_TX, 0, 1000)) 2798c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Warning: MAC TX did not stop!\n"); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_RX | 2828c2ecf20Sopenharmony_ci MT_MAC_SYS_CTRL_ENABLE_TX); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Page count on RxQ */ 2858c2ecf20Sopenharmony_ci ok = 0; 2868c2ecf20Sopenharmony_ci i = 200; 2878c2ecf20Sopenharmony_ci while (i--) { 2888c2ecf20Sopenharmony_ci if (!(mt76_rr(dev, MT_RXQ_STA) & 0x00ff0000) && 2898c2ecf20Sopenharmony_ci !mt76_rr(dev, 0x0a30) && 2908c2ecf20Sopenharmony_ci !mt76_rr(dev, 0x0a34)) { 2918c2ecf20Sopenharmony_ci if (ok++ > 5) 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci continue; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci msleep(1); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_MAC_STATUS, MT_MAC_STATUS_RX, 0, 1000)) 2998c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Warning: MAC RX did not stop!\n"); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!mt76_poll(dev, MT_USB_DMA_CFG, MT_USB_DMA_CFG_RX_BUSY, 0, 1000)) 3028c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Warning: RX DMA did not stop!\n"); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_civoid mt7601u_mac_stop(struct mt7601u_dev *dev) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci mt7601u_mac_stop_hw(dev); 3088c2ecf20Sopenharmony_ci flush_delayed_work(&dev->stat_work); 3098c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&dev->stat_work); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void mt7601u_stop_hardware(struct mt7601u_dev *dev) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci mt7601u_chip_onoff(dev, false, false); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint mt7601u_init_hardware(struct mt7601u_dev *dev) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci static const u16 beacon_offsets[16] = { 3208c2ecf20Sopenharmony_ci /* 512 byte per beacon */ 3218c2ecf20Sopenharmony_ci 0xc000, 0xc200, 0xc400, 0xc600, 3228c2ecf20Sopenharmony_ci 0xc800, 0xca00, 0xcc00, 0xce00, 3238c2ecf20Sopenharmony_ci 0xd000, 0xd200, 0xd400, 0xd600, 3248c2ecf20Sopenharmony_ci 0xd800, 0xda00, 0xdc00, 0xde00 3258c2ecf20Sopenharmony_ci }; 3268c2ecf20Sopenharmony_ci int ret; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci dev->beacon_offsets = beacon_offsets; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci mt7601u_chip_onoff(dev, true, false); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = mt7601u_wait_asic_ready(dev); 3338c2ecf20Sopenharmony_ci if (ret) 3348c2ecf20Sopenharmony_ci goto err; 3358c2ecf20Sopenharmony_ci ret = mt7601u_mcu_init(dev); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci goto err; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_WPDMA_GLO_CFG, 3408c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_TX_DMA_BUSY | 3418c2ecf20Sopenharmony_ci MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 100)) { 3428c2ecf20Sopenharmony_ci ret = -EIO; 3438c2ecf20Sopenharmony_ci goto err; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Wait for ASIC ready after FW load. */ 3478c2ecf20Sopenharmony_ci ret = mt7601u_wait_asic_ready(dev); 3488c2ecf20Sopenharmony_ci if (ret) 3498c2ecf20Sopenharmony_ci goto err; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci mt7601u_reset_csr_bbp(dev); 3528c2ecf20Sopenharmony_ci mt7601u_init_usb_dma(dev); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = mt7601u_mcu_cmd_init(dev); 3558c2ecf20Sopenharmony_ci if (ret) 3568c2ecf20Sopenharmony_ci goto err; 3578c2ecf20Sopenharmony_ci ret = mt7601u_dma_init(dev); 3588c2ecf20Sopenharmony_ci if (ret) 3598c2ecf20Sopenharmony_ci goto err_mcu; 3608c2ecf20Sopenharmony_ci ret = mt7601u_write_mac_initvals(dev); 3618c2ecf20Sopenharmony_ci if (ret) 3628c2ecf20Sopenharmony_ci goto err_rx; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!mt76_poll_msec(dev, MT_MAC_STATUS, 3658c2ecf20Sopenharmony_ci MT_MAC_STATUS_TX | MT_MAC_STATUS_RX, 0, 100)) { 3668c2ecf20Sopenharmony_ci ret = -EIO; 3678c2ecf20Sopenharmony_ci goto err_rx; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = mt7601u_init_bbp(dev); 3718c2ecf20Sopenharmony_ci if (ret) 3728c2ecf20Sopenharmony_ci goto err_rx; 3738c2ecf20Sopenharmony_ci ret = mt7601u_init_wcid_mem(dev); 3748c2ecf20Sopenharmony_ci if (ret) 3758c2ecf20Sopenharmony_ci goto err_rx; 3768c2ecf20Sopenharmony_ci ret = mt7601u_init_key_mem(dev); 3778c2ecf20Sopenharmony_ci if (ret) 3788c2ecf20Sopenharmony_ci goto err_rx; 3798c2ecf20Sopenharmony_ci ret = mt7601u_init_wcid_attr_mem(dev); 3808c2ecf20Sopenharmony_ci if (ret) 3818c2ecf20Sopenharmony_ci goto err_rx; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci mt76_clear(dev, MT_BEACON_TIME_CFG, (MT_BEACON_TIME_CFG_TIMER_EN | 3848c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_SYNC_MODE | 3858c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_TBTT_EN | 3868c2ecf20Sopenharmony_ci MT_BEACON_TIME_CFG_BEACON_TX)); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci mt7601u_reset_counters(dev); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci mt7601u_rmw(dev, MT_US_CYC_CFG, MT_US_CYC_CNT, 0x1e); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci mt7601u_wr(dev, MT_TXOP_CTRL_CFG, 3938c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | 3948c2ecf20Sopenharmony_ci FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ret = mt7601u_eeprom_init(dev); 3978c2ecf20Sopenharmony_ci if (ret) 3988c2ecf20Sopenharmony_ci goto err_rx; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci ret = mt7601u_phy_init(dev); 4018c2ecf20Sopenharmony_ci if (ret) 4028c2ecf20Sopenharmony_ci goto err_rx; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci mt7601u_set_rx_path(dev, 0); 4058c2ecf20Sopenharmony_ci mt7601u_set_tx_dac(dev, 0); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci mt7601u_mac_set_ctrlch(dev, false); 4088c2ecf20Sopenharmony_ci mt7601u_bbp_set_ctrlch(dev, false); 4098c2ecf20Sopenharmony_ci mt7601u_bbp_set_bw(dev, MT_BW_20); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cierr_rx: 4148c2ecf20Sopenharmony_ci mt7601u_dma_cleanup(dev); 4158c2ecf20Sopenharmony_cierr_mcu: 4168c2ecf20Sopenharmony_ci mt7601u_mcu_cmd_deinit(dev); 4178c2ecf20Sopenharmony_cierr: 4188c2ecf20Sopenharmony_ci mt7601u_chip_onoff(dev, false, false); 4198c2ecf20Sopenharmony_ci return ret; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_civoid mt7601u_cleanup(struct mt7601u_dev *dev) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci if (!test_and_clear_bit(MT7601U_STATE_INITIALIZED, &dev->state)) 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci mt7601u_stop_hardware(dev); 4288c2ecf20Sopenharmony_ci mt7601u_dma_cleanup(dev); 4298c2ecf20Sopenharmony_ci mt7601u_mcu_cmd_deinit(dev); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistruct mt7601u_dev *mt7601u_alloc_device(struct device *pdev) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct ieee80211_hw *hw; 4358c2ecf20Sopenharmony_ci struct mt7601u_dev *dev; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci hw = ieee80211_alloc_hw(sizeof(*dev), &mt7601u_ops); 4388c2ecf20Sopenharmony_ci if (!hw) 4398c2ecf20Sopenharmony_ci return NULL; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci dev = hw->priv; 4428c2ecf20Sopenharmony_ci dev->dev = pdev; 4438c2ecf20Sopenharmony_ci dev->hw = hw; 4448c2ecf20Sopenharmony_ci mutex_init(&dev->vendor_req_mutex); 4458c2ecf20Sopenharmony_ci mutex_init(&dev->reg_atomic_mutex); 4468c2ecf20Sopenharmony_ci mutex_init(&dev->hw_atomic_mutex); 4478c2ecf20Sopenharmony_ci mutex_init(&dev->mutex); 4488c2ecf20Sopenharmony_ci spin_lock_init(&dev->tx_lock); 4498c2ecf20Sopenharmony_ci spin_lock_init(&dev->rx_lock); 4508c2ecf20Sopenharmony_ci spin_lock_init(&dev->lock); 4518c2ecf20Sopenharmony_ci spin_lock_init(&dev->mac_lock); 4528c2ecf20Sopenharmony_ci spin_lock_init(&dev->con_mon_lock); 4538c2ecf20Sopenharmony_ci atomic_set(&dev->avg_ampdu_len, 1); 4548c2ecf20Sopenharmony_ci skb_queue_head_init(&dev->tx_skb_done); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci dev->stat_wq = alloc_workqueue("mt7601u", WQ_UNBOUND, 0); 4578c2ecf20Sopenharmony_ci if (!dev->stat_wq) { 4588c2ecf20Sopenharmony_ci ieee80211_free_hw(hw); 4598c2ecf20Sopenharmony_ci return NULL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return dev; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#define CHAN2G(_idx, _freq) { \ 4668c2ecf20Sopenharmony_ci .band = NL80211_BAND_2GHZ, \ 4678c2ecf20Sopenharmony_ci .center_freq = (_freq), \ 4688c2ecf20Sopenharmony_ci .hw_value = (_idx), \ 4698c2ecf20Sopenharmony_ci .max_power = 30, \ 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic const struct ieee80211_channel mt76_channels_2ghz[] = { 4738c2ecf20Sopenharmony_ci CHAN2G(1, 2412), 4748c2ecf20Sopenharmony_ci CHAN2G(2, 2417), 4758c2ecf20Sopenharmony_ci CHAN2G(3, 2422), 4768c2ecf20Sopenharmony_ci CHAN2G(4, 2427), 4778c2ecf20Sopenharmony_ci CHAN2G(5, 2432), 4788c2ecf20Sopenharmony_ci CHAN2G(6, 2437), 4798c2ecf20Sopenharmony_ci CHAN2G(7, 2442), 4808c2ecf20Sopenharmony_ci CHAN2G(8, 2447), 4818c2ecf20Sopenharmony_ci CHAN2G(9, 2452), 4828c2ecf20Sopenharmony_ci CHAN2G(10, 2457), 4838c2ecf20Sopenharmony_ci CHAN2G(11, 2462), 4848c2ecf20Sopenharmony_ci CHAN2G(12, 2467), 4858c2ecf20Sopenharmony_ci CHAN2G(13, 2472), 4868c2ecf20Sopenharmony_ci CHAN2G(14, 2484), 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci#define CCK_RATE(_idx, _rate) { \ 4908c2ecf20Sopenharmony_ci .bitrate = _rate, \ 4918c2ecf20Sopenharmony_ci .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ 4928c2ecf20Sopenharmony_ci .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ 4938c2ecf20Sopenharmony_ci .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci#define OFDM_RATE(_idx, _rate) { \ 4978c2ecf20Sopenharmony_ci .bitrate = _rate, \ 4988c2ecf20Sopenharmony_ci .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ 4998c2ecf20Sopenharmony_ci .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic struct ieee80211_rate mt76_rates[] = { 5038c2ecf20Sopenharmony_ci CCK_RATE(0, 10), 5048c2ecf20Sopenharmony_ci CCK_RATE(1, 20), 5058c2ecf20Sopenharmony_ci CCK_RATE(2, 55), 5068c2ecf20Sopenharmony_ci CCK_RATE(3, 110), 5078c2ecf20Sopenharmony_ci OFDM_RATE(0, 60), 5088c2ecf20Sopenharmony_ci OFDM_RATE(1, 90), 5098c2ecf20Sopenharmony_ci OFDM_RATE(2, 120), 5108c2ecf20Sopenharmony_ci OFDM_RATE(3, 180), 5118c2ecf20Sopenharmony_ci OFDM_RATE(4, 240), 5128c2ecf20Sopenharmony_ci OFDM_RATE(5, 360), 5138c2ecf20Sopenharmony_ci OFDM_RATE(6, 480), 5148c2ecf20Sopenharmony_ci OFDM_RATE(7, 540), 5158c2ecf20Sopenharmony_ci}; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int 5188c2ecf20Sopenharmony_cimt76_init_sband(struct mt7601u_dev *dev, struct ieee80211_supported_band *sband, 5198c2ecf20Sopenharmony_ci const struct ieee80211_channel *chan, int n_chan, 5208c2ecf20Sopenharmony_ci struct ieee80211_rate *rates, int n_rates) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct ieee80211_sta_ht_cap *ht_cap; 5238c2ecf20Sopenharmony_ci void *chanlist; 5248c2ecf20Sopenharmony_ci int size; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci size = n_chan * sizeof(*chan); 5278c2ecf20Sopenharmony_ci chanlist = devm_kmemdup(dev->dev, chan, size, GFP_KERNEL); 5288c2ecf20Sopenharmony_ci if (!chanlist) 5298c2ecf20Sopenharmony_ci return -ENOMEM; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci sband->channels = chanlist; 5328c2ecf20Sopenharmony_ci sband->n_channels = n_chan; 5338c2ecf20Sopenharmony_ci sband->bitrates = rates; 5348c2ecf20Sopenharmony_ci sband->n_bitrates = n_rates; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ht_cap = &sband->ht_cap; 5378c2ecf20Sopenharmony_ci ht_cap->ht_supported = true; 5388c2ecf20Sopenharmony_ci ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 5398c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_GRN_FLD | 5408c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_20 | 5418c2ecf20Sopenharmony_ci IEEE80211_HT_CAP_SGI_40 | 5428c2ecf20Sopenharmony_ci (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ht_cap->mcs.rx_mask[0] = 0xff; 5458c2ecf20Sopenharmony_ci ht_cap->mcs.rx_mask[4] = 0x1; 5468c2ecf20Sopenharmony_ci ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; 5478c2ecf20Sopenharmony_ci ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; 5488c2ecf20Sopenharmony_ci ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_2; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci dev->chandef.chan = &sband->channels[0]; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int 5568c2ecf20Sopenharmony_cimt76_init_sband_2g(struct mt7601u_dev *dev) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g), 5598c2ecf20Sopenharmony_ci GFP_KERNEL); 5608c2ecf20Sopenharmony_ci if (!dev->sband_2g) 5618c2ecf20Sopenharmony_ci return -ENOMEM; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = dev->sband_2g; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > 5668c2ecf20Sopenharmony_ci ARRAY_SIZE(mt76_channels_2ghz)); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci return mt76_init_sband(dev, dev->sband_2g, 5698c2ecf20Sopenharmony_ci &mt76_channels_2ghz[dev->ee->reg.start - 1], 5708c2ecf20Sopenharmony_ci dev->ee->reg.num, 5718c2ecf20Sopenharmony_ci mt76_rates, ARRAY_SIZE(mt76_rates)); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ciint mt7601u_register_device(struct mt7601u_dev *dev) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct ieee80211_hw *hw = dev->hw; 5778c2ecf20Sopenharmony_ci struct wiphy *wiphy = hw->wiphy; 5788c2ecf20Sopenharmony_ci int ret; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci /* Reserve WCID 0 for mcast - thanks to this APs WCID will go to 5818c2ecf20Sopenharmony_ci * entry no. 1 like it does in the vendor driver. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci dev->wcid_mask[0] |= 1; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* init fake wcid for monitor interfaces */ 5868c2ecf20Sopenharmony_ci dev->mon_wcid = devm_kmalloc(dev->dev, sizeof(*dev->mon_wcid), 5878c2ecf20Sopenharmony_ci GFP_KERNEL); 5888c2ecf20Sopenharmony_ci if (!dev->mon_wcid) 5898c2ecf20Sopenharmony_ci return -ENOMEM; 5908c2ecf20Sopenharmony_ci dev->mon_wcid->idx = 0xff; 5918c2ecf20Sopenharmony_ci dev->mon_wcid->hw_key_idx = -1; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci SET_IEEE80211_DEV(hw, dev->dev); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci hw->queues = 4; 5968c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SIGNAL_DBM); 5978c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, PS_NULLFUNC_STACK); 5988c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); 5998c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, AMPDU_AGGREGATION); 6008c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); 6018c2ecf20Sopenharmony_ci ieee80211_hw_set(hw, MFP_CAPABLE); 6028c2ecf20Sopenharmony_ci hw->max_rates = 1; 6038c2ecf20Sopenharmony_ci hw->max_report_rates = 7; 6048c2ecf20Sopenharmony_ci hw->max_rate_tries = 1; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci hw->sta_data_size = sizeof(struct mt76_sta); 6078c2ecf20Sopenharmony_ci hw->vif_data_size = sizeof(struct mt76_vif); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci SET_IEEE80211_PERM_ADDR(hw, dev->macaddr); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; 6128c2ecf20Sopenharmony_ci wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ret = mt76_init_sband_2g(dev); 6178c2ecf20Sopenharmony_ci if (ret) 6188c2ecf20Sopenharmony_ci return ret; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&dev->mac_work, mt7601u_mac_work); 6218c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&dev->stat_work, mt7601u_tx_stat); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = ieee80211_register_hw(hw); 6248c2ecf20Sopenharmony_ci if (ret) 6258c2ecf20Sopenharmony_ci return ret; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci mt7601u_init_debugfs(dev); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 631