18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* ZD1211 USB-WLAN driver for Linux 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* This file implements all the hardware specific functions for the ZD1211 98c2ecf20Sopenharmony_ci * and ZD1211B chips. Support for the ZD1211B was possible after Timothy 108c2ecf20Sopenharmony_ci * Legge sent me a ZD1211B device. Thank you Tim. -- Uli 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "zd_def.h" 188c2ecf20Sopenharmony_ci#include "zd_chip.h" 198c2ecf20Sopenharmony_ci#include "zd_mac.h" 208c2ecf20Sopenharmony_ci#include "zd_rf.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid zd_chip_init(struct zd_chip *chip, 238c2ecf20Sopenharmony_ci struct ieee80211_hw *hw, 248c2ecf20Sopenharmony_ci struct usb_interface *intf) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci memset(chip, 0, sizeof(*chip)); 278c2ecf20Sopenharmony_ci mutex_init(&chip->mutex); 288c2ecf20Sopenharmony_ci zd_usb_init(&chip->usb, hw, intf); 298c2ecf20Sopenharmony_ci zd_rf_init(&chip->rf); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid zd_chip_clear(struct zd_chip *chip) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci ZD_ASSERT(!mutex_is_locked(&chip->mutex)); 358c2ecf20Sopenharmony_ci zd_usb_clear(&chip->usb); 368c2ecf20Sopenharmony_ci zd_rf_clear(&chip->rf); 378c2ecf20Sopenharmony_ci mutex_destroy(&chip->mutex); 388c2ecf20Sopenharmony_ci ZD_MEMCLEAR(chip, sizeof(*chip)); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip)); 448c2ecf20Sopenharmony_ci return scnprintf(buffer, size, "%3phD", addr); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Prints an identifier line, which will support debugging. */ 488c2ecf20Sopenharmony_cistatic int scnprint_id(struct zd_chip *chip, char *buffer, size_t size) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci int i = 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci i = scnprintf(buffer, size, "zd1211%s chip ", 538c2ecf20Sopenharmony_ci zd_chip_is_zd1211b(chip) ? "b" : ""); 548c2ecf20Sopenharmony_ci i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i); 558c2ecf20Sopenharmony_ci i += scnprintf(buffer+i, size-i, " "); 568c2ecf20Sopenharmony_ci i += scnprint_mac_oui(chip, buffer+i, size-i); 578c2ecf20Sopenharmony_ci i += scnprintf(buffer+i, size-i, " "); 588c2ecf20Sopenharmony_ci i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); 598c2ecf20Sopenharmony_ci i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, 608c2ecf20Sopenharmony_ci chip->patch_cck_gain ? 'g' : '-', 618c2ecf20Sopenharmony_ci chip->patch_cr157 ? '7' : '-', 628c2ecf20Sopenharmony_ci chip->patch_6m_band_edge ? '6' : '-', 638c2ecf20Sopenharmony_ci chip->new_phy_layout ? 'N' : '-', 648c2ecf20Sopenharmony_ci chip->al2230s_bit ? 'S' : '-'); 658c2ecf20Sopenharmony_ci return i; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void print_id(struct zd_chip *chip) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci char buffer[80]; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci scnprint_id(chip, buffer, sizeof(buffer)); 738c2ecf20Sopenharmony_ci buffer[sizeof(buffer)-1] = 0; 748c2ecf20Sopenharmony_ci dev_info(zd_chip_dev(chip), "%s\n", buffer); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic zd_addr_t inc_addr(zd_addr_t addr) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci u16 a = (u16)addr; 808c2ecf20Sopenharmony_ci /* Control registers use byte addressing, but everything else uses word 818c2ecf20Sopenharmony_ci * addressing. */ 828c2ecf20Sopenharmony_ci if ((a & 0xf000) == CR_START) 838c2ecf20Sopenharmony_ci a += 2; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci a += 1; 868c2ecf20Sopenharmony_ci return (zd_addr_t)a; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* Read a variable number of 32-bit values. Parameter count is not allowed to 908c2ecf20Sopenharmony_ci * exceed USB_MAX_IOREAD32_COUNT. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ciint zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr, 938c2ecf20Sopenharmony_ci unsigned int count) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int r; 968c2ecf20Sopenharmony_ci int i; 978c2ecf20Sopenharmony_ci zd_addr_t a16[USB_MAX_IOREAD32_COUNT * 2]; 988c2ecf20Sopenharmony_ci u16 v16[USB_MAX_IOREAD32_COUNT * 2]; 998c2ecf20Sopenharmony_ci unsigned int count16; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (count > USB_MAX_IOREAD32_COUNT) 1028c2ecf20Sopenharmony_ci return -EINVAL; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* Use stack for values and addresses. */ 1058c2ecf20Sopenharmony_ci count16 = 2 * count; 1068c2ecf20Sopenharmony_ci BUG_ON(count16 * sizeof(zd_addr_t) > sizeof(a16)); 1078c2ecf20Sopenharmony_ci BUG_ON(count16 * sizeof(u16) > sizeof(v16)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1108c2ecf20Sopenharmony_ci int j = 2*i; 1118c2ecf20Sopenharmony_ci /* We read the high word always first. */ 1128c2ecf20Sopenharmony_ci a16[j] = inc_addr(addr[i]); 1138c2ecf20Sopenharmony_ci a16[j+1] = addr[i]; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci r = zd_ioread16v_locked(chip, v16, a16, count16); 1178c2ecf20Sopenharmony_ci if (r) { 1188c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 1198c2ecf20Sopenharmony_ci "error: %s. Error number %d\n", __func__, r); 1208c2ecf20Sopenharmony_ci return r; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1248c2ecf20Sopenharmony_ci int j = 2*i; 1258c2ecf20Sopenharmony_ci values[i] = (v16[j] << 16) | v16[j+1]; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int _zd_iowrite32v_async_locked(struct zd_chip *chip, 1328c2ecf20Sopenharmony_ci const struct zd_ioreq32 *ioreqs, 1338c2ecf20Sopenharmony_ci unsigned int count) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci int i, j, r; 1368c2ecf20Sopenharmony_ci struct zd_ioreq16 ioreqs16[USB_MAX_IOWRITE32_COUNT * 2]; 1378c2ecf20Sopenharmony_ci unsigned int count16; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Use stack for values and addresses. */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (count == 0) 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci if (count > USB_MAX_IOWRITE32_COUNT) 1468c2ecf20Sopenharmony_ci return -EINVAL; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci count16 = 2 * count; 1498c2ecf20Sopenharmony_ci BUG_ON(count16 * sizeof(struct zd_ioreq16) > sizeof(ioreqs16)); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 1528c2ecf20Sopenharmony_ci j = 2*i; 1538c2ecf20Sopenharmony_ci /* We write the high word always first. */ 1548c2ecf20Sopenharmony_ci ioreqs16[j].value = ioreqs[i].value >> 16; 1558c2ecf20Sopenharmony_ci ioreqs16[j].addr = inc_addr(ioreqs[i].addr); 1568c2ecf20Sopenharmony_ci ioreqs16[j+1].value = ioreqs[i].value; 1578c2ecf20Sopenharmony_ci ioreqs16[j+1].addr = ioreqs[i].addr; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci r = zd_usb_iowrite16v_async(&chip->usb, ioreqs16, count16); 1618c2ecf20Sopenharmony_ci#ifdef DEBUG 1628c2ecf20Sopenharmony_ci if (r) { 1638c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 1648c2ecf20Sopenharmony_ci "error %d in zd_usb_write16v\n", r); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci#endif /* DEBUG */ 1678c2ecf20Sopenharmony_ci return r; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, 1718c2ecf20Sopenharmony_ci unsigned int count) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci int r; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_start(&chip->usb); 1768c2ecf20Sopenharmony_ci r = _zd_iowrite32v_async_locked(chip, ioreqs, count); 1778c2ecf20Sopenharmony_ci if (r) { 1788c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_end(&chip->usb, 0); 1798c2ecf20Sopenharmony_ci return r; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciint zd_iowrite16a_locked(struct zd_chip *chip, 1858c2ecf20Sopenharmony_ci const struct zd_ioreq16 *ioreqs, unsigned int count) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int r; 1888c2ecf20Sopenharmony_ci unsigned int i, j, t, max; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 1918c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_start(&chip->usb); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci for (i = 0; i < count; i += j + t) { 1948c2ecf20Sopenharmony_ci t = 0; 1958c2ecf20Sopenharmony_ci max = count-i; 1968c2ecf20Sopenharmony_ci if (max > USB_MAX_IOWRITE16_COUNT) 1978c2ecf20Sopenharmony_ci max = USB_MAX_IOWRITE16_COUNT; 1988c2ecf20Sopenharmony_ci for (j = 0; j < max; j++) { 1998c2ecf20Sopenharmony_ci if (!ioreqs[i+j].addr) { 2008c2ecf20Sopenharmony_ci t = 1; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci r = zd_usb_iowrite16v_async(&chip->usb, &ioreqs[i], j); 2068c2ecf20Sopenharmony_ci if (r) { 2078c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_end(&chip->usb, 0); 2088c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 2098c2ecf20Sopenharmony_ci "error zd_usb_iowrite16v. Error number %d\n", 2108c2ecf20Sopenharmony_ci r); 2118c2ecf20Sopenharmony_ci return r; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* Writes a variable number of 32 bit registers. The functions will split 2198c2ecf20Sopenharmony_ci * that in several USB requests. A split can be forced by inserting an IO 2208c2ecf20Sopenharmony_ci * request with an zero address field. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ciint zd_iowrite32a_locked(struct zd_chip *chip, 2238c2ecf20Sopenharmony_ci const struct zd_ioreq32 *ioreqs, unsigned int count) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int r; 2268c2ecf20Sopenharmony_ci unsigned int i, j, t, max; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_start(&chip->usb); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci for (i = 0; i < count; i += j + t) { 2318c2ecf20Sopenharmony_ci t = 0; 2328c2ecf20Sopenharmony_ci max = count-i; 2338c2ecf20Sopenharmony_ci if (max > USB_MAX_IOWRITE32_COUNT) 2348c2ecf20Sopenharmony_ci max = USB_MAX_IOWRITE32_COUNT; 2358c2ecf20Sopenharmony_ci for (j = 0; j < max; j++) { 2368c2ecf20Sopenharmony_ci if (!ioreqs[i+j].addr) { 2378c2ecf20Sopenharmony_ci t = 1; 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci r = _zd_iowrite32v_async_locked(chip, &ioreqs[i], j); 2438c2ecf20Sopenharmony_ci if (r) { 2448c2ecf20Sopenharmony_ci zd_usb_iowrite16v_async_end(&chip->usb, 0); 2458c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 2468c2ecf20Sopenharmony_ci "error _%s. Error number %d\n", __func__, 2478c2ecf20Sopenharmony_ci r); 2488c2ecf20Sopenharmony_ci return r; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return zd_usb_iowrite16v_async_end(&chip->usb, 50 /* ms */); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciint zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int r; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 2608c2ecf20Sopenharmony_ci r = zd_ioread16_locked(chip, value, addr); 2618c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 2628c2ecf20Sopenharmony_ci return r; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciint zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int r; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 2708c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, value, addr); 2718c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 2728c2ecf20Sopenharmony_ci return r; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciint zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int r; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 2808c2ecf20Sopenharmony_ci r = zd_iowrite16_locked(chip, value, addr); 2818c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 2828c2ecf20Sopenharmony_ci return r; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciint zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int r; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 2908c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, value, addr); 2918c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 2928c2ecf20Sopenharmony_ci return r; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ciint zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses, 2968c2ecf20Sopenharmony_ci u32 *values, unsigned int count) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int r; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 3018c2ecf20Sopenharmony_ci r = zd_ioread32v_locked(chip, values, addresses, count); 3028c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 3038c2ecf20Sopenharmony_ci return r; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ciint zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, 3078c2ecf20Sopenharmony_ci unsigned int count) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int r; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 3128c2ecf20Sopenharmony_ci r = zd_iowrite32a_locked(chip, ioreqs, count); 3138c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 3148c2ecf20Sopenharmony_ci return r; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int read_pod(struct zd_chip *chip, u8 *rf_type) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int r; 3208c2ecf20Sopenharmony_ci u32 value; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 3238c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &value, E2P_POD); 3248c2ecf20Sopenharmony_ci if (r) 3258c2ecf20Sopenharmony_ci goto error; 3268c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* FIXME: AL2230 handling (Bit 7 in POD) */ 3298c2ecf20Sopenharmony_ci *rf_type = value & 0x0f; 3308c2ecf20Sopenharmony_ci chip->pa_type = (value >> 16) & 0x0f; 3318c2ecf20Sopenharmony_ci chip->patch_cck_gain = (value >> 8) & 0x1; 3328c2ecf20Sopenharmony_ci chip->patch_cr157 = (value >> 13) & 0x1; 3338c2ecf20Sopenharmony_ci chip->patch_6m_band_edge = (value >> 21) & 0x1; 3348c2ecf20Sopenharmony_ci chip->new_phy_layout = (value >> 31) & 0x1; 3358c2ecf20Sopenharmony_ci chip->al2230s_bit = (value >> 7) & 0x1; 3368c2ecf20Sopenharmony_ci chip->link_led = ((value >> 4) & 1) ? LED1 : LED2; 3378c2ecf20Sopenharmony_ci chip->supports_tx_led = 1; 3388c2ecf20Sopenharmony_ci if (value & (1 << 24)) { /* LED scenario */ 3398c2ecf20Sopenharmony_ci if (value & (1 << 29)) 3408c2ecf20Sopenharmony_ci chip->supports_tx_led = 0; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 3448c2ecf20Sopenharmony_ci "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d " 3458c2ecf20Sopenharmony_ci "patch 6M %d new PHY %d link LED%d tx led %d\n", 3468c2ecf20Sopenharmony_ci zd_rf_name(*rf_type), *rf_type, 3478c2ecf20Sopenharmony_ci chip->pa_type, chip->patch_cck_gain, 3488c2ecf20Sopenharmony_ci chip->patch_cr157, chip->patch_6m_band_edge, 3498c2ecf20Sopenharmony_ci chip->new_phy_layout, 3508c2ecf20Sopenharmony_ci chip->link_led == LED1 ? 1 : 2, 3518c2ecf20Sopenharmony_ci chip->supports_tx_led); 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_cierror: 3548c2ecf20Sopenharmony_ci *rf_type = 0; 3558c2ecf20Sopenharmony_ci chip->pa_type = 0; 3568c2ecf20Sopenharmony_ci chip->patch_cck_gain = 0; 3578c2ecf20Sopenharmony_ci chip->patch_cr157 = 0; 3588c2ecf20Sopenharmony_ci chip->patch_6m_band_edge = 0; 3598c2ecf20Sopenharmony_ci chip->new_phy_layout = 0; 3608c2ecf20Sopenharmony_ci return r; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int zd_write_mac_addr_common(struct zd_chip *chip, const u8 *mac_addr, 3648c2ecf20Sopenharmony_ci const struct zd_ioreq32 *in_reqs, 3658c2ecf20Sopenharmony_ci const char *type) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int r; 3688c2ecf20Sopenharmony_ci struct zd_ioreq32 reqs[2] = {in_reqs[0], in_reqs[1]}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (mac_addr) { 3718c2ecf20Sopenharmony_ci reqs[0].value = (mac_addr[3] << 24) 3728c2ecf20Sopenharmony_ci | (mac_addr[2] << 16) 3738c2ecf20Sopenharmony_ci | (mac_addr[1] << 8) 3748c2ecf20Sopenharmony_ci | mac_addr[0]; 3758c2ecf20Sopenharmony_ci reqs[1].value = (mac_addr[5] << 8) 3768c2ecf20Sopenharmony_ci | mac_addr[4]; 3778c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "%s addr %pM\n", type, mac_addr); 3788c2ecf20Sopenharmony_ci } else { 3798c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "set NULL %s\n", type); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 3838c2ecf20Sopenharmony_ci r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); 3848c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 3858c2ecf20Sopenharmony_ci return r; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* MAC address: if custom mac addresses are to be used CR_MAC_ADDR_P1 and 3898c2ecf20Sopenharmony_ci * CR_MAC_ADDR_P2 must be overwritten 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ciint zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci static const struct zd_ioreq32 reqs[2] = { 3948c2ecf20Sopenharmony_ci [0] = { .addr = CR_MAC_ADDR_P1 }, 3958c2ecf20Sopenharmony_ci [1] = { .addr = CR_MAC_ADDR_P2 }, 3968c2ecf20Sopenharmony_ci }; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return zd_write_mac_addr_common(chip, mac_addr, reqs, "mac"); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ciint zd_write_bssid(struct zd_chip *chip, const u8 *bssid) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci static const struct zd_ioreq32 reqs[2] = { 4048c2ecf20Sopenharmony_ci [0] = { .addr = CR_BSSID_P1 }, 4058c2ecf20Sopenharmony_ci [1] = { .addr = CR_BSSID_P2 }, 4068c2ecf20Sopenharmony_ci }; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return zd_write_mac_addr_common(chip, bssid, reqs, "bssid"); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ciint zd_read_regdomain(struct zd_chip *chip, u8 *regdomain) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int r; 4148c2ecf20Sopenharmony_ci u32 value; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 4178c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &value, E2P_SUBID); 4188c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 4198c2ecf20Sopenharmony_ci if (r) 4208c2ecf20Sopenharmony_ci return r; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci *regdomain = value >> 16; 4238c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "regdomain: %#04x\n", *regdomain); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int read_values(struct zd_chip *chip, u8 *values, size_t count, 4298c2ecf20Sopenharmony_ci zd_addr_t e2p_addr, u32 guard) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci int r; 4328c2ecf20Sopenharmony_ci int i; 4338c2ecf20Sopenharmony_ci u32 v; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 4368c2ecf20Sopenharmony_ci for (i = 0;;) { 4378c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &v, 4388c2ecf20Sopenharmony_ci (zd_addr_t)((u16)e2p_addr+i/2)); 4398c2ecf20Sopenharmony_ci if (r) 4408c2ecf20Sopenharmony_ci return r; 4418c2ecf20Sopenharmony_ci v -= guard; 4428c2ecf20Sopenharmony_ci if (i+4 < count) { 4438c2ecf20Sopenharmony_ci values[i++] = v; 4448c2ecf20Sopenharmony_ci values[i++] = v >> 8; 4458c2ecf20Sopenharmony_ci values[i++] = v >> 16; 4468c2ecf20Sopenharmony_ci values[i++] = v >> 24; 4478c2ecf20Sopenharmony_ci continue; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci for (;i < count; i++) 4508c2ecf20Sopenharmony_ci values[i] = v >> (8*(i%3)); 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int read_pwr_cal_values(struct zd_chip *chip) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci return read_values(chip, chip->pwr_cal_values, 4588c2ecf20Sopenharmony_ci E2P_CHANNEL_COUNT, E2P_PWR_CAL_VALUE1, 4598c2ecf20Sopenharmony_ci 0); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int read_pwr_int_values(struct zd_chip *chip) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci return read_values(chip, chip->pwr_int_values, 4658c2ecf20Sopenharmony_ci E2P_CHANNEL_COUNT, E2P_PWR_INT_VALUE1, 4668c2ecf20Sopenharmony_ci E2P_PWR_INT_GUARD); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int read_ofdm_cal_values(struct zd_chip *chip) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci int r; 4728c2ecf20Sopenharmony_ci int i; 4738c2ecf20Sopenharmony_ci static const zd_addr_t addresses[] = { 4748c2ecf20Sopenharmony_ci E2P_36M_CAL_VALUE1, 4758c2ecf20Sopenharmony_ci E2P_48M_CAL_VALUE1, 4768c2ecf20Sopenharmony_ci E2P_54M_CAL_VALUE1, 4778c2ecf20Sopenharmony_ci }; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 4808c2ecf20Sopenharmony_ci r = read_values(chip, chip->ofdm_cal_values[i], 4818c2ecf20Sopenharmony_ci E2P_CHANNEL_COUNT, addresses[i], 0); 4828c2ecf20Sopenharmony_ci if (r) 4838c2ecf20Sopenharmony_ci return r; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int read_cal_int_tables(struct zd_chip *chip) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci int r; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci r = read_pwr_cal_values(chip); 4938c2ecf20Sopenharmony_ci if (r) 4948c2ecf20Sopenharmony_ci return r; 4958c2ecf20Sopenharmony_ci r = read_pwr_int_values(chip); 4968c2ecf20Sopenharmony_ci if (r) 4978c2ecf20Sopenharmony_ci return r; 4988c2ecf20Sopenharmony_ci r = read_ofdm_cal_values(chip); 4998c2ecf20Sopenharmony_ci if (r) 5008c2ecf20Sopenharmony_ci return r; 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/* phy means physical registers */ 5058c2ecf20Sopenharmony_ciint zd_chip_lock_phy_regs(struct zd_chip *chip) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci int r; 5088c2ecf20Sopenharmony_ci u32 tmp; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 5118c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &tmp, CR_REG1); 5128c2ecf20Sopenharmony_ci if (r) { 5138c2ecf20Sopenharmony_ci dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r); 5148c2ecf20Sopenharmony_ci return r; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci tmp &= ~UNLOCK_PHY_REGS; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, tmp, CR_REG1); 5208c2ecf20Sopenharmony_ci if (r) 5218c2ecf20Sopenharmony_ci dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r); 5228c2ecf20Sopenharmony_ci return r; 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ciint zd_chip_unlock_phy_regs(struct zd_chip *chip) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci int r; 5288c2ecf20Sopenharmony_ci u32 tmp; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 5318c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &tmp, CR_REG1); 5328c2ecf20Sopenharmony_ci if (r) { 5338c2ecf20Sopenharmony_ci dev_err(zd_chip_dev(chip), 5348c2ecf20Sopenharmony_ci "error ioread32(CR_REG1): %d\n", r); 5358c2ecf20Sopenharmony_ci return r; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci tmp |= UNLOCK_PHY_REGS; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, tmp, CR_REG1); 5418c2ecf20Sopenharmony_ci if (r) 5428c2ecf20Sopenharmony_ci dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r); 5438c2ecf20Sopenharmony_ci return r; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */ 5478c2ecf20Sopenharmony_cistatic int patch_cr157(struct zd_chip *chip) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci int r; 5508c2ecf20Sopenharmony_ci u16 value; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (!chip->patch_cr157) 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci r = zd_ioread16_locked(chip, &value, E2P_PHY_REG); 5568c2ecf20Sopenharmony_ci if (r) 5578c2ecf20Sopenharmony_ci return r; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8); 5608c2ecf20Sopenharmony_ci return zd_iowrite32_locked(chip, value >> 8, ZD_CR157); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/* 5648c2ecf20Sopenharmony_ci * 6M band edge can be optionally overwritten for certain RF's 5658c2ecf20Sopenharmony_ci * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge 5668c2ecf20Sopenharmony_ci * bit (for AL2230, AL2230S) 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_cistatic int patch_6m_band_edge(struct zd_chip *chip, u8 channel) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 5718c2ecf20Sopenharmony_ci if (!chip->patch_6m_band_edge) 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return zd_rf_patch_6m_band_edge(&chip->rf, channel); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* Generic implementation of 6M band edge patching, used by most RFs via 5788c2ecf20Sopenharmony_ci * zd_rf_generic_patch_6m() */ 5798c2ecf20Sopenharmony_ciint zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct zd_ioreq16 ioreqs[] = { 5828c2ecf20Sopenharmony_ci { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, 5838c2ecf20Sopenharmony_ci { ZD_CR47, 0x1e }, 5848c2ecf20Sopenharmony_ci }; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* FIXME: Channel 11 is not the edge for all regulatory domains. */ 5878c2ecf20Sopenharmony_ci if (channel == 1 || channel == 11) 5888c2ecf20Sopenharmony_ci ioreqs[0].value = 0x12; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel); 5918c2ecf20Sopenharmony_ci return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int zd1211_hw_reset_phy(struct zd_chip *chip) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci static const struct zd_ioreq16 ioreqs[] = { 5978c2ecf20Sopenharmony_ci { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, 5988c2ecf20Sopenharmony_ci { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 }, 5998c2ecf20Sopenharmony_ci { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f }, 6008c2ecf20Sopenharmony_ci { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d }, 6018c2ecf20Sopenharmony_ci { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a }, 6028c2ecf20Sopenharmony_ci { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c }, 6038c2ecf20Sopenharmony_ci { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 }, 6048c2ecf20Sopenharmony_ci { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 }, 6058c2ecf20Sopenharmony_ci { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b }, 6068c2ecf20Sopenharmony_ci { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, 6078c2ecf20Sopenharmony_ci { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, 6088c2ecf20Sopenharmony_ci { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, 6098c2ecf20Sopenharmony_ci { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, 6108c2ecf20Sopenharmony_ci { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff }, 6118c2ecf20Sopenharmony_ci { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, 6128c2ecf20Sopenharmony_ci { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, 6138c2ecf20Sopenharmony_ci { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, 6148c2ecf20Sopenharmony_ci { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, 6158c2ecf20Sopenharmony_ci { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, 6168c2ecf20Sopenharmony_ci { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, 6178c2ecf20Sopenharmony_ci { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, 6188c2ecf20Sopenharmony_ci { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 }, 6198c2ecf20Sopenharmony_ci { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 }, 6208c2ecf20Sopenharmony_ci { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 }, 6218c2ecf20Sopenharmony_ci { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 }, 6228c2ecf20Sopenharmony_ci { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff }, 6238c2ecf20Sopenharmony_ci { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 }, 6248c2ecf20Sopenharmony_ci { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 }, 6258c2ecf20Sopenharmony_ci { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 }, 6268c2ecf20Sopenharmony_ci { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a }, 6278c2ecf20Sopenharmony_ci { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 }, 6288c2ecf20Sopenharmony_ci { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e }, 6298c2ecf20Sopenharmony_ci { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, 6308c2ecf20Sopenharmony_ci { }, 6318c2ecf20Sopenharmony_ci { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 }, 6328c2ecf20Sopenharmony_ci { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 }, 6338c2ecf20Sopenharmony_ci { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 }, 6348c2ecf20Sopenharmony_ci { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 }, 6358c2ecf20Sopenharmony_ci { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C }, 6368c2ecf20Sopenharmony_ci { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 }, 6378c2ecf20Sopenharmony_ci { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 }, 6388c2ecf20Sopenharmony_ci { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 }, 6398c2ecf20Sopenharmony_ci { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 }, 6408c2ecf20Sopenharmony_ci { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, 6418c2ecf20Sopenharmony_ci { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, 6428c2ecf20Sopenharmony_ci { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, 6438c2ecf20Sopenharmony_ci { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, 6448c2ecf20Sopenharmony_ci { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f }, 6458c2ecf20Sopenharmony_ci { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 }, 6468c2ecf20Sopenharmony_ci { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C }, 6478c2ecf20Sopenharmony_ci { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 }, 6488c2ecf20Sopenharmony_ci { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 }, 6498c2ecf20Sopenharmony_ci { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c }, 6508c2ecf20Sopenharmony_ci { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 }, 6518c2ecf20Sopenharmony_ci { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe }, 6528c2ecf20Sopenharmony_ci { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, 6538c2ecf20Sopenharmony_ci { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, 6548c2ecf20Sopenharmony_ci { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, 6558c2ecf20Sopenharmony_ci { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, 6568c2ecf20Sopenharmony_ci /* Note: ZD_CR204 must lead the ZD_CR203 */ 6578c2ecf20Sopenharmony_ci { ZD_CR204, 0x7d }, 6588c2ecf20Sopenharmony_ci { }, 6598c2ecf20Sopenharmony_ci { ZD_CR203, 0x30 }, 6608c2ecf20Sopenharmony_ci }; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci int r, t; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci r = zd_chip_lock_phy_regs(chip); 6678c2ecf20Sopenharmony_ci if (r) 6688c2ecf20Sopenharmony_ci goto out; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 6718c2ecf20Sopenharmony_ci if (r) 6728c2ecf20Sopenharmony_ci goto unlock; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci r = patch_cr157(chip); 6758c2ecf20Sopenharmony_ciunlock: 6768c2ecf20Sopenharmony_ci t = zd_chip_unlock_phy_regs(chip); 6778c2ecf20Sopenharmony_ci if (t && !r) 6788c2ecf20Sopenharmony_ci r = t; 6798c2ecf20Sopenharmony_ciout: 6808c2ecf20Sopenharmony_ci return r; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int zd1211b_hw_reset_phy(struct zd_chip *chip) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci static const struct zd_ioreq16 ioreqs[] = { 6868c2ecf20Sopenharmony_ci { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 }, 6878c2ecf20Sopenharmony_ci { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 }, 6888c2ecf20Sopenharmony_ci { ZD_CR10, 0x81 }, 6898c2ecf20Sopenharmony_ci /* power control { { ZD_CR11, 1 << 6 }, */ 6908c2ecf20Sopenharmony_ci { ZD_CR11, 0x00 }, 6918c2ecf20Sopenharmony_ci { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, 6928c2ecf20Sopenharmony_ci { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, 6938c2ecf20Sopenharmony_ci { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 }, 6948c2ecf20Sopenharmony_ci { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */ 6958c2ecf20Sopenharmony_ci { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, 6968c2ecf20Sopenharmony_ci { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, 6978c2ecf20Sopenharmony_ci { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, 6988c2ecf20Sopenharmony_ci { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */ 6998c2ecf20Sopenharmony_ci { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 }, 7008c2ecf20Sopenharmony_ci { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 }, 7018c2ecf20Sopenharmony_ci { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c }, 7028c2ecf20Sopenharmony_ci { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 }, 7038c2ecf20Sopenharmony_ci { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff }, 7048c2ecf20Sopenharmony_ci { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b }, 7058c2ecf20Sopenharmony_ci { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 }, 7068c2ecf20Sopenharmony_ci { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 }, 7078c2ecf20Sopenharmony_ci { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff }, 7088c2ecf20Sopenharmony_ci { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 }, 7098c2ecf20Sopenharmony_ci { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 }, 7108c2ecf20Sopenharmony_ci { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 }, 7118c2ecf20Sopenharmony_ci { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 }, 7128c2ecf20Sopenharmony_ci { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 }, 7138c2ecf20Sopenharmony_ci { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 }, 7148c2ecf20Sopenharmony_ci { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 }, 7158c2ecf20Sopenharmony_ci { ZD_CR94, 0x01 }, 7168c2ecf20Sopenharmony_ci { ZD_CR95, 0x20 }, /* ZD1211B */ 7178c2ecf20Sopenharmony_ci { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, 7188c2ecf20Sopenharmony_ci { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 }, 7198c2ecf20Sopenharmony_ci { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 }, 7208c2ecf20Sopenharmony_ci { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, 7218c2ecf20Sopenharmony_ci { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 }, 7228c2ecf20Sopenharmony_ci { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 }, 7238c2ecf20Sopenharmony_ci { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 }, 7248c2ecf20Sopenharmony_ci { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e }, 7258c2ecf20Sopenharmony_ci { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 }, 7268c2ecf20Sopenharmony_ci { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, 7278c2ecf20Sopenharmony_ci { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 }, 7288c2ecf20Sopenharmony_ci { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 }, 7298c2ecf20Sopenharmony_ci { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c }, 7308c2ecf20Sopenharmony_ci { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 }, 7318c2ecf20Sopenharmony_ci { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */ 7328c2ecf20Sopenharmony_ci { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */ 7338c2ecf20Sopenharmony_ci { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe }, 7348c2ecf20Sopenharmony_ci { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa }, 7358c2ecf20Sopenharmony_ci { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe }, 7368c2ecf20Sopenharmony_ci { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba }, 7378c2ecf20Sopenharmony_ci { ZD_CR170, 0xba }, { ZD_CR171, 0xba }, 7388c2ecf20Sopenharmony_ci /* Note: ZD_CR204 must lead the ZD_CR203 */ 7398c2ecf20Sopenharmony_ci { ZD_CR204, 0x7d }, 7408c2ecf20Sopenharmony_ci {}, 7418c2ecf20Sopenharmony_ci { ZD_CR203, 0x30 }, 7428c2ecf20Sopenharmony_ci }; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci int r, t; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci r = zd_chip_lock_phy_regs(chip); 7498c2ecf20Sopenharmony_ci if (r) 7508c2ecf20Sopenharmony_ci goto out; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 7538c2ecf20Sopenharmony_ci t = zd_chip_unlock_phy_regs(chip); 7548c2ecf20Sopenharmony_ci if (t && !r) 7558c2ecf20Sopenharmony_ci r = t; 7568c2ecf20Sopenharmony_ciout: 7578c2ecf20Sopenharmony_ci return r; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int hw_reset_phy(struct zd_chip *chip) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci return zd_chip_is_zd1211b(chip) ? zd1211b_hw_reset_phy(chip) : 7638c2ecf20Sopenharmony_ci zd1211_hw_reset_phy(chip); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int zd1211_hw_init_hmac(struct zd_chip *chip) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci static const struct zd_ioreq32 ioreqs[] = { 7698c2ecf20Sopenharmony_ci { CR_ZD1211_RETRY_MAX, ZD1211_RETRY_COUNT }, 7708c2ecf20Sopenharmony_ci { CR_RX_THRESHOLD, 0x000c0640 }, 7718c2ecf20Sopenharmony_ci }; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 7748c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 7758c2ecf20Sopenharmony_ci return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic int zd1211b_hw_init_hmac(struct zd_chip *chip) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci static const struct zd_ioreq32 ioreqs[] = { 7818c2ecf20Sopenharmony_ci { CR_ZD1211B_RETRY_MAX, ZD1211B_RETRY_COUNT }, 7828c2ecf20Sopenharmony_ci { CR_ZD1211B_CWIN_MAX_MIN_AC0, 0x007f003f }, 7838c2ecf20Sopenharmony_ci { CR_ZD1211B_CWIN_MAX_MIN_AC1, 0x007f003f }, 7848c2ecf20Sopenharmony_ci { CR_ZD1211B_CWIN_MAX_MIN_AC2, 0x003f001f }, 7858c2ecf20Sopenharmony_ci { CR_ZD1211B_CWIN_MAX_MIN_AC3, 0x001f000f }, 7868c2ecf20Sopenharmony_ci { CR_ZD1211B_AIFS_CTL1, 0x00280028 }, 7878c2ecf20Sopenharmony_ci { CR_ZD1211B_AIFS_CTL2, 0x008C003C }, 7888c2ecf20Sopenharmony_ci { CR_ZD1211B_TXOP, 0x01800824 }, 7898c2ecf20Sopenharmony_ci { CR_RX_THRESHOLD, 0x000c0eff, }, 7908c2ecf20Sopenharmony_ci }; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 7938c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 7948c2ecf20Sopenharmony_ci return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int hw_init_hmac(struct zd_chip *chip) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci int r; 8008c2ecf20Sopenharmony_ci static const struct zd_ioreq32 ioreqs[] = { 8018c2ecf20Sopenharmony_ci { CR_ACK_TIMEOUT_EXT, 0x20 }, 8028c2ecf20Sopenharmony_ci { CR_ADDA_MBIAS_WARMTIME, 0x30000808 }, 8038c2ecf20Sopenharmony_ci { CR_SNIFFER_ON, 0 }, 8048c2ecf20Sopenharmony_ci { CR_RX_FILTER, STA_RX_FILTER }, 8058c2ecf20Sopenharmony_ci { CR_GROUP_HASH_P1, 0x00 }, 8068c2ecf20Sopenharmony_ci { CR_GROUP_HASH_P2, 0x80000000 }, 8078c2ecf20Sopenharmony_ci { CR_REG1, 0xa4 }, 8088c2ecf20Sopenharmony_ci { CR_ADDA_PWR_DWN, 0x7f }, 8098c2ecf20Sopenharmony_ci { CR_BCN_PLCP_CFG, 0x00f00401 }, 8108c2ecf20Sopenharmony_ci { CR_PHY_DELAY, 0x00 }, 8118c2ecf20Sopenharmony_ci { CR_ACK_TIMEOUT_EXT, 0x80 }, 8128c2ecf20Sopenharmony_ci { CR_ADDA_PWR_DWN, 0x00 }, 8138c2ecf20Sopenharmony_ci { CR_ACK_TIME_80211, 0x100 }, 8148c2ecf20Sopenharmony_ci { CR_RX_PE_DELAY, 0x70 }, 8158c2ecf20Sopenharmony_ci { CR_PS_CTRL, 0x10000000 }, 8168c2ecf20Sopenharmony_ci { CR_RTS_CTS_RATE, 0x02030203 }, 8178c2ecf20Sopenharmony_ci { CR_AFTER_PNP, 0x1 }, 8188c2ecf20Sopenharmony_ci { CR_WEP_PROTECT, 0x114 }, 8198c2ecf20Sopenharmony_ci { CR_IFS_VALUE, IFS_VALUE_DEFAULT }, 8208c2ecf20Sopenharmony_ci { CR_CAM_MODE, MODE_AP_WDS}, 8218c2ecf20Sopenharmony_ci }; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 8248c2ecf20Sopenharmony_ci r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 8258c2ecf20Sopenharmony_ci if (r) 8268c2ecf20Sopenharmony_ci return r; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return zd_chip_is_zd1211b(chip) ? 8298c2ecf20Sopenharmony_ci zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip); 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistruct aw_pt_bi { 8338c2ecf20Sopenharmony_ci u32 atim_wnd_period; 8348c2ecf20Sopenharmony_ci u32 pre_tbtt; 8358c2ecf20Sopenharmony_ci u32 beacon_interval; 8368c2ecf20Sopenharmony_ci}; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci int r; 8418c2ecf20Sopenharmony_ci static const zd_addr_t aw_pt_bi_addr[] = 8428c2ecf20Sopenharmony_ci { CR_ATIM_WND_PERIOD, CR_PRE_TBTT, CR_BCN_INTERVAL }; 8438c2ecf20Sopenharmony_ci u32 values[3]; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr, 8468c2ecf20Sopenharmony_ci ARRAY_SIZE(aw_pt_bi_addr)); 8478c2ecf20Sopenharmony_ci if (r) { 8488c2ecf20Sopenharmony_ci memset(s, 0, sizeof(*s)); 8498c2ecf20Sopenharmony_ci return r; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci s->atim_wnd_period = values[0]; 8538c2ecf20Sopenharmony_ci s->pre_tbtt = values[1]; 8548c2ecf20Sopenharmony_ci s->beacon_interval = values[2]; 8558c2ecf20Sopenharmony_ci return 0; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct zd_ioreq32 reqs[3]; 8618c2ecf20Sopenharmony_ci u16 b_interval = s->beacon_interval & 0xffff; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (b_interval <= 5) 8648c2ecf20Sopenharmony_ci b_interval = 5; 8658c2ecf20Sopenharmony_ci if (s->pre_tbtt < 4 || s->pre_tbtt >= b_interval) 8668c2ecf20Sopenharmony_ci s->pre_tbtt = b_interval - 1; 8678c2ecf20Sopenharmony_ci if (s->atim_wnd_period >= s->pre_tbtt) 8688c2ecf20Sopenharmony_ci s->atim_wnd_period = s->pre_tbtt - 1; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci reqs[0].addr = CR_ATIM_WND_PERIOD; 8718c2ecf20Sopenharmony_ci reqs[0].value = s->atim_wnd_period; 8728c2ecf20Sopenharmony_ci reqs[1].addr = CR_PRE_TBTT; 8738c2ecf20Sopenharmony_ci reqs[1].value = s->pre_tbtt; 8748c2ecf20Sopenharmony_ci reqs[2].addr = CR_BCN_INTERVAL; 8758c2ecf20Sopenharmony_ci reqs[2].value = (s->beacon_interval & ~0xffff) | b_interval; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int set_beacon_interval(struct zd_chip *chip, u16 interval, 8828c2ecf20Sopenharmony_ci u8 dtim_period, int type) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci int r; 8858c2ecf20Sopenharmony_ci struct aw_pt_bi s; 8868c2ecf20Sopenharmony_ci u32 b_interval, mode_flag; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (interval > 0) { 8918c2ecf20Sopenharmony_ci switch (type) { 8928c2ecf20Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 8938c2ecf20Sopenharmony_ci case NL80211_IFTYPE_MESH_POINT: 8948c2ecf20Sopenharmony_ci mode_flag = BCN_MODE_IBSS; 8958c2ecf20Sopenharmony_ci break; 8968c2ecf20Sopenharmony_ci case NL80211_IFTYPE_AP: 8978c2ecf20Sopenharmony_ci mode_flag = BCN_MODE_AP; 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci default: 9008c2ecf20Sopenharmony_ci mode_flag = 0; 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci } else { 9048c2ecf20Sopenharmony_ci dtim_period = 0; 9058c2ecf20Sopenharmony_ci mode_flag = 0; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci b_interval = mode_flag | (dtim_period << 16) | interval; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, b_interval, CR_BCN_INTERVAL); 9118c2ecf20Sopenharmony_ci if (r) 9128c2ecf20Sopenharmony_ci return r; 9138c2ecf20Sopenharmony_ci r = get_aw_pt_bi(chip, &s); 9148c2ecf20Sopenharmony_ci if (r) 9158c2ecf20Sopenharmony_ci return r; 9168c2ecf20Sopenharmony_ci return set_aw_pt_bi(chip, &s); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ciint zd_set_beacon_interval(struct zd_chip *chip, u16 interval, u8 dtim_period, 9208c2ecf20Sopenharmony_ci int type) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci int r; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 9258c2ecf20Sopenharmony_ci r = set_beacon_interval(chip, interval, dtim_period, type); 9268c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 9278c2ecf20Sopenharmony_ci return r; 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic int hw_init(struct zd_chip *chip) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci int r; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 9358c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 9368c2ecf20Sopenharmony_ci r = hw_reset_phy(chip); 9378c2ecf20Sopenharmony_ci if (r) 9388c2ecf20Sopenharmony_ci return r; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci r = hw_init_hmac(chip); 9418c2ecf20Sopenharmony_ci if (r) 9428c2ecf20Sopenharmony_ci return r; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return set_beacon_interval(chip, 100, 0, NL80211_IFTYPE_UNSPECIFIED); 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci return (zd_addr_t)((u16)chip->fw_regs_base + offset); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci#ifdef DEBUG 9538c2ecf20Sopenharmony_cistatic int dump_cr(struct zd_chip *chip, const zd_addr_t addr, 9548c2ecf20Sopenharmony_ci const char *addr_string) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci int r; 9578c2ecf20Sopenharmony_ci u32 value; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &value, addr); 9608c2ecf20Sopenharmony_ci if (r) { 9618c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), 9628c2ecf20Sopenharmony_ci "error reading %s. Error number %d\n", addr_string, r); 9638c2ecf20Sopenharmony_ci return r; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "%s %#010x\n", 9678c2ecf20Sopenharmony_ci addr_string, (unsigned int)value); 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic int test_init(struct zd_chip *chip) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci int r; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci r = dump_cr(chip, CR_AFTER_PNP, "CR_AFTER_PNP"); 9768c2ecf20Sopenharmony_ci if (r) 9778c2ecf20Sopenharmony_ci return r; 9788c2ecf20Sopenharmony_ci r = dump_cr(chip, CR_GPI_EN, "CR_GPI_EN"); 9798c2ecf20Sopenharmony_ci if (r) 9808c2ecf20Sopenharmony_ci return r; 9818c2ecf20Sopenharmony_ci return dump_cr(chip, CR_INTERRUPT, "CR_INTERRUPT"); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void dump_fw_registers(struct zd_chip *chip) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci const zd_addr_t addr[4] = { 9878c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_FIRMWARE_VER), 9888c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_USB_SPEED), 9898c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_FIX_TX_RATE), 9908c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), 9918c2ecf20Sopenharmony_ci }; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci int r; 9948c2ecf20Sopenharmony_ci u16 values[4]; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci r = zd_ioread16v_locked(chip, values, (const zd_addr_t*)addr, 9978c2ecf20Sopenharmony_ci ARRAY_SIZE(addr)); 9988c2ecf20Sopenharmony_ci if (r) { 9998c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "error %d zd_ioread16v_locked\n", 10008c2ecf20Sopenharmony_ci r); 10018c2ecf20Sopenharmony_ci return; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "FW_FIRMWARE_VER %#06hx\n", values[0]); 10058c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "FW_USB_SPEED %#06hx\n", values[1]); 10068c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "FW_FIX_TX_RATE %#06hx\n", values[2]); 10078c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "FW_LINK_STATUS %#06hx\n", values[3]); 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci#endif /* DEBUG */ 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic int print_fw_version(struct zd_chip *chip) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct wiphy *wiphy = zd_chip_to_mac(chip)->hw->wiphy; 10148c2ecf20Sopenharmony_ci int r; 10158c2ecf20Sopenharmony_ci u16 version; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci r = zd_ioread16_locked(chip, &version, 10188c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_FIRMWARE_VER)); 10198c2ecf20Sopenharmony_ci if (r) 10208c2ecf20Sopenharmony_ci return r; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), 10258c2ecf20Sopenharmony_ci "%04hx", version); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int set_mandatory_rates(struct zd_chip *chip, int gmode) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci u32 rates; 10338c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 10348c2ecf20Sopenharmony_ci /* This sets the mandatory rates, which only depend from the standard 10358c2ecf20Sopenharmony_ci * that the device is supporting. Until further notice we should try 10368c2ecf20Sopenharmony_ci * to support 802.11g also for full speed USB. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci if (!gmode) 10398c2ecf20Sopenharmony_ci rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; 10408c2ecf20Sopenharmony_ci else 10418c2ecf20Sopenharmony_ci rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M| 10428c2ecf20Sopenharmony_ci CR_RATE_6M|CR_RATE_12M|CR_RATE_24M; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL); 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciint zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, 10488c2ecf20Sopenharmony_ci int preamble) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci u32 value = 0; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble); 10538c2ecf20Sopenharmony_ci value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; 10548c2ecf20Sopenharmony_ci value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* We always send 11M RTS/self-CTS messages, like the vendor driver. */ 10578c2ecf20Sopenharmony_ci value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_RTS_RATE; 10588c2ecf20Sopenharmony_ci value |= ZD_RX_CCK << RTSCTS_SH_RTS_MOD_TYPE; 10598c2ecf20Sopenharmony_ci value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE; 10608c2ecf20Sopenharmony_ci value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE); 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ciint zd_chip_enable_hwint(struct zd_chip *chip) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci int r; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 10708c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, HWINT_ENABLED, CR_INTERRUPT); 10718c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 10728c2ecf20Sopenharmony_ci return r; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic int disable_hwint(struct zd_chip *chip) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci return zd_iowrite32_locked(chip, HWINT_DISABLED, CR_INTERRUPT); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ciint zd_chip_disable_hwint(struct zd_chip *chip) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci int r; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 10858c2ecf20Sopenharmony_ci r = disable_hwint(chip); 10868c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 10878c2ecf20Sopenharmony_ci return r; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_cistatic int read_fw_regs_offset(struct zd_chip *chip) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci int r; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 10958c2ecf20Sopenharmony_ci r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base, 10968c2ecf20Sopenharmony_ci FWRAW_REGS_ADDR); 10978c2ecf20Sopenharmony_ci if (r) 10988c2ecf20Sopenharmony_ci return r; 10998c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n", 11008c2ecf20Sopenharmony_ci (u16)chip->fw_regs_base); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return 0; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/* Read mac address using pre-firmware interface */ 11068c2ecf20Sopenharmony_ciint zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr) 11078c2ecf20Sopenharmony_ci{ 11088c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 11098c2ecf20Sopenharmony_ci return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr, 11108c2ecf20Sopenharmony_ci ETH_ALEN); 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ciint zd_chip_init_hw(struct zd_chip *chip) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci int r; 11168c2ecf20Sopenharmony_ci u8 rf_type; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "\n"); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci#ifdef DEBUG 11238c2ecf20Sopenharmony_ci r = test_init(chip); 11248c2ecf20Sopenharmony_ci if (r) 11258c2ecf20Sopenharmony_ci goto out; 11268c2ecf20Sopenharmony_ci#endif 11278c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP); 11288c2ecf20Sopenharmony_ci if (r) 11298c2ecf20Sopenharmony_ci goto out; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci r = read_fw_regs_offset(chip); 11328c2ecf20Sopenharmony_ci if (r) 11338c2ecf20Sopenharmony_ci goto out; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* GPI is always disabled, also in the other driver. 11368c2ecf20Sopenharmony_ci */ 11378c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, 0, CR_GPI_EN); 11388c2ecf20Sopenharmony_ci if (r) 11398c2ecf20Sopenharmony_ci goto out; 11408c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX); 11418c2ecf20Sopenharmony_ci if (r) 11428c2ecf20Sopenharmony_ci goto out; 11438c2ecf20Sopenharmony_ci /* Currently we support IEEE 802.11g for full and high speed USB. 11448c2ecf20Sopenharmony_ci * It might be discussed, whether we should support pure b mode for 11458c2ecf20Sopenharmony_ci * full speed USB. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci r = set_mandatory_rates(chip, 1); 11488c2ecf20Sopenharmony_ci if (r) 11498c2ecf20Sopenharmony_ci goto out; 11508c2ecf20Sopenharmony_ci /* Disabling interrupts is certainly a smart thing here. 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci r = disable_hwint(chip); 11538c2ecf20Sopenharmony_ci if (r) 11548c2ecf20Sopenharmony_ci goto out; 11558c2ecf20Sopenharmony_ci r = read_pod(chip, &rf_type); 11568c2ecf20Sopenharmony_ci if (r) 11578c2ecf20Sopenharmony_ci goto out; 11588c2ecf20Sopenharmony_ci r = hw_init(chip); 11598c2ecf20Sopenharmony_ci if (r) 11608c2ecf20Sopenharmony_ci goto out; 11618c2ecf20Sopenharmony_ci r = zd_rf_init_hw(&chip->rf, rf_type); 11628c2ecf20Sopenharmony_ci if (r) 11638c2ecf20Sopenharmony_ci goto out; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci r = print_fw_version(chip); 11668c2ecf20Sopenharmony_ci if (r) 11678c2ecf20Sopenharmony_ci goto out; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci#ifdef DEBUG 11708c2ecf20Sopenharmony_ci dump_fw_registers(chip); 11718c2ecf20Sopenharmony_ci r = test_init(chip); 11728c2ecf20Sopenharmony_ci if (r) 11738c2ecf20Sopenharmony_ci goto out; 11748c2ecf20Sopenharmony_ci#endif /* DEBUG */ 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci r = read_cal_int_tables(chip); 11778c2ecf20Sopenharmony_ci if (r) 11788c2ecf20Sopenharmony_ci goto out; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci print_id(chip); 11818c2ecf20Sopenharmony_ciout: 11828c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 11838c2ecf20Sopenharmony_ci return r; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic int update_pwr_int(struct zd_chip *chip, u8 channel) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci u8 value = chip->pwr_int_values[channel - 1]; 11898c2ecf20Sopenharmony_ci return zd_iowrite16_locked(chip, value, ZD_CR31); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic int update_pwr_cal(struct zd_chip *chip, u8 channel) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci u8 value = chip->pwr_cal_values[channel-1]; 11958c2ecf20Sopenharmony_ci return zd_iowrite16_locked(chip, value, ZD_CR68); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int update_ofdm_cal(struct zd_chip *chip, u8 channel) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct zd_ioreq16 ioreqs[3]; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci ioreqs[0].addr = ZD_CR67; 12038c2ecf20Sopenharmony_ci ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1]; 12048c2ecf20Sopenharmony_ci ioreqs[1].addr = ZD_CR66; 12058c2ecf20Sopenharmony_ci ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1]; 12068c2ecf20Sopenharmony_ci ioreqs[2].addr = ZD_CR65; 12078c2ecf20Sopenharmony_ci ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1]; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic int update_channel_integration_and_calibration(struct zd_chip *chip, 12138c2ecf20Sopenharmony_ci u8 channel) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci int r; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (!zd_rf_should_update_pwr_int(&chip->rf)) 12188c2ecf20Sopenharmony_ci return 0; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci r = update_pwr_int(chip, channel); 12218c2ecf20Sopenharmony_ci if (r) 12228c2ecf20Sopenharmony_ci return r; 12238c2ecf20Sopenharmony_ci if (zd_chip_is_zd1211b(chip)) { 12248c2ecf20Sopenharmony_ci static const struct zd_ioreq16 ioreqs[] = { 12258c2ecf20Sopenharmony_ci { ZD_CR69, 0x28 }, 12268c2ecf20Sopenharmony_ci {}, 12278c2ecf20Sopenharmony_ci { ZD_CR69, 0x2a }, 12288c2ecf20Sopenharmony_ci }; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci r = update_ofdm_cal(chip, channel); 12318c2ecf20Sopenharmony_ci if (r) 12328c2ecf20Sopenharmony_ci return r; 12338c2ecf20Sopenharmony_ci r = update_pwr_cal(chip, channel); 12348c2ecf20Sopenharmony_ci if (r) 12358c2ecf20Sopenharmony_ci return r; 12368c2ecf20Sopenharmony_ci r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 12378c2ecf20Sopenharmony_ci if (r) 12388c2ecf20Sopenharmony_ci return r; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci return 0; 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci/* The CCK baseband gain can be optionally patched by the EEPROM */ 12458c2ecf20Sopenharmony_cistatic int patch_cck_gain(struct zd_chip *chip) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci int r; 12488c2ecf20Sopenharmony_ci u32 value; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf)) 12518c2ecf20Sopenharmony_ci return 0; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 12548c2ecf20Sopenharmony_ci r = zd_ioread32_locked(chip, &value, E2P_PHY_REG); 12558c2ecf20Sopenharmony_ci if (r) 12568c2ecf20Sopenharmony_ci return r; 12578c2ecf20Sopenharmony_ci dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff); 12588c2ecf20Sopenharmony_ci return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ciint zd_chip_set_channel(struct zd_chip *chip, u8 channel) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci int r, t; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 12668c2ecf20Sopenharmony_ci r = zd_chip_lock_phy_regs(chip); 12678c2ecf20Sopenharmony_ci if (r) 12688c2ecf20Sopenharmony_ci goto out; 12698c2ecf20Sopenharmony_ci r = zd_rf_set_channel(&chip->rf, channel); 12708c2ecf20Sopenharmony_ci if (r) 12718c2ecf20Sopenharmony_ci goto unlock; 12728c2ecf20Sopenharmony_ci r = update_channel_integration_and_calibration(chip, channel); 12738c2ecf20Sopenharmony_ci if (r) 12748c2ecf20Sopenharmony_ci goto unlock; 12758c2ecf20Sopenharmony_ci r = patch_cck_gain(chip); 12768c2ecf20Sopenharmony_ci if (r) 12778c2ecf20Sopenharmony_ci goto unlock; 12788c2ecf20Sopenharmony_ci r = patch_6m_band_edge(chip, channel); 12798c2ecf20Sopenharmony_ci if (r) 12808c2ecf20Sopenharmony_ci goto unlock; 12818c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS); 12828c2ecf20Sopenharmony_ciunlock: 12838c2ecf20Sopenharmony_ci t = zd_chip_unlock_phy_regs(chip); 12848c2ecf20Sopenharmony_ci if (t && !r) 12858c2ecf20Sopenharmony_ci r = t; 12868c2ecf20Sopenharmony_ciout: 12878c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 12888c2ecf20Sopenharmony_ci return r; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ciu8 zd_chip_get_channel(struct zd_chip *chip) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci u8 channel; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 12968c2ecf20Sopenharmony_ci channel = chip->rf.channel; 12978c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 12988c2ecf20Sopenharmony_ci return channel; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ciint zd_chip_control_leds(struct zd_chip *chip, enum led_status status) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci const zd_addr_t a[] = { 13048c2ecf20Sopenharmony_ci fw_reg_addr(chip, FW_REG_LED_LINK_STATUS), 13058c2ecf20Sopenharmony_ci CR_LED, 13068c2ecf20Sopenharmony_ci }; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci int r; 13098c2ecf20Sopenharmony_ci u16 v[ARRAY_SIZE(a)]; 13108c2ecf20Sopenharmony_ci struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = { 13118c2ecf20Sopenharmony_ci [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) }, 13128c2ecf20Sopenharmony_ci [1] = { CR_LED }, 13138c2ecf20Sopenharmony_ci }; 13148c2ecf20Sopenharmony_ci u16 other_led; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 13178c2ecf20Sopenharmony_ci r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a)); 13188c2ecf20Sopenharmony_ci if (r) 13198c2ecf20Sopenharmony_ci goto out; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci other_led = chip->link_led == LED1 ? LED2 : LED1; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci switch (status) { 13248c2ecf20Sopenharmony_ci case ZD_LED_OFF: 13258c2ecf20Sopenharmony_ci ioreqs[0].value = FW_LINK_OFF; 13268c2ecf20Sopenharmony_ci ioreqs[1].value = v[1] & ~(LED1|LED2); 13278c2ecf20Sopenharmony_ci break; 13288c2ecf20Sopenharmony_ci case ZD_LED_SCANNING: 13298c2ecf20Sopenharmony_ci ioreqs[0].value = FW_LINK_OFF; 13308c2ecf20Sopenharmony_ci ioreqs[1].value = v[1] & ~other_led; 13318c2ecf20Sopenharmony_ci if ((u32)ktime_get_seconds() % 3 == 0) { 13328c2ecf20Sopenharmony_ci ioreqs[1].value &= ~chip->link_led; 13338c2ecf20Sopenharmony_ci } else { 13348c2ecf20Sopenharmony_ci ioreqs[1].value |= chip->link_led; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci break; 13378c2ecf20Sopenharmony_ci case ZD_LED_ASSOCIATED: 13388c2ecf20Sopenharmony_ci ioreqs[0].value = FW_LINK_TX; 13398c2ecf20Sopenharmony_ci ioreqs[1].value = v[1] & ~other_led; 13408c2ecf20Sopenharmony_ci ioreqs[1].value |= chip->link_led; 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci default: 13438c2ecf20Sopenharmony_ci r = -EINVAL; 13448c2ecf20Sopenharmony_ci goto out; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) { 13488c2ecf20Sopenharmony_ci r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 13498c2ecf20Sopenharmony_ci if (r) 13508c2ecf20Sopenharmony_ci goto out; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci r = 0; 13538c2ecf20Sopenharmony_ciout: 13548c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 13558c2ecf20Sopenharmony_ci return r; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ciint zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci int r; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G)) 13638c2ecf20Sopenharmony_ci return -EINVAL; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 13668c2ecf20Sopenharmony_ci r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); 13678c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 13688c2ecf20Sopenharmony_ci return r; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) 13728c2ecf20Sopenharmony_ci{ 13738c2ecf20Sopenharmony_ci return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci/** 13778c2ecf20Sopenharmony_ci * zd_rx_rate - report zd-rate 13788c2ecf20Sopenharmony_ci * @rx_frame: received frame 13798c2ecf20Sopenharmony_ci * @status: rx_status as given by the device 13808c2ecf20Sopenharmony_ci * 13818c2ecf20Sopenharmony_ci * This function converts the rate as encoded in the received packet to the 13828c2ecf20Sopenharmony_ci * zd-rate, we are using on other places in the driver. 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_ciu8 zd_rx_rate(const void *rx_frame, const struct rx_status *status) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci u8 zd_rate; 13878c2ecf20Sopenharmony_ci if (status->frame_status & ZD_RX_OFDM) { 13888c2ecf20Sopenharmony_ci zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame); 13898c2ecf20Sopenharmony_ci } else { 13908c2ecf20Sopenharmony_ci switch (zd_cck_plcp_header_signal(rx_frame)) { 13918c2ecf20Sopenharmony_ci case ZD_CCK_PLCP_SIGNAL_1M: 13928c2ecf20Sopenharmony_ci zd_rate = ZD_CCK_RATE_1M; 13938c2ecf20Sopenharmony_ci break; 13948c2ecf20Sopenharmony_ci case ZD_CCK_PLCP_SIGNAL_2M: 13958c2ecf20Sopenharmony_ci zd_rate = ZD_CCK_RATE_2M; 13968c2ecf20Sopenharmony_ci break; 13978c2ecf20Sopenharmony_ci case ZD_CCK_PLCP_SIGNAL_5M5: 13988c2ecf20Sopenharmony_ci zd_rate = ZD_CCK_RATE_5_5M; 13998c2ecf20Sopenharmony_ci break; 14008c2ecf20Sopenharmony_ci case ZD_CCK_PLCP_SIGNAL_11M: 14018c2ecf20Sopenharmony_ci zd_rate = ZD_CCK_RATE_11M; 14028c2ecf20Sopenharmony_ci break; 14038c2ecf20Sopenharmony_ci default: 14048c2ecf20Sopenharmony_ci zd_rate = 0; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci return zd_rate; 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ciint zd_chip_switch_radio_on(struct zd_chip *chip) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci int r; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14168c2ecf20Sopenharmony_ci r = zd_switch_radio_on(&chip->rf); 14178c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14188c2ecf20Sopenharmony_ci return r; 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ciint zd_chip_switch_radio_off(struct zd_chip *chip) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci int r; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14268c2ecf20Sopenharmony_ci r = zd_switch_radio_off(&chip->rf); 14278c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14288c2ecf20Sopenharmony_ci return r; 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ciint zd_chip_enable_int(struct zd_chip *chip) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci int r; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14368c2ecf20Sopenharmony_ci r = zd_usb_enable_int(&chip->usb); 14378c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14388c2ecf20Sopenharmony_ci return r; 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_civoid zd_chip_disable_int(struct zd_chip *chip) 14428c2ecf20Sopenharmony_ci{ 14438c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14448c2ecf20Sopenharmony_ci zd_usb_disable_int(&chip->usb); 14458c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* cancel pending interrupt work */ 14488c2ecf20Sopenharmony_ci cancel_work_sync(&zd_chip_to_mac(chip)->process_intr); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ciint zd_chip_enable_rxtx(struct zd_chip *chip) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci int r; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14568c2ecf20Sopenharmony_ci zd_usb_enable_tx(&chip->usb); 14578c2ecf20Sopenharmony_ci r = zd_usb_enable_rx(&chip->usb); 14588c2ecf20Sopenharmony_ci zd_tx_watchdog_enable(&chip->usb); 14598c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14608c2ecf20Sopenharmony_ci return r; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_civoid zd_chip_disable_rxtx(struct zd_chip *chip) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 14668c2ecf20Sopenharmony_ci zd_tx_watchdog_disable(&chip->usb); 14678c2ecf20Sopenharmony_ci zd_usb_disable_rx(&chip->usb); 14688c2ecf20Sopenharmony_ci zd_usb_disable_tx(&chip->usb); 14698c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ciint zd_rfwritev_locked(struct zd_chip *chip, 14738c2ecf20Sopenharmony_ci const u32* values, unsigned int count, u8 bits) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci int r; 14768c2ecf20Sopenharmony_ci unsigned int i; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 14798c2ecf20Sopenharmony_ci r = zd_rfwrite_locked(chip, values[i], bits); 14808c2ecf20Sopenharmony_ci if (r) 14818c2ecf20Sopenharmony_ci return r; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci/* 14888c2ecf20Sopenharmony_ci * We can optionally program the RF directly through CR regs, if supported by 14898c2ecf20Sopenharmony_ci * the hardware. This is much faster than the older method. 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_ciint zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci const struct zd_ioreq16 ioreqs[] = { 14948c2ecf20Sopenharmony_ci { ZD_CR244, (value >> 16) & 0xff }, 14958c2ecf20Sopenharmony_ci { ZD_CR243, (value >> 8) & 0xff }, 14968c2ecf20Sopenharmony_ci { ZD_CR242, value & 0xff }, 14978c2ecf20Sopenharmony_ci }; 14988c2ecf20Sopenharmony_ci ZD_ASSERT(mutex_is_locked(&chip->mutex)); 14998c2ecf20Sopenharmony_ci return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ciint zd_rfwritev_cr_locked(struct zd_chip *chip, 15038c2ecf20Sopenharmony_ci const u32 *values, unsigned int count) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci int r; 15068c2ecf20Sopenharmony_ci unsigned int i; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 15098c2ecf20Sopenharmony_ci r = zd_rfwrite_cr_locked(chip, values[i]); 15108c2ecf20Sopenharmony_ci if (r) 15118c2ecf20Sopenharmony_ci return r; 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci return 0; 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ciint zd_chip_set_multicast_hash(struct zd_chip *chip, 15188c2ecf20Sopenharmony_ci struct zd_mc_hash *hash) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci const struct zd_ioreq32 ioreqs[] = { 15218c2ecf20Sopenharmony_ci { CR_GROUP_HASH_P1, hash->low }, 15228c2ecf20Sopenharmony_ci { CR_GROUP_HASH_P2, hash->high }, 15238c2ecf20Sopenharmony_ci }; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs)); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ciu64 zd_chip_get_tsf(struct zd_chip *chip) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci int r; 15318c2ecf20Sopenharmony_ci static const zd_addr_t aw_pt_bi_addr[] = 15328c2ecf20Sopenharmony_ci { CR_TSF_LOW_PART, CR_TSF_HIGH_PART }; 15338c2ecf20Sopenharmony_ci u32 values[2]; 15348c2ecf20Sopenharmony_ci u64 tsf; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 15378c2ecf20Sopenharmony_ci r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr, 15388c2ecf20Sopenharmony_ci ARRAY_SIZE(aw_pt_bi_addr)); 15398c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 15408c2ecf20Sopenharmony_ci if (r) 15418c2ecf20Sopenharmony_ci return 0; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci tsf = values[1]; 15448c2ecf20Sopenharmony_ci tsf = (tsf << 32) | values[0]; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci return tsf; 15478c2ecf20Sopenharmony_ci} 1548