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