0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <asm/unaligned.h>
0018 #include "hw.h"
0019 #include "ar9002_phy.h"
0020
0021 #define SIZE_EEPROM_AR9287 (sizeof(struct ar9287_eeprom) / sizeof(u16))
0022
0023 static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
0024 {
0025 u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
0026
0027 return (version & AR5416_EEP_VER_MAJOR_MASK) >>
0028 AR5416_EEP_VER_MAJOR_SHIFT;
0029 }
0030
0031 static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
0032 {
0033 u16 version = le16_to_cpu(ah->eeprom.map9287.baseEepHeader.version);
0034
0035 return version & AR5416_EEP_VER_MINOR_MASK;
0036 }
0037
0038 static bool __ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
0039 {
0040 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0041 u16 *eep_data;
0042 int addr, eep_start_loc = AR9287_EEP_START_LOC;
0043 eep_data = (u16 *)eep;
0044
0045 for (addr = 0; addr < SIZE_EEPROM_AR9287; addr++) {
0046 if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data))
0047 return false;
0048 eep_data++;
0049 }
0050
0051 return true;
0052 }
0053
0054 static bool __ath9k_hw_usb_ar9287_fill_eeprom(struct ath_hw *ah)
0055 {
0056 u16 *eep_data = (u16 *)&ah->eeprom.map9287;
0057
0058 ath9k_hw_usb_gen_fill_eeprom(ah, eep_data,
0059 AR9287_HTC_EEP_START_LOC,
0060 SIZE_EEPROM_AR9287);
0061 return true;
0062 }
0063
0064 static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
0065 {
0066 struct ath_common *common = ath9k_hw_common(ah);
0067
0068 if (!ath9k_hw_use_flash(ah)) {
0069 ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n");
0070 }
0071
0072 if (common->bus_ops->ath_bus_type == ATH_USB)
0073 return __ath9k_hw_usb_ar9287_fill_eeprom(ah);
0074 else
0075 return __ath9k_hw_ar9287_fill_eeprom(ah);
0076 }
0077
0078 #ifdef CONFIG_ATH9K_COMMON_DEBUG
0079 static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size,
0080 struct modal_eep_ar9287_header *modal_hdr)
0081 {
0082 PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0]));
0083 PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1]));
0084 PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon));
0085 PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]);
0086 PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]);
0087 PR_EEP("Switch Settle", modal_hdr->switchSettling);
0088 PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]);
0089 PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]);
0090 PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]);
0091 PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]);
0092 PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
0093 PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
0094 PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn);
0095 PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
0096 PR_EEP("CCA Threshold)", modal_hdr->thresh62);
0097 PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
0098 PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
0099 PR_EEP("xpdGain", modal_hdr->xpdGain);
0100 PR_EEP("External PD", modal_hdr->xpd);
0101 PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]);
0102 PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]);
0103 PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]);
0104 PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]);
0105 PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap);
0106 PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
0107 PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
0108 PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
0109 PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc);
0110 PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]);
0111 PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]);
0112 PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]);
0113 PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]);
0114 PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40);
0115 PR_EEP("AR92x7 Version", modal_hdr->version);
0116 PR_EEP("DriverBias1", modal_hdr->db1);
0117 PR_EEP("DriverBias2", modal_hdr->db1);
0118 PR_EEP("CCK OutputBias", modal_hdr->ob_cck);
0119 PR_EEP("PSK OutputBias", modal_hdr->ob_psk);
0120 PR_EEP("QAM OutputBias", modal_hdr->ob_qam);
0121 PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off);
0122
0123 return len;
0124 }
0125
0126 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
0127 u8 *buf, u32 len, u32 size)
0128 {
0129 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0130 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
0131 u32 binBuildNumber = le32_to_cpu(pBase->binBuildNumber);
0132
0133 if (!dump_base_hdr) {
0134 len += scnprintf(buf + len, size - len,
0135 "%20s :\n", "2GHz modal Header");
0136 len = ar9287_dump_modal_eeprom(buf, len, size,
0137 &eep->modalHeader);
0138 goto out;
0139 }
0140
0141 PR_EEP("Major Version", ath9k_hw_ar9287_get_eeprom_ver(ah));
0142 PR_EEP("Minor Version", ath9k_hw_ar9287_get_eeprom_rev(ah));
0143 PR_EEP("Checksum", le16_to_cpu(pBase->checksum));
0144 PR_EEP("Length", le16_to_cpu(pBase->length));
0145 PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0]));
0146 PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1]));
0147 PR_EEP("TX Mask", pBase->txMask);
0148 PR_EEP("RX Mask", pBase->rxMask);
0149 PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
0150 PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
0151 PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags &
0152 AR5416_OPFLAGS_N_2G_HT20));
0153 PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags &
0154 AR5416_OPFLAGS_N_2G_HT40));
0155 PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags &
0156 AR5416_OPFLAGS_N_5G_HT20));
0157 PR_EEP("Disable 5Ghz HT40", !!(pBase->opCapFlags &
0158 AR5416_OPFLAGS_N_5G_HT40));
0159 PR_EEP("Big Endian", !!(pBase->eepMisc & AR5416_EEPMISC_BIG_ENDIAN));
0160 PR_EEP("Cal Bin Major Ver", (binBuildNumber >> 24) & 0xFF);
0161 PR_EEP("Cal Bin Minor Ver", (binBuildNumber >> 16) & 0xFF);
0162 PR_EEP("Cal Bin Build", (binBuildNumber >> 8) & 0xFF);
0163 PR_EEP("Power Table Offset", pBase->pwrTableOffset);
0164 PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
0165
0166 len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
0167 pBase->macAddr);
0168
0169 out:
0170 if (len > size)
0171 len = size;
0172
0173 return len;
0174 }
0175 #else
0176 static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
0177 u8 *buf, u32 len, u32 size)
0178 {
0179 return 0;
0180 }
0181 #endif
0182
0183
0184 static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
0185 {
0186 u32 el;
0187 int i, err;
0188 bool need_swap;
0189 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0190
0191 err = ath9k_hw_nvram_swap_data(ah, &need_swap, SIZE_EEPROM_AR9287);
0192 if (err)
0193 return err;
0194
0195 if (need_swap)
0196 el = swab16((__force u16)eep->baseEepHeader.length);
0197 else
0198 el = le16_to_cpu(eep->baseEepHeader.length);
0199
0200 el = min(el / sizeof(u16), SIZE_EEPROM_AR9287);
0201 if (!ath9k_hw_nvram_validate_checksum(ah, el))
0202 return -EINVAL;
0203
0204 if (need_swap) {
0205 EEPROM_FIELD_SWAB16(eep->baseEepHeader.length);
0206 EEPROM_FIELD_SWAB16(eep->baseEepHeader.checksum);
0207 EEPROM_FIELD_SWAB16(eep->baseEepHeader.version);
0208 EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[0]);
0209 EEPROM_FIELD_SWAB16(eep->baseEepHeader.regDmn[1]);
0210 EEPROM_FIELD_SWAB16(eep->baseEepHeader.rfSilent);
0211 EEPROM_FIELD_SWAB16(eep->baseEepHeader.blueToothOptions);
0212 EEPROM_FIELD_SWAB16(eep->baseEepHeader.deviceCap);
0213 EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlCommon);
0214
0215 for (i = 0; i < AR9287_MAX_CHAINS; i++)
0216 EEPROM_FIELD_SWAB32(eep->modalHeader.antCtrlChain[i]);
0217
0218 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++)
0219 EEPROM_FIELD_SWAB16(
0220 eep->modalHeader.spurChans[i].spurChan);
0221 }
0222
0223 if (!ath9k_hw_nvram_check_version(ah, AR9287_EEP_VER,
0224 AR5416_EEP_NO_BACK_VER))
0225 return -EINVAL;
0226
0227 return 0;
0228 }
0229
0230 #undef SIZE_EEPROM_AR9287
0231
0232 static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
0233 enum eeprom_param param)
0234 {
0235 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0236 struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
0237 struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
0238 u16 ver_minor = ath9k_hw_ar9287_get_eeprom_rev(ah);
0239
0240 switch (param) {
0241 case EEP_NFTHRESH_2:
0242 return pModal->noiseFloorThreshCh[0];
0243 case EEP_MAC_LSW:
0244 return get_unaligned_be16(pBase->macAddr);
0245 case EEP_MAC_MID:
0246 return get_unaligned_be16(pBase->macAddr + 2);
0247 case EEP_MAC_MSW:
0248 return get_unaligned_be16(pBase->macAddr + 4);
0249 case EEP_REG_0:
0250 return le16_to_cpu(pBase->regDmn[0]);
0251 case EEP_OP_CAP:
0252 return le16_to_cpu(pBase->deviceCap);
0253 case EEP_OP_MODE:
0254 return pBase->opCapFlags;
0255 case EEP_RF_SILENT:
0256 return le16_to_cpu(pBase->rfSilent);
0257 case EEP_TX_MASK:
0258 return pBase->txMask;
0259 case EEP_RX_MASK:
0260 return pBase->rxMask;
0261 case EEP_DEV_TYPE:
0262 return pBase->deviceType;
0263 case EEP_OL_PWRCTRL:
0264 return pBase->openLoopPwrCntl;
0265 case EEP_TEMPSENSE_SLOPE:
0266 if (ver_minor >= AR9287_EEP_MINOR_VER_2)
0267 return pBase->tempSensSlope;
0268 else
0269 return 0;
0270 case EEP_TEMPSENSE_SLOPE_PAL_ON:
0271 if (ver_minor >= AR9287_EEP_MINOR_VER_3)
0272 return pBase->tempSensSlopePalOn;
0273 else
0274 return 0;
0275 case EEP_ANTENNA_GAIN_2G:
0276 return max_t(u8, pModal->antennaGainCh[0],
0277 pModal->antennaGainCh[1]);
0278 default:
0279 return 0;
0280 }
0281 }
0282
0283 static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
0284 struct ath9k_channel *chan,
0285 struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
0286 u8 *pCalChans, u16 availPiers, int8_t *pPwr)
0287 {
0288 u16 idxL = 0, idxR = 0, numPiers;
0289 bool match;
0290 struct chan_centers centers;
0291
0292 ath9k_hw_get_channel_centers(ah, chan, ¢ers);
0293
0294 for (numPiers = 0; numPiers < availPiers; numPiers++) {
0295 if (pCalChans[numPiers] == AR5416_BCHAN_UNUSED)
0296 break;
0297 }
0298
0299 match = ath9k_hw_get_lower_upper_index(
0300 (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
0301 pCalChans, numPiers, &idxL, &idxR);
0302
0303 if (match) {
0304 *pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
0305 } else {
0306 *pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
0307 (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
0308 }
0309
0310 }
0311
0312 static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
0313 int32_t txPower, u16 chain)
0314 {
0315 u32 tmpVal;
0316 u32 a;
0317
0318
0319
0320 tmpVal = REG_READ(ah, 0xa270);
0321 tmpVal = tmpVal & 0xFCFFFFFF;
0322 tmpVal = tmpVal | (0x3 << 24);
0323 REG_WRITE(ah, 0xa270, tmpVal);
0324
0325
0326
0327 tmpVal = REG_READ(ah, 0xb270);
0328 tmpVal = tmpVal & 0xFCFFFFFF;
0329 tmpVal = tmpVal | (0x3 << 24);
0330 REG_WRITE(ah, 0xb270, tmpVal);
0331
0332
0333
0334 if (chain == 0) {
0335 tmpVal = REG_READ(ah, 0xa398);
0336 tmpVal = tmpVal & 0xff00ffff;
0337 a = (txPower)&0xff;
0338 tmpVal = tmpVal | (a << 16);
0339 REG_WRITE(ah, 0xa398, tmpVal);
0340 }
0341
0342
0343
0344 if (chain == 1) {
0345 tmpVal = REG_READ(ah, 0xb398);
0346 tmpVal = tmpVal & 0xff00ffff;
0347 a = (txPower)&0xff;
0348 tmpVal = tmpVal | (a << 16);
0349 REG_WRITE(ah, 0xb398, tmpVal);
0350 }
0351 }
0352
0353 static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
0354 struct ath9k_channel *chan)
0355 {
0356 struct cal_data_per_freq_ar9287 *pRawDataset;
0357 struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
0358 u8 *pCalBChans = NULL;
0359 u16 pdGainOverlap_t2;
0360 u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
0361 u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
0362 u16 numPiers = 0, i, j;
0363 u16 numXpdGain, xpdMask;
0364 u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
0365 u32 reg32, regOffset, regChainOffset, regval;
0366 int16_t diff = 0;
0367 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0368
0369 xpdMask = pEepData->modalHeader.xpdGain;
0370
0371 if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
0372 pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
0373 else
0374 pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
0375 AR_PHY_TPCRG5_PD_GAIN_OVERLAP));
0376
0377 if (IS_CHAN_2GHZ(chan)) {
0378 pCalBChans = pEepData->calFreqPier2G;
0379 numPiers = AR9287_NUM_2G_CAL_PIERS;
0380 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0381 pRawDatasetOpenLoop =
0382 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
0383 ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
0384 }
0385 }
0386
0387 numXpdGain = 0;
0388
0389
0390 for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
0391 if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
0392 if (numXpdGain >= AR5416_NUM_PD_GAINS)
0393 break;
0394 xpdGainValues[numXpdGain] =
0395 (u16)(AR5416_PD_GAINS_IN_MASK-i);
0396 numXpdGain++;
0397 }
0398 }
0399
0400 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
0401 (numXpdGain - 1) & 0x3);
0402 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1,
0403 xpdGainValues[0]);
0404 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
0405 xpdGainValues[1]);
0406 REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
0407 xpdGainValues[2]);
0408
0409 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
0410 regChainOffset = i * 0x1000;
0411
0412 if (pEepData->baseEepHeader.txMask & (1 << i)) {
0413 pRawDatasetOpenLoop =
0414 (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
0415
0416 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0417 int8_t txPower;
0418 ar9287_eeprom_get_tx_gain_index(ah, chan,
0419 pRawDatasetOpenLoop,
0420 pCalBChans, numPiers,
0421 &txPower);
0422 ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
0423 } else {
0424 pRawDataset =
0425 (struct cal_data_per_freq_ar9287 *)
0426 pEepData->calPierData2G[i];
0427
0428 ath9k_hw_get_gain_boundaries_pdadcs(ah, chan,
0429 pRawDataset,
0430 pCalBChans, numPiers,
0431 pdGainOverlap_t2,
0432 gainBoundaries,
0433 pdadcValues,
0434 numXpdGain);
0435 }
0436
0437 ENABLE_REGWRITE_BUFFER(ah);
0438
0439 if (i == 0) {
0440 if (!ath9k_hw_ar9287_get_eeprom(ah,
0441 EEP_OL_PWRCTRL)) {
0442
0443 regval = SM(pdGainOverlap_t2,
0444 AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
0445 | SM(gainBoundaries[0],
0446 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
0447 | SM(gainBoundaries[1],
0448 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
0449 | SM(gainBoundaries[2],
0450 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
0451 | SM(gainBoundaries[3],
0452 AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
0453
0454 REG_WRITE(ah,
0455 AR_PHY_TPCRG5 + regChainOffset,
0456 regval);
0457 }
0458 }
0459
0460 if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
0461 pEepData->baseEepHeader.pwrTableOffset) {
0462 diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
0463 (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
0464 diff *= 2;
0465
0466 for (j = 0; j < ((u16)AR5416_NUM_PDADC_VALUES-diff); j++)
0467 pdadcValues[j] = pdadcValues[j+diff];
0468
0469 for (j = (u16)(AR5416_NUM_PDADC_VALUES-diff);
0470 j < AR5416_NUM_PDADC_VALUES; j++)
0471 pdadcValues[j] =
0472 pdadcValues[AR5416_NUM_PDADC_VALUES-diff];
0473 }
0474
0475 if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0476 regOffset = AR_PHY_BASE +
0477 (672 << 2) + regChainOffset;
0478
0479 for (j = 0; j < 32; j++) {
0480 reg32 = get_unaligned_le32(&pdadcValues[4 * j]);
0481
0482 REG_WRITE(ah, regOffset, reg32);
0483 regOffset += 4;
0484 }
0485 }
0486 REGWRITE_BUFFER_FLUSH(ah);
0487 }
0488 }
0489 }
0490
0491 static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
0492 struct ath9k_channel *chan,
0493 int16_t *ratesArray,
0494 u16 cfgCtl,
0495 u16 antenna_reduction,
0496 u16 powerLimit)
0497 {
0498 #define CMP_CTL \
0499 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
0500 pEepData->ctlIndex[i])
0501
0502 #define CMP_NO_CTL \
0503 (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
0504 ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
0505
0506 u16 twiceMaxEdgePower;
0507 int i;
0508 struct cal_ctl_data_ar9287 *rep;
0509 struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
0510 targetPowerCck = {0, {0, 0, 0, 0} };
0511 struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
0512 targetPowerCckExt = {0, {0, 0, 0, 0} };
0513 struct cal_target_power_ht targetPowerHt20,
0514 targetPowerHt40 = {0, {0, 0, 0, 0} };
0515 u16 scaledPower = 0, minCtlPower;
0516 static const u16 ctlModesFor11g[] = {
0517 CTL_11B, CTL_11G, CTL_2GHT20,
0518 CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40
0519 };
0520 u16 numCtlModes = 0;
0521 const u16 *pCtlMode = NULL;
0522 u16 ctlMode, freq;
0523 struct chan_centers centers;
0524 int tx_chainmask;
0525 u16 twiceMinEdgePower;
0526 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0527 tx_chainmask = ah->txchainmask;
0528
0529 ath9k_hw_get_channel_centers(ah, chan, ¢ers);
0530 scaledPower = ath9k_hw_get_scaled_power(ah, powerLimit,
0531 antenna_reduction);
0532
0533
0534
0535
0536 if (IS_CHAN_2GHZ(chan)) {
0537
0538 numCtlModes =
0539 ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
0540
0541 pCtlMode = ctlModesFor11g;
0542
0543 ath9k_hw_get_legacy_target_powers(ah, chan,
0544 pEepData->calTargetPowerCck,
0545 AR9287_NUM_2G_CCK_TARGET_POWERS,
0546 &targetPowerCck, 4, false);
0547 ath9k_hw_get_legacy_target_powers(ah, chan,
0548 pEepData->calTargetPower2G,
0549 AR9287_NUM_2G_20_TARGET_POWERS,
0550 &targetPowerOfdm, 4, false);
0551 ath9k_hw_get_target_powers(ah, chan,
0552 pEepData->calTargetPower2GHT20,
0553 AR9287_NUM_2G_20_TARGET_POWERS,
0554 &targetPowerHt20, 8, false);
0555
0556 if (IS_CHAN_HT40(chan)) {
0557
0558 numCtlModes = ARRAY_SIZE(ctlModesFor11g);
0559 ath9k_hw_get_target_powers(ah, chan,
0560 pEepData->calTargetPower2GHT40,
0561 AR9287_NUM_2G_40_TARGET_POWERS,
0562 &targetPowerHt40, 8, true);
0563 ath9k_hw_get_legacy_target_powers(ah, chan,
0564 pEepData->calTargetPowerCck,
0565 AR9287_NUM_2G_CCK_TARGET_POWERS,
0566 &targetPowerCckExt, 4, true);
0567 ath9k_hw_get_legacy_target_powers(ah, chan,
0568 pEepData->calTargetPower2G,
0569 AR9287_NUM_2G_20_TARGET_POWERS,
0570 &targetPowerOfdmExt, 4, true);
0571 }
0572 }
0573
0574 for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
0575 bool isHt40CtlMode =
0576 (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
0577
0578 if (isHt40CtlMode)
0579 freq = centers.synth_center;
0580 else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
0581 freq = centers.ext_center;
0582 else
0583 freq = centers.ctl_center;
0584
0585 twiceMaxEdgePower = MAX_RATE_POWER;
0586
0587 for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
0588 struct cal_ctl_edges *pRdEdgesPower;
0589
0590
0591
0592
0593
0594 if (CMP_CTL || CMP_NO_CTL) {
0595 rep = &(pEepData->ctlData[i]);
0596 pRdEdgesPower =
0597 rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
0598
0599 twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
0600 pRdEdgesPower,
0601 IS_CHAN_2GHZ(chan),
0602 AR5416_NUM_BAND_EDGES);
0603
0604 if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
0605 twiceMaxEdgePower = min(twiceMaxEdgePower,
0606 twiceMinEdgePower);
0607 } else {
0608 twiceMaxEdgePower = twiceMinEdgePower;
0609 break;
0610 }
0611 }
0612 }
0613
0614 minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
0615
0616
0617 switch (pCtlMode[ctlMode]) {
0618 case CTL_11B:
0619 for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
0620 targetPowerCck.tPow2x[i] =
0621 (u8)min((u16)targetPowerCck.tPow2x[i],
0622 minCtlPower);
0623 }
0624 break;
0625 case CTL_11A:
0626 case CTL_11G:
0627 for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
0628 targetPowerOfdm.tPow2x[i] =
0629 (u8)min((u16)targetPowerOfdm.tPow2x[i],
0630 minCtlPower);
0631 }
0632 break;
0633 case CTL_5GHT20:
0634 case CTL_2GHT20:
0635 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
0636 targetPowerHt20.tPow2x[i] =
0637 (u8)min((u16)targetPowerHt20.tPow2x[i],
0638 minCtlPower);
0639 }
0640 break;
0641 case CTL_11B_EXT:
0642 targetPowerCckExt.tPow2x[0] =
0643 (u8)min((u16)targetPowerCckExt.tPow2x[0],
0644 minCtlPower);
0645 break;
0646 case CTL_11A_EXT:
0647 case CTL_11G_EXT:
0648 targetPowerOfdmExt.tPow2x[0] =
0649 (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
0650 minCtlPower);
0651 break;
0652 case CTL_5GHT40:
0653 case CTL_2GHT40:
0654 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
0655 targetPowerHt40.tPow2x[i] =
0656 (u8)min((u16)targetPowerHt40.tPow2x[i],
0657 minCtlPower);
0658 }
0659 break;
0660 default:
0661 break;
0662 }
0663 }
0664
0665
0666
0667 ratesArray[rate6mb] =
0668 ratesArray[rate9mb] =
0669 ratesArray[rate12mb] =
0670 ratesArray[rate18mb] =
0671 ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
0672
0673 ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
0674 ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
0675 ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3];
0676 ratesArray[rateXr] = targetPowerOfdm.tPow2x[0];
0677
0678 for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++)
0679 ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i];
0680
0681 if (IS_CHAN_2GHZ(chan)) {
0682 ratesArray[rate1l] = targetPowerCck.tPow2x[0];
0683 ratesArray[rate2s] =
0684 ratesArray[rate2l] = targetPowerCck.tPow2x[1];
0685 ratesArray[rate5_5s] =
0686 ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
0687 ratesArray[rate11s] =
0688 ratesArray[rate11l] = targetPowerCck.tPow2x[3];
0689 }
0690 if (IS_CHAN_HT40(chan)) {
0691 for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
0692 ratesArray[rateHt40_0 + i] = targetPowerHt40.tPow2x[i];
0693
0694 ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
0695 ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
0696 ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
0697
0698 if (IS_CHAN_2GHZ(chan))
0699 ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
0700 }
0701
0702 #undef CMP_CTL
0703 #undef CMP_NO_CTL
0704 }
0705
0706 static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
0707 struct ath9k_channel *chan, u16 cfgCtl,
0708 u8 twiceAntennaReduction,
0709 u8 powerLimit, bool test)
0710 {
0711 struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
0712 struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
0713 struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
0714 int16_t ratesArray[Ar5416RateSize];
0715 u8 ht40PowerIncForPdadc = 2;
0716 int i;
0717
0718 memset(ratesArray, 0, sizeof(ratesArray));
0719
0720 if (ath9k_hw_ar9287_get_eeprom_rev(ah) >= AR9287_EEP_MINOR_VER_2)
0721 ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
0722
0723 ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
0724 &ratesArray[0], cfgCtl,
0725 twiceAntennaReduction,
0726 powerLimit);
0727
0728 ath9k_hw_set_ar9287_power_cal_table(ah, chan);
0729
0730 regulatory->max_power_level = 0;
0731 for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
0732 if (ratesArray[i] > MAX_RATE_POWER)
0733 ratesArray[i] = MAX_RATE_POWER;
0734
0735 if (ratesArray[i] > regulatory->max_power_level)
0736 regulatory->max_power_level = ratesArray[i];
0737 }
0738
0739 ath9k_hw_update_regulatory_maxpower(ah);
0740
0741 if (test)
0742 return;
0743
0744 for (i = 0; i < Ar5416RateSize; i++)
0745 ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
0746
0747 ENABLE_REGWRITE_BUFFER(ah);
0748
0749
0750 REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
0751 ATH9K_POW_SM(ratesArray[rate18mb], 24)
0752 | ATH9K_POW_SM(ratesArray[rate12mb], 16)
0753 | ATH9K_POW_SM(ratesArray[rate9mb], 8)
0754 | ATH9K_POW_SM(ratesArray[rate6mb], 0));
0755
0756 REG_WRITE(ah, AR_PHY_POWER_TX_RATE2,
0757 ATH9K_POW_SM(ratesArray[rate54mb], 24)
0758 | ATH9K_POW_SM(ratesArray[rate48mb], 16)
0759 | ATH9K_POW_SM(ratesArray[rate36mb], 8)
0760 | ATH9K_POW_SM(ratesArray[rate24mb], 0));
0761
0762
0763 if (IS_CHAN_2GHZ(chan)) {
0764 REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
0765 ATH9K_POW_SM(ratesArray[rate2s], 24)
0766 | ATH9K_POW_SM(ratesArray[rate2l], 16)
0767 | ATH9K_POW_SM(ratesArray[rateXr], 8)
0768 | ATH9K_POW_SM(ratesArray[rate1l], 0));
0769 REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
0770 ATH9K_POW_SM(ratesArray[rate11s], 24)
0771 | ATH9K_POW_SM(ratesArray[rate11l], 16)
0772 | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
0773 | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
0774 }
0775
0776
0777 REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
0778 ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
0779 | ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
0780 | ATH9K_POW_SM(ratesArray[rateHt20_1], 8)
0781 | ATH9K_POW_SM(ratesArray[rateHt20_0], 0));
0782
0783 REG_WRITE(ah, AR_PHY_POWER_TX_RATE6,
0784 ATH9K_POW_SM(ratesArray[rateHt20_7], 24)
0785 | ATH9K_POW_SM(ratesArray[rateHt20_6], 16)
0786 | ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
0787 | ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
0788
0789
0790 if (IS_CHAN_HT40(chan)) {
0791 if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
0792 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
0793 ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
0794 | ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
0795 | ATH9K_POW_SM(ratesArray[rateHt40_1], 8)
0796 | ATH9K_POW_SM(ratesArray[rateHt40_0], 0));
0797
0798 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
0799 ATH9K_POW_SM(ratesArray[rateHt40_7], 24)
0800 | ATH9K_POW_SM(ratesArray[rateHt40_6], 16)
0801 | ATH9K_POW_SM(ratesArray[rateHt40_5], 8)
0802 | ATH9K_POW_SM(ratesArray[rateHt40_4], 0));
0803 } else {
0804 REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
0805 ATH9K_POW_SM(ratesArray[rateHt40_3] +
0806 ht40PowerIncForPdadc, 24)
0807 | ATH9K_POW_SM(ratesArray[rateHt40_2] +
0808 ht40PowerIncForPdadc, 16)
0809 | ATH9K_POW_SM(ratesArray[rateHt40_1] +
0810 ht40PowerIncForPdadc, 8)
0811 | ATH9K_POW_SM(ratesArray[rateHt40_0] +
0812 ht40PowerIncForPdadc, 0));
0813
0814 REG_WRITE(ah, AR_PHY_POWER_TX_RATE8,
0815 ATH9K_POW_SM(ratesArray[rateHt40_7] +
0816 ht40PowerIncForPdadc, 24)
0817 | ATH9K_POW_SM(ratesArray[rateHt40_6] +
0818 ht40PowerIncForPdadc, 16)
0819 | ATH9K_POW_SM(ratesArray[rateHt40_5] +
0820 ht40PowerIncForPdadc, 8)
0821 | ATH9K_POW_SM(ratesArray[rateHt40_4] +
0822 ht40PowerIncForPdadc, 0));
0823 }
0824
0825
0826 REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
0827 ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
0828 | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
0829 | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
0830 | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
0831 }
0832
0833
0834 if (ah->tpc_enabled) {
0835 int ht40_delta;
0836
0837 ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
0838 ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
0839
0840 REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
0841 MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
0842 } else {
0843
0844 REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
0845 }
0846
0847 REGWRITE_BUFFER_FLUSH(ah);
0848 }
0849
0850 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
0851 struct ath9k_channel *chan)
0852 {
0853 struct ar9287_eeprom *eep = &ah->eeprom.map9287;
0854 struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
0855 u32 regChainOffset, regval;
0856 u8 txRxAttenLocal;
0857 int i;
0858
0859 pModal = &eep->modalHeader;
0860
0861 REG_WRITE(ah, AR_PHY_SWITCH_COM, le32_to_cpu(pModal->antCtrlCommon));
0862
0863 for (i = 0; i < AR9287_MAX_CHAINS; i++) {
0864 regChainOffset = i * 0x1000;
0865
0866 REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset,
0867 le32_to_cpu(pModal->antCtrlChain[i]));
0868
0869 REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset,
0870 (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset)
0871 & ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF |
0872 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) |
0873 SM(pModal->iqCalICh[i],
0874 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) |
0875 SM(pModal->iqCalQCh[i],
0876 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
0877
0878 txRxAttenLocal = pModal->txRxAttenCh[i];
0879
0880 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
0881 AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
0882 pModal->bswMargin[i]);
0883 REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
0884 AR_PHY_GAIN_2GHZ_XATTEN1_DB,
0885 pModal->bswAtten[i]);
0886 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
0887 AR9280_PHY_RXGAIN_TXRX_ATTEN,
0888 txRxAttenLocal);
0889 REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
0890 AR9280_PHY_RXGAIN_TXRX_MARGIN,
0891 pModal->rxTxMarginCh[i]);
0892 }
0893
0894
0895 if (IS_CHAN_HT40(chan))
0896 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
0897 AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40);
0898 else
0899 REG_RMW_FIELD(ah, AR_PHY_SETTLING,
0900 AR_PHY_SETTLING_SWITCH, pModal->switchSettling);
0901
0902 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
0903 AR_PHY_DESIRED_SZ_ADC, pModal->adcDesiredSize);
0904
0905 REG_WRITE(ah, AR_PHY_RF_CTL4,
0906 SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF)
0907 | SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF)
0908 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON)
0909 | SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON));
0910
0911 REG_RMW_FIELD(ah, AR_PHY_RF_CTL3,
0912 AR_PHY_TX_END_TO_A2_RX_ON, pModal->txEndToRxOn);
0913
0914 REG_RMW_FIELD(ah, AR_PHY_CCA,
0915 AR9280_PHY_CCA_THRESH62, pModal->thresh62);
0916 REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
0917 AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
0918
0919 regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
0920 regval &= ~(AR9287_AN_RF2G3_DB1 |
0921 AR9287_AN_RF2G3_DB2 |
0922 AR9287_AN_RF2G3_OB_CCK |
0923 AR9287_AN_RF2G3_OB_PSK |
0924 AR9287_AN_RF2G3_OB_QAM |
0925 AR9287_AN_RF2G3_OB_PAL_OFF);
0926 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
0927 SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
0928 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
0929 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
0930 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
0931 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
0932
0933 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
0934
0935 regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
0936 regval &= ~(AR9287_AN_RF2G3_DB1 |
0937 AR9287_AN_RF2G3_DB2 |
0938 AR9287_AN_RF2G3_OB_CCK |
0939 AR9287_AN_RF2G3_OB_PSK |
0940 AR9287_AN_RF2G3_OB_QAM |
0941 AR9287_AN_RF2G3_OB_PAL_OFF);
0942 regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
0943 SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
0944 SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
0945 SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
0946 SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
0947 SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
0948
0949 ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
0950
0951 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
0952 AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
0953 REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
0954 AR_PHY_TX_END_PA_ON, pModal->txFrameToPaOn);
0955
0956 ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TOP2,
0957 AR9287_AN_TOP2_XPABIAS_LVL,
0958 AR9287_AN_TOP2_XPABIAS_LVL_S,
0959 pModal->xpaBiasLvl);
0960 }
0961
0962 static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
0963 u16 i, bool is2GHz)
0964 {
0965 __le16 spur_ch = ah->eeprom.map9287.modalHeader.spurChans[i].spurChan;
0966
0967 return le16_to_cpu(spur_ch);
0968 }
0969
0970 static u8 ath9k_hw_ar9287_get_eepmisc(struct ath_hw *ah)
0971 {
0972 return ah->eeprom.map9287.baseEepHeader.eepMisc;
0973 }
0974
0975 const struct eeprom_ops eep_ar9287_ops = {
0976 .check_eeprom = ath9k_hw_ar9287_check_eeprom,
0977 .get_eeprom = ath9k_hw_ar9287_get_eeprom,
0978 .fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
0979 .dump_eeprom = ath9k_hw_ar9287_dump_eeprom,
0980 .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
0981 .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
0982 .set_board_values = ath9k_hw_ar9287_set_board_values,
0983 .set_txpower = ath9k_hw_ar9287_set_txpower,
0984 .get_spur_channel = ath9k_hw_ar9287_get_spur_channel,
0985 .get_eepmisc = ath9k_hw_ar9287_get_eepmisc
0986 };