linux/drivers/net/wireless/ath/ath9k/ar9002_calib.c
<<
>>
Prefs
   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 "hw.h"
  18#include "hw-ops.h"
  19#include "ar9002_phy.h"
  20
  21#define AR9285_CLCAL_REDO_THRESH    1
  22
  23enum ar9002_cal_types {
  24        ADC_GAIN_CAL = BIT(0),
  25        ADC_DC_CAL = BIT(1),
  26        IQ_MISMATCH_CAL = BIT(2),
  27};
  28
  29static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
  30                                struct ath9k_channel *chan,
  31                                enum ar9002_cal_types cal_type)
  32{
  33        bool supported = false;
  34        switch (ah->supp_cals & cal_type) {
  35        case IQ_MISMATCH_CAL:
  36                supported = true;
  37                break;
  38        case ADC_GAIN_CAL:
  39        case ADC_DC_CAL:
  40                /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
  41                if (!((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
  42                      IS_CHAN_HT20(chan)))
  43                        supported = true;
  44                break;
  45        }
  46        return supported;
  47}
  48
  49static void ar9002_hw_setup_calibration(struct ath_hw *ah,
  50                                        struct ath9k_cal_list *currCal)
  51{
  52        struct ath_common *common = ath9k_hw_common(ah);
  53
  54        REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
  55                      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
  56                      currCal->calData->calCountMax);
  57
  58        switch (currCal->calData->calType) {
  59        case IQ_MISMATCH_CAL:
  60                REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
  61                ath_dbg(common, CALIBRATE,
  62                        "starting IQ Mismatch Calibration\n");
  63                break;
  64        case ADC_GAIN_CAL:
  65                REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
  66                ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n");
  67                break;
  68        case ADC_DC_CAL:
  69                REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
  70                ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n");
  71                break;
  72        }
  73
  74        REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
  75                    AR_PHY_TIMING_CTRL4_DO_CAL);
  76}
  77
  78static bool ar9002_hw_per_calibration(struct ath_hw *ah,
  79                                      struct ath9k_channel *ichan,
  80                                      u8 rxchainmask,
  81                                      struct ath9k_cal_list *currCal)
  82{
  83        struct ath9k_hw_cal_data *caldata = ah->caldata;
  84        bool iscaldone = false;
  85
  86        if (currCal->calState == CAL_RUNNING) {
  87                if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
  88                      AR_PHY_TIMING_CTRL4_DO_CAL)) {
  89
  90                        currCal->calData->calCollect(ah);
  91                        ah->cal_samples++;
  92
  93                        if (ah->cal_samples >=
  94                            currCal->calData->calNumSamples) {
  95                                int i, numChains = 0;
  96                                for (i = 0; i < AR5416_MAX_CHAINS; i++) {
  97                                        if (rxchainmask & (1 << i))
  98                                                numChains++;
  99                                }
 100
 101                                currCal->calData->calPostProc(ah, numChains);
 102                                caldata->CalValid |= currCal->calData->calType;
 103                                currCal->calState = CAL_DONE;
 104                                iscaldone = true;
 105                        } else {
 106                                ar9002_hw_setup_calibration(ah, currCal);
 107                        }
 108                }
 109        } else if (!(caldata->CalValid & currCal->calData->calType)) {
 110                ath9k_hw_reset_calibration(ah, currCal);
 111        }
 112
 113        return iscaldone;
 114}
 115
 116static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
 117{
 118        int i;
 119
 120        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 121                ah->totalPowerMeasI[i] +=
 122                        REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
 123                ah->totalPowerMeasQ[i] +=
 124                        REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
 125                ah->totalIqCorrMeas[i] +=
 126                        (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
 127                ath_dbg(ath9k_hw_common(ah), CALIBRATE,
 128                        "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
 129                        ah->cal_samples, i, ah->totalPowerMeasI[i],
 130                        ah->totalPowerMeasQ[i],
 131                        ah->totalIqCorrMeas[i]);
 132        }
 133}
 134
 135static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
 136{
 137        int i;
 138
 139        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 140                ah->totalAdcIOddPhase[i] +=
 141                        REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
 142                ah->totalAdcIEvenPhase[i] +=
 143                        REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
 144                ah->totalAdcQOddPhase[i] +=
 145                        REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
 146                ah->totalAdcQEvenPhase[i] +=
 147                        REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
 148
 149                ath_dbg(ath9k_hw_common(ah), CALIBRATE,
 150                        "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
 151                        ah->cal_samples, i,
 152                        ah->totalAdcIOddPhase[i],
 153                        ah->totalAdcIEvenPhase[i],
 154                        ah->totalAdcQOddPhase[i],
 155                        ah->totalAdcQEvenPhase[i]);
 156        }
 157}
 158
 159static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
 160{
 161        int i;
 162
 163        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
 164                ah->totalAdcDcOffsetIOddPhase[i] +=
 165                        (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
 166                ah->totalAdcDcOffsetIEvenPhase[i] +=
 167                        (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
 168                ah->totalAdcDcOffsetQOddPhase[i] +=
 169                        (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
 170                ah->totalAdcDcOffsetQEvenPhase[i] +=
 171                        (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
 172
 173                ath_dbg(ath9k_hw_common(ah), CALIBRATE,
 174                        "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
 175                        ah->cal_samples, i,
 176                        ah->totalAdcDcOffsetIOddPhase[i],
 177                        ah->totalAdcDcOffsetIEvenPhase[i],
 178                        ah->totalAdcDcOffsetQOddPhase[i],
 179                        ah->totalAdcDcOffsetQEvenPhase[i]);
 180        }
 181}
 182
 183static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
 184{
 185        struct ath_common *common = ath9k_hw_common(ah);
 186        u32 powerMeasQ, powerMeasI, iqCorrMeas;
 187        u32 qCoffDenom, iCoffDenom;
 188        int32_t qCoff, iCoff;
 189        int iqCorrNeg, i;
 190
 191        for (i = 0; i < numChains; i++) {
 192                powerMeasI = ah->totalPowerMeasI[i];
 193                powerMeasQ = ah->totalPowerMeasQ[i];
 194                iqCorrMeas = ah->totalIqCorrMeas[i];
 195
 196                ath_dbg(common, CALIBRATE,
 197                        "Starting IQ Cal and Correction for Chain %d\n",
 198                        i);
 199
 200                ath_dbg(common, CALIBRATE,
 201                        "Original: Chn %d iq_corr_meas = 0x%08x\n",
 202                        i, ah->totalIqCorrMeas[i]);
 203
 204                iqCorrNeg = 0;
 205
 206                if (iqCorrMeas > 0x80000000) {
 207                        iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
 208                        iqCorrNeg = 1;
 209                }
 210
 211                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",
 212                        i, powerMeasI);
 213                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",
 214                        i, powerMeasQ);
 215                ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);
 216
 217                iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
 218                qCoffDenom = powerMeasQ / 64;
 219
 220                if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
 221                    (qCoffDenom != 0)) {
 222                        iCoff = iqCorrMeas / iCoffDenom;
 223                        qCoff = powerMeasI / qCoffDenom - 64;
 224                        ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",
 225                                i, iCoff);
 226                        ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",
 227                                i, qCoff);
 228
 229                        iCoff = iCoff & 0x3f;
 230                        ath_dbg(common, CALIBRATE,
 231                                "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
 232                        if (iqCorrNeg == 0x0)
 233                                iCoff = 0x40 - iCoff;
 234
 235                        if (qCoff > 15)
 236                                qCoff = 15;
 237                        else if (qCoff <= -16)
 238                                qCoff = -16;
 239
 240                        ath_dbg(common, CALIBRATE,
 241                                "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
 242                                i, iCoff, qCoff);
 243
 244                        REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
 245                                      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
 246                                      iCoff);
 247                        REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
 248                                      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
 249                                      qCoff);
 250                        ath_dbg(common, CALIBRATE,
 251                                "IQ Cal and Correction done for Chain %d\n",
 252                                i);
 253                }
 254        }
 255
 256        REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
 257                    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
 258}
 259
 260static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
 261{
 262        struct ath_common *common = ath9k_hw_common(ah);
 263        u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
 264        u32 qGainMismatch, iGainMismatch, val, i;
 265
 266        for (i = 0; i < numChains; i++) {
 267                iOddMeasOffset = ah->totalAdcIOddPhase[i];
 268                iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
 269                qOddMeasOffset = ah->totalAdcQOddPhase[i];
 270                qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
 271
 272                ath_dbg(common, CALIBRATE,
 273                        "Starting ADC Gain Cal for Chain %d\n", i);
 274
 275                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n",
 276                        i, iOddMeasOffset);
 277                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n",
 278                        i, iEvenMeasOffset);
 279                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n",
 280                        i, qOddMeasOffset);
 281                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n",
 282                        i, qEvenMeasOffset);
 283
 284                if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
 285                        iGainMismatch =
 286                                ((iEvenMeasOffset * 32) /
 287                                 iOddMeasOffset) & 0x3f;
 288                        qGainMismatch =
 289                                ((qOddMeasOffset * 32) /
 290                                 qEvenMeasOffset) & 0x3f;
 291
 292                        ath_dbg(common, CALIBRATE,
 293                                "Chn %d gain_mismatch_i = 0x%08x\n",
 294                                i, iGainMismatch);
 295                        ath_dbg(common, CALIBRATE,
 296                                "Chn %d gain_mismatch_q = 0x%08x\n",
 297                                i, qGainMismatch);
 298
 299                        val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
 300                        val &= 0xfffff000;
 301                        val |= (qGainMismatch) | (iGainMismatch << 6);
 302                        REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
 303
 304                        ath_dbg(common, CALIBRATE,
 305                                "ADC Gain Cal done for Chain %d\n", i);
 306                }
 307        }
 308
 309        REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
 310                  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
 311                  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
 312}
 313
 314static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
 315{
 316        struct ath_common *common = ath9k_hw_common(ah);
 317        u32 iOddMeasOffset, iEvenMeasOffset, val, i;
 318        int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
 319        const struct ath9k_percal_data *calData =
 320                ah->cal_list_curr->calData;
 321        u32 numSamples =
 322                (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
 323
 324        for (i = 0; i < numChains; i++) {
 325                iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
 326                iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
 327                qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
 328                qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
 329
 330                ath_dbg(common, CALIBRATE,
 331                        "Starting ADC DC Offset Cal for Chain %d\n", i);
 332
 333                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n",
 334                        i, iOddMeasOffset);
 335                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n",
 336                        i, iEvenMeasOffset);
 337                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n",
 338                        i, qOddMeasOffset);
 339                ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n",
 340                        i, qEvenMeasOffset);
 341
 342                iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
 343                               numSamples) & 0x1ff;
 344                qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
 345                               numSamples) & 0x1ff;
 346
 347                ath_dbg(common, CALIBRATE,
 348                        "Chn %d dc_offset_mismatch_i = 0x%08x\n",
 349                        i, iDcMismatch);
 350                ath_dbg(common, CALIBRATE,
 351                        "Chn %d dc_offset_mismatch_q = 0x%08x\n",
 352                        i, qDcMismatch);
 353
 354                val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
 355                val &= 0xc0000fff;
 356                val |= (qDcMismatch << 12) | (iDcMismatch << 21);
 357                REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
 358
 359                ath_dbg(common, CALIBRATE,
 360                        "ADC DC Offset Cal done for Chain %d\n", i);
 361        }
 362
 363        REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
 364                  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
 365                  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
 366}
 367
 368static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
 369{
 370        u32 rddata;
 371        int32_t delta, currPDADC, slope;
 372
 373        rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
 374        currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
 375
 376        if (ah->initPDADC == 0 || currPDADC == 0) {
 377                /*
 378                 * Zero value indicates that no frames have been transmitted
 379                 * yet, can't do temperature compensation until frames are
 380                 * transmitted.
 381                 */
 382                return;
 383        } else {
 384                slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
 385
 386                if (slope == 0) { /* to avoid divide by zero case */
 387                        delta = 0;
 388                } else {
 389                        delta = ((currPDADC - ah->initPDADC)*4) / slope;
 390                }
 391                REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
 392                              AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
 393                REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
 394                              AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
 395        }
 396}
 397
 398static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
 399{
 400        u32 rddata, i;
 401        int delta, currPDADC, regval;
 402
 403        rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
 404        currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
 405
 406        if (ah->initPDADC == 0 || currPDADC == 0)
 407                return;
 408
 409        if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
 410                delta = (currPDADC - ah->initPDADC + 4) / 8;
 411        else
 412                delta = (currPDADC - ah->initPDADC + 5) / 10;
 413
 414        if (delta != ah->PDADCdelta) {
 415                ah->PDADCdelta = delta;
 416                for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
 417                        regval = ah->originalGain[i] - delta;
 418                        if (regval < 0)
 419                                regval = 0;
 420
 421                        REG_RMW_FIELD(ah,
 422                                      AR_PHY_TX_GAIN_TBL1 + i * 4,
 423                                      AR_PHY_TX_GAIN, regval);
 424                }
 425        }
 426}
 427
 428static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
 429{
 430        u32 regVal;
 431        unsigned int i;
 432        u32 regList[][2] = {
 433                { AR9285_AN_TOP3, 0 },
 434                { AR9285_AN_RXTXBB1, 0 },
 435                { AR9285_AN_RF2G1, 0 },
 436                { AR9285_AN_RF2G2, 0 },
 437                { AR9285_AN_TOP2, 0 },
 438                { AR9285_AN_RF2G8, 0 },
 439                { AR9285_AN_RF2G7, 0 },
 440                { AR9285_AN_RF2G3, 0 },
 441        };
 442
 443        REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList));
 444
 445        ENABLE_REG_RMW_BUFFER(ah);
 446        /* 7834, b1=0 */
 447        REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
 448        /* 9808, b27=1 */
 449        REG_SET_BIT(ah, 0x9808, 1 << 27);
 450        /* 786c,b23,1, pwddac=1 */
 451        REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC);
 452        /* 7854, b5,1, pdrxtxbb=1 */
 453        REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1);
 454        /* 7854, b7,1, pdv2i=1 */
 455        REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I);
 456        /* 7854, b8,1, pddacinterface=1 */
 457        REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF);
 458        /* 7824,b12,0, offcal=0 */
 459        REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL);
 460        /* 7838, b1,0, pwddb=0 */
 461        REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB);
 462        /* 7820,b11,0, enpacal=0 */
 463        REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL);
 464        /* 7820,b25,1, pdpadrv1=0 */
 465        REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1);
 466        /* 7820,b24,0, pdpadrv2=0 */
 467        REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2);
 468        /* 7820,b23,0, pdpaout=0 */
 469        REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT);
 470        /* 783c,b14-16,7, padrvgn2tab_0=7 */
 471        REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
 472        /*
 473         * 7838,b29-31,0, padrvgn1tab_0=0
 474         * does not matter since we turn it off
 475         */
 476        REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
 477        /* 7828, b0-11, ccom=fff */
 478        REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
 479        REG_RMW_BUFFER_FLUSH(ah);
 480
 481        /* Set:
 482         * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
 483         * txon=1,paon=1,oscon=1,synthon_force=1
 484         */
 485        REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
 486        udelay(30);
 487        REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
 488
 489        /* find off_6_1; */
 490        for (i = 6; i > 0; i--) {
 491                regVal = REG_READ(ah, AR9285_AN_RF2G6);
 492                regVal |= (1 << (20 + i));
 493                REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
 494                udelay(1);
 495                /* regVal = REG_READ(ah, 0x7834); */
 496                regVal &= (~(0x1 << (20 + i)));
 497                regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9),
 498                              AR9285_AN_RXTXBB1_SPARE9)
 499                            << (20 + i));
 500                REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
 501        }
 502
 503        regVal = (regVal >> 20) & 0x7f;
 504
 505        /* Update PA cal info */
 506        if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
 507                if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
 508                        ah->pacal_info.max_skipcount =
 509                                2 * ah->pacal_info.max_skipcount;
 510                ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
 511        } else {
 512                ah->pacal_info.max_skipcount = 1;
 513                ah->pacal_info.skipcount = 0;
 514                ah->pacal_info.prev_offset = regVal;
 515        }
 516
 517
 518        ENABLE_REG_RMW_BUFFER(ah);
 519        /* 7834, b1=1 */
 520        REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
 521        /* 9808, b27=0 */
 522        REG_CLR_BIT(ah, 0x9808, 1 << 27);
 523        REG_RMW_BUFFER_FLUSH(ah);
 524
 525        ENABLE_REGWRITE_BUFFER(ah);
 526        for (i = 0; i < ARRAY_SIZE(regList); i++)
 527                REG_WRITE(ah, regList[i][0], regList[i][1]);
 528
 529        REGWRITE_BUFFER_FLUSH(ah);
 530}
 531
 532static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
 533{
 534        struct ath_common *common = ath9k_hw_common(ah);
 535        u32 regVal;
 536        int i, offset, offs_6_1, offs_0;
 537        u32 ccomp_org, reg_field;
 538        u32 regList[][2] = {
 539                { 0x786c, 0 },
 540                { 0x7854, 0 },
 541                { 0x7820, 0 },
 542                { 0x7824, 0 },
 543                { 0x7868, 0 },
 544                { 0x783c, 0 },
 545                { 0x7838, 0 },
 546        };
 547
 548        ath_dbg(common, CALIBRATE, "Running PA Calibration\n");
 549
 550        /* PA CAL is not needed for high power solution */
 551        if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
 552            AR5416_EEP_TXGAIN_HIGH_POWER)
 553                return;
 554
 555        for (i = 0; i < ARRAY_SIZE(regList); i++)
 556                regList[i][1] = REG_READ(ah, regList[i][0]);
 557
 558        regVal = REG_READ(ah, 0x7834);
 559        regVal &= (~(0x1));
 560        REG_WRITE(ah, 0x7834, regVal);
 561        regVal = REG_READ(ah, 0x9808);
 562        regVal |= (0x1 << 27);
 563        REG_WRITE(ah, 0x9808, regVal);
 564
 565        REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
 566        REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
 567        REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
 568        REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
 569        REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
 570        REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
 571        REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
 572        REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
 573        REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
 574        REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
 575        REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
 576        REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
 577        ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
 578        REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
 579
 580        REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
 581        udelay(30);
 582        REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
 583        REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
 584
 585        for (i = 6; i > 0; i--) {
 586                regVal = REG_READ(ah, 0x7834);
 587                regVal |= (1 << (19 + i));
 588                REG_WRITE(ah, 0x7834, regVal);
 589                udelay(1);
 590                regVal = REG_READ(ah, 0x7834);
 591                regVal &= (~(0x1 << (19 + i)));
 592                reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
 593                regVal |= (reg_field << (19 + i));
 594                REG_WRITE(ah, 0x7834, regVal);
 595        }
 596
 597        REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
 598        udelay(1);
 599        reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
 600        REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
 601        offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
 602        offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
 603
 604        offset = (offs_6_1<<1) | offs_0;
 605        offset = offset - 0;
 606        offs_6_1 = offset>>1;
 607        offs_0 = offset & 1;
 608
 609        if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
 610                if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
 611                        ah->pacal_info.max_skipcount =
 612                                2 * ah->pacal_info.max_skipcount;
 613                ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
 614        } else {
 615                ah->pacal_info.max_skipcount = 1;
 616                ah->pacal_info.skipcount = 0;
 617                ah->pacal_info.prev_offset = offset;
 618        }
 619
 620        REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
 621        REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
 622
 623        regVal = REG_READ(ah, 0x7834);
 624        regVal |= 0x1;
 625        REG_WRITE(ah, 0x7834, regVal);
 626        regVal = REG_READ(ah, 0x9808);
 627        regVal &= (~(0x1 << 27));
 628        REG_WRITE(ah, 0x9808, regVal);
 629
 630        for (i = 0; i < ARRAY_SIZE(regList); i++)
 631                REG_WRITE(ah, regList[i][0], regList[i][1]);
 632
 633        REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
 634}
 635
 636static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)
 637{
 638        if (AR_SREV_9271(ah)) {
 639                if (is_reset || !ah->pacal_info.skipcount)
 640                        ar9271_hw_pa_cal(ah, is_reset);
 641                else
 642                        ah->pacal_info.skipcount--;
 643        } else if (AR_SREV_9285_12_OR_LATER(ah)) {
 644                if (is_reset || !ah->pacal_info.skipcount)
 645                        ar9285_hw_pa_cal(ah, is_reset);
 646                else
 647                        ah->pacal_info.skipcount--;
 648        }
 649}
 650
 651static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
 652{
 653        if (OLC_FOR_AR9287_10_LATER)
 654                ar9287_hw_olc_temp_compensation(ah);
 655        else if (OLC_FOR_AR9280_20_LATER)
 656                ar9280_hw_olc_temp_compensation(ah);
 657}
 658
 659static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
 660                               u8 rxchainmask, bool longcal)
 661{
 662        struct ath9k_cal_list *currCal = ah->cal_list_curr;
 663        bool nfcal, nfcal_pending = false, percal_pending;
 664        int ret;
 665
 666        nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
 667        if (ah->caldata)
 668                nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 669
 670        percal_pending = (currCal &&
 671                          (currCal->calState == CAL_RUNNING ||
 672                           currCal->calState == CAL_WAITING));
 673
 674        if (percal_pending && !nfcal) {
 675                if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
 676                        return 0;
 677
 678                ah->cal_list_curr = currCal = currCal->calNext;
 679                if (currCal->calState == CAL_WAITING)
 680                        ath9k_hw_reset_calibration(ah, currCal);
 681
 682                return 0;
 683        }
 684
 685        /* Do NF cal only at longer intervals */
 686        if (longcal || nfcal_pending) {
 687                /*
 688                 * Get the value from the previous NF cal and update
 689                 * history buffer.
 690                 */
 691                if (ath9k_hw_getnf(ah, chan)) {
 692                        /*
 693                         * Load the NF from history buffer of the current
 694                         * channel.
 695                         * NF is slow time-variant, so it is OK to use a
 696                         * historical value.
 697                         */
 698                        ret = ath9k_hw_loadnf(ah, ah->curchan);
 699                        if (ret < 0)
 700                                return ret;
 701                }
 702
 703                if (longcal) {
 704                        ath9k_hw_start_nfcal(ah, false);
 705                        /* Do periodic PAOffset Cal */
 706                        ar9002_hw_pa_cal(ah, false);
 707                        ar9002_hw_olc_temp_compensation(ah);
 708                }
 709        }
 710
 711        return !percal_pending;
 712}
 713
 714/* Carrier leakage Calibration fix */
 715static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 716{
 717        struct ath_common *common = ath9k_hw_common(ah);
 718
 719        REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
 720        if (IS_CHAN_HT20(chan)) {
 721                REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
 722                REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
 723                REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
 724                            AR_PHY_AGC_CONTROL_FLTR_CAL);
 725                REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
 726                REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
 727                if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
 728                                  AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
 729                        ath_dbg(common, CALIBRATE,
 730                                "offset calibration failed to complete in %d ms; noisy environment?\n",
 731                                AH_WAIT_TIMEOUT / 1000);
 732                        return false;
 733                }
 734                REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
 735                REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
 736                REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
 737        }
 738        REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
 739        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
 740        REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
 741        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
 742        if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
 743                          0, AH_WAIT_TIMEOUT)) {
 744                ath_dbg(common, CALIBRATE,
 745                        "offset calibration failed to complete in %d ms; noisy environment?\n",
 746                        AH_WAIT_TIMEOUT / 1000);
 747                return false;
 748        }
 749
 750        REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
 751        REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
 752        REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
 753
 754        return true;
 755}
 756
 757static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
 758{
 759        int i;
 760        u_int32_t txgain_max;
 761        u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
 762        u_int32_t reg_clc_I0, reg_clc_Q0;
 763        u_int32_t i0_num = 0;
 764        u_int32_t q0_num = 0;
 765        u_int32_t total_num = 0;
 766        u_int32_t reg_rf2g5_org;
 767        bool retv = true;
 768
 769        if (!(ar9285_hw_cl_cal(ah, chan)))
 770                return false;
 771
 772        txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
 773                        AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
 774
 775        for (i = 0; i < (txgain_max+1); i++) {
 776                clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
 777                           AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
 778                if (!(gain_mask & (1 << clc_gain))) {
 779                        gain_mask |= (1 << clc_gain);
 780                        clc_num++;
 781                }
 782        }
 783
 784        for (i = 0; i < clc_num; i++) {
 785                reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
 786                              & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
 787                reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
 788                              & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
 789                if (reg_clc_I0 == 0)
 790                        i0_num++;
 791
 792                if (reg_clc_Q0 == 0)
 793                        q0_num++;
 794        }
 795        total_num = i0_num + q0_num;
 796        if (total_num > AR9285_CLCAL_REDO_THRESH) {
 797                reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
 798                if (AR_SREV_9285E_20(ah)) {
 799                        REG_WRITE(ah, AR9285_RF2G5,
 800                                  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
 801                                  AR9285_RF2G5_IC50TX_XE_SET);
 802                } else {
 803                        REG_WRITE(ah, AR9285_RF2G5,
 804                                  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
 805                                  AR9285_RF2G5_IC50TX_SET);
 806                }
 807                retv = ar9285_hw_cl_cal(ah, chan);
 808                REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
 809        }
 810        return retv;
 811}
 812
 813static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
 814{
 815        struct ath_common *common = ath9k_hw_common(ah);
 816
 817        if (AR_SREV_9271(ah)) {
 818                if (!ar9285_hw_cl_cal(ah, chan))
 819                        return false;
 820        } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
 821                if (!ar9285_hw_clc(ah, chan))
 822                        return false;
 823        } else {
 824                if (AR_SREV_9280_20_OR_LATER(ah)) {
 825                        if (!AR_SREV_9287_11_OR_LATER(ah))
 826                                REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
 827                                            AR_PHY_ADC_CTL_OFF_PWDADC);
 828                        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
 829                                    AR_PHY_AGC_CONTROL_FLTR_CAL);
 830                }
 831
 832                /* Calibrate the AGC */
 833                REG_WRITE(ah, AR_PHY_AGC_CONTROL,
 834                          REG_READ(ah, AR_PHY_AGC_CONTROL) |
 835                          AR_PHY_AGC_CONTROL_CAL);
 836
 837                /* Poll for offset calibration complete */
 838                if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
 839                                   AR_PHY_AGC_CONTROL_CAL,
 840                                   0, AH_WAIT_TIMEOUT)) {
 841                        ath_dbg(common, CALIBRATE,
 842                                "offset calibration failed to complete in %d ms; noisy environment?\n",
 843                                AH_WAIT_TIMEOUT / 1000);
 844                        return false;
 845                }
 846
 847                if (AR_SREV_9280_20_OR_LATER(ah)) {
 848                        if (!AR_SREV_9287_11_OR_LATER(ah))
 849                                REG_SET_BIT(ah, AR_PHY_ADC_CTL,
 850                                            AR_PHY_ADC_CTL_OFF_PWDADC);
 851                        REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
 852                                    AR_PHY_AGC_CONTROL_FLTR_CAL);
 853                }
 854        }
 855
 856        /* Do PA Calibration */
 857        ar9002_hw_pa_cal(ah, true);
 858        ath9k_hw_loadnf(ah, chan);
 859        ath9k_hw_start_nfcal(ah, true);
 860
 861        if (ah->caldata)
 862                set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 863
 864        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 865
 866        /* Enable IQ, ADC Gain and ADC DC offset CALs */
 867        if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
 868                ah->supp_cals = IQ_MISMATCH_CAL;
 869
 870                if (AR_SREV_9160_10_OR_LATER(ah))
 871                        ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
 872
 873                if (AR_SREV_9287(ah))
 874                        ah->supp_cals &= ~ADC_GAIN_CAL;
 875
 876                if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
 877                        INIT_CAL(&ah->adcgain_caldata);
 878                        INSERT_CAL(ah, &ah->adcgain_caldata);
 879                        ath_dbg(common, CALIBRATE,
 880                                        "enabling ADC Gain Calibration\n");
 881                }
 882
 883                if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
 884                        INIT_CAL(&ah->adcdc_caldata);
 885                        INSERT_CAL(ah, &ah->adcdc_caldata);
 886                        ath_dbg(common, CALIBRATE,
 887                                        "enabling ADC DC Calibration\n");
 888                }
 889
 890                if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
 891                        INIT_CAL(&ah->iq_caldata);
 892                        INSERT_CAL(ah, &ah->iq_caldata);
 893                        ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
 894                }
 895
 896                ah->cal_list_curr = ah->cal_list;
 897
 898                if (ah->cal_list_curr)
 899                        ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
 900        }
 901
 902        if (ah->caldata)
 903                ah->caldata->CalValid = 0;
 904
 905        return true;
 906}
 907
 908static const struct ath9k_percal_data iq_cal_multi_sample = {
 909        IQ_MISMATCH_CAL,
 910        MAX_CAL_SAMPLES,
 911        PER_MIN_LOG_COUNT,
 912        ar9002_hw_iqcal_collect,
 913        ar9002_hw_iqcalibrate
 914};
 915static const struct ath9k_percal_data iq_cal_single_sample = {
 916        IQ_MISMATCH_CAL,
 917        MIN_CAL_SAMPLES,
 918        PER_MAX_LOG_COUNT,
 919        ar9002_hw_iqcal_collect,
 920        ar9002_hw_iqcalibrate
 921};
 922static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
 923        ADC_GAIN_CAL,
 924        MAX_CAL_SAMPLES,
 925        PER_MIN_LOG_COUNT,
 926        ar9002_hw_adc_gaincal_collect,
 927        ar9002_hw_adc_gaincal_calibrate
 928};
 929static const struct ath9k_percal_data adc_gain_cal_single_sample = {
 930        ADC_GAIN_CAL,
 931        MIN_CAL_SAMPLES,
 932        PER_MAX_LOG_COUNT,
 933        ar9002_hw_adc_gaincal_collect,
 934        ar9002_hw_adc_gaincal_calibrate
 935};
 936static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
 937        ADC_DC_CAL,
 938        MAX_CAL_SAMPLES,
 939        PER_MIN_LOG_COUNT,
 940        ar9002_hw_adc_dccal_collect,
 941        ar9002_hw_adc_dccal_calibrate
 942};
 943static const struct ath9k_percal_data adc_dc_cal_single_sample = {
 944        ADC_DC_CAL,
 945        MIN_CAL_SAMPLES,
 946        PER_MAX_LOG_COUNT,
 947        ar9002_hw_adc_dccal_collect,
 948        ar9002_hw_adc_dccal_calibrate
 949};
 950
 951static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
 952{
 953        if (AR_SREV_9100(ah)) {
 954                ah->iq_caldata.calData = &iq_cal_multi_sample;
 955                ah->supp_cals = IQ_MISMATCH_CAL;
 956                return;
 957        }
 958
 959        if (AR_SREV_9160_10_OR_LATER(ah)) {
 960                if (AR_SREV_9280_20_OR_LATER(ah)) {
 961                        ah->iq_caldata.calData = &iq_cal_single_sample;
 962                        ah->adcgain_caldata.calData =
 963                                &adc_gain_cal_single_sample;
 964                        ah->adcdc_caldata.calData =
 965                                &adc_dc_cal_single_sample;
 966                } else {
 967                        ah->iq_caldata.calData = &iq_cal_multi_sample;
 968                        ah->adcgain_caldata.calData =
 969                                &adc_gain_cal_multi_sample;
 970                        ah->adcdc_caldata.calData =
 971                                &adc_dc_cal_multi_sample;
 972                }
 973                ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
 974
 975                if (AR_SREV_9287(ah))
 976                        ah->supp_cals &= ~ADC_GAIN_CAL;
 977        }
 978}
 979
 980void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
 981{
 982        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
 983        struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 984
 985        priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
 986        priv_ops->init_cal = ar9002_hw_init_cal;
 987        priv_ops->setup_calibration = ar9002_hw_setup_calibration;
 988
 989        ops->calibrate = ar9002_hw_calibrate;
 990}
 991