iPXE
ath9k_ar9002_calib.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008-2011 Atheros Communications Inc.
00003  *
00004  * Modified for iPXE by Scott K Logan <logans@cottsay.net> July 2011
00005  * Original from Linux kernel 3.0.1
00006  *
00007  * Permission to use, copy, modify, and/or distribute this software for any
00008  * purpose with or without fee is hereby granted, provided that the above
00009  * copyright notice and this permission notice appear in all copies.
00010  *
00011  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00012  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00013  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00014  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00015  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00016  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00017  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00018  */
00019 
00020 #include "hw.h"
00021 #include "hw-ops.h"
00022 #include "ar9002_phy.h"
00023 
00024 #define AR9285_CLCAL_REDO_THRESH    1
00025 
00026 enum ar9002_cal_types {
00027         ADC_GAIN_CAL = BIT(0),
00028         ADC_DC_CAL = BIT(1),
00029         IQ_MISMATCH_CAL = BIT(2),
00030 };
00031 
00032 static int ar9002_hw_is_cal_supported(struct ath_hw *ah,
00033                                 struct ath9k_channel *chan,
00034                                 enum ar9002_cal_types cal_type)
00035 {
00036         int supported = 0;
00037         switch (ah->supp_cals & cal_type) {
00038         case IQ_MISMATCH_CAL:
00039                 /* Run IQ Mismatch for non-CCK only */
00040                 if (!IS_CHAN_B(chan))
00041                         supported = 1;
00042                 break;
00043         case ADC_GAIN_CAL:
00044         case ADC_DC_CAL:
00045                 /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
00046                 if (!IS_CHAN_B(chan) &&
00047                     !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
00048                         supported = 1;
00049                 break;
00050         }
00051         return supported;
00052 }
00053 
00054 static void ar9002_hw_setup_calibration(struct ath_hw *ah,
00055                                         struct ath9k_cal_list *currCal)
00056 {
00057         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
00058                       AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
00059                       currCal->calData->calCountMax);
00060 
00061         switch (currCal->calData->calType) {
00062         case IQ_MISMATCH_CAL:
00063                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
00064                 DBG2("ath9k: "
00065                         "starting IQ Mismatch Calibration\n");
00066                 break;
00067         case ADC_GAIN_CAL:
00068                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
00069                 DBG2("ath9k: "
00070                         "starting ADC Gain Calibration\n");
00071                 break;
00072         case ADC_DC_CAL:
00073                 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
00074                 DBG2("ath9k: "
00075                         "starting ADC DC Calibration\n");
00076                 break;
00077         }
00078 
00079         REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
00080                     AR_PHY_TIMING_CTRL4_DO_CAL);
00081 }
00082 
00083 static int ar9002_hw_per_calibration(struct ath_hw *ah,
00084                                       struct ath9k_channel *ichan __unused,
00085                                       u8 rxchainmask,
00086                                       struct ath9k_cal_list *currCal)
00087 {
00088         struct ath9k_hw_cal_data *caldata = ah->caldata;
00089         int iscaldone = 0;
00090 
00091         if (currCal->calState == CAL_RUNNING) {
00092                 if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
00093                       AR_PHY_TIMING_CTRL4_DO_CAL)) {
00094 
00095                         currCal->calData->calCollect(ah);
00096                         ah->cal_samples++;
00097 
00098                         if (ah->cal_samples >=
00099                             currCal->calData->calNumSamples) {
00100                                 int i, numChains = 0;
00101                                 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
00102                                         if (rxchainmask & (1 << i))
00103                                                 numChains++;
00104                                 }
00105 
00106                                 currCal->calData->calPostProc(ah, numChains);
00107                                 caldata->CalValid |= currCal->calData->calType;
00108                                 currCal->calState = CAL_DONE;
00109                                 iscaldone = 1;
00110                         } else {
00111                                 ar9002_hw_setup_calibration(ah, currCal);
00112                         }
00113                 }
00114         } else if (!(caldata->CalValid & currCal->calData->calType)) {
00115                 ath9k_hw_reset_calibration(ah, currCal);
00116         }
00117 
00118         return iscaldone;
00119 }
00120 
00121 static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
00122 {
00123         int i;
00124 
00125         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
00126                 ah->totalPowerMeasI[i] +=
00127                         REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
00128                 ah->totalPowerMeasQ[i] +=
00129                         REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
00130                 ah->totalIqCorrMeas[i] +=
00131                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
00132                 DBG2("ath9k: "
00133                         "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
00134                         ah->cal_samples, i, ah->totalPowerMeasI[i],
00135                         ah->totalPowerMeasQ[i],
00136                         ah->totalIqCorrMeas[i]);
00137         }
00138 }
00139 
00140 static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
00141 {
00142         int i;
00143 
00144         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
00145                 ah->totalAdcIOddPhase[i] +=
00146                         REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
00147                 ah->totalAdcIEvenPhase[i] +=
00148                         REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
00149                 ah->totalAdcQOddPhase[i] +=
00150                         REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
00151                 ah->totalAdcQEvenPhase[i] +=
00152                         REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
00153 
00154                 DBG2("ath9k: "
00155                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
00156                         ah->cal_samples, i,
00157                         ah->totalAdcIOddPhase[i],
00158                         ah->totalAdcIEvenPhase[i],
00159                         ah->totalAdcQOddPhase[i],
00160                         ah->totalAdcQEvenPhase[i]);
00161         }
00162 }
00163 
00164 static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
00165 {
00166         int i;
00167 
00168         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
00169                 ah->totalAdcDcOffsetIOddPhase[i] +=
00170                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
00171                 ah->totalAdcDcOffsetIEvenPhase[i] +=
00172                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
00173                 ah->totalAdcDcOffsetQOddPhase[i] +=
00174                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
00175                 ah->totalAdcDcOffsetQEvenPhase[i] +=
00176                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
00177 
00178                 DBG2("ath9k: "
00179                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
00180                         ah->cal_samples, i,
00181                         ah->totalAdcDcOffsetIOddPhase[i],
00182                         ah->totalAdcDcOffsetIEvenPhase[i],
00183                         ah->totalAdcDcOffsetQOddPhase[i],
00184                         ah->totalAdcDcOffsetQEvenPhase[i]);
00185         }
00186 }
00187 
00188 static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
00189 {
00190         u32 powerMeasQ, powerMeasI, iqCorrMeas;
00191         u32 qCoffDenom, iCoffDenom;
00192         int32_t qCoff, iCoff;
00193         int iqCorrNeg, i;
00194 
00195         for (i = 0; i < numChains; i++) {
00196                 powerMeasI = ah->totalPowerMeasI[i];
00197                 powerMeasQ = ah->totalPowerMeasQ[i];
00198                 iqCorrMeas = ah->totalIqCorrMeas[i];
00199 
00200                 DBG2("ath9k: "
00201                         "Starting IQ Cal and Correction for Chain %d\n",
00202                         i);
00203 
00204                 DBG2("ath9k: "
00205                         "Orignal: Chn %diq_corr_meas = 0x%08x\n",
00206                         i, ah->totalIqCorrMeas[i]);
00207 
00208                 iqCorrNeg = 0;
00209 
00210                 if (iqCorrMeas > 0x80000000) {
00211                         iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
00212                         iqCorrNeg = 1;
00213                 }
00214 
00215                 DBG2("ath9k: "
00216                         "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
00217                 DBG2("ath9k: "
00218                         "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
00219                 DBG2("ath9k: iqCorrNeg is 0x%08x\n",
00220                         iqCorrNeg);
00221 
00222                 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
00223                 qCoffDenom = powerMeasQ / 64;
00224 
00225                 if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
00226                     (qCoffDenom != 0)) {
00227                         iCoff = iqCorrMeas / iCoffDenom;
00228                         qCoff = powerMeasI / qCoffDenom - 64;
00229                         DBG2("ath9k: "
00230                                 "Chn %d iCoff = 0x%08x\n", i, iCoff);
00231                         DBG2("ath9k: "
00232                                 "Chn %d qCoff = 0x%08x\n", i, qCoff);
00233 
00234                         iCoff = iCoff & 0x3f;
00235                         DBG2("ath9k: "
00236                                 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
00237                         if (iqCorrNeg == 0x0)
00238                                 iCoff = 0x40 - iCoff;
00239 
00240                         if (qCoff > 15)
00241                                 qCoff = 15;
00242                         else if (qCoff <= -16)
00243                                 qCoff = -16;
00244 
00245                         DBG2("ath9k: "
00246                                 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
00247                                 i, iCoff, qCoff);
00248 
00249                         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
00250                                       AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
00251                                       iCoff);
00252                         REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
00253                                       AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
00254                                       qCoff);
00255                         DBG2("ath9k: "
00256                                 "IQ Cal and Correction done for Chain %d\n",
00257                                 i);
00258                 }
00259         }
00260 
00261         REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
00262                     AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
00263 }
00264 
00265 static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
00266 {
00267         u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
00268         u32 qGainMismatch, iGainMismatch, val, i;
00269 
00270         for (i = 0; i < numChains; i++) {
00271                 iOddMeasOffset = ah->totalAdcIOddPhase[i];
00272                 iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
00273                 qOddMeasOffset = ah->totalAdcQOddPhase[i];
00274                 qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
00275 
00276                 DBG2("ath9k: "
00277                         "Starting ADC Gain Cal for Chain %d\n", i);
00278 
00279                 DBG2("ath9k: "
00280                         "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
00281                         iOddMeasOffset);
00282                 DBG2("ath9k: "
00283                         "Chn %d pwr_meas_even_i = 0x%08x\n", i,
00284                         iEvenMeasOffset);
00285                 DBG2("ath9k: "
00286                         "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
00287                         qOddMeasOffset);
00288                 DBG2("ath9k: "
00289                         "Chn %d pwr_meas_even_q = 0x%08x\n", i,
00290                         qEvenMeasOffset);
00291 
00292                 if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
00293                         iGainMismatch =
00294                                 ((iEvenMeasOffset * 32) /
00295                                  iOddMeasOffset) & 0x3f;
00296                         qGainMismatch =
00297                                 ((qOddMeasOffset * 32) /
00298                                  qEvenMeasOffset) & 0x3f;
00299 
00300                         DBG2("ath9k: "
00301                                 "Chn %d gain_mismatch_i = 0x%08x\n", i,
00302                                 iGainMismatch);
00303                         DBG2("ath9k: "
00304                                 "Chn %d gain_mismatch_q = 0x%08x\n", i,
00305                                 qGainMismatch);
00306 
00307                         val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
00308                         val &= 0xfffff000;
00309                         val |= (qGainMismatch) | (iGainMismatch << 6);
00310                         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
00311 
00312                         DBG2("ath9k: "
00313                                 "ADC Gain Cal done for Chain %d\n", i);
00314                 }
00315         }
00316 
00317         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
00318                   REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
00319                   AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
00320 }
00321 
00322 static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
00323 {
00324         u32 iOddMeasOffset, iEvenMeasOffset, val, i;
00325         int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
00326         const struct ath9k_percal_data *calData =
00327                 ah->cal_list_curr->calData;
00328         u32 numSamples =
00329                 (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
00330 
00331         for (i = 0; i < numChains; i++) {
00332                 iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
00333                 iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
00334                 qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
00335                 qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
00336 
00337                 DBG2("ath9k: "
00338                         "Starting ADC DC Offset Cal for Chain %d\n", i);
00339 
00340                 DBG2("ath9k: "
00341                         "Chn %d pwr_meas_odd_i = %d\n", i,
00342                         iOddMeasOffset);
00343                 DBG2("ath9k: "
00344                         "Chn %d pwr_meas_even_i = %d\n", i,
00345                         iEvenMeasOffset);
00346                 DBG2("ath9k: "
00347                         "Chn %d pwr_meas_odd_q = %d\n", i,
00348                         qOddMeasOffset);
00349                 DBG2("ath9k: "
00350                         "Chn %d pwr_meas_even_q = %d\n", i,
00351                         qEvenMeasOffset);
00352 
00353                 iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
00354                                numSamples) & 0x1ff;
00355                 qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
00356                                numSamples) & 0x1ff;
00357 
00358                 DBG2("ath9k: "
00359                         "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
00360                         iDcMismatch);
00361                 DBG2("ath9k: "
00362                         "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
00363                         qDcMismatch);
00364 
00365                 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
00366                 val &= 0xc0000fff;
00367                 val |= (qDcMismatch << 12) | (iDcMismatch << 21);
00368                 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
00369 
00370                 DBG2("ath9k: "
00371                         "ADC DC Offset Cal done for Chain %d\n", i);
00372         }
00373 
00374         REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
00375                   REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
00376                   AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
00377 }
00378 
00379 static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
00380 {
00381         u32 rddata;
00382         int32_t delta, currPDADC, slope;
00383 
00384         rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
00385         currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
00386 
00387         if (ah->initPDADC == 0 || currPDADC == 0) {
00388                 /*
00389                  * Zero value indicates that no frames have been transmitted
00390                  * yet, can't do temperature compensation until frames are
00391                  * transmitted.
00392                  */
00393                 return;
00394         } else {
00395                 slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
00396 
00397                 if (slope == 0) { /* to avoid divide by zero case */
00398                         delta = 0;
00399                 } else {
00400                         delta = ((currPDADC - ah->initPDADC)*4) / slope;
00401                 }
00402                 REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
00403                               AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
00404                 REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
00405                               AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
00406         }
00407 }
00408 
00409 static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
00410 {
00411         u32 rddata, i;
00412         int delta, currPDADC, regval;
00413 
00414         rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
00415         currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
00416 
00417         if (ah->initPDADC == 0 || currPDADC == 0)
00418                 return;
00419 
00420         if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
00421                 delta = (currPDADC - ah->initPDADC + 4) / 8;
00422         else
00423                 delta = (currPDADC - ah->initPDADC + 5) / 10;
00424 
00425         if (delta != ah->PDADCdelta) {
00426                 ah->PDADCdelta = delta;
00427                 for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
00428                         regval = ah->originalGain[i] - delta;
00429                         if (regval < 0)
00430                                 regval = 0;
00431 
00432                         REG_RMW_FIELD(ah,
00433                                       AR_PHY_TX_GAIN_TBL1 + i * 4,
00434                                       AR_PHY_TX_GAIN, regval);
00435                 }
00436         }
00437 }
00438 
00439 static void ar9271_hw_pa_cal(struct ath_hw *ah, int is_reset)
00440 {
00441         u32 regVal;
00442         unsigned int i;
00443         u32 regList[][2] = {
00444                 { 0x786c, 0 },
00445                 { 0x7854, 0 },
00446                 { 0x7820, 0 },
00447                 { 0x7824, 0 },
00448                 { 0x7868, 0 },
00449                 { 0x783c, 0 },
00450                 { 0x7838, 0 } ,
00451                 { 0x7828, 0 } ,
00452         };
00453 
00454         for (i = 0; i < ARRAY_SIZE(regList); i++)
00455                 regList[i][1] = REG_READ(ah, regList[i][0]);
00456 
00457         regVal = REG_READ(ah, 0x7834);
00458         regVal &= (~(0x1));
00459         REG_WRITE(ah, 0x7834, regVal);
00460         regVal = REG_READ(ah, 0x9808);
00461         regVal |= (0x1 << 27);
00462         REG_WRITE(ah, 0x9808, regVal);
00463 
00464         /* 786c,b23,1, pwddac=1 */
00465         REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
00466         /* 7854, b5,1, pdrxtxbb=1 */
00467         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
00468         /* 7854, b7,1, pdv2i=1 */
00469         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
00470         /* 7854, b8,1, pddacinterface=1 */
00471         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
00472         /* 7824,b12,0, offcal=0 */
00473         REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
00474         /* 7838, b1,0, pwddb=0 */
00475         REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
00476         /* 7820,b11,0, enpacal=0 */
00477         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
00478         /* 7820,b25,1, pdpadrv1=0 */
00479         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
00480         /* 7820,b24,0, pdpadrv2=0 */
00481         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
00482         /* 7820,b23,0, pdpaout=0 */
00483         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
00484         /* 783c,b14-16,7, padrvgn2tab_0=7 */
00485         REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
00486         /*
00487          * 7838,b29-31,0, padrvgn1tab_0=0
00488          * does not matter since we turn it off
00489          */
00490         REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
00491 
00492         REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
00493 
00494         /* Set:
00495          * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
00496          * txon=1,paon=1,oscon=1,synthon_force=1
00497          */
00498         REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
00499         udelay(30);
00500         REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
00501 
00502         /* find off_6_1; */
00503         for (i = 6; i > 0; i--) {
00504                 regVal = REG_READ(ah, 0x7834);
00505                 regVal |= (1 << (20 + i));
00506                 REG_WRITE(ah, 0x7834, regVal);
00507                 udelay(1);
00508                 /* regVal = REG_READ(ah, 0x7834); */
00509                 regVal &= (~(0x1 << (20 + i)));
00510                 regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
00511                             << (20 + i));
00512                 REG_WRITE(ah, 0x7834, regVal);
00513         }
00514 
00515         regVal = (regVal >> 20) & 0x7f;
00516 
00517         /* Update PA cal info */
00518         if ((!is_reset) && ((unsigned int)ah->pacal_info.prev_offset == regVal)) {
00519                 if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
00520                         ah->pacal_info.max_skipcount =
00521                                 2 * ah->pacal_info.max_skipcount;
00522                 ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
00523         } else {
00524                 ah->pacal_info.max_skipcount = 1;
00525                 ah->pacal_info.skipcount = 0;
00526                 ah->pacal_info.prev_offset = regVal;
00527         }
00528 
00529         ENABLE_REGWRITE_BUFFER(ah);
00530 
00531         regVal = REG_READ(ah, 0x7834);
00532         regVal |= 0x1;
00533         REG_WRITE(ah, 0x7834, regVal);
00534         regVal = REG_READ(ah, 0x9808);
00535         regVal &= (~(0x1 << 27));
00536         REG_WRITE(ah, 0x9808, regVal);
00537 
00538         for (i = 0; i < ARRAY_SIZE(regList); i++)
00539                 REG_WRITE(ah, regList[i][0], regList[i][1]);
00540 
00541         REGWRITE_BUFFER_FLUSH(ah);
00542 }
00543 
00544 static inline void ar9285_hw_pa_cal(struct ath_hw *ah, int is_reset)
00545 {
00546         u32 regVal;
00547         unsigned int i;
00548         int offset, offs_6_1, offs_0;
00549         u32 ccomp_org, reg_field;
00550         u32 regList[][2] = {
00551                 { 0x786c, 0 },
00552                 { 0x7854, 0 },
00553                 { 0x7820, 0 },
00554                 { 0x7824, 0 },
00555                 { 0x7868, 0 },
00556                 { 0x783c, 0 },
00557                 { 0x7838, 0 },
00558         };
00559 
00560         DBG2("ath9k: Running PA Calibration\n");
00561 
00562         /* PA CAL is not needed for high power solution */
00563         if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
00564             AR5416_EEP_TXGAIN_HIGH_POWER)
00565                 return;
00566 
00567         for (i = 0; i < ARRAY_SIZE(regList); i++)
00568                 regList[i][1] = REG_READ(ah, regList[i][0]);
00569 
00570         regVal = REG_READ(ah, 0x7834);
00571         regVal &= (~(0x1));
00572         REG_WRITE(ah, 0x7834, regVal);
00573         regVal = REG_READ(ah, 0x9808);
00574         regVal |= (0x1 << 27);
00575         REG_WRITE(ah, 0x9808, regVal);
00576 
00577         REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
00578         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
00579         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
00580         REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
00581         REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
00582         REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
00583         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
00584         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
00585         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
00586         REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
00587         REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
00588         REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
00589         ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
00590         REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
00591 
00592         REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
00593         udelay(30);
00594         REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
00595         REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
00596 
00597         for (i = 6; i > 0; i--) {
00598                 regVal = REG_READ(ah, 0x7834);
00599                 regVal |= (1 << (19 + i));
00600                 REG_WRITE(ah, 0x7834, regVal);
00601                 udelay(1);
00602                 regVal = REG_READ(ah, 0x7834);
00603                 regVal &= (~(0x1 << (19 + i)));
00604                 reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
00605                 regVal |= (reg_field << (19 + i));
00606                 REG_WRITE(ah, 0x7834, regVal);
00607         }
00608 
00609         REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
00610         udelay(1);
00611         reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
00612         REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
00613         offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
00614         offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
00615 
00616         offset = (offs_6_1<<1) | offs_0;
00617         offset = offset - 0;
00618         offs_6_1 = offset>>1;
00619         offs_0 = offset & 1;
00620 
00621         if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
00622                 if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
00623                         ah->pacal_info.max_skipcount =
00624                                 2 * ah->pacal_info.max_skipcount;
00625                 ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
00626         } else {
00627                 ah->pacal_info.max_skipcount = 1;
00628                 ah->pacal_info.skipcount = 0;
00629                 ah->pacal_info.prev_offset = offset;
00630         }
00631 
00632         REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
00633         REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
00634 
00635         regVal = REG_READ(ah, 0x7834);
00636         regVal |= 0x1;
00637         REG_WRITE(ah, 0x7834, regVal);
00638         regVal = REG_READ(ah, 0x9808);
00639         regVal &= (~(0x1 << 27));
00640         REG_WRITE(ah, 0x9808, regVal);
00641 
00642         for (i = 0; i < ARRAY_SIZE(regList); i++)
00643                 REG_WRITE(ah, regList[i][0], regList[i][1]);
00644 
00645         REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
00646 }
00647 
00648 static void ar9002_hw_pa_cal(struct ath_hw *ah, int is_reset)
00649 {
00650         if (AR_SREV_9271(ah)) {
00651                 if (is_reset || !ah->pacal_info.skipcount)
00652                         ar9271_hw_pa_cal(ah, is_reset);
00653                 else
00654                         ah->pacal_info.skipcount--;
00655         } else if (AR_SREV_9285_12_OR_LATER(ah)) {
00656                 if (is_reset || !ah->pacal_info.skipcount)
00657                         ar9285_hw_pa_cal(ah, is_reset);
00658                 else
00659                         ah->pacal_info.skipcount--;
00660         }
00661 }
00662 
00663 static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
00664 {
00665         if (OLC_FOR_AR9287_10_LATER)
00666                 ar9287_hw_olc_temp_compensation(ah);
00667         else if (OLC_FOR_AR9280_20_LATER)
00668                 ar9280_hw_olc_temp_compensation(ah);
00669 }
00670 
00671 static int ar9002_hw_calibrate(struct ath_hw *ah,
00672                                 struct ath9k_channel *chan,
00673                                 u8 rxchainmask,
00674                                 int longcal)
00675 {
00676         int iscaldone = 1;
00677         struct ath9k_cal_list *currCal = ah->cal_list_curr;
00678         int nfcal, nfcal_pending = 0;
00679 
00680         nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
00681         if (ah->caldata)
00682                 nfcal_pending = ah->caldata->nfcal_pending;
00683 
00684         if (currCal && !nfcal &&
00685             (currCal->calState == CAL_RUNNING ||
00686              currCal->calState == CAL_WAITING)) {
00687                 iscaldone = ar9002_hw_per_calibration(ah, chan,
00688                                                       rxchainmask, currCal);
00689                 if (iscaldone) {
00690                         ah->cal_list_curr = currCal = currCal->calNext;
00691 
00692                         if (currCal->calState == CAL_WAITING) {
00693                                 iscaldone = 0;
00694                                 ath9k_hw_reset_calibration(ah, currCal);
00695                         }
00696                 }
00697         }
00698 
00699         /* Do NF cal only at longer intervals */
00700         if (longcal || nfcal_pending) {
00701                 /*
00702                  * Get the value from the previous NF cal and update
00703                  * history buffer.
00704                  */
00705                 if (ath9k_hw_getnf(ah, chan)) {
00706                         /*
00707                          * Load the NF from history buffer of the current
00708                          * channel.
00709                          * NF is slow time-variant, so it is OK to use a
00710                          * historical value.
00711                          */
00712                         ath9k_hw_loadnf(ah, ah->curchan);
00713                 }
00714 
00715                 if (longcal) {
00716                         ath9k_hw_start_nfcal(ah, 0);
00717                         /* Do periodic PAOffset Cal */
00718                         ar9002_hw_pa_cal(ah, 0);
00719                         ar9002_hw_olc_temp_compensation(ah);
00720                 }
00721         }
00722 
00723         return iscaldone;
00724 }
00725 
00726 /* Carrier leakage Calibration fix */
00727 static int ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
00728 {
00729         REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
00730         if (IS_CHAN_HT20(chan)) {
00731                 REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
00732                 REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
00733                 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
00734                             AR_PHY_AGC_CONTROL_FLTR_CAL);
00735                 REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
00736                 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
00737                 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
00738                                   AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
00739                         DBG("ath9k: "
00740                                 "offset calibration failed to complete in 1ms; noisy environment?\n");
00741                         return 0;
00742                 }
00743                 REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
00744                 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
00745                 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
00746         }
00747         REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
00748         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
00749         REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
00750         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
00751         if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
00752                           0, AH_WAIT_TIMEOUT)) {
00753                 DBG("ath9k: "
00754                         "offset calibration failed to complete in 1ms; noisy environment?\n");
00755                 return 0;
00756         }
00757 
00758         REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
00759         REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
00760         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
00761 
00762         return 1;
00763 }
00764 
00765 static int ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
00766 {
00767         unsigned int i;
00768         uint32_t txgain_max;
00769         uint32_t clc_gain, gain_mask = 0, clc_num = 0;
00770         uint32_t reg_clc_I0, reg_clc_Q0;
00771         uint32_t i0_num = 0;
00772         uint32_t q0_num = 0;
00773         uint32_t total_num = 0;
00774         uint32_t reg_rf2g5_org;
00775         int retv = 1;
00776 
00777         if (!(ar9285_hw_cl_cal(ah, chan)))
00778                 return 0;
00779 
00780         txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
00781                         AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
00782 
00783         for (i = 0; i < (txgain_max+1); i++) {
00784                 clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
00785                            AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
00786                 if (!(gain_mask & (1 << clc_gain))) {
00787                         gain_mask |= (1 << clc_gain);
00788                         clc_num++;
00789                 }
00790         }
00791 
00792         for (i = 0; i < clc_num; i++) {
00793                 reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
00794                               & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
00795                 reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
00796                               & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
00797                 if (reg_clc_I0 == 0)
00798                         i0_num++;
00799 
00800                 if (reg_clc_Q0 == 0)
00801                         q0_num++;
00802         }
00803         total_num = i0_num + q0_num;
00804         if (total_num > AR9285_CLCAL_REDO_THRESH) {
00805                 reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
00806                 if (AR_SREV_9285E_20(ah)) {
00807                         REG_WRITE(ah, AR9285_RF2G5,
00808                                   (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
00809                                   AR9285_RF2G5_IC50TX_XE_SET);
00810                 } else {
00811                         REG_WRITE(ah, AR9285_RF2G5,
00812                                   (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
00813                                   AR9285_RF2G5_IC50TX_SET);
00814                 }
00815                 retv = ar9285_hw_cl_cal(ah, chan);
00816                 REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
00817         }
00818         return retv;
00819 }
00820 
00821 static int ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
00822 {
00823         if (AR_SREV_9271(ah)) {
00824                 if (!ar9285_hw_cl_cal(ah, chan))
00825                         return 0;
00826         } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
00827                 if (!ar9285_hw_clc(ah, chan))
00828                         return 0;
00829         } else {
00830                 if (AR_SREV_9280_20_OR_LATER(ah)) {
00831                         if (!AR_SREV_9287_11_OR_LATER(ah))
00832                                 REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
00833                                             AR_PHY_ADC_CTL_OFF_PWDADC);
00834                         REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
00835                                     AR_PHY_AGC_CONTROL_FLTR_CAL);
00836                 }
00837 
00838                 /* Calibrate the AGC */
00839                 REG_WRITE(ah, AR_PHY_AGC_CONTROL,
00840                           REG_READ(ah, AR_PHY_AGC_CONTROL) |
00841                           AR_PHY_AGC_CONTROL_CAL);
00842 
00843                 /* Poll for offset calibration complete */
00844                 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
00845                                    AR_PHY_AGC_CONTROL_CAL,
00846                                    0, AH_WAIT_TIMEOUT)) {
00847                         DBG("ath9k: "
00848                                 "offset calibration failed to complete in 1ms; noisy environment?\n");
00849                         return 0;
00850                 }
00851 
00852                 if (AR_SREV_9280_20_OR_LATER(ah)) {
00853                         if (!AR_SREV_9287_11_OR_LATER(ah))
00854                                 REG_SET_BIT(ah, AR_PHY_ADC_CTL,
00855                                             AR_PHY_ADC_CTL_OFF_PWDADC);
00856                         REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
00857                                     AR_PHY_AGC_CONTROL_FLTR_CAL);
00858                 }
00859         }
00860 
00861         /* Do PA Calibration */
00862         ar9002_hw_pa_cal(ah, 1);
00863 
00864         /* Do NF Calibration after DC offset and other calibrations */
00865         ath9k_hw_start_nfcal(ah, 1);
00866 
00867         if (ah->caldata)
00868                 ah->caldata->nfcal_pending = 1;
00869 
00870         ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
00871 
00872         /* Enable IQ, ADC Gain and ADC DC offset CALs */
00873         if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
00874                 ah->supp_cals = IQ_MISMATCH_CAL;
00875 
00876                 if (AR_SREV_9160_10_OR_LATER(ah))
00877                         ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
00878 
00879                 if (AR_SREV_9287(ah))
00880                         ah->supp_cals &= ~ADC_GAIN_CAL;
00881 
00882                 if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
00883                         INIT_CAL(&ah->adcgain_caldata);
00884                         INSERT_CAL(ah, &ah->adcgain_caldata);
00885                         DBG2("ath9k: "
00886                                         "enabling ADC Gain Calibration.\n");
00887                 }
00888 
00889                 if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
00890                         INIT_CAL(&ah->adcdc_caldata);
00891                         INSERT_CAL(ah, &ah->adcdc_caldata);
00892                         DBG2("ath9k: "
00893                                         "enabling ADC DC Calibration.\n");
00894                 }
00895 
00896                 if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
00897                         INIT_CAL(&ah->iq_caldata);
00898                         INSERT_CAL(ah, &ah->iq_caldata);
00899                         DBG2("ath9k: "
00900                                         "enabling IQ Calibration.\n");
00901                 }
00902 
00903                 ah->cal_list_curr = ah->cal_list;
00904 
00905                 if (ah->cal_list_curr)
00906                         ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
00907         }
00908 
00909         if (ah->caldata)
00910                 ah->caldata->CalValid = 0;
00911 
00912         return 1;
00913 }
00914 
00915 static const struct ath9k_percal_data iq_cal_multi_sample = {
00916         IQ_MISMATCH_CAL,
00917         MAX_CAL_SAMPLES,
00918         PER_MIN_LOG_COUNT,
00919         ar9002_hw_iqcal_collect,
00920         ar9002_hw_iqcalibrate
00921 };
00922 static const struct ath9k_percal_data iq_cal_single_sample = {
00923         IQ_MISMATCH_CAL,
00924         MIN_CAL_SAMPLES,
00925         PER_MAX_LOG_COUNT,
00926         ar9002_hw_iqcal_collect,
00927         ar9002_hw_iqcalibrate
00928 };
00929 static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
00930         ADC_GAIN_CAL,
00931         MAX_CAL_SAMPLES,
00932         PER_MIN_LOG_COUNT,
00933         ar9002_hw_adc_gaincal_collect,
00934         ar9002_hw_adc_gaincal_calibrate
00935 };
00936 static const struct ath9k_percal_data adc_gain_cal_single_sample = {
00937         ADC_GAIN_CAL,
00938         MIN_CAL_SAMPLES,
00939         PER_MAX_LOG_COUNT,
00940         ar9002_hw_adc_gaincal_collect,
00941         ar9002_hw_adc_gaincal_calibrate
00942 };
00943 static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
00944         ADC_DC_CAL,
00945         MAX_CAL_SAMPLES,
00946         PER_MIN_LOG_COUNT,
00947         ar9002_hw_adc_dccal_collect,
00948         ar9002_hw_adc_dccal_calibrate
00949 };
00950 static const struct ath9k_percal_data adc_dc_cal_single_sample = {
00951         ADC_DC_CAL,
00952         MIN_CAL_SAMPLES,
00953         PER_MAX_LOG_COUNT,
00954         ar9002_hw_adc_dccal_collect,
00955         ar9002_hw_adc_dccal_calibrate
00956 };
00957 
00958 static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
00959 {
00960         if (AR_SREV_9100(ah)) {
00961                 ah->iq_caldata.calData = &iq_cal_multi_sample;
00962                 ah->supp_cals = IQ_MISMATCH_CAL;
00963                 return;
00964         }
00965 
00966         if (AR_SREV_9160_10_OR_LATER(ah)) {
00967                 if (AR_SREV_9280_20_OR_LATER(ah)) {
00968                         ah->iq_caldata.calData = &iq_cal_single_sample;
00969                         ah->adcgain_caldata.calData =
00970                                 &adc_gain_cal_single_sample;
00971                         ah->adcdc_caldata.calData =
00972                                 &adc_dc_cal_single_sample;
00973                 } else {
00974                         ah->iq_caldata.calData = &iq_cal_multi_sample;
00975                         ah->adcgain_caldata.calData =
00976                                 &adc_gain_cal_multi_sample;
00977                         ah->adcdc_caldata.calData =
00978                                 &adc_dc_cal_multi_sample;
00979                 }
00980                 ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
00981 
00982                 if (AR_SREV_9287(ah))
00983                         ah->supp_cals &= ~ADC_GAIN_CAL;
00984         }
00985 }
00986 
00987 void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
00988 {
00989         struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
00990         struct ath_hw_ops *ops = ath9k_hw_ops(ah);
00991 
00992         priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
00993         priv_ops->init_cal = ar9002_hw_init_cal;
00994         priv_ops->setup_calibration = ar9002_hw_setup_calibration;
00995 
00996         ops->calibrate = ar9002_hw_calibrate;
00997 }