1 /* 2 * Copyright (c) 2008-2011 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <asm/unaligned.h> 18 #include "hw.h" 19 #include "ar9002_phy.h" 20 21 #define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16)) 22 23 static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah) 24 { 25 return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF; 26 } 27 28 static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah) 29 { 30 return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF; 31 } 32 33 static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) 34 { 35 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 36 u16 *eep_data; 37 int addr, eep_start_loc = AR9287_EEP_START_LOC; 38 eep_data = (u16 *)eep; 39 40 for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { 41 if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) 42 return false; 43 eep_data++; 44 } 45 46 return true; 47 } 48 49 static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah) 50 { 51 u16 *eep_data = (u16 *)&ah->eeprom.map9287; 52 53 ath9k_hw_usb_gen_fill_eeprom(ah, eep_data, 54 AR9287_HTC_EEP_START_LOC, 55 SIZE_EEPROM_AR9287); 56 return true; 57 } 58 59 static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) 60 { 61 struct ath_common *common = ath9k_hw_common(ah); 62 63 if (!ath9k_hw_use_flash(ah)) { 64 ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n"); 65 } 66 67 if (common->bus_ops->ath_bus_type == ATH_USB) 68 return __ath9k_hw_usb_ar9287_fill_eeprom(ah); 69 else 70 return __ath9k_hw_ar9287_fill_eeprom(ah); 71 } 72 73 #if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) 74 static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size, 75 struct modal_eep_ar9287_header *modal_hdr) 76 { 77 PR_EEP("Chain0 Ant. Control", modal_hdr->antCtrlChain[0]); 78 PR_EEP("Chain1 Ant. Control", modal_hdr->antCtrlChain[1]); 79 PR_EEP("Ant. Common Control", modal_hdr->antCtrlCommon); 80 PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); 81 PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); 82 PR_EEP("Switch Settle", modal_hdr->switchSettling); 83 PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); 84 PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]); 85 PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); 86 PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]); 87 PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); 88 PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); 89 PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); 90 PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); 91 PR_EEP("CCA Threshold)", modal_hdr->thresh62); 92 PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); 93 PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); 94 PR_EEP("xpdGain", modal_hdr->xpdGain); 95 PR_EEP("External PD", modal_hdr->xpd); 96 PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); 97 PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]); 98 PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); 99 PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]); 100 PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); 101 PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); 102 PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); 103 PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); 104 PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); 105 PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); 106 PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]); 107 PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); 108 PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]); 109 PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); 110 PR_EEP("AR92x7 Version", modal_hdr->version); 111 PR_EEP("DriverBias1", modal_hdr->db1); 112 PR_EEP("DriverBias2", modal_hdr->db1); 113 PR_EEP("CCK OutputBias", modal_hdr->ob_cck); 114 PR_EEP("PSK OutputBias", modal_hdr->ob_psk); 115 PR_EEP("QAM OutputBias", modal_hdr->ob_qam); 116 PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off); 117 118 return len; 119 } 120 121 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, 122 u8 *buf, u32 len, u32 size) 123 { 124 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 125 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; 126 127 if (!dump_base_hdr) { 128 len += scnprintf(buf + len, size - len, 129 "%20s :\n", "2GHz modal Header"); 130 len = ar9287_dump_modal_eeprom(buf, len, size, 131 &eep->modalHeader); 132 goto out; 133 } 134 135 PR_EEP("Major Version", pBase->version >> 12); 136 PR_EEP("Minor Version", pBase->version & 0xFFF); 137 PR_EEP("Checksum", pBase->checksum); 138 PR_EEP("Length", pBase->length); 139 PR_EEP("RegDomain1", pBase->regDmn[0]); 140 PR_EEP("RegDomain2", pBase->regDmn[1]); 141 PR_EEP("TX Mask", pBase->txMask); 142 PR_EEP("RX Mask", pBase->rxMask); 143 PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); 144 PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); 145 PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & 146 AR5416_OPFLAGS_N_2G_HT20)); 147 PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & 148 AR5416_OPFLAGS_N_2G_HT40)); 149 PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & 150 AR5416_OPFLAGS_N_5G_HT20)); 151 PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags & 152 AR5416_OPFLAGS_N_5G_HT40)); 153 PR_EEP("Big Endian", !!(pBase->eepMisc & 0x01)); 154 PR_EEP("Cal Bin Major Ver", (pBase->binBuildNumber >> 24) & 0xFF); 155 PR_EEP("Cal Bin Minor Ver", (pBase->binBuildNumber >> 16) & 0xFF); 156 PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF); 157 PR_EEP("Power Table Offset", pBase->pwrTableOffset); 158 PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); 159 160 len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", 161 pBase->macAddr); 162 163 out: 164 if (len > size) 165 len = size; 166 167 return len; 168 } 169 #else 170 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, 171 u8 *buf, u32 len, u32 size) 172 { 173 return 0; 174 } 175 #endif 176 177 178 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) 179 { 180 u32 sum = 0, el, integer; 181 u16 temp, word, magic, magic2, *eepdata; 182 int i, addr; 183 bool need_swap = false; 184 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 185 struct ath_common *common = ath9k_hw_common(ah); 186 187 if (!ath9k_hw_use_flash(ah)) { 188 if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, 189 &magic)) { 190 ath_err(common, "Reading Magic # failed\n"); 191 return false; 192 } 193 194 ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); 195 196 if (magic != AR5416_EEPROM_MAGIC) { 197 magic2 = swab16(magic); 198 199 if (magic2 == AR5416_EEPROM_MAGIC) { 200 need_swap = true; 201 eepdata = (u16 *)(&ah->eeprom); 202 203 for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) { 204 temp = swab16(*eepdata); 205 *eepdata = temp; 206 eepdata++; 207 } 208 } else { 209 ath_err(common, 210 "Invalid EEPROM Magic. Endianness mismatch.\n"); 211 return -EINVAL; 212 } 213 } 214 } 215 216 ath_dbg(common, EEPROM, "need_swap = %s\n", 217 need_swap ? "True" : "False"); 218 219 if (need_swap) 220 el = swab16(ah->eeprom.map9287.baseEepHeader.length); 221 else 222 el = ah->eeprom.map9287.baseEepHeader.length; 223 224 if (el > sizeof(struct ar9287_eeprom)) 225 el = sizeof(struct ar9287_eeprom) / sizeof(u16); 226 else 227 el = el / sizeof(u16); 228 229 eepdata = (u16 *)(&ah->eeprom); 230 231 for (i = 0; i < el; i++) 232 sum ^= *eepdata++; 233 234 if (need_swap) { 235 word = swab16(eep->baseEepHeader.length); 236 eep->baseEepHeader.length = word; 237 238 word = swab16(eep->baseEepHeader.checksum); 239 eep->baseEepHeader.checksum = word; 240 241 word = swab16(eep->baseEepHeader.version); 242 eep->baseEepHeader.version = word; 243 244 word = swab16(eep->baseEepHeader.regDmn[0]); 245 eep->baseEepHeader.regDmn[0] = word; 246 247 word = swab16(eep->baseEepHeader.regDmn[1]); 248 eep->baseEepHeader.regDmn[1] = word; 249 250 word = swab16(eep->baseEepHeader.rfSilent); 251 eep->baseEepHeader.rfSilent = word; 252 253 word = swab16(eep->baseEepHeader.blueToothOptions); 254 eep->baseEepHeader.blueToothOptions = word; 255 256 word = swab16(eep->baseEepHeader.deviceCap); 257 eep->baseEepHeader.deviceCap = word; 258 259 integer = swab32(eep->modalHeader.antCtrlCommon); 260 eep->modalHeader.antCtrlCommon = integer; 261 262 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 263 integer = swab32(eep->modalHeader.antCtrlChain[i]); 264 eep->modalHeader.antCtrlChain[i] = integer; 265 } 266 267 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 268 word = swab16(eep->modalHeader.spurChans[i].spurChan); 269 eep->modalHeader.spurChans[i].spurChan = word; 270 } 271 } 272 273 if (sum != 0xffff || ah->eep_ops->get_eeprom_ver(ah) != AR9287_EEP_VER 274 || ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_NO_BACK_VER) { 275 ath_err(common, "Bad EEPROM checksum 0x%x or revision 0x%04x\n", 276 sum, ah->eep_ops->get_eeprom_ver(ah)); 277 return -EINVAL; 278 } 279 280 return 0; 281 } 282 283 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, 284 enum eeprom_param param) 285 { 286 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 287 struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 288 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; 289 u16 ver_minor; 290 291 ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; 292 293 switch (param) { 294 case EEP_NFTHRESH_2: 295 return pModal->noiseFloorThreshCh[0]; 296 case EEP_MAC_LSW: 297 return get_unaligned_be16(pBase->macAddr); 298 case EEP_MAC_MID: 299 return get_unaligned_be16(pBase->macAddr + 2); 300 case EEP_MAC_MSW: 301 return get_unaligned_be16(pBase->macAddr + 4); 302 case EEP_REG_0: 303 return pBase->regDmn[0]; 304 case EEP_OP_CAP: 305 return pBase->deviceCap; 306 case EEP_OP_MODE: 307 return pBase->opCapFlags; 308 case EEP_RF_SILENT: 309 return pBase->rfSilent; 310 case EEP_MINOR_REV: 311 return ver_minor; 312 case EEP_TX_MASK: 313 return pBase->txMask; 314 case EEP_RX_MASK: 315 return pBase->rxMask; 316 case EEP_DEV_TYPE: 317 return pBase->deviceType; 318 case EEP_OL_PWRCTRL: 319 return pBase->openLoopPwrCntl; 320 case EEP_TEMPSENSE_SLOPE: 321 if (ver_minor >= AR9287_EEP_MINOR_VER_2) 322 return pBase->tempSensSlope; 323 else 324 return 0; 325 case EEP_TEMPSENSE_SLOPE_PAL_ON: 326 if (ver_minor >= AR9287_EEP_MINOR_VER_3) 327 return pBase->tempSensSlopePalOn; 328 else 329 return 0; 330 case EEP_ANTENNA_GAIN_2G: 331 return max_t(u8, pModal->antennaGainCh[0], 332 pModal->antennaGainCh[1]); 333 default: 334 return 0; 335 } 336 } 337 338 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, 339 struct ath9k_channel *chan, 340 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, 341 u8 *pCalChans, u16 availPiers, int8_t *pPwr) 342 { 343 u16 idxL = 0, idxR = 0, numPiers; 344 bool match; 345 struct chan_centers centers; 346 347 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 348 349 for (numPiers = 0; numPiers < availPiers; numPiers++) { 350 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) 351 break; 352 } 353 354 match = ath9k_hw_get_lower_upper_index( 355 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), 356 pCalChans, numPiers, &idxL, &idxR); 357 358 if (match) { 359 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; 360 } else { 361 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + 362 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; 363 } 364 365 } 366 367 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, 368 int32_t txPower, u16 chain) 369 { 370 u32 tmpVal; 371 u32 a; 372 373 /* Enable OLPC for chain 0 */ 374 375 tmpVal = REG_READ(ah, 0xa270); 376 tmpVal = tmpVal & 0xFCFFFFFF; 377 tmpVal = tmpVal | (0x3 << 24); 378 REG_WRITE(ah, 0xa270, tmpVal); 379 380 /* Enable OLPC for chain 1 */ 381 382 tmpVal = REG_READ(ah, 0xb270); 383 tmpVal = tmpVal & 0xFCFFFFFF; 384 tmpVal = tmpVal | (0x3 << 24); 385 REG_WRITE(ah, 0xb270, tmpVal); 386 387 /* Write the OLPC ref power for chain 0 */ 388 389 if (chain == 0) { 390 tmpVal = REG_READ(ah, 0xa398); 391 tmpVal = tmpVal & 0xff00ffff; 392 a = (txPower)&0xff; 393 tmpVal = tmpVal | (a << 16); 394 REG_WRITE(ah, 0xa398, tmpVal); 395 } 396 397 /* Write the OLPC ref power for chain 1 */ 398 399 if (chain == 1) { 400 tmpVal = REG_READ(ah, 0xb398); 401 tmpVal = tmpVal & 0xff00ffff; 402 a = (txPower)&0xff; 403 tmpVal = tmpVal | (a << 16); 404 REG_WRITE(ah, 0xb398, tmpVal); 405 } 406 } 407 408 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, 409 struct ath9k_channel *chan) 410 { 411 struct cal_data_per_freq_ar9287 *pRawDataset; 412 struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; 413 u8 *pCalBChans = NULL; 414 u16 pdGainOverlap_t2; 415 u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; 416 u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 417 u16 numPiers = 0, i, j; 418 u16 numXpdGain, xpdMask; 419 u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; 420 u32 reg32, regOffset, regChainOffset, regval; 421 int16_t diff = 0; 422 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 423 424 xpdMask = pEepData->modalHeader.xpdGain; 425 426 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 427 AR9287_EEP_MINOR_VER_2) 428 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 429 else 430 pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), 431 AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 432 433 if (IS_CHAN_2GHZ(chan)) { 434 pCalBChans = pEepData->calFreqPier2G; 435 numPiers = AR9287_NUM_2G_CAL_PIERS; 436 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 437 pRawDatasetOpenLoop = 438 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0]; 439 ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; 440 } 441 } 442 443 numXpdGain = 0; 444 445 /* Calculate the value of xpdgains from the xpdGain Mask */ 446 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 447 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 448 if (numXpdGain >= AR5416_NUM_PD_GAINS) 449 break; 450 xpdGainValues[numXpdGain] = 451 (u16)(AR5416_PD_GAINS_IN_MASK-i); 452 numXpdGain++; 453 } 454 } 455 456 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 457 (numXpdGain - 1) & 0x3); 458 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, 459 xpdGainValues[0]); 460 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, 461 xpdGainValues[1]); 462 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 463 xpdGainValues[2]); 464 465 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 466 regChainOffset = i * 0x1000; 467 468 if (pEepData->baseEepHeader.txMask & (1 << i)) { 469 pRawDatasetOpenLoop = 470 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i]; 471 472 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 473 int8_t txPower; 474 ar9287_eeprom_get_tx_gain_index(ah, chan, 475 pRawDatasetOpenLoop, 476 pCalBChans, numPiers, 477 &txPower); 478 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); 479 } else { 480 pRawDataset = 481 (struct cal_data_per_freq_ar9287 *) 482 pEepData->calPierData2G[i]; 483 484 ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, 485 pRawDataset, 486 pCalBChans, numPiers, 487 pdGainOverlap_t2, 488 gainBoundaries, 489 pdadcValues, 490 numXpdGain); 491 } 492 493 ENABLE_REGWRITE_BUFFER(ah); 494 495 if (i == 0) { 496 if (!ath9k_hw_ar9287_get_eeprom(ah, 497 EEP_OL_PWRCTRL)) { 498 499 regval = SM(pdGainOverlap_t2, 500 AR_PHY_TPCRG5_PD_GAIN_OVERLAP) 501 | SM(gainBoundaries[0], 502 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) 503 | SM(gainBoundaries[1], 504 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) 505 | SM(gainBoundaries[2], 506 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) 507 | SM(gainBoundaries[3], 508 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4); 509 510 REG_WRITE(ah, 511 AR_PHY_TPCRG5 + regChainOffset, 512 regval); 513 } 514 } 515 516 if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != 517 pEepData->baseEepHeader.pwrTableOffset) { 518 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset - 519 (int32_t)AR9287_PWR_TABLE_OFFSET_DB); 520 diff *= 2; 521 522 for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++) 523 pdadcValues[j] = pdadcValues[j+diff]; 524 525 for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff); 526 j < AR5416_NUM_PDADC_VALUES; j++) 527 pdadcValues[j] = 528 pdadcValues[AR5416_NUM_PDADC_VALUES-diff]; 529 } 530 531 if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 532 regOffset = AR_PHY_BASE + 533 (672 << 2) + regChainOffset; 534 535 for (j = 0; j < 32; j++) { 536 reg32 = get_unaligned_le32(&pdadcValues[4 * j]); 537 538 REG_WRITE(ah, regOffset, reg32); 539 regOffset += 4; 540 } 541 } 542 REGWRITE_BUFFER_FLUSH(ah); 543 } 544 } 545 } 546 547 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, 548 struct ath9k_channel *chan, 549 int16_t *ratesArray, 550 u16 cfgCtl, 551 u16 antenna_reduction, 552 u16 powerLimit) 553 { 554 #define CMP_CTL \ 555 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ 556 pEepData->ctlIndex[i]) 557 558 #define CMP_NO_CTL \ 559 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ 560 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) 561 562 u16 twiceMaxEdgePower; 563 int i; 564 struct cal_ctl_data_ar9287 *rep; 565 struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, 566 targetPowerCck = {0, {0, 0, 0, 0} }; 567 struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, 568 targetPowerCckExt = {0, {0, 0, 0, 0} }; 569 struct cal_target_power_ht targetPowerHt20, 570 targetPowerHt40 = {0, {0, 0, 0, 0} }; 571 u16 scaledPower = 0, minCtlPower; 572 static const u16 ctlModesFor11g[] = { 573 CTL_11B, CTL_11G, CTL_2GHT20, 574 CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 575 }; 576 u16 numCtlModes = 0; 577 const u16 *pCtlMode = NULL; 578 u16 ctlMode, freq; 579 struct chan_centers centers; 580 int tx_chainmask; 581 u16 twiceMinEdgePower; 582 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 583 tx_chainmask = ah->txchainmask; 584 585 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 586 scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit, 587 antenna_reduction); 588 589 /* 590 * Get TX power from EEPROM. 591 */ 592 if (IS_CHAN_2GHZ(chan)) { 593 /* CTL_11B, CTL_11G, CTL_2GHT20 */ 594 numCtlModes = 595 ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; 596 597 pCtlMode = ctlModesFor11g; 598 599 ath9k_hw_get_legacy_target_powers(ah, chan, 600 pEepData->calTargetPowerCck, 601 AR9287_NUM_2G_CCK_TARGET_POWERS, 602 &targetPowerCck, 4, false); 603 ath9k_hw_get_legacy_target_powers(ah, chan, 604 pEepData->calTargetPower2G, 605 AR9287_NUM_2G_20_TARGET_POWERS, 606 &targetPowerOfdm, 4, false); 607 ath9k_hw_get_target_powers(ah, chan, 608 pEepData->calTargetPower2GHT20, 609 AR9287_NUM_2G_20_TARGET_POWERS, 610 &targetPowerHt20, 8, false); 611 612 if (IS_CHAN_HT40(chan)) { 613 /* All 2G CTLs */ 614 numCtlModes = ARRAY_SIZE(ctlModesFor11g); 615 ath9k_hw_get_target_powers(ah, chan, 616 pEepData->calTargetPower2GHT40, 617 AR9287_NUM_2G_40_TARGET_POWERS, 618 &targetPowerHt40, 8, true); 619 ath9k_hw_get_legacy_target_powers(ah, chan, 620 pEepData->calTargetPowerCck, 621 AR9287_NUM_2G_CCK_TARGET_POWERS, 622 &targetPowerCckExt, 4, true); 623 ath9k_hw_get_legacy_target_powers(ah, chan, 624 pEepData->calTargetPower2G, 625 AR9287_NUM_2G_20_TARGET_POWERS, 626 &targetPowerOfdmExt, 4, true); 627 } 628 } 629 630 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 631 bool isHt40CtlMode = 632 (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false; 633 634 if (isHt40CtlMode) 635 freq = centers.synth_center; 636 else if (pCtlMode[ctlMode] & EXT_ADDITIVE) 637 freq = centers.ext_center; 638 else 639 freq = centers.ctl_center; 640 641 twiceMaxEdgePower = MAX_RATE_POWER; 642 /* Walk through the CTL indices stored in EEPROM */ 643 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 644 struct cal_ctl_edges *pRdEdgesPower; 645 646 /* 647 * Compare test group from regulatory channel list 648 * with test mode from pCtlMode list 649 */ 650 if (CMP_CTL || CMP_NO_CTL) { 651 rep = &(pEepData->ctlData[i]); 652 pRdEdgesPower = 653 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1]; 654 655 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, 656 pRdEdgesPower, 657 IS_CHAN_2GHZ(chan), 658 AR5416_NUM_BAND_EDGES); 659 660 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 661 twiceMaxEdgePower = min(twiceMaxEdgePower, 662 twiceMinEdgePower); 663 } else { 664 twiceMaxEdgePower = twiceMinEdgePower; 665 break; 666 } 667 } 668 } 669 670 minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); 671 672 /* Apply ctl mode to correct target power set */ 673 switch (pCtlMode[ctlMode]) { 674 case CTL_11B: 675 for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { 676 targetPowerCck.tPow2x[i] = 677 (u8)min((u16)targetPowerCck.tPow2x[i], 678 minCtlPower); 679 } 680 break; 681 case CTL_11A: 682 case CTL_11G: 683 for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { 684 targetPowerOfdm.tPow2x[i] = 685 (u8)min((u16)targetPowerOfdm.tPow2x[i], 686 minCtlPower); 687 } 688 break; 689 case CTL_5GHT20: 690 case CTL_2GHT20: 691 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { 692 targetPowerHt20.tPow2x[i] = 693 (u8)min((u16)targetPowerHt20.tPow2x[i], 694 minCtlPower); 695 } 696 break; 697 case CTL_11B_EXT: 698 targetPowerCckExt.tPow2x[0] = 699 (u8)min((u16)targetPowerCckExt.tPow2x[0], 700 minCtlPower); 701 break; 702 case CTL_11A_EXT: 703 case CTL_11G_EXT: 704 targetPowerOfdmExt.tPow2x[0] = 705 (u8)min((u16)targetPowerOfdmExt.tPow2x[0], 706 minCtlPower); 707 break; 708 case CTL_5GHT40: 709 case CTL_2GHT40: 710 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { 711 targetPowerHt40.tPow2x[i] = 712 (u8)min((u16)targetPowerHt40.tPow2x[i], 713 minCtlPower); 714 } 715 break; 716 default: 717 break; 718 } 719 } 720 721 /* Now set the rates array */ 722 723 ratesArray[rate6mb] = 724 ratesArray[rate9mb] = 725 ratesArray[rate12mb] = 726 ratesArray[rate18mb] = 727 ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; 728 729 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; 730 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; 731 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; 732 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; 733 734 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) 735 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; 736 737 if (IS_CHAN_2GHZ(chan)) { 738 ratesArray[rate1l] = targetPowerCck.tPow2x[0]; 739 ratesArray[rate2s] = 740 ratesArray[rate2l] = targetPowerCck.tPow2x[1]; 741 ratesArray[rate5_5s] = 742 ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; 743 ratesArray[rate11s] = 744 ratesArray[rate11l] = targetPowerCck.tPow2x[3]; 745 } 746 if (IS_CHAN_HT40(chan)) { 747 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) 748 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; 749 750 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; 751 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; 752 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; 753 754 if (IS_CHAN_2GHZ(chan)) 755 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; 756 } 757 758 #undef CMP_CTL 759 #undef CMP_NO_CTL 760 } 761 762 static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, 763 struct ath9k_channel *chan, u16 cfgCtl, 764 u8 twiceAntennaReduction, 765 u8 powerLimit, bool test) 766 { 767 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); 768 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 769 struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; 770 int16_t ratesArray[Ar5416RateSize]; 771 u8 ht40PowerIncForPdadc = 2; 772 int i; 773 774 memset(ratesArray, 0, sizeof(ratesArray)); 775 776 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 777 AR9287_EEP_MINOR_VER_2) 778 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 779 780 ath9k_hw_set_ar9287_power_per_rate_table(ah, chan, 781 &ratesArray[0], cfgCtl, 782 twiceAntennaReduction, 783 powerLimit); 784 785 ath9k_hw_set_ar9287_power_cal_table(ah, chan); 786 787 regulatory->max_power_level = 0; 788 for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { 789 if (ratesArray[i] > MAX_RATE_POWER) 790 ratesArray[i] = MAX_RATE_POWER; 791 792 if (ratesArray[i] > regulatory->max_power_level) 793 regulatory->max_power_level = ratesArray[i]; 794 } 795 796 ath9k_hw_update_regulatory_maxpower(ah); 797 798 if (test) 799 return; 800 801 for (i = 0; i < Ar5416RateSize; i++) 802 ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; 803 804 ENABLE_REGWRITE_BUFFER(ah); 805 806 /* OFDM power per rate */ 807 REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, 808 ATH9K_POW_SM(ratesArray[rate18mb], 24) 809 | ATH9K_POW_SM(ratesArray[rate12mb], 16) 810 | ATH9K_POW_SM(ratesArray[rate9mb], 8) 811 | ATH9K_POW_SM(ratesArray[rate6mb], 0)); 812 813 REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, 814 ATH9K_POW_SM(ratesArray[rate54mb], 24) 815 | ATH9K_POW_SM(ratesArray[rate48mb], 16) 816 | ATH9K_POW_SM(ratesArray[rate36mb], 8) 817 | ATH9K_POW_SM(ratesArray[rate24mb], 0)); 818 819 /* CCK power per rate */ 820 if (IS_CHAN_2GHZ(chan)) { 821 REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, 822 ATH9K_POW_SM(ratesArray[rate2s], 24) 823 | ATH9K_POW_SM(ratesArray[rate2l], 16) 824 | ATH9K_POW_SM(ratesArray[rateXr], 8) 825 | ATH9K_POW_SM(ratesArray[rate1l], 0)); 826 REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, 827 ATH9K_POW_SM(ratesArray[rate11s], 24) 828 | ATH9K_POW_SM(ratesArray[rate11l], 16) 829 | ATH9K_POW_SM(ratesArray[rate5_5s], 8) 830 | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); 831 } 832 833 /* HT20 power per rate */ 834 REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, 835 ATH9K_POW_SM(ratesArray[rateHt20_3], 24) 836 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) 837 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) 838 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); 839 840 REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, 841 ATH9K_POW_SM(ratesArray[rateHt20_7], 24) 842 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) 843 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) 844 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); 845 846 /* HT40 power per rate */ 847 if (IS_CHAN_HT40(chan)) { 848 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 849 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, 850 ATH9K_POW_SM(ratesArray[rateHt40_3], 24) 851 | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) 852 | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) 853 | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); 854 855 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, 856 ATH9K_POW_SM(ratesArray[rateHt40_7], 24) 857 | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) 858 | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) 859 | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); 860 } else { 861 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, 862 ATH9K_POW_SM(ratesArray[rateHt40_3] + 863 ht40PowerIncForPdadc, 24) 864 | ATH9K_POW_SM(ratesArray[rateHt40_2] + 865 ht40PowerIncForPdadc, 16) 866 | ATH9K_POW_SM(ratesArray[rateHt40_1] + 867 ht40PowerIncForPdadc, 8) 868 | ATH9K_POW_SM(ratesArray[rateHt40_0] + 869 ht40PowerIncForPdadc, 0)); 870 871 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, 872 ATH9K_POW_SM(ratesArray[rateHt40_7] + 873 ht40PowerIncForPdadc, 24) 874 | ATH9K_POW_SM(ratesArray[rateHt40_6] + 875 ht40PowerIncForPdadc, 16) 876 | ATH9K_POW_SM(ratesArray[rateHt40_5] + 877 ht40PowerIncForPdadc, 8) 878 | ATH9K_POW_SM(ratesArray[rateHt40_4] + 879 ht40PowerIncForPdadc, 0)); 880 } 881 882 /* Dup/Ext power per rate */ 883 REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, 884 ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) 885 | ATH9K_POW_SM(ratesArray[rateExtCck], 16) 886 | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) 887 | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); 888 } 889 REGWRITE_BUFFER_FLUSH(ah); 890 } 891 892 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, 893 struct ath9k_channel *chan) 894 { 895 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 896 struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 897 u32 regChainOffset, regval; 898 u8 txRxAttenLocal; 899 int i; 900 901 pModal = &eep->modalHeader; 902 903 REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 904 905 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 906 regChainOffset = i * 0x1000; 907 908 REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 909 pModal->antCtrlChain[i]); 910 911 REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, 912 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) 913 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 914 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 915 SM(pModal->iqCalICh[i], 916 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 917 SM(pModal->iqCalQCh[i], 918 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 919 920 txRxAttenLocal = pModal->txRxAttenCh[i]; 921 922 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 923 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 924 pModal->bswMargin[i]); 925 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 926 AR_PHY_GAIN_2GHZ_XATTEN1_DB, 927 pModal->bswAtten[i]); 928 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 929 AR9280_PHY_RXGAIN_TXRX_ATTEN, 930 txRxAttenLocal); 931 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 932 AR9280_PHY_RXGAIN_TXRX_MARGIN, 933 pModal->rxTxMarginCh[i]); 934 } 935 936 937 if (IS_CHAN_HT40(chan)) 938 REG_RMW_FIELD(ah, AR_PHY_SETTLING, 939 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 940 else 941 REG_RMW_FIELD(ah, AR_PHY_SETTLING, 942 AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 943 944 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 945 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 946 947 REG_WRITE(ah, AR_PHY_RF_CTL4, 948 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 949 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 950 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 951 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 952 953 REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 954 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 955 956 REG_RMW_FIELD(ah, AR_PHY_CCA, 957 AR9280_PHY_CCA_THRESH62, pModal->thresh62); 958 REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 959 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 960 961 regval = REG_READ(ah, AR9287_AN_RF2G3_CH0); 962 regval &= ~(AR9287_AN_RF2G3_DB1 | 963 AR9287_AN_RF2G3_DB2 | 964 AR9287_AN_RF2G3_OB_CCK | 965 AR9287_AN_RF2G3_OB_PSK | 966 AR9287_AN_RF2G3_OB_QAM | 967 AR9287_AN_RF2G3_OB_PAL_OFF); 968 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 969 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 970 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 971 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 972 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 973 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 974 975 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval); 976 977 regval = REG_READ(ah, AR9287_AN_RF2G3_CH1); 978 regval &= ~(AR9287_AN_RF2G3_DB1 | 979 AR9287_AN_RF2G3_DB2 | 980 AR9287_AN_RF2G3_OB_CCK | 981 AR9287_AN_RF2G3_OB_PSK | 982 AR9287_AN_RF2G3_OB_QAM | 983 AR9287_AN_RF2G3_OB_PAL_OFF); 984 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 985 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 986 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 987 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 988 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 989 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 990 991 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval); 992 993 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 994 AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); 995 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 996 AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); 997 998 ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, 999 AR9287_AN_TOP2_XPABIAS_LVL, 1000 AR9287_AN_TOP2_XPABIAS_LVL_S, 1001 pModal->xpaBiasLvl); 1002 } 1003 1004 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah, 1005 u16 i, bool is2GHz) 1006 { 1007 return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan; 1008 } 1009 1010 const struct eeprom_ops eep_ar9287_ops = { 1011 .check_eeprom = ath9k_hw_ar9287_check_eeprom, 1012 .get_eeprom = ath9k_hw_ar9287_get_eeprom, 1013 .fill_eeprom = ath9k_hw_ar9287_fill_eeprom, 1014 .dump_eeprom = ath9k_hw_ar9287_dump_eeprom, 1015 .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver, 1016 .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, 1017 .set_board_values = ath9k_hw_ar9287_set_board_values, 1018 .set_txpower = ath9k_hw_ar9287_set_txpower, 1019 .get_spur_channel = ath9k_hw_ar9287_get_spur_channel 1020 }; 1021