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 el, integer; 181 u16 word; 182 int i, err; 183 bool need_swap; 184 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 185 186 err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287); 187 if (err) 188 return err; 189 190 if (need_swap) 191 el = swab16(eep->baseEepHeader.length); 192 else 193 el = eep->baseEepHeader.length; 194 195 el = min(el / sizeof(u16), SIZE_EEPROM_AR9287); 196 if (!ath9k_hw_nvram_validate_checksum(ah, el)) 197 return -EINVAL; 198 199 if (need_swap) { 200 word = swab16(eep->baseEepHeader.length); 201 eep->baseEepHeader.length = word; 202 203 word = swab16(eep->baseEepHeader.checksum); 204 eep->baseEepHeader.checksum = word; 205 206 word = swab16(eep->baseEepHeader.version); 207 eep->baseEepHeader.version = word; 208 209 word = swab16(eep->baseEepHeader.regDmn[0]); 210 eep->baseEepHeader.regDmn[0] = word; 211 212 word = swab16(eep->baseEepHeader.regDmn[1]); 213 eep->baseEepHeader.regDmn[1] = word; 214 215 word = swab16(eep->baseEepHeader.rfSilent); 216 eep->baseEepHeader.rfSilent = word; 217 218 word = swab16(eep->baseEepHeader.blueToothOptions); 219 eep->baseEepHeader.blueToothOptions = word; 220 221 word = swab16(eep->baseEepHeader.deviceCap); 222 eep->baseEepHeader.deviceCap = word; 223 224 integer = swab32(eep->modalHeader.antCtrlCommon); 225 eep->modalHeader.antCtrlCommon = integer; 226 227 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 228 integer = swab32(eep->modalHeader.antCtrlChain[i]); 229 eep->modalHeader.antCtrlChain[i] = integer; 230 } 231 232 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 233 word = swab16(eep->modalHeader.spurChans[i].spurChan); 234 eep->modalHeader.spurChans[i].spurChan = word; 235 } 236 } 237 238 if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER, 239 AR5416_EEP_NO_BACK_VER)) 240 return -EINVAL; 241 242 return 0; 243 } 244 245 #undef SIZE_EEPROM_AR9287 246 247 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, 248 enum eeprom_param param) 249 { 250 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 251 struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 252 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; 253 u16 ver_minor; 254 255 ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK; 256 257 switch (param) { 258 case EEP_NFTHRESH_2: 259 return pModal->noiseFloorThreshCh[0]; 260 case EEP_MAC_LSW: 261 return get_unaligned_be16(pBase->macAddr); 262 case EEP_MAC_MID: 263 return get_unaligned_be16(pBase->macAddr + 2); 264 case EEP_MAC_MSW: 265 return get_unaligned_be16(pBase->macAddr + 4); 266 case EEP_REG_0: 267 return pBase->regDmn[0]; 268 case EEP_OP_CAP: 269 return pBase->deviceCap; 270 case EEP_OP_MODE: 271 return pBase->opCapFlags; 272 case EEP_RF_SILENT: 273 return pBase->rfSilent; 274 case EEP_MINOR_REV: 275 return ver_minor; 276 case EEP_TX_MASK: 277 return pBase->txMask; 278 case EEP_RX_MASK: 279 return pBase->rxMask; 280 case EEP_DEV_TYPE: 281 return pBase->deviceType; 282 case EEP_OL_PWRCTRL: 283 return pBase->openLoopPwrCntl; 284 case EEP_TEMPSENSE_SLOPE: 285 if (ver_minor >= AR9287_EEP_MINOR_VER_2) 286 return pBase->tempSensSlope; 287 else 288 return 0; 289 case EEP_TEMPSENSE_SLOPE_PAL_ON: 290 if (ver_minor >= AR9287_EEP_MINOR_VER_3) 291 return pBase->tempSensSlopePalOn; 292 else 293 return 0; 294 case EEP_ANTENNA_GAIN_2G: 295 return max_t(u8, pModal->antennaGainCh[0], 296 pModal->antennaGainCh[1]); 297 default: 298 return 0; 299 } 300 } 301 302 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah, 303 struct ath9k_channel *chan, 304 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop, 305 u8 *pCalChans, u16 availPiers, int8_t *pPwr) 306 { 307 u16 idxL = 0, idxR = 0, numPiers; 308 bool match; 309 struct chan_centers centers; 310 311 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 312 313 for (numPiers = 0; numPiers < availPiers; numPiers++) { 314 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED) 315 break; 316 } 317 318 match = ath9k_hw_get_lower_upper_index( 319 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), 320 pCalChans, numPiers, &idxL, &idxR); 321 322 if (match) { 323 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0]; 324 } else { 325 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] + 326 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2; 327 } 328 329 } 330 331 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, 332 int32_t txPower, u16 chain) 333 { 334 u32 tmpVal; 335 u32 a; 336 337 /* Enable OLPC for chain 0 */ 338 339 tmpVal = REG_READ(ah, 0xa270); 340 tmpVal = tmpVal & 0xFCFFFFFF; 341 tmpVal = tmpVal | (0x3 << 24); 342 REG_WRITE(ah, 0xa270, tmpVal); 343 344 /* Enable OLPC for chain 1 */ 345 346 tmpVal = REG_READ(ah, 0xb270); 347 tmpVal = tmpVal & 0xFCFFFFFF; 348 tmpVal = tmpVal | (0x3 << 24); 349 REG_WRITE(ah, 0xb270, tmpVal); 350 351 /* Write the OLPC ref power for chain 0 */ 352 353 if (chain == 0) { 354 tmpVal = REG_READ(ah, 0xa398); 355 tmpVal = tmpVal & 0xff00ffff; 356 a = (txPower)&0xff; 357 tmpVal = tmpVal | (a << 16); 358 REG_WRITE(ah, 0xa398, tmpVal); 359 } 360 361 /* Write the OLPC ref power for chain 1 */ 362 363 if (chain == 1) { 364 tmpVal = REG_READ(ah, 0xb398); 365 tmpVal = tmpVal & 0xff00ffff; 366 a = (txPower)&0xff; 367 tmpVal = tmpVal | (a << 16); 368 REG_WRITE(ah, 0xb398, tmpVal); 369 } 370 } 371 372 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, 373 struct ath9k_channel *chan) 374 { 375 struct cal_data_per_freq_ar9287 *pRawDataset; 376 struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; 377 u8 *pCalBChans = NULL; 378 u16 pdGainOverlap_t2; 379 u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; 380 u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; 381 u16 numPiers = 0, i, j; 382 u16 numXpdGain, xpdMask; 383 u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; 384 u32 reg32, regOffset, regChainOffset, regval; 385 int16_t diff = 0; 386 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 387 388 xpdMask = pEepData->modalHeader.xpdGain; 389 390 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 391 AR9287_EEP_MINOR_VER_2) 392 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap; 393 else 394 pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), 395 AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); 396 397 if (IS_CHAN_2GHZ(chan)) { 398 pCalBChans = pEepData->calFreqPier2G; 399 numPiers = AR9287_NUM_2G_CAL_PIERS; 400 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 401 pRawDatasetOpenLoop = 402 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0]; 403 ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0]; 404 } 405 } 406 407 numXpdGain = 0; 408 409 /* Calculate the value of xpdgains from the xpdGain Mask */ 410 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { 411 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { 412 if (numXpdGain >= AR5416_NUM_PD_GAINS) 413 break; 414 xpdGainValues[numXpdGain] = 415 (u16)(AR5416_PD_GAINS_IN_MASK-i); 416 numXpdGain++; 417 } 418 } 419 420 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, 421 (numXpdGain - 1) & 0x3); 422 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, 423 xpdGainValues[0]); 424 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, 425 xpdGainValues[1]); 426 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 427 xpdGainValues[2]); 428 429 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 430 regChainOffset = i * 0x1000; 431 432 if (pEepData->baseEepHeader.txMask & (1 << i)) { 433 pRawDatasetOpenLoop = 434 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i]; 435 436 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 437 int8_t txPower; 438 ar9287_eeprom_get_tx_gain_index(ah, chan, 439 pRawDatasetOpenLoop, 440 pCalBChans, numPiers, 441 &txPower); 442 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i); 443 } else { 444 pRawDataset = 445 (struct cal_data_per_freq_ar9287 *) 446 pEepData->calPierData2G[i]; 447 448 ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, 449 pRawDataset, 450 pCalBChans, numPiers, 451 pdGainOverlap_t2, 452 gainBoundaries, 453 pdadcValues, 454 numXpdGain); 455 } 456 457 ENABLE_REGWRITE_BUFFER(ah); 458 459 if (i == 0) { 460 if (!ath9k_hw_ar9287_get_eeprom(ah, 461 EEP_OL_PWRCTRL)) { 462 463 regval = SM(pdGainOverlap_t2, 464 AR_PHY_TPCRG5_PD_GAIN_OVERLAP) 465 | SM(gainBoundaries[0], 466 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) 467 | SM(gainBoundaries[1], 468 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) 469 | SM(gainBoundaries[2], 470 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) 471 | SM(gainBoundaries[3], 472 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4); 473 474 REG_WRITE(ah, 475 AR_PHY_TPCRG5 + regChainOffset, 476 regval); 477 } 478 } 479 480 if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB != 481 pEepData->baseEepHeader.pwrTableOffset) { 482 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset - 483 (int32_t)AR9287_PWR_TABLE_OFFSET_DB); 484 diff *= 2; 485 486 for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++) 487 pdadcValues[j] = pdadcValues[j+diff]; 488 489 for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff); 490 j < AR5416_NUM_PDADC_VALUES; j++) 491 pdadcValues[j] = 492 pdadcValues[AR5416_NUM_PDADC_VALUES-diff]; 493 } 494 495 if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 496 regOffset = AR_PHY_BASE + 497 (672 << 2) + regChainOffset; 498 499 for (j = 0; j < 32; j++) { 500 reg32 = get_unaligned_le32(&pdadcValues[4 * j]); 501 502 REG_WRITE(ah, regOffset, reg32); 503 regOffset += 4; 504 } 505 } 506 REGWRITE_BUFFER_FLUSH(ah); 507 } 508 } 509 } 510 511 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, 512 struct ath9k_channel *chan, 513 int16_t *ratesArray, 514 u16 cfgCtl, 515 u16 antenna_reduction, 516 u16 powerLimit) 517 { 518 #define CMP_CTL \ 519 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ 520 pEepData->ctlIndex[i]) 521 522 #define CMP_NO_CTL \ 523 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ 524 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) 525 526 u16 twiceMaxEdgePower; 527 int i; 528 struct cal_ctl_data_ar9287 *rep; 529 struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, 530 targetPowerCck = {0, {0, 0, 0, 0} }; 531 struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} }, 532 targetPowerCckExt = {0, {0, 0, 0, 0} }; 533 struct cal_target_power_ht targetPowerHt20, 534 targetPowerHt40 = {0, {0, 0, 0, 0} }; 535 u16 scaledPower = 0, minCtlPower; 536 static const u16 ctlModesFor11g[] = { 537 CTL_11B, CTL_11G, CTL_2GHT20, 538 CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 539 }; 540 u16 numCtlModes = 0; 541 const u16 *pCtlMode = NULL; 542 u16 ctlMode, freq; 543 struct chan_centers centers; 544 int tx_chainmask; 545 u16 twiceMinEdgePower; 546 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 547 tx_chainmask = ah->txchainmask; 548 549 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 550 scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit, 551 antenna_reduction); 552 553 /* 554 * Get TX power from EEPROM. 555 */ 556 if (IS_CHAN_2GHZ(chan)) { 557 /* CTL_11B, CTL_11G, CTL_2GHT20 */ 558 numCtlModes = 559 ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; 560 561 pCtlMode = ctlModesFor11g; 562 563 ath9k_hw_get_legacy_target_powers(ah, chan, 564 pEepData->calTargetPowerCck, 565 AR9287_NUM_2G_CCK_TARGET_POWERS, 566 &targetPowerCck, 4, false); 567 ath9k_hw_get_legacy_target_powers(ah, chan, 568 pEepData->calTargetPower2G, 569 AR9287_NUM_2G_20_TARGET_POWERS, 570 &targetPowerOfdm, 4, false); 571 ath9k_hw_get_target_powers(ah, chan, 572 pEepData->calTargetPower2GHT20, 573 AR9287_NUM_2G_20_TARGET_POWERS, 574 &targetPowerHt20, 8, false); 575 576 if (IS_CHAN_HT40(chan)) { 577 /* All 2G CTLs */ 578 numCtlModes = ARRAY_SIZE(ctlModesFor11g); 579 ath9k_hw_get_target_powers(ah, chan, 580 pEepData->calTargetPower2GHT40, 581 AR9287_NUM_2G_40_TARGET_POWERS, 582 &targetPowerHt40, 8, true); 583 ath9k_hw_get_legacy_target_powers(ah, chan, 584 pEepData->calTargetPowerCck, 585 AR9287_NUM_2G_CCK_TARGET_POWERS, 586 &targetPowerCckExt, 4, true); 587 ath9k_hw_get_legacy_target_powers(ah, chan, 588 pEepData->calTargetPower2G, 589 AR9287_NUM_2G_20_TARGET_POWERS, 590 &targetPowerOfdmExt, 4, true); 591 } 592 } 593 594 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { 595 bool isHt40CtlMode = 596 (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false; 597 598 if (isHt40CtlMode) 599 freq = centers.synth_center; 600 else if (pCtlMode[ctlMode] & EXT_ADDITIVE) 601 freq = centers.ext_center; 602 else 603 freq = centers.ctl_center; 604 605 twiceMaxEdgePower = MAX_RATE_POWER; 606 /* Walk through the CTL indices stored in EEPROM */ 607 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { 608 struct cal_ctl_edges *pRdEdgesPower; 609 610 /* 611 * Compare test group from regulatory channel list 612 * with test mode from pCtlMode list 613 */ 614 if (CMP_CTL || CMP_NO_CTL) { 615 rep = &(pEepData->ctlData[i]); 616 pRdEdgesPower = 617 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1]; 618 619 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, 620 pRdEdgesPower, 621 IS_CHAN_2GHZ(chan), 622 AR5416_NUM_BAND_EDGES); 623 624 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { 625 twiceMaxEdgePower = min(twiceMaxEdgePower, 626 twiceMinEdgePower); 627 } else { 628 twiceMaxEdgePower = twiceMinEdgePower; 629 break; 630 } 631 } 632 } 633 634 minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); 635 636 /* Apply ctl mode to correct target power set */ 637 switch (pCtlMode[ctlMode]) { 638 case CTL_11B: 639 for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { 640 targetPowerCck.tPow2x[i] = 641 (u8)min((u16)targetPowerCck.tPow2x[i], 642 minCtlPower); 643 } 644 break; 645 case CTL_11A: 646 case CTL_11G: 647 for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { 648 targetPowerOfdm.tPow2x[i] = 649 (u8)min((u16)targetPowerOfdm.tPow2x[i], 650 minCtlPower); 651 } 652 break; 653 case CTL_5GHT20: 654 case CTL_2GHT20: 655 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { 656 targetPowerHt20.tPow2x[i] = 657 (u8)min((u16)targetPowerHt20.tPow2x[i], 658 minCtlPower); 659 } 660 break; 661 case CTL_11B_EXT: 662 targetPowerCckExt.tPow2x[0] = 663 (u8)min((u16)targetPowerCckExt.tPow2x[0], 664 minCtlPower); 665 break; 666 case CTL_11A_EXT: 667 case CTL_11G_EXT: 668 targetPowerOfdmExt.tPow2x[0] = 669 (u8)min((u16)targetPowerOfdmExt.tPow2x[0], 670 minCtlPower); 671 break; 672 case CTL_5GHT40: 673 case CTL_2GHT40: 674 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { 675 targetPowerHt40.tPow2x[i] = 676 (u8)min((u16)targetPowerHt40.tPow2x[i], 677 minCtlPower); 678 } 679 break; 680 default: 681 break; 682 } 683 } 684 685 /* Now set the rates array */ 686 687 ratesArray[rate6mb] = 688 ratesArray[rate9mb] = 689 ratesArray[rate12mb] = 690 ratesArray[rate18mb] = 691 ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0]; 692 693 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; 694 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; 695 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; 696 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; 697 698 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) 699 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; 700 701 if (IS_CHAN_2GHZ(chan)) { 702 ratesArray[rate1l] = targetPowerCck.tPow2x[0]; 703 ratesArray[rate2s] = 704 ratesArray[rate2l] = targetPowerCck.tPow2x[1]; 705 ratesArray[rate5_5s] = 706 ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; 707 ratesArray[rate11s] = 708 ratesArray[rate11l] = targetPowerCck.tPow2x[3]; 709 } 710 if (IS_CHAN_HT40(chan)) { 711 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) 712 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i]; 713 714 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; 715 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; 716 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; 717 718 if (IS_CHAN_2GHZ(chan)) 719 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; 720 } 721 722 #undef CMP_CTL 723 #undef CMP_NO_CTL 724 } 725 726 static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, 727 struct ath9k_channel *chan, u16 cfgCtl, 728 u8 twiceAntennaReduction, 729 u8 powerLimit, bool test) 730 { 731 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); 732 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; 733 struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; 734 int16_t ratesArray[Ar5416RateSize]; 735 u8 ht40PowerIncForPdadc = 2; 736 int i; 737 738 memset(ratesArray, 0, sizeof(ratesArray)); 739 740 if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= 741 AR9287_EEP_MINOR_VER_2) 742 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; 743 744 ath9k_hw_set_ar9287_power_per_rate_table(ah, chan, 745 &ratesArray[0], cfgCtl, 746 twiceAntennaReduction, 747 powerLimit); 748 749 ath9k_hw_set_ar9287_power_cal_table(ah, chan); 750 751 regulatory->max_power_level = 0; 752 for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { 753 if (ratesArray[i] > MAX_RATE_POWER) 754 ratesArray[i] = MAX_RATE_POWER; 755 756 if (ratesArray[i] > regulatory->max_power_level) 757 regulatory->max_power_level = ratesArray[i]; 758 } 759 760 ath9k_hw_update_regulatory_maxpower(ah); 761 762 if (test) 763 return; 764 765 for (i = 0; i < Ar5416RateSize; i++) 766 ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; 767 768 ENABLE_REGWRITE_BUFFER(ah); 769 770 /* OFDM power per rate */ 771 REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, 772 ATH9K_POW_SM(ratesArray[rate18mb], 24) 773 | ATH9K_POW_SM(ratesArray[rate12mb], 16) 774 | ATH9K_POW_SM(ratesArray[rate9mb], 8) 775 | ATH9K_POW_SM(ratesArray[rate6mb], 0)); 776 777 REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, 778 ATH9K_POW_SM(ratesArray[rate54mb], 24) 779 | ATH9K_POW_SM(ratesArray[rate48mb], 16) 780 | ATH9K_POW_SM(ratesArray[rate36mb], 8) 781 | ATH9K_POW_SM(ratesArray[rate24mb], 0)); 782 783 /* CCK power per rate */ 784 if (IS_CHAN_2GHZ(chan)) { 785 REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, 786 ATH9K_POW_SM(ratesArray[rate2s], 24) 787 | ATH9K_POW_SM(ratesArray[rate2l], 16) 788 | ATH9K_POW_SM(ratesArray[rateXr], 8) 789 | ATH9K_POW_SM(ratesArray[rate1l], 0)); 790 REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, 791 ATH9K_POW_SM(ratesArray[rate11s], 24) 792 | ATH9K_POW_SM(ratesArray[rate11l], 16) 793 | ATH9K_POW_SM(ratesArray[rate5_5s], 8) 794 | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); 795 } 796 797 /* HT20 power per rate */ 798 REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, 799 ATH9K_POW_SM(ratesArray[rateHt20_3], 24) 800 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) 801 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) 802 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); 803 804 REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, 805 ATH9K_POW_SM(ratesArray[rateHt20_7], 24) 806 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) 807 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) 808 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); 809 810 /* HT40 power per rate */ 811 if (IS_CHAN_HT40(chan)) { 812 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) { 813 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, 814 ATH9K_POW_SM(ratesArray[rateHt40_3], 24) 815 | ATH9K_POW_SM(ratesArray[rateHt40_2], 16) 816 | ATH9K_POW_SM(ratesArray[rateHt40_1], 8) 817 | ATH9K_POW_SM(ratesArray[rateHt40_0], 0)); 818 819 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, 820 ATH9K_POW_SM(ratesArray[rateHt40_7], 24) 821 | ATH9K_POW_SM(ratesArray[rateHt40_6], 16) 822 | ATH9K_POW_SM(ratesArray[rateHt40_5], 8) 823 | ATH9K_POW_SM(ratesArray[rateHt40_4], 0)); 824 } else { 825 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, 826 ATH9K_POW_SM(ratesArray[rateHt40_3] + 827 ht40PowerIncForPdadc, 24) 828 | ATH9K_POW_SM(ratesArray[rateHt40_2] + 829 ht40PowerIncForPdadc, 16) 830 | ATH9K_POW_SM(ratesArray[rateHt40_1] + 831 ht40PowerIncForPdadc, 8) 832 | ATH9K_POW_SM(ratesArray[rateHt40_0] + 833 ht40PowerIncForPdadc, 0)); 834 835 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, 836 ATH9K_POW_SM(ratesArray[rateHt40_7] + 837 ht40PowerIncForPdadc, 24) 838 | ATH9K_POW_SM(ratesArray[rateHt40_6] + 839 ht40PowerIncForPdadc, 16) 840 | ATH9K_POW_SM(ratesArray[rateHt40_5] + 841 ht40PowerIncForPdadc, 8) 842 | ATH9K_POW_SM(ratesArray[rateHt40_4] + 843 ht40PowerIncForPdadc, 0)); 844 } 845 846 /* Dup/Ext power per rate */ 847 REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, 848 ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) 849 | ATH9K_POW_SM(ratesArray[rateExtCck], 16) 850 | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) 851 | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); 852 } 853 854 /* TPC initializations */ 855 if (ah->tpc_enabled) { 856 int ht40_delta; 857 858 ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0; 859 ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta); 860 /* Enable TPC */ 861 REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, 862 MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE); 863 } else { 864 /* Disable TPC */ 865 REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER); 866 } 867 868 REGWRITE_BUFFER_FLUSH(ah); 869 } 870 871 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, 872 struct ath9k_channel *chan) 873 { 874 struct ar9287_eeprom *eep = &ah->eeprom.map9287; 875 struct modal_eep_ar9287_header *pModal = &eep->modalHeader; 876 u32 regChainOffset, regval; 877 u8 txRxAttenLocal; 878 int i; 879 880 pModal = &eep->modalHeader; 881 882 REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); 883 884 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 885 regChainOffset = i * 0x1000; 886 887 REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, 888 pModal->antCtrlChain[i]); 889 890 REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, 891 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) 892 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | 893 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | 894 SM(pModal->iqCalICh[i], 895 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | 896 SM(pModal->iqCalQCh[i], 897 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); 898 899 txRxAttenLocal = pModal->txRxAttenCh[i]; 900 901 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 902 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 903 pModal->bswMargin[i]); 904 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, 905 AR_PHY_GAIN_2GHZ_XATTEN1_DB, 906 pModal->bswAtten[i]); 907 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 908 AR9280_PHY_RXGAIN_TXRX_ATTEN, 909 txRxAttenLocal); 910 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, 911 AR9280_PHY_RXGAIN_TXRX_MARGIN, 912 pModal->rxTxMarginCh[i]); 913 } 914 915 916 if (IS_CHAN_HT40(chan)) 917 REG_RMW_FIELD(ah, AR_PHY_SETTLING, 918 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); 919 else 920 REG_RMW_FIELD(ah, AR_PHY_SETTLING, 921 AR_PHY_SETTLING_SWITCH, pModal->switchSettling); 922 923 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, 924 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize); 925 926 REG_WRITE(ah, AR_PHY_RF_CTL4, 927 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) 928 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) 929 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) 930 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); 931 932 REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, 933 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn); 934 935 REG_RMW_FIELD(ah, AR_PHY_CCA, 936 AR9280_PHY_CCA_THRESH62, pModal->thresh62); 937 REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, 938 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62); 939 940 regval = REG_READ(ah, AR9287_AN_RF2G3_CH0); 941 regval &= ~(AR9287_AN_RF2G3_DB1 | 942 AR9287_AN_RF2G3_DB2 | 943 AR9287_AN_RF2G3_OB_CCK | 944 AR9287_AN_RF2G3_OB_PSK | 945 AR9287_AN_RF2G3_OB_QAM | 946 AR9287_AN_RF2G3_OB_PAL_OFF); 947 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 948 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 949 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 950 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 951 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 952 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 953 954 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval); 955 956 regval = REG_READ(ah, AR9287_AN_RF2G3_CH1); 957 regval &= ~(AR9287_AN_RF2G3_DB1 | 958 AR9287_AN_RF2G3_DB2 | 959 AR9287_AN_RF2G3_OB_CCK | 960 AR9287_AN_RF2G3_OB_PSK | 961 AR9287_AN_RF2G3_OB_QAM | 962 AR9287_AN_RF2G3_OB_PAL_OFF); 963 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) | 964 SM(pModal->db2, AR9287_AN_RF2G3_DB2) | 965 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) | 966 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) | 967 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) | 968 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF)); 969 970 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval); 971 972 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 973 AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart); 974 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, 975 AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn); 976 977 ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2, 978 AR9287_AN_TOP2_XPABIAS_LVL, 979 AR9287_AN_TOP2_XPABIAS_LVL_S, 980 pModal->xpaBiasLvl); 981 } 982 983 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah, 984 u16 i, bool is2GHz) 985 { 986 return ah->eeprom.map9287.modalHeader.spurChans[i].spurChan; 987 } 988 989 const struct eeprom_ops eep_ar9287_ops = { 990 .check_eeprom = ath9k_hw_ar9287_check_eeprom, 991 .get_eeprom = ath9k_hw_ar9287_get_eeprom, 992 .fill_eeprom = ath9k_hw_ar9287_fill_eeprom, 993 .dump_eeprom = ath9k_hw_ar9287_dump_eeprom, 994 .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver, 995 .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, 996 .set_board_values = ath9k_hw_ar9287_set_board_values, 997 .set_txpower = ath9k_hw_ar9287_set_txpower, 998 .get_spur_channel = ath9k_hw_ar9287_get_spur_channel 999 }; 1000