1 /* 2 * Copyright (c) 2010-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 "ar9003_phy.h" 20 #include "ar9003_rtt.h" 21 22 #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT 23 #define MAX_MAG_DELTA 11 24 #define MAX_PHS_DELTA 10 25 26 struct coeff { 27 int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; 28 int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; 29 int iqc_coeff[2]; 30 }; 31 32 enum ar9003_cal_types { 33 IQ_MISMATCH_CAL = BIT(0), 34 TEMP_COMP_CAL = BIT(1), 35 }; 36 37 static void ar9003_hw_setup_calibration(struct ath_hw *ah, 38 struct ath9k_cal_list *currCal) 39 { 40 struct ath_common *common = ath9k_hw_common(ah); 41 42 /* Select calibration to run */ 43 switch (currCal->calData->calType) { 44 case IQ_MISMATCH_CAL: 45 /* 46 * Start calibration with 47 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples 48 */ 49 REG_RMW_FIELD(ah, AR_PHY_TIMING4, 50 AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, 51 currCal->calData->calCountMax); 52 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 53 54 ath_dbg(common, ATH_DBG_CALIBRATE, 55 "starting IQ Mismatch Calibration\n"); 56 57 /* Kick-off cal */ 58 REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); 59 break; 60 case TEMP_COMP_CAL: 61 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, 62 AR_PHY_65NM_CH0_THERM_LOCAL, 1); 63 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, 64 AR_PHY_65NM_CH0_THERM_START, 1); 65 66 ath_dbg(common, ATH_DBG_CALIBRATE, 67 "starting Temperature Compensation Calibration\n"); 68 break; 69 } 70 } 71 72 /* 73 * Generic calibration routine. 74 * Recalibrate the lower PHY chips to account for temperature/environment 75 * changes. 76 */ 77 static bool ar9003_hw_per_calibration(struct ath_hw *ah, 78 struct ath9k_channel *ichan, 79 u8 rxchainmask, 80 struct ath9k_cal_list *currCal) 81 { 82 struct ath9k_hw_cal_data *caldata = ah->caldata; 83 /* Cal is assumed not done until explicitly set below */ 84 bool iscaldone = false; 85 86 /* Calibration in progress. */ 87 if (currCal->calState == CAL_RUNNING) { 88 /* Check to see if it has finished. */ 89 if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { 90 /* 91 * Accumulate cal measures for active chains 92 */ 93 currCal->calData->calCollect(ah); 94 ah->cal_samples++; 95 96 if (ah->cal_samples >= 97 currCal->calData->calNumSamples) { 98 unsigned int i, numChains = 0; 99 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 100 if (rxchainmask & (1 << i)) 101 numChains++; 102 } 103 104 /* 105 * Process accumulated data 106 */ 107 currCal->calData->calPostProc(ah, numChains); 108 109 /* Calibration has finished. */ 110 caldata->CalValid |= currCal->calData->calType; 111 currCal->calState = CAL_DONE; 112 iscaldone = true; 113 } else { 114 /* 115 * Set-up collection of another sub-sample until we 116 * get desired number 117 */ 118 ar9003_hw_setup_calibration(ah, currCal); 119 } 120 } 121 } else if (!(caldata->CalValid & currCal->calData->calType)) { 122 /* If current cal is marked invalid in channel, kick it off */ 123 ath9k_hw_reset_calibration(ah, currCal); 124 } 125 126 return iscaldone; 127 } 128 129 static bool ar9003_hw_calibrate(struct ath_hw *ah, 130 struct ath9k_channel *chan, 131 u8 rxchainmask, 132 bool longcal) 133 { 134 bool iscaldone = true; 135 struct ath9k_cal_list *currCal = ah->cal_list_curr; 136 137 /* 138 * For given calibration: 139 * 1. Call generic cal routine 140 * 2. When this cal is done (isCalDone) if we have more cals waiting 141 * (eg after reset), mask this to upper layers by not propagating 142 * isCalDone if it is set to TRUE. 143 * Instead, change isCalDone to FALSE and setup the waiting cal(s) 144 * to be run. 145 */ 146 if (currCal && 147 (currCal->calState == CAL_RUNNING || 148 currCal->calState == CAL_WAITING)) { 149 iscaldone = ar9003_hw_per_calibration(ah, chan, 150 rxchainmask, currCal); 151 if (iscaldone) { 152 ah->cal_list_curr = currCal = currCal->calNext; 153 154 if (currCal->calState == CAL_WAITING) { 155 iscaldone = false; 156 ath9k_hw_reset_calibration(ah, currCal); 157 } 158 } 159 } 160 161 /* Do NF cal only at longer intervals */ 162 if (longcal) { 163 /* 164 * Get the value from the previous NF cal and update 165 * history buffer. 166 */ 167 ath9k_hw_getnf(ah, chan); 168 169 /* 170 * Load the NF from history buffer of the current channel. 171 * NF is slow time-variant, so it is OK to use a historical 172 * value. 173 */ 174 ath9k_hw_loadnf(ah, ah->curchan); 175 176 /* start NF calibration, without updating BB NF register */ 177 ath9k_hw_start_nfcal(ah, false); 178 } 179 180 return iscaldone; 181 } 182 183 static void ar9003_hw_iqcal_collect(struct ath_hw *ah) 184 { 185 int i; 186 187 /* Accumulate IQ cal measures for active chains */ 188 for (i = 0; i < AR5416_MAX_CHAINS; i++) { 189 if (ah->txchainmask & BIT(i)) { 190 ah->totalPowerMeasI[i] += 191 REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 192 ah->totalPowerMeasQ[i] += 193 REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 194 ah->totalIqCorrMeas[i] += 195 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 196 ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, 197 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 198 ah->cal_samples, i, ah->totalPowerMeasI[i], 199 ah->totalPowerMeasQ[i], 200 ah->totalIqCorrMeas[i]); 201 } 202 } 203 } 204 205 static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 206 { 207 struct ath_common *common = ath9k_hw_common(ah); 208 u32 powerMeasQ, powerMeasI, iqCorrMeas; 209 u32 qCoffDenom, iCoffDenom; 210 int32_t qCoff, iCoff; 211 int iqCorrNeg, i; 212 static const u_int32_t offset_array[3] = { 213 AR_PHY_RX_IQCAL_CORR_B0, 214 AR_PHY_RX_IQCAL_CORR_B1, 215 AR_PHY_RX_IQCAL_CORR_B2, 216 }; 217 218 for (i = 0; i < numChains; i++) { 219 powerMeasI = ah->totalPowerMeasI[i]; 220 powerMeasQ = ah->totalPowerMeasQ[i]; 221 iqCorrMeas = ah->totalIqCorrMeas[i]; 222 223 ath_dbg(common, ATH_DBG_CALIBRATE, 224 "Starting IQ Cal and Correction for Chain %d\n", 225 i); 226 227 ath_dbg(common, ATH_DBG_CALIBRATE, 228 "Orignal: Chn %diq_corr_meas = 0x%08x\n", 229 i, ah->totalIqCorrMeas[i]); 230 231 iqCorrNeg = 0; 232 233 if (iqCorrMeas > 0x80000000) { 234 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 235 iqCorrNeg = 1; 236 } 237 238 ath_dbg(common, ATH_DBG_CALIBRATE, 239 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); 240 ath_dbg(common, ATH_DBG_CALIBRATE, 241 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); 242 ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", 243 iqCorrNeg); 244 245 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256; 246 qCoffDenom = powerMeasQ / 64; 247 248 if ((iCoffDenom != 0) && (qCoffDenom != 0)) { 249 iCoff = iqCorrMeas / iCoffDenom; 250 qCoff = powerMeasI / qCoffDenom - 64; 251 ath_dbg(common, ATH_DBG_CALIBRATE, 252 "Chn %d iCoff = 0x%08x\n", i, iCoff); 253 ath_dbg(common, ATH_DBG_CALIBRATE, 254 "Chn %d qCoff = 0x%08x\n", i, qCoff); 255 256 /* Force bounds on iCoff */ 257 if (iCoff >= 63) 258 iCoff = 63; 259 else if (iCoff <= -63) 260 iCoff = -63; 261 262 /* Negate iCoff if iqCorrNeg == 0 */ 263 if (iqCorrNeg == 0x0) 264 iCoff = -iCoff; 265 266 /* Force bounds on qCoff */ 267 if (qCoff >= 63) 268 qCoff = 63; 269 else if (qCoff <= -63) 270 qCoff = -63; 271 272 iCoff = iCoff & 0x7f; 273 qCoff = qCoff & 0x7f; 274 275 ath_dbg(common, ATH_DBG_CALIBRATE, 276 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 277 i, iCoff, qCoff); 278 ath_dbg(common, ATH_DBG_CALIBRATE, 279 "Register offset (0x%04x) before update = 0x%x\n", 280 offset_array[i], 281 REG_READ(ah, offset_array[i])); 282 283 REG_RMW_FIELD(ah, offset_array[i], 284 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 285 iCoff); 286 REG_RMW_FIELD(ah, offset_array[i], 287 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 288 qCoff); 289 ath_dbg(common, ATH_DBG_CALIBRATE, 290 "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n", 291 offset_array[i], 292 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, 293 REG_READ(ah, offset_array[i])); 294 ath_dbg(common, ATH_DBG_CALIBRATE, 295 "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n", 296 offset_array[i], 297 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, 298 REG_READ(ah, offset_array[i])); 299 300 ath_dbg(common, ATH_DBG_CALIBRATE, 301 "IQ Cal and Correction done for Chain %d\n", i); 302 } 303 } 304 305 REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, 306 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); 307 ath_dbg(common, ATH_DBG_CALIBRATE, 308 "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n", 309 (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), 310 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, 311 REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); 312 } 313 314 static const struct ath9k_percal_data iq_cal_single_sample = { 315 IQ_MISMATCH_CAL, 316 MIN_CAL_SAMPLES, 317 PER_MAX_LOG_COUNT, 318 ar9003_hw_iqcal_collect, 319 ar9003_hw_iqcalibrate 320 }; 321 322 static void ar9003_hw_init_cal_settings(struct ath_hw *ah) 323 { 324 ah->iq_caldata.calData = &iq_cal_single_sample; 325 } 326 327 /* 328 * solve 4x4 linear equation used in loopback iq cal. 329 */ 330 static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah, 331 s32 sin_2phi_1, 332 s32 cos_2phi_1, 333 s32 sin_2phi_2, 334 s32 cos_2phi_2, 335 s32 mag_a0_d0, 336 s32 phs_a0_d0, 337 s32 mag_a1_d0, 338 s32 phs_a1_d0, 339 s32 solved_eq[]) 340 { 341 s32 f1 = cos_2phi_1 - cos_2phi_2, 342 f3 = sin_2phi_1 - sin_2phi_2, 343 f2; 344 s32 mag_tx, phs_tx, mag_rx, phs_rx; 345 const s32 result_shift = 1 << 15; 346 struct ath_common *common = ath9k_hw_common(ah); 347 348 f2 = (f1 * f1 + f3 * f3) / result_shift; 349 350 if (!f2) { 351 ath_dbg(common, ATH_DBG_CALIBRATE, "Divide by 0\n"); 352 return false; 353 } 354 355 /* mag mismatch, tx */ 356 mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); 357 /* phs mismatch, tx */ 358 phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); 359 360 mag_tx = (mag_tx / f2); 361 phs_tx = (phs_tx / f2); 362 363 /* mag mismatch, rx */ 364 mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / 365 result_shift; 366 /* phs mismatch, rx */ 367 phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / 368 result_shift; 369 370 solved_eq[0] = mag_tx; 371 solved_eq[1] = phs_tx; 372 solved_eq[2] = mag_rx; 373 solved_eq[3] = phs_rx; 374 375 return true; 376 } 377 378 static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im) 379 { 380 s32 abs_i = abs(in_re), 381 abs_q = abs(in_im), 382 max_abs, min_abs; 383 384 if (abs_i > abs_q) { 385 max_abs = abs_i; 386 min_abs = abs_q; 387 } else { 388 max_abs = abs_q; 389 min_abs = abs_i; 390 } 391 392 return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4); 393 } 394 395 #define DELPT 32 396 397 static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, 398 s32 chain_idx, 399 const s32 iq_res[], 400 s32 iqc_coeff[]) 401 { 402 s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0, 403 i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1, 404 i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0, 405 i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; 406 s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1, 407 phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1, 408 sin_2phi_1, cos_2phi_1, 409 sin_2phi_2, cos_2phi_2; 410 s32 mag_tx, phs_tx, mag_rx, phs_rx; 411 s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx, 412 q_q_coff, q_i_coff; 413 const s32 res_scale = 1 << 15; 414 const s32 delpt_shift = 1 << 8; 415 s32 mag1, mag2; 416 struct ath_common *common = ath9k_hw_common(ah); 417 418 i2_m_q2_a0_d0 = iq_res[0] & 0xfff; 419 i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; 420 iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); 421 422 if (i2_m_q2_a0_d0 > 0x800) 423 i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); 424 425 if (i2_p_q2_a0_d0 > 0x800) 426 i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1); 427 428 if (iq_corr_a0_d0 > 0x800) 429 iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); 430 431 i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; 432 i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); 433 iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; 434 435 if (i2_m_q2_a0_d1 > 0x800) 436 i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); 437 438 if (i2_p_q2_a0_d1 > 0x800) 439 i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1); 440 441 if (iq_corr_a0_d1 > 0x800) 442 iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); 443 444 i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); 445 i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; 446 iq_corr_a1_d0 = iq_res[4] & 0xfff; 447 448 if (i2_m_q2_a1_d0 > 0x800) 449 i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); 450 451 if (i2_p_q2_a1_d0 > 0x800) 452 i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1); 453 454 if (iq_corr_a1_d0 > 0x800) 455 iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); 456 457 i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; 458 i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); 459 iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; 460 461 if (i2_m_q2_a1_d1 > 0x800) 462 i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); 463 464 if (i2_p_q2_a1_d1 > 0x800) 465 i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1); 466 467 if (iq_corr_a1_d1 > 0x800) 468 iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); 469 470 if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || 471 (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { 472 ath_dbg(common, ATH_DBG_CALIBRATE, 473 "Divide by 0:\n" 474 "a0_d0=%d\n" 475 "a0_d1=%d\n" 476 "a2_d0=%d\n" 477 "a1_d1=%d\n", 478 i2_p_q2_a0_d0, i2_p_q2_a0_d1, 479 i2_p_q2_a1_d0, i2_p_q2_a1_d1); 480 return false; 481 } 482 483 mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; 484 phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; 485 486 mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; 487 phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; 488 489 mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; 490 phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; 491 492 mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; 493 phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; 494 495 /* w/o analog phase shift */ 496 sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); 497 /* w/o analog phase shift */ 498 cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); 499 /* w/ analog phase shift */ 500 sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); 501 /* w/ analog phase shift */ 502 cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); 503 504 /* 505 * force sin^2 + cos^2 = 1; 506 * find magnitude by approximation 507 */ 508 mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); 509 mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); 510 511 if ((mag1 == 0) || (mag2 == 0)) { 512 ath_dbg(common, ATH_DBG_CALIBRATE, 513 "Divide by 0: mag1=%d, mag2=%d\n", 514 mag1, mag2); 515 return false; 516 } 517 518 /* normalization sin and cos by mag */ 519 sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); 520 cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); 521 sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); 522 cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); 523 524 /* calculate IQ mismatch */ 525 if (!ar9003_hw_solve_iq_cal(ah, 526 sin_2phi_1, cos_2phi_1, 527 sin_2phi_2, cos_2phi_2, 528 mag_a0_d0, phs_a0_d0, 529 mag_a1_d0, 530 phs_a1_d0, solved_eq)) { 531 ath_dbg(common, ATH_DBG_CALIBRATE, 532 "Call to ar9003_hw_solve_iq_cal() failed.\n"); 533 return false; 534 } 535 536 mag_tx = solved_eq[0]; 537 phs_tx = solved_eq[1]; 538 mag_rx = solved_eq[2]; 539 phs_rx = solved_eq[3]; 540 541 ath_dbg(common, ATH_DBG_CALIBRATE, 542 "chain %d: mag mismatch=%d phase mismatch=%d\n", 543 chain_idx, mag_tx/res_scale, phs_tx/res_scale); 544 545 if (res_scale == mag_tx) { 546 ath_dbg(common, ATH_DBG_CALIBRATE, 547 "Divide by 0: mag_tx=%d, res_scale=%d\n", 548 mag_tx, res_scale); 549 return false; 550 } 551 552 /* calculate and quantize Tx IQ correction factor */ 553 mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); 554 phs_corr_tx = -phs_tx; 555 556 q_q_coff = (mag_corr_tx * 128 / res_scale); 557 q_i_coff = (phs_corr_tx * 256 / res_scale); 558 559 ath_dbg(common, ATH_DBG_CALIBRATE, 560 "tx chain %d: mag corr=%d phase corr=%d\n", 561 chain_idx, q_q_coff, q_i_coff); 562 563 if (q_i_coff < -63) 564 q_i_coff = -63; 565 if (q_i_coff > 63) 566 q_i_coff = 63; 567 if (q_q_coff < -63) 568 q_q_coff = -63; 569 if (q_q_coff > 63) 570 q_q_coff = 63; 571 572 iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; 573 574 ath_dbg(common, ATH_DBG_CALIBRATE, 575 "tx chain %d: iq corr coeff=%x\n", 576 chain_idx, iqc_coeff[0]); 577 578 if (-mag_rx == res_scale) { 579 ath_dbg(common, ATH_DBG_CALIBRATE, 580 "Divide by 0: mag_rx=%d, res_scale=%d\n", 581 mag_rx, res_scale); 582 return false; 583 } 584 585 /* calculate and quantize Rx IQ correction factors */ 586 mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); 587 phs_corr_rx = -phs_rx; 588 589 q_q_coff = (mag_corr_rx * 128 / res_scale); 590 q_i_coff = (phs_corr_rx * 256 / res_scale); 591 592 ath_dbg(common, ATH_DBG_CALIBRATE, 593 "rx chain %d: mag corr=%d phase corr=%d\n", 594 chain_idx, q_q_coff, q_i_coff); 595 596 if (q_i_coff < -63) 597 q_i_coff = -63; 598 if (q_i_coff > 63) 599 q_i_coff = 63; 600 if (q_q_coff < -63) 601 q_q_coff = -63; 602 if (q_q_coff > 63) 603 q_q_coff = 63; 604 605 iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; 606 607 ath_dbg(common, ATH_DBG_CALIBRATE, 608 "rx chain %d: iq corr coeff=%x\n", 609 chain_idx, iqc_coeff[1]); 610 611 return true; 612 } 613 614 static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, 615 int max_delta) 616 { 617 int mp_max = -64, max_idx = 0; 618 int mp_min = 63, min_idx = 0; 619 int mp_avg = 0, i, outlier_idx = 0, mp_count = 0; 620 621 /* find min/max mismatch across all calibrated gains */ 622 for (i = 0; i < nmeasurement; i++) { 623 if (mp_coeff[i] > mp_max) { 624 mp_max = mp_coeff[i]; 625 max_idx = i; 626 } else if (mp_coeff[i] < mp_min) { 627 mp_min = mp_coeff[i]; 628 min_idx = i; 629 } 630 } 631 632 /* find average (exclude max abs value) */ 633 for (i = 0; i < nmeasurement; i++) { 634 if ((abs(mp_coeff[i]) < abs(mp_max)) || 635 (abs(mp_coeff[i]) < abs(mp_min))) { 636 mp_avg += mp_coeff[i]; 637 mp_count++; 638 } 639 } 640 641 /* 642 * finding mean magnitude/phase if possible, otherwise 643 * just use the last value as the mean 644 */ 645 if (mp_count) 646 mp_avg /= mp_count; 647 else 648 mp_avg = mp_coeff[nmeasurement - 1]; 649 650 /* detect outlier */ 651 if (abs(mp_max - mp_min) > max_delta) { 652 if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) 653 outlier_idx = max_idx; 654 else 655 outlier_idx = min_idx; 656 657 mp_coeff[outlier_idx] = mp_avg; 658 } 659 } 660 661 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, 662 u8 num_chains, 663 struct coeff *coeff, 664 bool is_reusable) 665 { 666 int i, im, nmeasurement; 667 u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; 668 struct ath9k_hw_cal_data *caldata = ah->caldata; 669 670 memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); 671 for (i = 0; i < MAX_MEASUREMENT / 2; i++) { 672 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] = 673 AR_PHY_TX_IQCAL_CORR_COEFF_B0(i); 674 if (!AR_SREV_9485(ah)) { 675 tx_corr_coeff[i * 2][1] = 676 tx_corr_coeff[(i * 2) + 1][1] = 677 AR_PHY_TX_IQCAL_CORR_COEFF_B1(i); 678 679 tx_corr_coeff[i * 2][2] = 680 tx_corr_coeff[(i * 2) + 1][2] = 681 AR_PHY_TX_IQCAL_CORR_COEFF_B2(i); 682 } 683 } 684 685 /* Load the average of 2 passes */ 686 for (i = 0; i < num_chains; i++) { 687 nmeasurement = REG_READ_FIELD(ah, 688 AR_PHY_TX_IQCAL_STATUS_B0, 689 AR_PHY_CALIBRATED_GAINS_0); 690 691 if (nmeasurement > MAX_MEASUREMENT) 692 nmeasurement = MAX_MEASUREMENT; 693 694 /* detect outlier only if nmeasurement > 1 */ 695 if (nmeasurement > 1) { 696 /* Detect magnitude outlier */ 697 ar9003_hw_detect_outlier(coeff->mag_coeff[i], 698 nmeasurement, MAX_MAG_DELTA); 699 700 /* Detect phase outlier */ 701 ar9003_hw_detect_outlier(coeff->phs_coeff[i], 702 nmeasurement, MAX_PHS_DELTA); 703 } 704 705 for (im = 0; im < nmeasurement; im++) { 706 707 coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | 708 ((coeff->phs_coeff[i][im] & 0x7f) << 7); 709 710 if ((im % 2) == 0) 711 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 712 AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 713 coeff->iqc_coeff[0]); 714 else 715 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 716 AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 717 coeff->iqc_coeff[0]); 718 719 if (caldata) 720 caldata->tx_corr_coeff[im][i] = 721 coeff->iqc_coeff[0]; 722 } 723 if (caldata) 724 caldata->num_measures[i] = nmeasurement; 725 } 726 727 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 728 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 729 REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 730 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 731 732 if (caldata) 733 caldata->done_txiqcal_once = is_reusable; 734 735 return; 736 } 737 738 static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) 739 { 740 struct ath_common *common = ath9k_hw_common(ah); 741 u8 tx_gain_forced; 742 743 tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 744 AR_PHY_TXGAIN_FORCE); 745 if (tx_gain_forced) 746 REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, 747 AR_PHY_TXGAIN_FORCE, 0); 748 749 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, 750 AR_PHY_TX_IQCAL_START_DO_CAL, 1); 751 752 if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, 753 AR_PHY_TX_IQCAL_START_DO_CAL, 0, 754 AH_WAIT_TIMEOUT)) { 755 ath_dbg(common, ATH_DBG_CALIBRATE, 756 "Tx IQ Cal is not completed.\n"); 757 return false; 758 } 759 return true; 760 } 761 762 static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) 763 { 764 struct ath_common *common = ath9k_hw_common(ah); 765 const u32 txiqcal_status[AR9300_MAX_CHAINS] = { 766 AR_PHY_TX_IQCAL_STATUS_B0, 767 AR_PHY_TX_IQCAL_STATUS_B1, 768 AR_PHY_TX_IQCAL_STATUS_B2, 769 }; 770 const u_int32_t chan_info_tab[] = { 771 AR_PHY_CHAN_INFO_TAB_0, 772 AR_PHY_CHAN_INFO_TAB_1, 773 AR_PHY_CHAN_INFO_TAB_2, 774 }; 775 struct coeff coeff; 776 s32 iq_res[6]; 777 u8 num_chains = 0; 778 int i, im, j; 779 int nmeasurement; 780 781 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 782 if (ah->txchainmask & (1 << i)) 783 num_chains++; 784 } 785 786 for (i = 0; i < num_chains; i++) { 787 nmeasurement = REG_READ_FIELD(ah, 788 AR_PHY_TX_IQCAL_STATUS_B0, 789 AR_PHY_CALIBRATED_GAINS_0); 790 if (nmeasurement > MAX_MEASUREMENT) 791 nmeasurement = MAX_MEASUREMENT; 792 793 for (im = 0; im < nmeasurement; im++) { 794 ath_dbg(common, ATH_DBG_CALIBRATE, 795 "Doing Tx IQ Cal for chain %d.\n", i); 796 797 if (REG_READ(ah, txiqcal_status[i]) & 798 AR_PHY_TX_IQCAL_STATUS_FAILED) { 799 ath_dbg(common, ATH_DBG_CALIBRATE, 800 "Tx IQ Cal failed for chain %d.\n", i); 801 goto tx_iqcal_fail; 802 } 803 804 for (j = 0; j < 3; j++) { 805 u32 idx = 2 * j, offset = 4 * (3 * im + j); 806 807 REG_RMW_FIELD(ah, 808 AR_PHY_CHAN_INFO_MEMORY, 809 AR_PHY_CHAN_INFO_TAB_S2_READ, 810 0); 811 812 /* 32 bits */ 813 iq_res[idx] = REG_READ(ah, 814 chan_info_tab[i] + 815 offset); 816 817 REG_RMW_FIELD(ah, 818 AR_PHY_CHAN_INFO_MEMORY, 819 AR_PHY_CHAN_INFO_TAB_S2_READ, 820 1); 821 822 /* 16 bits */ 823 iq_res[idx + 1] = 0xffff & REG_READ(ah, 824 chan_info_tab[i] + offset); 825 826 ath_dbg(common, ATH_DBG_CALIBRATE, 827 "IQ RES[%d]=0x%x" 828 "IQ_RES[%d]=0x%x\n", 829 idx, iq_res[idx], idx + 1, 830 iq_res[idx + 1]); 831 } 832 833 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, 834 coeff.iqc_coeff)) { 835 ath_dbg(common, ATH_DBG_CALIBRATE, 836 "Failed in calculation of \ 837 IQ correction.\n"); 838 goto tx_iqcal_fail; 839 } 840 841 coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; 842 coeff.phs_coeff[i][im] = 843 (coeff.iqc_coeff[0] >> 7) & 0x7f; 844 845 if (coeff.mag_coeff[i][im] > 63) 846 coeff.mag_coeff[i][im] -= 128; 847 if (coeff.phs_coeff[i][im] > 63) 848 coeff.phs_coeff[i][im] -= 128; 849 } 850 } 851 ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, 852 &coeff, is_reusable); 853 854 return; 855 856 tx_iqcal_fail: 857 ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); 858 return; 859 } 860 861 static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) 862 { 863 struct ath9k_hw_cal_data *caldata = ah->caldata; 864 u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; 865 int i, im; 866 867 memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); 868 for (i = 0; i < MAX_MEASUREMENT / 2; i++) { 869 tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] = 870 AR_PHY_TX_IQCAL_CORR_COEFF_B0(i); 871 if (!AR_SREV_9485(ah)) { 872 tx_corr_coeff[i * 2][1] = 873 tx_corr_coeff[(i * 2) + 1][1] = 874 AR_PHY_TX_IQCAL_CORR_COEFF_B1(i); 875 876 tx_corr_coeff[i * 2][2] = 877 tx_corr_coeff[(i * 2) + 1][2] = 878 AR_PHY_TX_IQCAL_CORR_COEFF_B2(i); 879 } 880 } 881 882 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 883 if (!(ah->txchainmask & (1 << i))) 884 continue; 885 886 for (im = 0; im < caldata->num_measures[i]; im++) { 887 if ((im % 2) == 0) 888 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 889 AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, 890 caldata->tx_corr_coeff[im][i]); 891 else 892 REG_RMW_FIELD(ah, tx_corr_coeff[im][i], 893 AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, 894 caldata->tx_corr_coeff[im][i]); 895 } 896 } 897 898 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, 899 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); 900 REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, 901 AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); 902 } 903 904 static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) 905 { 906 struct ath9k_rtt_hist *hist; 907 u32 *table; 908 int i; 909 bool restore; 910 911 if (!ah->caldata) 912 return false; 913 914 hist = &ah->caldata->rtt_hist; 915 if (!hist->num_readings) 916 return false; 917 918 ar9003_hw_rtt_enable(ah); 919 ar9003_hw_rtt_set_mask(ah, 0x00); 920 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 921 if (!(ah->rxchainmask & (1 << i))) 922 continue; 923 table = &hist->table[i][hist->num_readings][0]; 924 ar9003_hw_rtt_load_hist(ah, i, table); 925 } 926 restore = ar9003_hw_rtt_force_restore(ah); 927 ar9003_hw_rtt_disable(ah); 928 929 return restore; 930 } 931 932 static bool ar9003_hw_init_cal(struct ath_hw *ah, 933 struct ath9k_channel *chan) 934 { 935 struct ath_common *common = ath9k_hw_common(ah); 936 struct ath9k_hw_cal_data *caldata = ah->caldata; 937 bool txiqcal_done = false, txclcal_done = false; 938 bool is_reusable = true, status = true; 939 bool run_rtt_cal = false, run_agc_cal; 940 bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); 941 u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL | 942 AR_PHY_AGC_CONTROL_FLTR_CAL | 943 AR_PHY_AGC_CONTROL_PKDET_CAL; 944 int i, j; 945 u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, 946 AR_PHY_CL_TAB_1, 947 AR_PHY_CL_TAB_2 }; 948 949 if (rtt) { 950 if (!ar9003_hw_rtt_restore(ah, chan)) 951 run_rtt_cal = true; 952 953 ath_dbg(common, ATH_DBG_CALIBRATE, "RTT restore %s\n", 954 run_rtt_cal ? "failed" : "succeed"); 955 } 956 run_agc_cal = run_rtt_cal; 957 958 if (run_rtt_cal) { 959 ar9003_hw_rtt_enable(ah); 960 ar9003_hw_rtt_set_mask(ah, 0x00); 961 ar9003_hw_rtt_clear_hist(ah); 962 } 963 964 if (rtt && !run_rtt_cal) { 965 agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL); 966 agc_supp_cals &= agc_ctrl; 967 agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL | 968 AR_PHY_AGC_CONTROL_FLTR_CAL | 969 AR_PHY_AGC_CONTROL_PKDET_CAL); 970 REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); 971 } 972 973 if (ah->enabled_cals & TX_CL_CAL) { 974 if (caldata && caldata->done_txclcal_once) 975 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, 976 AR_PHY_CL_CAL_ENABLE); 977 else { 978 REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, 979 AR_PHY_CL_CAL_ENABLE); 980 run_agc_cal = true; 981 } 982 } 983 984 if (!(ah->enabled_cals & TX_IQ_CAL)) 985 goto skip_tx_iqcal; 986 987 /* Do Tx IQ Calibration */ 988 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, 989 AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, 990 DELPT); 991 992 /* 993 * For AR9485 or later chips, TxIQ cal runs as part of 994 * AGC calibration 995 */ 996 if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { 997 if (caldata && !caldata->done_txiqcal_once) 998 REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, 999 AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 1000 else 1001 REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, 1002 AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); 1003 txiqcal_done = run_agc_cal = true; 1004 goto skip_tx_iqcal; 1005 } else if (caldata && !caldata->done_txiqcal_once) 1006 run_agc_cal = true; 1007 1008 txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); 1009 REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); 1010 udelay(5); 1011 REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); 1012 1013 skip_tx_iqcal: 1014 if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { 1015 /* Calibrate the AGC */ 1016 REG_WRITE(ah, AR_PHY_AGC_CONTROL, 1017 REG_READ(ah, AR_PHY_AGC_CONTROL) | 1018 AR_PHY_AGC_CONTROL_CAL); 1019 1020 /* Poll for offset calibration complete */ 1021 status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 1022 AR_PHY_AGC_CONTROL_CAL, 1023 0, AH_WAIT_TIMEOUT); 1024 } 1025 if (rtt && !run_rtt_cal) { 1026 agc_ctrl |= agc_supp_cals; 1027 REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); 1028 } 1029 1030 if (!status) { 1031 if (run_rtt_cal) 1032 ar9003_hw_rtt_disable(ah); 1033 1034 ath_dbg(common, ATH_DBG_CALIBRATE, 1035 "offset calibration failed to complete in 1ms;" 1036 "noisy environment?\n"); 1037 return false; 1038 } 1039 1040 if (txiqcal_done) 1041 ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); 1042 else if (caldata && caldata->done_txiqcal_once) 1043 ar9003_hw_tx_iq_cal_reload(ah); 1044 1045 #define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) 1046 if (caldata && (ah->enabled_cals & TX_CL_CAL)) { 1047 txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & 1048 AR_PHY_AGC_CONTROL_CLC_SUCCESS); 1049 if (caldata->done_txclcal_once) { 1050 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 1051 if (!(ah->txchainmask & (1 << i))) 1052 continue; 1053 for (j = 0; j < MAX_CL_TAB_ENTRY; j++) 1054 REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), 1055 caldata->tx_clcal[i][j]); 1056 } 1057 } else if (is_reusable && txclcal_done) { 1058 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 1059 if (!(ah->txchainmask & (1 << i))) 1060 continue; 1061 for (j = 0; j < MAX_CL_TAB_ENTRY; j++) 1062 caldata->tx_clcal[i][j] = 1063 REG_READ(ah, 1064 CL_TAB_ENTRY(cl_idx[i])); 1065 } 1066 caldata->done_txclcal_once = true; 1067 } 1068 } 1069 #undef CL_TAB_ENTRY 1070 1071 if (run_rtt_cal && caldata) { 1072 struct ath9k_rtt_hist *hist = &caldata->rtt_hist; 1073 if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) { 1074 u32 *table; 1075 1076 hist->num_readings++; 1077 for (i = 0; i < AR9300_MAX_CHAINS; i++) { 1078 if (!(ah->rxchainmask & (1 << i))) 1079 continue; 1080 table = &hist->table[i][hist->num_readings][0]; 1081 ar9003_hw_rtt_fill_hist(ah, i, table); 1082 } 1083 } 1084 1085 ar9003_hw_rtt_disable(ah); 1086 } 1087 1088 /* Initialize list pointers */ 1089 ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 1090 ah->supp_cals = IQ_MISMATCH_CAL; 1091 1092 if (ah->supp_cals & IQ_MISMATCH_CAL) { 1093 INIT_CAL(&ah->iq_caldata); 1094 INSERT_CAL(ah, &ah->iq_caldata); 1095 ath_dbg(common, ATH_DBG_CALIBRATE, 1096 "enabling IQ Calibration.\n"); 1097 } 1098 1099 if (ah->supp_cals & TEMP_COMP_CAL) { 1100 INIT_CAL(&ah->tempCompCalData); 1101 INSERT_CAL(ah, &ah->tempCompCalData); 1102 ath_dbg(common, ATH_DBG_CALIBRATE, 1103 "enabling Temperature Compensation Calibration.\n"); 1104 } 1105 1106 /* Initialize current pointer to first element in list */ 1107 ah->cal_list_curr = ah->cal_list; 1108 1109 if (ah->cal_list_curr) 1110 ath9k_hw_reset_calibration(ah, ah->cal_list_curr); 1111 1112 if (caldata) 1113 caldata->CalValid = 0; 1114 1115 return true; 1116 } 1117 1118 void ar9003_hw_attach_calib_ops(struct ath_hw *ah) 1119 { 1120 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 1121 struct ath_hw_ops *ops = ath9k_hw_ops(ah); 1122 1123 priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; 1124 priv_ops->init_cal = ar9003_hw_init_cal; 1125 priv_ops->setup_calibration = ar9003_hw_setup_calibration; 1126 1127 ops->calibrate = ar9003_hw_calibrate; 1128 } 1129