1203c4805SLuis R. Rodriguez /* 25b68138eSSujith Manoharan * Copyright (c) 2008-2011 Atheros Communications Inc. 3203c4805SLuis R. Rodriguez * 4203c4805SLuis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any 5203c4805SLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 6203c4805SLuis R. Rodriguez * copyright notice and this permission notice appear in all copies. 7203c4805SLuis R. Rodriguez * 8203c4805SLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9203c4805SLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10203c4805SLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11203c4805SLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12203c4805SLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13203c4805SLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14203c4805SLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15203c4805SLuis R. Rodriguez */ 16203c4805SLuis R. Rodriguez 175bb12791SLuis R. Rodriguez #include "hw.h" 1856398519SMartin Blumenstingl #include <linux/ath9k_platform.h> 19203c4805SLuis R. Rodriguez 2079d7f4bcSSujith void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val) 2179d7f4bcSSujith { 2279d7f4bcSSujith REG_WRITE(ah, reg, val); 2379d7f4bcSSujith 2479d7f4bcSSujith if (ah->config.analog_shiftreg) 2579d7f4bcSSujith udelay(100); 2679d7f4bcSSujith } 2779d7f4bcSSujith 28b5aec950SSujith void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, 29203c4805SLuis R. Rodriguez u32 shift, u32 val) 30203c4805SLuis R. Rodriguez { 312028523bSOleksij Rempel REG_RMW(ah, reg, ((val << shift) & mask), mask); 32203c4805SLuis R. Rodriguez 33203c4805SLuis R. Rodriguez if (ah->config.analog_shiftreg) 34203c4805SLuis R. Rodriguez udelay(100); 35203c4805SLuis R. Rodriguez } 36203c4805SLuis R. Rodriguez 37b5aec950SSujith int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, 38b5aec950SSujith int16_t targetLeft, int16_t targetRight) 39203c4805SLuis R. Rodriguez { 40203c4805SLuis R. Rodriguez int16_t rv; 41203c4805SLuis R. Rodriguez 42203c4805SLuis R. Rodriguez if (srcRight == srcLeft) { 43203c4805SLuis R. Rodriguez rv = targetLeft; 44203c4805SLuis R. Rodriguez } else { 45203c4805SLuis R. Rodriguez rv = (int16_t) (((target - srcLeft) * targetRight + 46203c4805SLuis R. Rodriguez (srcRight - target) * targetLeft) / 47203c4805SLuis R. Rodriguez (srcRight - srcLeft)); 48203c4805SLuis R. Rodriguez } 49203c4805SLuis R. Rodriguez return rv; 50203c4805SLuis R. Rodriguez } 51203c4805SLuis R. Rodriguez 52b5aec950SSujith bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, 53b5aec950SSujith u16 *indexL, u16 *indexR) 54203c4805SLuis R. Rodriguez { 55203c4805SLuis R. Rodriguez u16 i; 56203c4805SLuis R. Rodriguez 57203c4805SLuis R. Rodriguez if (target <= pList[0]) { 58203c4805SLuis R. Rodriguez *indexL = *indexR = 0; 59203c4805SLuis R. Rodriguez return true; 60203c4805SLuis R. Rodriguez } 61203c4805SLuis R. Rodriguez if (target >= pList[listSize - 1]) { 62203c4805SLuis R. Rodriguez *indexL = *indexR = (u16) (listSize - 1); 63203c4805SLuis R. Rodriguez return true; 64203c4805SLuis R. Rodriguez } 65203c4805SLuis R. Rodriguez 66203c4805SLuis R. Rodriguez for (i = 0; i < listSize - 1; i++) { 67203c4805SLuis R. Rodriguez if (pList[i] == target) { 68203c4805SLuis R. Rodriguez *indexL = *indexR = i; 69203c4805SLuis R. Rodriguez return true; 70203c4805SLuis R. Rodriguez } 71203c4805SLuis R. Rodriguez if (target < pList[i + 1]) { 72203c4805SLuis R. Rodriguez *indexL = i; 73203c4805SLuis R. Rodriguez *indexR = (u16) (i + 1); 74203c4805SLuis R. Rodriguez return false; 75203c4805SLuis R. Rodriguez } 76203c4805SLuis R. Rodriguez } 77203c4805SLuis R. Rodriguez return false; 78203c4805SLuis R. Rodriguez } 79203c4805SLuis R. Rodriguez 8004cf53f4SSujith Manoharan void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, 8104cf53f4SSujith Manoharan int eep_start_loc, int size) 8204cf53f4SSujith Manoharan { 8304cf53f4SSujith Manoharan int i = 0, j, addr; 8404cf53f4SSujith Manoharan u32 addrdata[8]; 8504cf53f4SSujith Manoharan u32 data[8]; 8604cf53f4SSujith Manoharan 8704cf53f4SSujith Manoharan for (addr = 0; addr < size; addr++) { 8804cf53f4SSujith Manoharan addrdata[i] = AR5416_EEPROM_OFFSET + 8904cf53f4SSujith Manoharan ((addr + eep_start_loc) << AR5416_EEPROM_S); 9004cf53f4SSujith Manoharan i++; 9104cf53f4SSujith Manoharan if (i == 8) { 9204cf53f4SSujith Manoharan REG_READ_MULTI(ah, addrdata, data, i); 9304cf53f4SSujith Manoharan 9404cf53f4SSujith Manoharan for (j = 0; j < i; j++) { 9504cf53f4SSujith Manoharan *eep_data = data[j]; 9604cf53f4SSujith Manoharan eep_data++; 9704cf53f4SSujith Manoharan } 9804cf53f4SSujith Manoharan i = 0; 9904cf53f4SSujith Manoharan } 10004cf53f4SSujith Manoharan } 10104cf53f4SSujith Manoharan 10204cf53f4SSujith Manoharan if (i != 0) { 10304cf53f4SSujith Manoharan REG_READ_MULTI(ah, addrdata, data, i); 10404cf53f4SSujith Manoharan 10504cf53f4SSujith Manoharan for (j = 0; j < i; j++) { 10604cf53f4SSujith Manoharan *eep_data = data[j]; 10704cf53f4SSujith Manoharan eep_data++; 10804cf53f4SSujith Manoharan } 10904cf53f4SSujith Manoharan } 11004cf53f4SSujith Manoharan } 11104cf53f4SSujith Manoharan 11256398519SMartin Blumenstingl static bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size, 11356398519SMartin Blumenstingl off_t offset, u16 *data) 114ab5c4f71SGabor Juhos { 115b7dcf68fSDan Carpenter if (offset >= blob_size) 116ab5c4f71SGabor Juhos return false; 117ab5c4f71SGabor Juhos 11856398519SMartin Blumenstingl *data = blob[offset]; 119ab5c4f71SGabor Juhos return true; 120ab5c4f71SGabor Juhos } 121ab5c4f71SGabor Juhos 12256398519SMartin Blumenstingl static bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata, 12356398519SMartin Blumenstingl off_t offset, u16 *data) 12456398519SMartin Blumenstingl { 12556398519SMartin Blumenstingl return ath9k_hw_nvram_read_array(pdata->eeprom_data, 12656398519SMartin Blumenstingl ARRAY_SIZE(pdata->eeprom_data), 12756398519SMartin Blumenstingl offset, data); 12856398519SMartin Blumenstingl } 12956398519SMartin Blumenstingl 13056398519SMartin Blumenstingl static bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob, 13156398519SMartin Blumenstingl off_t offset, u16 *data) 13256398519SMartin Blumenstingl { 13356398519SMartin Blumenstingl return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data, 13456398519SMartin Blumenstingl eeprom_blob->size / sizeof(u16), 13556398519SMartin Blumenstingl offset, data); 13656398519SMartin Blumenstingl } 13756398519SMartin Blumenstingl 138eb3a97a6SChristian Lamparter static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset, 139eb3a97a6SChristian Lamparter u16 *data) 140eb3a97a6SChristian Lamparter { 141eb3a97a6SChristian Lamparter return ath9k_hw_nvram_read_array(ah->nvmem_blob, 142eb3a97a6SChristian Lamparter ah->nvmem_blob_len / sizeof(u16), 143eb3a97a6SChristian Lamparter offset, data); 144eb3a97a6SChristian Lamparter } 145eb3a97a6SChristian Lamparter 1460e4b9f2fSGabor Juhos bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) 147203c4805SLuis R. Rodriguez { 1480e4b9f2fSGabor Juhos struct ath_common *common = ath9k_hw_common(ah); 14956398519SMartin Blumenstingl struct ath9k_platform_data *pdata = ah->dev->platform_data; 1502fd2cdfbSGabor Juhos bool ret; 1512fd2cdfbSGabor Juhos 152eb3a97a6SChristian Lamparter if (ah->nvmem_blob) 153eb3a97a6SChristian Lamparter ret = ath9k_hw_nvram_read_nvmem(ah, off, data); 154eb3a97a6SChristian Lamparter else if (ah->eeprom_blob) 15556398519SMartin Blumenstingl ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data); 156641c1f4aSGustavo A. R. Silva else if (pdata && !pdata->use_eeprom) 15756398519SMartin Blumenstingl ret = ath9k_hw_nvram_read_pdata(pdata, off, data); 158ab5c4f71SGabor Juhos else 1592fd2cdfbSGabor Juhos ret = common->bus_ops->eeprom_read(common, off, data); 160ab5c4f71SGabor Juhos 1612fd2cdfbSGabor Juhos if (!ret) 1627177d8f9SGabor Juhos ath_dbg(common, EEPROM, 1637177d8f9SGabor Juhos "unable to read eeprom region at offset %u\n", off); 1642fd2cdfbSGabor Juhos 1652fd2cdfbSGabor Juhos return ret; 166203c4805SLuis R. Rodriguez } 167203c4805SLuis R. Rodriguez 1686fa658fdSMartin Blumenstingl int ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size) 1696fa658fdSMartin Blumenstingl { 1706fa658fdSMartin Blumenstingl u16 magic; 1716fa658fdSMartin Blumenstingl u16 *eepdata; 1726fa658fdSMartin Blumenstingl int i; 17368fbe792SMartin Blumenstingl bool needs_byteswap = false; 1746fa658fdSMartin Blumenstingl struct ath_common *common = ath9k_hw_common(ah); 1756fa658fdSMartin Blumenstingl 1766fa658fdSMartin Blumenstingl if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) { 1776fa658fdSMartin Blumenstingl ath_err(common, "Reading Magic # failed\n"); 1786fa658fdSMartin Blumenstingl return -EIO; 1796fa658fdSMartin Blumenstingl } 1806fa658fdSMartin Blumenstingl 18165dc1a5dSFelix Fietkau if (swab16(magic) == AR5416_EEPROM_MAGIC) { 18268fbe792SMartin Blumenstingl needs_byteswap = true; 18368fbe792SMartin Blumenstingl ath_dbg(common, EEPROM, 18468fbe792SMartin Blumenstingl "EEPROM needs byte-swapping to correct endianness.\n"); 18568fbe792SMartin Blumenstingl } else if (magic != AR5416_EEPROM_MAGIC) { 18668fbe792SMartin Blumenstingl if (ath9k_hw_use_flash(ah)) { 18768fbe792SMartin Blumenstingl ath_dbg(common, EEPROM, 18868fbe792SMartin Blumenstingl "Ignoring invalid EEPROM magic (0x%04x).\n", 18968fbe792SMartin Blumenstingl magic); 19068fbe792SMartin Blumenstingl } else { 19168fbe792SMartin Blumenstingl ath_err(common, 19268fbe792SMartin Blumenstingl "Invalid EEPROM magic (0x%04x).\n", magic); 19368fbe792SMartin Blumenstingl return -EINVAL; 19468fbe792SMartin Blumenstingl } 19568fbe792SMartin Blumenstingl } 19668fbe792SMartin Blumenstingl 19768fbe792SMartin Blumenstingl if (needs_byteswap) { 1986fa658fdSMartin Blumenstingl if (ah->ah_flags & AH_NO_EEP_SWAP) { 1996fa658fdSMartin Blumenstingl ath_info(common, 2006fa658fdSMartin Blumenstingl "Ignoring endianness difference in EEPROM magic bytes.\n"); 2016fa658fdSMartin Blumenstingl } else { 2026fa658fdSMartin Blumenstingl eepdata = (u16 *)(&ah->eeprom); 2036fa658fdSMartin Blumenstingl 2046fa658fdSMartin Blumenstingl for (i = 0; i < size; i++) 2056fa658fdSMartin Blumenstingl eepdata[i] = swab16(eepdata[i]); 2066fa658fdSMartin Blumenstingl } 20768fbe792SMartin Blumenstingl } 20868fbe792SMartin Blumenstingl 2094bca5303SMartin Blumenstingl if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) { 21068fbe792SMartin Blumenstingl *swap_needed = true; 21168fbe792SMartin Blumenstingl ath_dbg(common, EEPROM, 2124bca5303SMartin Blumenstingl "Big Endian EEPROM detected according to EEPMISC register.\n"); 2134bca5303SMartin Blumenstingl } else { 2144bca5303SMartin Blumenstingl *swap_needed = false; 21568fbe792SMartin Blumenstingl } 2166fa658fdSMartin Blumenstingl 2176fa658fdSMartin Blumenstingl return 0; 2186fa658fdSMartin Blumenstingl } 2196fa658fdSMartin Blumenstingl 2206fa658fdSMartin Blumenstingl bool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size) 2216fa658fdSMartin Blumenstingl { 2226fa658fdSMartin Blumenstingl u32 i, sum = 0; 2236fa658fdSMartin Blumenstingl u16 *eepdata = (u16 *)(&ah->eeprom); 2246fa658fdSMartin Blumenstingl struct ath_common *common = ath9k_hw_common(ah); 2256fa658fdSMartin Blumenstingl 2266fa658fdSMartin Blumenstingl for (i = 0; i < size; i++) 2276fa658fdSMartin Blumenstingl sum ^= eepdata[i]; 2286fa658fdSMartin Blumenstingl 2296fa658fdSMartin Blumenstingl if (sum != 0xffff) { 2306fa658fdSMartin Blumenstingl ath_err(common, "Bad EEPROM checksum 0x%x\n", sum); 2316fa658fdSMartin Blumenstingl return false; 2326fa658fdSMartin Blumenstingl } 2336fa658fdSMartin Blumenstingl 2346fa658fdSMartin Blumenstingl return true; 2356fa658fdSMartin Blumenstingl } 2366fa658fdSMartin Blumenstingl 2376fa658fdSMartin Blumenstingl bool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev) 2386fa658fdSMartin Blumenstingl { 2396fa658fdSMartin Blumenstingl struct ath_common *common = ath9k_hw_common(ah); 2406fa658fdSMartin Blumenstingl 2416fa658fdSMartin Blumenstingl if (ah->eep_ops->get_eeprom_ver(ah) != version || 2426fa658fdSMartin Blumenstingl ah->eep_ops->get_eeprom_rev(ah) < minrev) { 2436fa658fdSMartin Blumenstingl ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n", 2446fa658fdSMartin Blumenstingl ah->eep_ops->get_eeprom_ver(ah), 2456fa658fdSMartin Blumenstingl ah->eep_ops->get_eeprom_rev(ah)); 24619f2ce3fSDan Carpenter return false; 2476fa658fdSMartin Blumenstingl } 2486fa658fdSMartin Blumenstingl 2496fa658fdSMartin Blumenstingl return true; 2506fa658fdSMartin Blumenstingl } 2516fa658fdSMartin Blumenstingl 252b5aec950SSujith void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, 253203c4805SLuis R. Rodriguez u8 *pVpdList, u16 numIntercepts, 254203c4805SLuis R. Rodriguez u8 *pRetVpdList) 255203c4805SLuis R. Rodriguez { 256203c4805SLuis R. Rodriguez u16 i, k; 257203c4805SLuis R. Rodriguez u8 currPwr = pwrMin; 258203c4805SLuis R. Rodriguez u16 idxL = 0, idxR = 0; 259203c4805SLuis R. Rodriguez 260203c4805SLuis R. Rodriguez for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 261203c4805SLuis R. Rodriguez ath9k_hw_get_lower_upper_index(currPwr, pPwrList, 262203c4805SLuis R. Rodriguez numIntercepts, &(idxL), 263203c4805SLuis R. Rodriguez &(idxR)); 264203c4805SLuis R. Rodriguez if (idxR < 1) 265203c4805SLuis R. Rodriguez idxR = 1; 266203c4805SLuis R. Rodriguez if (idxL == numIntercepts - 1) 267203c4805SLuis R. Rodriguez idxL = (u16) (numIntercepts - 2); 268203c4805SLuis R. Rodriguez if (pPwrList[idxL] == pPwrList[idxR]) 269203c4805SLuis R. Rodriguez k = pVpdList[idxL]; 270203c4805SLuis R. Rodriguez else 271203c4805SLuis R. Rodriguez k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + 272203c4805SLuis R. Rodriguez (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 273203c4805SLuis R. Rodriguez (pPwrList[idxR] - pPwrList[idxL])); 274203c4805SLuis R. Rodriguez pRetVpdList[i] = (u8) k; 275203c4805SLuis R. Rodriguez currPwr += 2; 276203c4805SLuis R. Rodriguez } 277203c4805SLuis R. Rodriguez } 278203c4805SLuis R. Rodriguez 279b5aec950SSujith void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, 280203c4805SLuis R. Rodriguez struct ath9k_channel *chan, 281203c4805SLuis R. Rodriguez struct cal_target_power_leg *powInfo, 282203c4805SLuis R. Rodriguez u16 numChannels, 283203c4805SLuis R. Rodriguez struct cal_target_power_leg *pNewPower, 284203c4805SLuis R. Rodriguez u16 numRates, bool isExtTarget) 285203c4805SLuis R. Rodriguez { 286203c4805SLuis R. Rodriguez struct chan_centers centers; 287203c4805SLuis R. Rodriguez u16 clo, chi; 288203c4805SLuis R. Rodriguez int i; 289203c4805SLuis R. Rodriguez int matchIndex = -1, lowIndex = -1; 290203c4805SLuis R. Rodriguez u16 freq; 291203c4805SLuis R. Rodriguez 292203c4805SLuis R. Rodriguez ath9k_hw_get_channel_centers(ah, chan, ¢ers); 293203c4805SLuis R. Rodriguez freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; 294203c4805SLuis R. Rodriguez 295203c4805SLuis R. Rodriguez if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, 296203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan))) { 297203c4805SLuis R. Rodriguez matchIndex = 0; 298203c4805SLuis R. Rodriguez } else { 299203c4805SLuis R. Rodriguez for (i = 0; (i < numChannels) && 300203c4805SLuis R. Rodriguez (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 301203c4805SLuis R. Rodriguez if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 302203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan))) { 303203c4805SLuis R. Rodriguez matchIndex = i; 304203c4805SLuis R. Rodriguez break; 30573f57f83SRoel Kluin } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 30673f57f83SRoel Kluin IS_CHAN_2GHZ(chan)) && i > 0 && 30773f57f83SRoel Kluin freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 30873f57f83SRoel Kluin IS_CHAN_2GHZ(chan))) { 309203c4805SLuis R. Rodriguez lowIndex = i - 1; 310203c4805SLuis R. Rodriguez break; 311203c4805SLuis R. Rodriguez } 312203c4805SLuis R. Rodriguez } 313203c4805SLuis R. Rodriguez if ((matchIndex == -1) && (lowIndex == -1)) 314203c4805SLuis R. Rodriguez matchIndex = i - 1; 315203c4805SLuis R. Rodriguez } 316203c4805SLuis R. Rodriguez 317203c4805SLuis R. Rodriguez if (matchIndex != -1) { 318203c4805SLuis R. Rodriguez *pNewPower = powInfo[matchIndex]; 319203c4805SLuis R. Rodriguez } else { 320203c4805SLuis R. Rodriguez clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 321203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan)); 322203c4805SLuis R. Rodriguez chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 323203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan)); 324203c4805SLuis R. Rodriguez 325203c4805SLuis R. Rodriguez for (i = 0; i < numRates; i++) { 326203c4805SLuis R. Rodriguez pNewPower->tPow2x[i] = 327203c4805SLuis R. Rodriguez (u8)ath9k_hw_interpolate(freq, clo, chi, 328203c4805SLuis R. Rodriguez powInfo[lowIndex].tPow2x[i], 329203c4805SLuis R. Rodriguez powInfo[lowIndex + 1].tPow2x[i]); 330203c4805SLuis R. Rodriguez } 331203c4805SLuis R. Rodriguez } 332203c4805SLuis R. Rodriguez } 333203c4805SLuis R. Rodriguez 334b5aec950SSujith void ath9k_hw_get_target_powers(struct ath_hw *ah, 335203c4805SLuis R. Rodriguez struct ath9k_channel *chan, 336203c4805SLuis R. Rodriguez struct cal_target_power_ht *powInfo, 337203c4805SLuis R. Rodriguez u16 numChannels, 338203c4805SLuis R. Rodriguez struct cal_target_power_ht *pNewPower, 339203c4805SLuis R. Rodriguez u16 numRates, bool isHt40Target) 340203c4805SLuis R. Rodriguez { 341203c4805SLuis R. Rodriguez struct chan_centers centers; 342203c4805SLuis R. Rodriguez u16 clo, chi; 343203c4805SLuis R. Rodriguez int i; 344203c4805SLuis R. Rodriguez int matchIndex = -1, lowIndex = -1; 345203c4805SLuis R. Rodriguez u16 freq; 346203c4805SLuis R. Rodriguez 347203c4805SLuis R. Rodriguez ath9k_hw_get_channel_centers(ah, chan, ¢ers); 348203c4805SLuis R. Rodriguez freq = isHt40Target ? centers.synth_center : centers.ctl_center; 349203c4805SLuis R. Rodriguez 350203c4805SLuis R. Rodriguez if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { 351203c4805SLuis R. Rodriguez matchIndex = 0; 352203c4805SLuis R. Rodriguez } else { 353203c4805SLuis R. Rodriguez for (i = 0; (i < numChannels) && 354203c4805SLuis R. Rodriguez (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 355203c4805SLuis R. Rodriguez if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 356203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan))) { 357203c4805SLuis R. Rodriguez matchIndex = i; 358203c4805SLuis R. Rodriguez break; 359203c4805SLuis R. Rodriguez } else 36073f57f83SRoel Kluin if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 36173f57f83SRoel Kluin IS_CHAN_2GHZ(chan)) && i > 0 && 36273f57f83SRoel Kluin freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 36373f57f83SRoel Kluin IS_CHAN_2GHZ(chan))) { 364203c4805SLuis R. Rodriguez lowIndex = i - 1; 365203c4805SLuis R. Rodriguez break; 366203c4805SLuis R. Rodriguez } 367203c4805SLuis R. Rodriguez } 368203c4805SLuis R. Rodriguez if ((matchIndex == -1) && (lowIndex == -1)) 369203c4805SLuis R. Rodriguez matchIndex = i - 1; 370203c4805SLuis R. Rodriguez } 371203c4805SLuis R. Rodriguez 372203c4805SLuis R. Rodriguez if (matchIndex != -1) { 373203c4805SLuis R. Rodriguez *pNewPower = powInfo[matchIndex]; 374203c4805SLuis R. Rodriguez } else { 375203c4805SLuis R. Rodriguez clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 376203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan)); 377203c4805SLuis R. Rodriguez chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 378203c4805SLuis R. Rodriguez IS_CHAN_2GHZ(chan)); 379203c4805SLuis R. Rodriguez 380203c4805SLuis R. Rodriguez for (i = 0; i < numRates; i++) { 381203c4805SLuis R. Rodriguez pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, 382203c4805SLuis R. Rodriguez clo, chi, 383203c4805SLuis R. Rodriguez powInfo[lowIndex].tPow2x[i], 384203c4805SLuis R. Rodriguez powInfo[lowIndex + 1].tPow2x[i]); 385203c4805SLuis R. Rodriguez } 386203c4805SLuis R. Rodriguez } 387203c4805SLuis R. Rodriguez } 388203c4805SLuis R. Rodriguez 389b5aec950SSujith u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, 390203c4805SLuis R. Rodriguez bool is2GHz, int num_band_edges) 391203c4805SLuis R. Rodriguez { 3924ddfcd7dSFelix Fietkau u16 twiceMaxEdgePower = MAX_RATE_POWER; 393203c4805SLuis R. Rodriguez int i; 394203c4805SLuis R. Rodriguez 395203c4805SLuis R. Rodriguez for (i = 0; (i < num_band_edges) && 396203c4805SLuis R. Rodriguez (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 397203c4805SLuis R. Rodriguez if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { 398e702ba18SFelix Fietkau twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl); 399203c4805SLuis R. Rodriguez break; 400203c4805SLuis R. Rodriguez } else if ((i > 0) && 401203c4805SLuis R. Rodriguez (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, 402203c4805SLuis R. Rodriguez is2GHz))) { 403203c4805SLuis R. Rodriguez if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, 404203c4805SLuis R. Rodriguez is2GHz) < freq && 405e702ba18SFelix Fietkau CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) { 406203c4805SLuis R. Rodriguez twiceMaxEdgePower = 407e702ba18SFelix Fietkau CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl); 408203c4805SLuis R. Rodriguez } 409203c4805SLuis R. Rodriguez break; 410203c4805SLuis R. Rodriguez } 411203c4805SLuis R. Rodriguez } 412203c4805SLuis R. Rodriguez 413203c4805SLuis R. Rodriguez return twiceMaxEdgePower; 414203c4805SLuis R. Rodriguez } 415203c4805SLuis R. Rodriguez 416ea6f792bSGabor Juhos u16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit, 417ea6f792bSGabor Juhos u8 antenna_reduction) 418ea6f792bSGabor Juhos { 4198f942b9bSGabor Juhos u16 reduction = antenna_reduction; 420ea6f792bSGabor Juhos 421ea6f792bSGabor Juhos /* 422ea6f792bSGabor Juhos * Reduce scaled Power by number of chains active 423ea6f792bSGabor Juhos * to get the per chain tx power level. 424ea6f792bSGabor Juhos */ 425ea6f792bSGabor Juhos switch (ar5416_get_ntxchains(ah->txchainmask)) { 426ea6f792bSGabor Juhos case 1: 427ea6f792bSGabor Juhos break; 428ea6f792bSGabor Juhos case 2: 4296010e72cSGabor Juhos reduction += POWER_CORRECTION_FOR_TWO_CHAIN; 430ea6f792bSGabor Juhos break; 431ea6f792bSGabor Juhos case 3: 4326010e72cSGabor Juhos reduction += POWER_CORRECTION_FOR_THREE_CHAIN; 433ea6f792bSGabor Juhos break; 434ea6f792bSGabor Juhos } 435ea6f792bSGabor Juhos 4368f942b9bSGabor Juhos if (power_limit > reduction) 4378f942b9bSGabor Juhos power_limit -= reduction; 4388f942b9bSGabor Juhos else 4398f942b9bSGabor Juhos power_limit = 0; 440ea6f792bSGabor Juhos 441b037b107SSven Eckelmann return min_t(u16, power_limit, MAX_RATE_POWER); 442ea6f792bSGabor Juhos } 443ea6f792bSGabor Juhos 444a55f8588SSujith void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah) 445a55f8588SSujith { 446a55f8588SSujith struct ath_common *common = ath9k_hw_common(ah); 447a55f8588SSujith struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); 448a55f8588SSujith 449a55f8588SSujith switch (ar5416_get_ntxchains(ah->txchainmask)) { 450a55f8588SSujith case 1: 451a55f8588SSujith break; 452a55f8588SSujith case 2: 4536010e72cSGabor Juhos regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN; 454a55f8588SSujith break; 455a55f8588SSujith case 3: 4566010e72cSGabor Juhos regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN; 457a55f8588SSujith break; 458a55f8588SSujith default: 459d2182b69SJoe Perches ath_dbg(common, EEPROM, "Invalid chainmask configuration\n"); 460a55f8588SSujith break; 461a55f8588SSujith } 462a55f8588SSujith } 463a55f8588SSujith 464115277a3SFelix Fietkau void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, 465115277a3SFelix Fietkau struct ath9k_channel *chan, 466115277a3SFelix Fietkau void *pRawDataSet, 467115277a3SFelix Fietkau u8 *bChans, u16 availPiers, 468115277a3SFelix Fietkau u16 tPdGainOverlap, 469115277a3SFelix Fietkau u16 *pPdGainBoundaries, u8 *pPDADCValues, 470115277a3SFelix Fietkau u16 numXpdGains) 471115277a3SFelix Fietkau { 472115277a3SFelix Fietkau int i, j, k; 473115277a3SFelix Fietkau int16_t ss; 474115277a3SFelix Fietkau u16 idxL = 0, idxR = 0, numPiers; 475115277a3SFelix Fietkau static u8 vpdTableL[AR5416_NUM_PD_GAINS] 476115277a3SFelix Fietkau [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 477115277a3SFelix Fietkau static u8 vpdTableR[AR5416_NUM_PD_GAINS] 478115277a3SFelix Fietkau [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 479115277a3SFelix Fietkau static u8 vpdTableI[AR5416_NUM_PD_GAINS] 480115277a3SFelix Fietkau [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; 481115277a3SFelix Fietkau 482115277a3SFelix Fietkau u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; 483115277a3SFelix Fietkau u8 minPwrT4[AR5416_NUM_PD_GAINS]; 484115277a3SFelix Fietkau u8 maxPwrT4[AR5416_NUM_PD_GAINS]; 485115277a3SFelix Fietkau int16_t vpdStep; 486115277a3SFelix Fietkau int16_t tmpVal; 487115277a3SFelix Fietkau u16 sizeCurrVpdTable, maxIndex, tgtIndex; 488115277a3SFelix Fietkau bool match; 489115277a3SFelix Fietkau int16_t minDelta = 0; 490115277a3SFelix Fietkau struct chan_centers centers; 491115277a3SFelix Fietkau int pdgain_boundary_default; 492115277a3SFelix Fietkau struct cal_data_per_freq *data_def = pRawDataSet; 493115277a3SFelix Fietkau struct cal_data_per_freq_4k *data_4k = pRawDataSet; 494940cd2c1SFelix Fietkau struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet; 495115277a3SFelix Fietkau bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah); 496940cd2c1SFelix Fietkau int intercepts; 497940cd2c1SFelix Fietkau 498940cd2c1SFelix Fietkau if (AR_SREV_9287(ah)) 499940cd2c1SFelix Fietkau intercepts = AR9287_PD_GAIN_ICEPTS; 500940cd2c1SFelix Fietkau else 501940cd2c1SFelix Fietkau intercepts = AR5416_PD_GAIN_ICEPTS; 502115277a3SFelix Fietkau 503115277a3SFelix Fietkau memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS); 504115277a3SFelix Fietkau ath9k_hw_get_channel_centers(ah, chan, ¢ers); 505115277a3SFelix Fietkau 506115277a3SFelix Fietkau for (numPiers = 0; numPiers < availPiers; numPiers++) { 507115277a3SFelix Fietkau if (bChans[numPiers] == AR5416_BCHAN_UNUSED) 508115277a3SFelix Fietkau break; 509115277a3SFelix Fietkau } 510115277a3SFelix Fietkau 511115277a3SFelix Fietkau match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, 512115277a3SFelix Fietkau IS_CHAN_2GHZ(chan)), 513115277a3SFelix Fietkau bChans, numPiers, &idxL, &idxR); 514115277a3SFelix Fietkau 515115277a3SFelix Fietkau if (match) { 516940cd2c1SFelix Fietkau if (AR_SREV_9287(ah)) { 517940cd2c1SFelix Fietkau for (i = 0; i < numXpdGains; i++) { 518940cd2c1SFelix Fietkau minPwrT4[i] = data_9287[idxL].pwrPdg[i][0]; 51983d6f1f1SArnd Bergmann maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1]; 520940cd2c1SFelix Fietkau ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 521940cd2c1SFelix Fietkau data_9287[idxL].pwrPdg[i], 522940cd2c1SFelix Fietkau data_9287[idxL].vpdPdg[i], 523940cd2c1SFelix Fietkau intercepts, 524940cd2c1SFelix Fietkau vpdTableI[i]); 525940cd2c1SFelix Fietkau } 526940cd2c1SFelix Fietkau } else if (eeprom_4k) { 527115277a3SFelix Fietkau for (i = 0; i < numXpdGains; i++) { 528115277a3SFelix Fietkau minPwrT4[i] = data_4k[idxL].pwrPdg[i][0]; 52983d6f1f1SArnd Bergmann maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1]; 530115277a3SFelix Fietkau ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 531115277a3SFelix Fietkau data_4k[idxL].pwrPdg[i], 532115277a3SFelix Fietkau data_4k[idxL].vpdPdg[i], 533940cd2c1SFelix Fietkau intercepts, 534115277a3SFelix Fietkau vpdTableI[i]); 535115277a3SFelix Fietkau } 536115277a3SFelix Fietkau } else { 537115277a3SFelix Fietkau for (i = 0; i < numXpdGains; i++) { 538115277a3SFelix Fietkau minPwrT4[i] = data_def[idxL].pwrPdg[i][0]; 53983d6f1f1SArnd Bergmann maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1]; 540115277a3SFelix Fietkau ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 541115277a3SFelix Fietkau data_def[idxL].pwrPdg[i], 542115277a3SFelix Fietkau data_def[idxL].vpdPdg[i], 543940cd2c1SFelix Fietkau intercepts, 544115277a3SFelix Fietkau vpdTableI[i]); 545115277a3SFelix Fietkau } 546115277a3SFelix Fietkau } 547115277a3SFelix Fietkau } else { 548115277a3SFelix Fietkau for (i = 0; i < numXpdGains; i++) { 549940cd2c1SFelix Fietkau if (AR_SREV_9287(ah)) { 550940cd2c1SFelix Fietkau pVpdL = data_9287[idxL].vpdPdg[i]; 551940cd2c1SFelix Fietkau pPwrL = data_9287[idxL].pwrPdg[i]; 552940cd2c1SFelix Fietkau pVpdR = data_9287[idxR].vpdPdg[i]; 553940cd2c1SFelix Fietkau pPwrR = data_9287[idxR].pwrPdg[i]; 554940cd2c1SFelix Fietkau } else if (eeprom_4k) { 555115277a3SFelix Fietkau pVpdL = data_4k[idxL].vpdPdg[i]; 556115277a3SFelix Fietkau pPwrL = data_4k[idxL].pwrPdg[i]; 557115277a3SFelix Fietkau pVpdR = data_4k[idxR].vpdPdg[i]; 558115277a3SFelix Fietkau pPwrR = data_4k[idxR].pwrPdg[i]; 559115277a3SFelix Fietkau } else { 560115277a3SFelix Fietkau pVpdL = data_def[idxL].vpdPdg[i]; 561115277a3SFelix Fietkau pPwrL = data_def[idxL].pwrPdg[i]; 562115277a3SFelix Fietkau pVpdR = data_def[idxR].vpdPdg[i]; 563115277a3SFelix Fietkau pPwrR = data_def[idxR].pwrPdg[i]; 564115277a3SFelix Fietkau } 565115277a3SFelix Fietkau 566115277a3SFelix Fietkau minPwrT4[i] = max(pPwrL[0], pPwrR[0]); 567115277a3SFelix Fietkau 568115277a3SFelix Fietkau maxPwrT4[i] = 569940cd2c1SFelix Fietkau min(pPwrL[intercepts - 1], 570940cd2c1SFelix Fietkau pPwrR[intercepts - 1]); 571115277a3SFelix Fietkau 572115277a3SFelix Fietkau 573115277a3SFelix Fietkau ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 574115277a3SFelix Fietkau pPwrL, pVpdL, 575940cd2c1SFelix Fietkau intercepts, 576115277a3SFelix Fietkau vpdTableL[i]); 577115277a3SFelix Fietkau ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], 578115277a3SFelix Fietkau pPwrR, pVpdR, 579940cd2c1SFelix Fietkau intercepts, 580115277a3SFelix Fietkau vpdTableR[i]); 581115277a3SFelix Fietkau 582115277a3SFelix Fietkau for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { 583115277a3SFelix Fietkau vpdTableI[i][j] = 584115277a3SFelix Fietkau (u8)(ath9k_hw_interpolate((u16) 585115277a3SFelix Fietkau FREQ2FBIN(centers. 586115277a3SFelix Fietkau synth_center, 587115277a3SFelix Fietkau IS_CHAN_2GHZ 588115277a3SFelix Fietkau (chan)), 589115277a3SFelix Fietkau bChans[idxL], bChans[idxR], 590115277a3SFelix Fietkau vpdTableL[i][j], vpdTableR[i][j])); 591115277a3SFelix Fietkau } 592115277a3SFelix Fietkau } 593115277a3SFelix Fietkau } 594115277a3SFelix Fietkau 595115277a3SFelix Fietkau k = 0; 596115277a3SFelix Fietkau 597115277a3SFelix Fietkau for (i = 0; i < numXpdGains; i++) { 598115277a3SFelix Fietkau if (i == (numXpdGains - 1)) 599115277a3SFelix Fietkau pPdGainBoundaries[i] = 600115277a3SFelix Fietkau (u16)(maxPwrT4[i] / 2); 601115277a3SFelix Fietkau else 602115277a3SFelix Fietkau pPdGainBoundaries[i] = 603115277a3SFelix Fietkau (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); 604115277a3SFelix Fietkau 605115277a3SFelix Fietkau pPdGainBoundaries[i] = 606115277a3SFelix Fietkau min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]); 607115277a3SFelix Fietkau 608115277a3SFelix Fietkau minDelta = 0; 609115277a3SFelix Fietkau 610115277a3SFelix Fietkau if (i == 0) { 611115277a3SFelix Fietkau if (AR_SREV_9280_20_OR_LATER(ah)) 612115277a3SFelix Fietkau ss = (int16_t)(0 - (minPwrT4[i] / 2)); 613115277a3SFelix Fietkau else 614115277a3SFelix Fietkau ss = 0; 615115277a3SFelix Fietkau } else { 616115277a3SFelix Fietkau ss = (int16_t)((pPdGainBoundaries[i - 1] - 617115277a3SFelix Fietkau (minPwrT4[i] / 2)) - 618115277a3SFelix Fietkau tPdGainOverlap + 1 + minDelta); 619115277a3SFelix Fietkau } 620115277a3SFelix Fietkau vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); 621115277a3SFelix Fietkau vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 622115277a3SFelix Fietkau 623115277a3SFelix Fietkau while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 624115277a3SFelix Fietkau tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); 625115277a3SFelix Fietkau pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); 626115277a3SFelix Fietkau ss++; 627115277a3SFelix Fietkau } 628115277a3SFelix Fietkau 629115277a3SFelix Fietkau sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); 630115277a3SFelix Fietkau tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - 631115277a3SFelix Fietkau (minPwrT4[i] / 2)); 632115277a3SFelix Fietkau maxIndex = (tgtIndex < sizeCurrVpdTable) ? 633115277a3SFelix Fietkau tgtIndex : sizeCurrVpdTable; 634115277a3SFelix Fietkau 635115277a3SFelix Fietkau while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { 636115277a3SFelix Fietkau pPDADCValues[k++] = vpdTableI[i][ss++]; 637115277a3SFelix Fietkau } 638115277a3SFelix Fietkau 639115277a3SFelix Fietkau vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - 640115277a3SFelix Fietkau vpdTableI[i][sizeCurrVpdTable - 2]); 641115277a3SFelix Fietkau vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); 642115277a3SFelix Fietkau 643115277a3SFelix Fietkau if (tgtIndex >= maxIndex) { 644115277a3SFelix Fietkau while ((ss <= tgtIndex) && 645115277a3SFelix Fietkau (k < (AR5416_NUM_PDADC_VALUES - 1))) { 646115277a3SFelix Fietkau tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + 647115277a3SFelix Fietkau (ss - maxIndex + 1) * vpdStep)); 648115277a3SFelix Fietkau pPDADCValues[k++] = (u8)((tmpVal > 255) ? 649115277a3SFelix Fietkau 255 : tmpVal); 650115277a3SFelix Fietkau ss++; 651115277a3SFelix Fietkau } 652115277a3SFelix Fietkau } 653115277a3SFelix Fietkau } 654115277a3SFelix Fietkau 655115277a3SFelix Fietkau if (eeprom_4k) 656115277a3SFelix Fietkau pdgain_boundary_default = 58; 657115277a3SFelix Fietkau else 658115277a3SFelix Fietkau pdgain_boundary_default = pPdGainBoundaries[i - 1]; 659115277a3SFelix Fietkau 660115277a3SFelix Fietkau while (i < AR5416_PD_GAINS_IN_MASK) { 661115277a3SFelix Fietkau pPdGainBoundaries[i] = pdgain_boundary_default; 662115277a3SFelix Fietkau i++; 663115277a3SFelix Fietkau } 664115277a3SFelix Fietkau 665115277a3SFelix Fietkau while (k < AR5416_NUM_PDADC_VALUES) { 666115277a3SFelix Fietkau pPDADCValues[k] = pPDADCValues[k - 1]; 667115277a3SFelix Fietkau k++; 668115277a3SFelix Fietkau } 669115277a3SFelix Fietkau } 670115277a3SFelix Fietkau 671f637cfd6SLuis R. Rodriguez int ath9k_hw_eeprom_init(struct ath_hw *ah) 672203c4805SLuis R. Rodriguez { 67315c9ee7aSSenthil Balasubramanian if (AR_SREV_9300_20_OR_LATER(ah)) 67415c9ee7aSSenthil Balasubramanian ah->eep_ops = &eep_ar9300_ops; 67515c9ee7aSSenthil Balasubramanian else if (AR_SREV_9287(ah)) { 6760b8f6f2bSLuis R. Rodriguez ah->eep_ops = &eep_ar9287_ops; 677d7e7d229SLuis R. Rodriguez } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { 678203c4805SLuis R. Rodriguez ah->eep_ops = &eep_4k_ops; 679203c4805SLuis R. Rodriguez } else { 680203c4805SLuis R. Rodriguez ah->eep_ops = &eep_def_ops; 681203c4805SLuis R. Rodriguez } 682203c4805SLuis R. Rodriguez 683203c4805SLuis R. Rodriguez if (!ah->eep_ops->fill_eeprom(ah)) 684203c4805SLuis R. Rodriguez return -EIO; 685203c4805SLuis R. Rodriguez 686*76d7b996SMinghao Chi return ah->eep_ops->check_eeprom(ah); 687203c4805SLuis R. Rodriguez } 688