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