Branch data Line data Source code
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 : : #include "ar9003_mci.h"
22 : :
23 : : #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
24 : : #define MAX_MAG_DELTA 11
25 : : #define MAX_PHS_DELTA 10
26 : : #define MAXIQCAL 3
27 : :
28 : : struct coeff {
29 : : int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
30 : : int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
31 : : int iqc_coeff[2];
32 : : };
33 : :
34 : : enum ar9003_cal_types {
35 : : IQ_MISMATCH_CAL = BIT(0),
36 : : };
37 : :
38 : 41 : static void ar9003_hw_setup_calibration(struct ath_hw *ah,
39 : : struct ath9k_cal_list *currCal)
40 : : {
41 [ + - ]: 41 : struct ath_common *common = ath9k_hw_common(ah);
42 : :
43 : : /* Select calibration to run */
44 [ + - ]: 41 : switch (currCal->calData->calType) {
45 : 41 : case IQ_MISMATCH_CAL:
46 : : /*
47 : : * Start calibration with
48 : : * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
49 : : */
50 : 41 : REG_RMW_FIELD(ah, AR_PHY_TIMING4,
51 : : AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
52 : : currCal->calData->calCountMax);
53 : 41 : REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
54 : :
55 [ - + ]: 41 : ath_dbg(common, CALIBRATE,
56 : : "starting IQ Mismatch Calibration\n");
57 : :
58 : : /* Kick-off cal */
59 : 41 : REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
60 : 41 : break;
61 : 0 : default:
62 : 0 : ath_err(common, "Invalid calibration type\n");
63 : 0 : break;
64 : : }
65 : 41 : }
66 : :
67 : : /*
68 : : * Generic calibration routine.
69 : : * Recalibrate the lower PHY chips to account for temperature/environment
70 : : * changes.
71 : : */
72 : 0 : static bool ar9003_hw_per_calibration(struct ath_hw *ah,
73 : : struct ath9k_channel *ichan,
74 : : u8 rxchainmask,
75 : : struct ath9k_cal_list *currCal)
76 : : {
77 : 0 : struct ath9k_hw_cal_data *caldata = ah->caldata;
78 : 0 : const struct ath9k_percal_data *cur_caldata = currCal->calData;
79 : :
80 : : /* Calibration in progress. */
81 [ # # ]: 0 : if (currCal->calState == CAL_RUNNING) {
82 : : /* Check to see if it has finished. */
83 [ # # ]: 0 : if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)
84 : : return false;
85 : :
86 : : /*
87 : : * Accumulate cal measures for active chains
88 : : */
89 : 0 : cur_caldata->calCollect(ah);
90 : 0 : ah->cal_samples++;
91 : :
92 [ # # ]: 0 : if (ah->cal_samples >= cur_caldata->calNumSamples) {
93 : : unsigned int i, numChains = 0;
94 [ # # ]: 0 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
95 [ # # ]: 0 : if (rxchainmask & (1 << i))
96 : 0 : numChains++;
97 : : }
98 : :
99 : : /*
100 : : * Process accumulated data
101 : : */
102 : 0 : cur_caldata->calPostProc(ah, numChains);
103 : :
104 : : /* Calibration has finished. */
105 : 0 : caldata->CalValid |= cur_caldata->calType;
106 : 0 : currCal->calState = CAL_DONE;
107 : 0 : return true;
108 : : } else {
109 : : /*
110 : : * Set-up collection of another sub-sample until we
111 : : * get desired number
112 : : */
113 : 0 : ar9003_hw_setup_calibration(ah, currCal);
114 : : }
115 [ # # ]: 0 : } else if (!(caldata->CalValid & cur_caldata->calType)) {
116 : : /* If current cal is marked invalid in channel, kick it off */
117 : 0 : ath9k_hw_reset_calibration(ah, currCal);
118 : : }
119 : :
120 : : return false;
121 : : }
122 : :
123 : 0 : static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
124 : : u8 rxchainmask, bool longcal)
125 : : {
126 : 0 : bool iscaldone = true;
127 : 0 : struct ath9k_cal_list *currCal = ah->cal_list_curr;
128 : 0 : int ret;
129 : :
130 : : /*
131 : : * For given calibration:
132 : : * 1. Call generic cal routine
133 : : * 2. When this cal is done (isCalDone) if we have more cals waiting
134 : : * (eg after reset), mask this to upper layers by not propagating
135 : : * isCalDone if it is set to TRUE.
136 : : * Instead, change isCalDone to FALSE and setup the waiting cal(s)
137 : : * to be run.
138 : : */
139 [ # # ]: 0 : if (currCal &&
140 [ # # ]: 0 : (currCal->calState == CAL_RUNNING ||
141 : : currCal->calState == CAL_WAITING)) {
142 : 0 : iscaldone = ar9003_hw_per_calibration(ah, chan,
143 : : rxchainmask, currCal);
144 [ # # ]: 0 : if (iscaldone) {
145 : 0 : ah->cal_list_curr = currCal = currCal->calNext;
146 : :
147 [ # # ]: 0 : if (currCal->calState == CAL_WAITING) {
148 : 0 : iscaldone = false;
149 : 0 : ath9k_hw_reset_calibration(ah, currCal);
150 : : }
151 : : }
152 : : }
153 : :
154 : : /*
155 : : * Do NF cal only at longer intervals. Get the value from
156 : : * the previous NF cal and update history buffer.
157 : : */
158 [ # # # # ]: 0 : if (longcal && ath9k_hw_getnf(ah, chan)) {
159 : : /*
160 : : * Load the NF from history buffer of the current channel.
161 : : * NF is slow time-variant, so it is OK to use a historical
162 : : * value.
163 : : */
164 : 0 : ret = ath9k_hw_loadnf(ah, ah->curchan);
165 [ # # ]: 0 : if (ret < 0)
166 : : return ret;
167 : :
168 : : /* start NF calibration, without updating BB NF register */
169 : 0 : ath9k_hw_start_nfcal(ah, false);
170 : : }
171 : :
172 : 0 : return iscaldone;
173 : : }
174 : :
175 : 0 : static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
176 : : {
177 : 0 : int i;
178 : :
179 : : /* Accumulate IQ cal measures for active chains */
180 [ # # ]: 0 : for (i = 0; i < AR5416_MAX_CHAINS; i++) {
181 [ # # ]: 0 : if (ah->txchainmask & BIT(i)) {
182 : 0 : ah->totalPowerMeasI[i] +=
183 : 0 : REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
184 : 0 : ah->totalPowerMeasQ[i] +=
185 : 0 : REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
186 : 0 : ah->totalIqCorrMeas[i] +=
187 : 0 : (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
188 [ # # ]: 0 : ath_dbg(ath9k_hw_common(ah), CALIBRATE,
189 : : "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
190 : : ah->cal_samples, i, ah->totalPowerMeasI[i],
191 : : ah->totalPowerMeasQ[i],
192 : : ah->totalIqCorrMeas[i]);
193 : : }
194 : : }
195 : 0 : }
196 : :
197 : 0 : static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
198 : : {
199 : 0 : struct ath_common *common = ath9k_hw_common(ah);
200 : 0 : u32 powerMeasQ, powerMeasI, iqCorrMeas;
201 : 0 : u32 qCoffDenom, iCoffDenom;
202 : 0 : int32_t qCoff, iCoff;
203 : 0 : int iqCorrNeg, i;
204 : 0 : static const u_int32_t offset_array[3] = {
205 : : AR_PHY_RX_IQCAL_CORR_B0,
206 : : AR_PHY_RX_IQCAL_CORR_B1,
207 : : AR_PHY_RX_IQCAL_CORR_B2,
208 : : };
209 : :
210 [ # # ]: 0 : for (i = 0; i < numChains; i++) {
211 : 0 : powerMeasI = ah->totalPowerMeasI[i];
212 : 0 : powerMeasQ = ah->totalPowerMeasQ[i];
213 : 0 : iqCorrMeas = ah->totalIqCorrMeas[i];
214 : :
215 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
216 : : "Starting IQ Cal and Correction for Chain %d\n", i);
217 : :
218 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
219 : : "Original: Chn %d iq_corr_meas = 0x%08x\n",
220 : : i, ah->totalIqCorrMeas[i]);
221 : :
222 : 0 : iqCorrNeg = 0;
223 : :
224 [ # # ]: 0 : if (iqCorrMeas > 0x80000000) {
225 : 0 : iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
226 : 0 : iqCorrNeg = 1;
227 : : }
228 : :
229 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",
230 : : i, powerMeasI);
231 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",
232 : : i, powerMeasQ);
233 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);
234 : :
235 : 0 : iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
236 : 0 : qCoffDenom = powerMeasQ / 64;
237 : :
238 [ # # # # ]: 0 : if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
239 : 0 : iCoff = iqCorrMeas / iCoffDenom;
240 : 0 : qCoff = powerMeasI / qCoffDenom - 64;
241 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",
242 : : i, iCoff);
243 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",
244 : : i, qCoff);
245 : :
246 : : /* Force bounds on iCoff */
247 : 0 : if (iCoff >= 63)
248 : : iCoff = 63;
249 : : else if (iCoff <= -63)
250 : : iCoff = -63;
251 : :
252 : : /* Negate iCoff if iqCorrNeg == 0 */
253 [ # # ]: 0 : if (iqCorrNeg == 0x0)
254 : 0 : iCoff = -iCoff;
255 : :
256 : : /* Force bounds on qCoff */
257 : 0 : if (qCoff >= 63)
258 : : qCoff = 63;
259 : : else if (qCoff <= -63)
260 : : qCoff = -63;
261 : :
262 : 0 : iCoff = iCoff & 0x7f;
263 : 0 : qCoff = qCoff & 0x7f;
264 : :
265 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
266 : : "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
267 : : i, iCoff, qCoff);
268 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
269 : : "Register offset (0x%04x) before update = 0x%x\n",
270 : : offset_array[i],
271 : : REG_READ(ah, offset_array[i]));
272 : :
273 [ # # # # ]: 0 : if (AR_SREV_9565(ah) &&
274 [ # # ]: 0 : (iCoff == 63 || qCoff == 63 ||
275 : : iCoff == -63 || qCoff == -63))
276 : : return;
277 : :
278 : 0 : REG_RMW_FIELD(ah, offset_array[i],
279 : : AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
280 : : iCoff);
281 : 0 : REG_RMW_FIELD(ah, offset_array[i],
282 : : AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
283 : : qCoff);
284 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
285 : : "Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
286 : : offset_array[i],
287 : : AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
288 : : REG_READ(ah, offset_array[i]));
289 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
290 : : "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
291 : : offset_array[i],
292 : : AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
293 : : REG_READ(ah, offset_array[i]));
294 : :
295 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
296 : : "IQ Cal and Correction done for Chain %d\n", i);
297 : : }
298 : : }
299 : :
300 : 0 : REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
301 : : AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
302 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
303 : : "IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
304 : : (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
305 : : AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
306 : : REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
307 : : }
308 : :
309 : : static const struct ath9k_percal_data iq_cal_single_sample = {
310 : : IQ_MISMATCH_CAL,
311 : : MIN_CAL_SAMPLES,
312 : : PER_MAX_LOG_COUNT,
313 : : ar9003_hw_iqcal_collect,
314 : : ar9003_hw_iqcalibrate
315 : : };
316 : :
317 : 5 : static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
318 : : {
319 : 5 : ah->iq_caldata.calData = &iq_cal_single_sample;
320 : :
321 [ + - ]: 5 : if (AR_SREV_9300_20_OR_LATER(ah)) {
322 : 5 : ah->enabled_cals |= TX_IQ_CAL;
323 [ + + + - ]: 5 : if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
324 : 3 : ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
325 : : }
326 : :
327 : 5 : ah->supp_cals = IQ_MISMATCH_CAL;
328 : 5 : }
329 : :
330 : : #define OFF_UPPER_LT 24
331 : : #define OFF_LOWER_LT 7
332 : :
333 : 0 : static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah,
334 : : bool txiqcal_done)
335 : : {
336 [ # # ]: 0 : struct ath_common *common = ath9k_hw_common(ah);
337 : 0 : int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2,
338 : : dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3;
339 : 0 : int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2,
340 : : dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3;
341 : 0 : int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2,
342 : : dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3;
343 : 0 : bool status;
344 : 0 : u32 temp, val;
345 : :
346 : : /*
347 : : * Clear offset and IQ calibration, run AGC cal.
348 : : */
349 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
350 : : AR_PHY_AGC_CONTROL_OFFSET_CAL);
351 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
352 : : AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
353 [ # # ]: 0 : REG_WRITE(ah, AR_PHY_AGC_CONTROL,
354 : : REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
355 : :
356 [ # # ]: 0 : status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
357 : : AR_PHY_AGC_CONTROL_CAL,
358 : : 0, AH_WAIT_TIMEOUT);
359 [ # # ]: 0 : if (!status) {
360 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
361 : : "AGC cal without offset cal failed to complete in 1ms");
362 : 0 : return false;
363 : : }
364 : :
365 : : /*
366 : : * Allow only offset calibration and disable the others
367 : : * (Carrier Leak calibration, TX Filter calibration and
368 : : * Peak Detector offset calibration).
369 : : */
370 [ # # ]: 0 : REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
371 : : AR_PHY_AGC_CONTROL_OFFSET_CAL);
372 : 0 : REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
373 : : AR_PHY_CL_CAL_ENABLE);
374 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
375 : : AR_PHY_AGC_CONTROL_FLTR_CAL);
376 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
377 : : AR_PHY_AGC_CONTROL_PKDET_CAL);
378 : :
379 : 0 : ch0_done = 0;
380 : 0 : ch1_done = 0;
381 : 0 : ch2_done = 0;
382 : :
383 [ # # # # : 0 : while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) {
# # ]
384 : 0 : osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3;
385 : 0 : osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3;
386 : 0 : osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3;
387 : :
388 : 0 : REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
389 : :
390 [ # # ]: 0 : REG_WRITE(ah, AR_PHY_AGC_CONTROL,
391 : : REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
392 : :
393 [ # # ]: 0 : status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
394 : : AR_PHY_AGC_CONTROL_CAL,
395 : : 0, AH_WAIT_TIMEOUT);
396 [ # # ]: 0 : if (!status) {
397 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
398 : : "DC offset cal failed to complete in 1ms");
399 : 0 : return false;
400 : : }
401 : :
402 : 0 : REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
403 : :
404 : : /*
405 : : * High gain.
406 : : */
407 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
408 : : ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8)));
409 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
410 : : ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8)));
411 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
412 : : ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8)));
413 : :
414 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
415 : 0 : dc_off_ch0_i1 = (temp >> 26) & 0x1f;
416 : 0 : dc_off_ch0_q1 = (temp >> 21) & 0x1f;
417 : :
418 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
419 : 0 : dc_off_ch1_i1 = (temp >> 26) & 0x1f;
420 : 0 : dc_off_ch1_q1 = (temp >> 21) & 0x1f;
421 : :
422 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
423 : 0 : dc_off_ch2_i1 = (temp >> 26) & 0x1f;
424 : 0 : dc_off_ch2_q1 = (temp >> 21) & 0x1f;
425 : :
426 : : /*
427 : : * Low gain.
428 : : */
429 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
430 : : ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8)));
431 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
432 : : ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8)));
433 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
434 : : ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8)));
435 : :
436 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
437 : 0 : dc_off_ch0_i2 = (temp >> 26) & 0x1f;
438 : 0 : dc_off_ch0_q2 = (temp >> 21) & 0x1f;
439 : :
440 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
441 : 0 : dc_off_ch1_i2 = (temp >> 26) & 0x1f;
442 : 0 : dc_off_ch1_q2 = (temp >> 21) & 0x1f;
443 : :
444 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
445 : 0 : dc_off_ch2_i2 = (temp >> 26) & 0x1f;
446 : 0 : dc_off_ch2_q2 = (temp >> 21) & 0x1f;
447 : :
448 : : /*
449 : : * Loopback.
450 : : */
451 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
452 : : ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8)));
453 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
454 : : ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8)));
455 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
456 : : ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8)));
457 : :
458 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
459 : 0 : dc_off_ch0_i3 = (temp >> 26) & 0x1f;
460 : 0 : dc_off_ch0_q3 = (temp >> 21) & 0x1f;
461 : :
462 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
463 : 0 : dc_off_ch1_i3 = (temp >> 26) & 0x1f;
464 : 0 : dc_off_ch1_q3 = (temp >> 21) & 0x1f;
465 : :
466 : 0 : temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
467 : 0 : dc_off_ch2_i3 = (temp >> 26) & 0x1f;
468 : 0 : dc_off_ch2_q3 = (temp >> 21) & 0x1f;
469 : :
470 [ # # # # ]: 0 : if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) ||
471 [ # # # # ]: 0 : (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) ||
472 [ # # # # ]: 0 : (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) ||
473 [ # # # # ]: 0 : (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) ||
474 [ # # # # ]: 0 : (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) ||
475 [ # # ]: 0 : (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) {
476 [ # # ]: 0 : if (osdac_ch0 == 3) {
477 : : ch0_done = 1;
478 : : } else {
479 : 0 : osdac_ch0++;
480 : :
481 : 0 : val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff;
482 : 0 : val |= (osdac_ch0 << 30);
483 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val);
484 : :
485 : 0 : ch0_done = 0;
486 : : }
487 : : } else {
488 : : ch0_done = 1;
489 : : }
490 : :
491 [ # # # # ]: 0 : if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) ||
492 [ # # # # ]: 0 : (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) ||
493 [ # # # # ]: 0 : (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) ||
494 [ # # # # ]: 0 : (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) ||
495 [ # # # # ]: 0 : (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) ||
496 [ # # ]: 0 : (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) {
497 [ # # ]: 0 : if (osdac_ch1 == 3) {
498 : : ch1_done = 1;
499 : : } else {
500 : 0 : osdac_ch1++;
501 : :
502 : 0 : val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff;
503 : 0 : val |= (osdac_ch1 << 30);
504 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val);
505 : :
506 : 0 : ch1_done = 0;
507 : : }
508 : : } else {
509 : : ch1_done = 1;
510 : : }
511 : :
512 [ # # # # ]: 0 : if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) ||
513 [ # # # # ]: 0 : (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) ||
514 [ # # # # ]: 0 : (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) ||
515 [ # # # # ]: 0 : (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) ||
516 [ # # # # ]: 0 : (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) ||
517 [ # # ]: 0 : (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) {
518 [ # # ]: 0 : if (osdac_ch2 == 3) {
519 : : ch2_done = 1;
520 : : } else {
521 : 0 : osdac_ch2++;
522 : :
523 : 0 : val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff;
524 : 0 : val |= (osdac_ch2 << 30);
525 : 0 : REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val);
526 : :
527 : 0 : ch2_done = 0;
528 : : }
529 : : } else {
530 : : ch2_done = 1;
531 : : }
532 : : }
533 : :
534 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
535 : : AR_PHY_AGC_CONTROL_OFFSET_CAL);
536 : 0 : REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
537 : :
538 : : /*
539 : : * We don't need to check txiqcal_done here since it is always
540 : : * set for AR9550.
541 : : */
542 [ # # ]: 0 : REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
543 : : AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
544 : :
545 : 0 : return true;
546 : : }
547 : :
548 : : /*
549 : : * solve 4x4 linear equation used in loopback iq cal.
550 : : */
551 : 0 : static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
552 : : s32 sin_2phi_1,
553 : : s32 cos_2phi_1,
554 : : s32 sin_2phi_2,
555 : : s32 cos_2phi_2,
556 : : s32 mag_a0_d0,
557 : : s32 phs_a0_d0,
558 : : s32 mag_a1_d0,
559 : : s32 phs_a1_d0,
560 : : s32 solved_eq[])
561 : : {
562 : 0 : s32 f1 = cos_2phi_1 - cos_2phi_2,
563 : 0 : f3 = sin_2phi_1 - sin_2phi_2,
564 : : f2;
565 : 0 : s32 mag_tx, phs_tx, mag_rx, phs_rx;
566 : 0 : const s32 result_shift = 1 << 15;
567 [ # # ]: 0 : struct ath_common *common = ath9k_hw_common(ah);
568 : :
569 : 0 : f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9;
570 : :
571 [ # # ]: 0 : if (!f2) {
572 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Divide by 0\n");
573 : 0 : return false;
574 : : }
575 : :
576 : : /* mag mismatch, tx */
577 : 0 : mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
578 : : /* phs mismatch, tx */
579 : 0 : phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
580 : :
581 : 0 : mag_tx = (mag_tx / f2);
582 : 0 : phs_tx = (phs_tx / f2);
583 : :
584 : : /* mag mismatch, rx */
585 : 0 : mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
586 : : result_shift;
587 : : /* phs mismatch, rx */
588 : 0 : phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
589 : : result_shift;
590 : :
591 : 0 : solved_eq[0] = mag_tx;
592 : 0 : solved_eq[1] = phs_tx;
593 : 0 : solved_eq[2] = mag_rx;
594 : 0 : solved_eq[3] = phs_rx;
595 : :
596 : 0 : return true;
597 : : }
598 : :
599 : 0 : static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im)
600 : : {
601 : 0 : s32 abs_i = abs(in_re),
602 : 0 : abs_q = abs(in_im),
603 : : max_abs, min_abs;
604 : :
605 : 0 : if (abs_i > abs_q) {
606 : : max_abs = abs_i;
607 : : min_abs = abs_q;
608 : : } else {
609 : 0 : max_abs = abs_q;
610 : 0 : min_abs = abs_i;
611 : : }
612 : :
613 : 0 : return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
614 : : }
615 : :
616 : : #define DELPT 32
617 : :
618 : 10 : static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
619 : : s32 chain_idx,
620 : : const s32 iq_res[],
621 : : s32 iqc_coeff[])
622 : : {
623 : 10 : s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
624 : : i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
625 : : i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
626 : : i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
627 : 10 : s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
628 : : phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
629 : : sin_2phi_1, cos_2phi_1,
630 : : sin_2phi_2, cos_2phi_2;
631 : 10 : s32 mag_tx, phs_tx, mag_rx, phs_rx;
632 : 10 : s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
633 : : q_q_coff, q_i_coff;
634 : 10 : const s32 res_scale = 1 << 15;
635 : 10 : const s32 delpt_shift = 1 << 8;
636 : 10 : s32 mag1, mag2;
637 [ + + ]: 10 : struct ath_common *common = ath9k_hw_common(ah);
638 : :
639 : 10 : i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
640 : 10 : i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
641 : 10 : iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
642 : :
643 [ + + ]: 10 : if (i2_m_q2_a0_d0 > 0x800)
644 : 4 : i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
645 : :
646 [ + + ]: 10 : if (i2_p_q2_a0_d0 > 0x800)
647 : 4 : i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
648 : :
649 [ + + ]: 10 : if (iq_corr_a0_d0 > 0x800)
650 : 4 : iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
651 : :
652 : 10 : i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
653 : 10 : i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
654 : 10 : iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
655 : :
656 [ + + ]: 10 : if (i2_m_q2_a0_d1 > 0x800)
657 : 6 : i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
658 : :
659 [ + + ]: 10 : if (iq_corr_a0_d1 > 0x800)
660 : 2 : iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
661 : :
662 : 10 : i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
663 : 10 : i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
664 : 10 : iq_corr_a1_d0 = iq_res[4] & 0xfff;
665 : :
666 [ + + ]: 10 : if (i2_m_q2_a1_d0 > 0x800)
667 : 1 : i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
668 : :
669 [ + + ]: 10 : if (i2_p_q2_a1_d0 > 0x800)
670 : 1 : i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
671 : :
672 [ + + ]: 10 : if (iq_corr_a1_d0 > 0x800)
673 : 4 : iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
674 : :
675 : 10 : i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
676 : 10 : i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
677 : 10 : iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
678 : :
679 [ + + ]: 10 : if (i2_m_q2_a1_d1 > 0x800)
680 : 4 : i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
681 : :
682 [ + + ]: 10 : if (i2_p_q2_a1_d1 > 0x800)
683 : 1 : i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
684 : :
685 [ + + ]: 10 : if (iq_corr_a1_d1 > 0x800)
686 : 5 : iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
687 : :
688 [ + - + + : 10 : if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
+ + ]
689 [ - + ]: 8 : (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
690 [ - + ]: 2 : ath_dbg(common, CALIBRATE,
691 : : "Divide by 0:\n"
692 : : "a0_d0=%d\n"
693 : : "a0_d1=%d\n"
694 : : "a2_d0=%d\n"
695 : : "a1_d1=%d\n",
696 : : i2_p_q2_a0_d0, i2_p_q2_a0_d1,
697 : : i2_p_q2_a1_d0, i2_p_q2_a1_d1);
698 : 2 : return false;
699 : : }
700 : :
701 [ + + + - ]: 8 : if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) ||
702 [ + - + - ]: 1 : (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
703 [ - + ]: 1 : (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
704 [ # # ]: 0 : (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
705 [ # # ]: 0 : (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
706 [ # # ]: 0 : (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
707 [ # # ]: 0 : (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
708 [ # # ]: 0 : (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
709 [ # # ]: 0 : (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
710 : : (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
711 : : return false;
712 : : }
713 : :
714 : 0 : mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
715 : 0 : phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
716 : :
717 : 0 : mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
718 : 0 : phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
719 : :
720 : 0 : mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
721 : 0 : phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
722 : :
723 : 0 : mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
724 : 0 : phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
725 : :
726 : : /* w/o analog phase shift */
727 : 0 : sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
728 : : /* w/o analog phase shift */
729 : 0 : cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
730 : : /* w/ analog phase shift */
731 : 0 : sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
732 : : /* w/ analog phase shift */
733 : 0 : cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
734 : :
735 : : /*
736 : : * force sin^2 + cos^2 = 1;
737 : : * find magnitude by approximation
738 : : */
739 [ # # ]: 0 : mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
740 [ # # ]: 0 : mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
741 : :
742 [ # # # # ]: 0 : if ((mag1 == 0) || (mag2 == 0)) {
743 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n",
744 : : mag1, mag2);
745 : 0 : return false;
746 : : }
747 : :
748 : : /* normalization sin and cos by mag */
749 : 0 : sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
750 : 0 : cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
751 : 0 : sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
752 : 0 : cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
753 : :
754 : : /* calculate IQ mismatch */
755 [ # # ]: 0 : if (!ar9003_hw_solve_iq_cal(ah,
756 : : sin_2phi_1, cos_2phi_1,
757 : : sin_2phi_2, cos_2phi_2,
758 : : mag_a0_d0, phs_a0_d0,
759 : : mag_a1_d0,
760 : : phs_a1_d0, solved_eq)) {
761 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
762 : : "Call to ar9003_hw_solve_iq_cal() failed\n");
763 : 0 : return false;
764 : : }
765 : :
766 : 0 : mag_tx = solved_eq[0];
767 : 0 : phs_tx = solved_eq[1];
768 : 0 : mag_rx = solved_eq[2];
769 : 0 : phs_rx = solved_eq[3];
770 : :
771 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
772 : : "chain %d: mag mismatch=%d phase mismatch=%d\n",
773 : : chain_idx, mag_tx/res_scale, phs_tx/res_scale);
774 : :
775 [ # # ]: 0 : if (res_scale == mag_tx) {
776 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
777 : : "Divide by 0: mag_tx=%d, res_scale=%d\n",
778 : : mag_tx, res_scale);
779 : 0 : return false;
780 : : }
781 : :
782 : : /* calculate and quantize Tx IQ correction factor */
783 : 0 : mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
784 : 0 : phs_corr_tx = -phs_tx;
785 : :
786 : 0 : q_q_coff = (mag_corr_tx * 128 / res_scale);
787 : 0 : q_i_coff = (phs_corr_tx * 256 / res_scale);
788 : :
789 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d phase corr=%d\n",
790 : : chain_idx, q_q_coff, q_i_coff);
791 : :
792 [ # # ]: 0 : if (q_i_coff < -63)
793 : : q_i_coff = -63;
794 : 0 : if (q_i_coff > 63)
795 : : q_i_coff = 63;
796 [ # # ]: 0 : if (q_q_coff < -63)
797 : : q_q_coff = -63;
798 : 0 : if (q_q_coff > 63)
799 : : q_q_coff = 63;
800 : :
801 : 0 : iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
802 : :
803 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
804 : : chain_idx, iqc_coeff[0]);
805 : :
806 [ # # ]: 0 : if (-mag_rx == res_scale) {
807 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
808 : : "Divide by 0: mag_rx=%d, res_scale=%d\n",
809 : : mag_rx, res_scale);
810 : 0 : return false;
811 : : }
812 : :
813 : : /* calculate and quantize Rx IQ correction factors */
814 : 0 : mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
815 : 0 : phs_corr_rx = -phs_rx;
816 : :
817 : 0 : q_q_coff = (mag_corr_rx * 128 / res_scale);
818 : 0 : q_i_coff = (phs_corr_rx * 256 / res_scale);
819 : :
820 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "rx chain %d: mag corr=%d phase corr=%d\n",
821 : : chain_idx, q_q_coff, q_i_coff);
822 : :
823 [ # # ]: 0 : if (q_i_coff < -63)
824 : : q_i_coff = -63;
825 : 0 : if (q_i_coff > 63)
826 : : q_i_coff = 63;
827 [ # # ]: 0 : if (q_q_coff < -63)
828 : : q_q_coff = -63;
829 : 0 : if (q_q_coff > 63)
830 : : q_q_coff = 63;
831 : :
832 : 0 : iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
833 : :
834 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
835 : : chain_idx, iqc_coeff[1]);
836 : :
837 : : return true;
838 : : }
839 : :
840 : 0 : static void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
841 : : int nmeasurement,
842 : : int max_delta)
843 : : {
844 : 0 : int mp_max = -64, max_idx = 0;
845 : 0 : int mp_min = 63, min_idx = 0;
846 : 0 : int mp_avg = 0, i, outlier_idx = 0, mp_count = 0;
847 : :
848 : : /* find min/max mismatch across all calibrated gains */
849 [ # # ]: 0 : for (i = 0; i < nmeasurement; i++) {
850 [ # # ]: 0 : if (mp_coeff[i][0] > mp_max) {
851 : : mp_max = mp_coeff[i][0];
852 : : max_idx = i;
853 [ # # ]: 0 : } else if (mp_coeff[i][0] < mp_min) {
854 : 0 : mp_min = mp_coeff[i][0];
855 : 0 : min_idx = i;
856 : : }
857 : : }
858 : :
859 : : /* find average (exclude max abs value) */
860 [ # # ]: 0 : for (i = 0; i < nmeasurement; i++) {
861 [ # # ]: 0 : if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
862 [ # # ]: 0 : (abs(mp_coeff[i][0]) < abs(mp_min))) {
863 : 0 : mp_avg += mp_coeff[i][0];
864 : 0 : mp_count++;
865 : : }
866 : : }
867 : :
868 : : /*
869 : : * finding mean magnitude/phase if possible, otherwise
870 : : * just use the last value as the mean
871 : : */
872 [ # # ]: 0 : if (mp_count)
873 : 0 : mp_avg /= mp_count;
874 : : else
875 : 0 : mp_avg = mp_coeff[nmeasurement - 1][0];
876 : :
877 : : /* detect outlier */
878 [ # # ]: 0 : if (abs(mp_max - mp_min) > max_delta) {
879 [ # # ]: 0 : if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
880 : : outlier_idx = max_idx;
881 : : else
882 : 0 : outlier_idx = min_idx;
883 : :
884 : 0 : mp_coeff[outlier_idx][0] = mp_avg;
885 : : }
886 : 0 : }
887 : :
888 : 1 : static void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
889 : : struct coeff *coeff,
890 : : bool is_reusable)
891 : : {
892 : 1 : int i, im, nmeasurement;
893 : 1 : int magnitude, phase;
894 : 1 : u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
895 : 1 : struct ath9k_hw_cal_data *caldata = ah->caldata;
896 : :
897 : 1 : memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
898 [ + + ]: 5 : for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
899 : 8 : tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
900 [ + - ]: 4 : AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
901 [ + - ]: 4 : if (!AR_SREV_9485(ah)) {
902 : 4 : tx_corr_coeff[i * 2][1] =
903 : 4 : tx_corr_coeff[(i * 2) + 1][1] =
904 : 4 : AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
905 : :
906 : 4 : tx_corr_coeff[i * 2][2] =
907 : 4 : tx_corr_coeff[(i * 2) + 1][2] =
908 : 4 : AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
909 : : }
910 : : }
911 : :
912 : : /* Load the average of 2 passes */
913 [ + + ]: 4 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
914 [ + + ]: 3 : if (!(ah->txchainmask & (1 << i)))
915 : 1 : continue;
916 [ + - ]: 4 : nmeasurement = REG_READ_FIELD(ah,
917 : : AR_PHY_TX_IQCAL_STATUS_B0,
918 : : AR_PHY_CALIBRATED_GAINS_0);
919 : :
920 : 2 : if (nmeasurement > MAX_MEASUREMENT)
921 : : nmeasurement = MAX_MEASUREMENT;
922 : :
923 : : /*
924 : : * Skip normal outlier detection for AR9550.
925 : : */
926 [ + - ]: 2 : if (!AR_SREV_9550(ah)) {
927 : : /* detect outlier only if nmeasurement > 1 */
928 [ - + ]: 2 : if (nmeasurement > 1) {
929 : : /* Detect magnitude outlier */
930 : 0 : ar9003_hw_detect_outlier(coeff->mag_coeff[i],
931 : : nmeasurement,
932 : : MAX_MAG_DELTA);
933 : :
934 : : /* Detect phase outlier */
935 : 0 : ar9003_hw_detect_outlier(coeff->phs_coeff[i],
936 : : nmeasurement,
937 : : MAX_PHS_DELTA);
938 : : }
939 : : }
940 : :
941 [ - + ]: 2 : for (im = 0; im < nmeasurement; im++) {
942 : 0 : magnitude = coeff->mag_coeff[i][im][0];
943 : 0 : phase = coeff->phs_coeff[i][im][0];
944 : :
945 : 0 : coeff->iqc_coeff[0] =
946 : 0 : (phase & 0x7f) | ((magnitude & 0x7f) << 7);
947 : :
948 [ # # ]: 0 : if ((im % 2) == 0)
949 : 0 : REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
950 : : AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
951 : : coeff->iqc_coeff[0]);
952 : : else
953 : 0 : REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
954 : : AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
955 : : coeff->iqc_coeff[0]);
956 : :
957 [ # # ]: 0 : if (caldata)
958 : 0 : caldata->tx_corr_coeff[im][i] =
959 : 0 : coeff->iqc_coeff[0];
960 : : }
961 [ + - ]: 2 : if (caldata)
962 : 2 : caldata->num_measures[i] = nmeasurement;
963 : : }
964 : :
965 : 1 : REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
966 : : AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
967 : 1 : REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
968 : : AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
969 : :
970 [ + - ]: 1 : if (caldata) {
971 [ - + ]: 1 : if (is_reusable)
972 : 0 : set_bit(TXIQCAL_DONE, &caldata->cal_flags);
973 : : else
974 : 1 : clear_bit(TXIQCAL_DONE, &caldata->cal_flags);
975 : : }
976 : :
977 : 1 : return;
978 : : }
979 : :
980 : 10 : static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
981 : : {
982 : 10 : struct ath_common *common = ath9k_hw_common(ah);
983 : 10 : u8 tx_gain_forced;
984 : :
985 : 10 : tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
986 : : AR_PHY_TXGAIN_FORCE);
987 [ + + ]: 10 : if (tx_gain_forced)
988 : 8 : REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
989 : : AR_PHY_TXGAIN_FORCE, 0);
990 : :
991 [ + - ]: 20 : REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
992 : : AR_PHY_TX_IQCAL_START_DO_CAL, 1);
993 : :
994 [ + - - + ]: 20 : if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
995 : : AR_PHY_TX_IQCAL_START_DO_CAL, 0,
996 : : AH_WAIT_TIMEOUT)) {
997 [ # # ]: 0 : ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n");
998 : 0 : return false;
999 : : }
1000 : : return true;
1001 : : }
1002 : :
1003 : 0 : static void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
1004 : : struct coeff *coeff,
1005 : : int i, int nmeasurement)
1006 : : {
1007 : 0 : struct ath_common *common = ath9k_hw_common(ah);
1008 : 0 : int im, ix, iy, temp;
1009 : :
1010 [ # # ]: 0 : for (im = 0; im < nmeasurement; im++) {
1011 [ # # ]: 0 : for (ix = 0; ix < MAXIQCAL - 1; ix++) {
1012 [ # # ]: 0 : for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
1013 : 0 : if (coeff->mag_coeff[i][im][iy] <
1014 [ # # ]: 0 : coeff->mag_coeff[i][im][ix]) {
1015 : 0 : temp = coeff->mag_coeff[i][im][ix];
1016 : 0 : coeff->mag_coeff[i][im][ix] =
1017 : : coeff->mag_coeff[i][im][iy];
1018 : 0 : coeff->mag_coeff[i][im][iy] = temp;
1019 : : }
1020 : 0 : if (coeff->phs_coeff[i][im][iy] <
1021 [ # # ]: 0 : coeff->phs_coeff[i][im][ix]) {
1022 : 0 : temp = coeff->phs_coeff[i][im][ix];
1023 : 0 : coeff->phs_coeff[i][im][ix] =
1024 : : coeff->phs_coeff[i][im][iy];
1025 : 0 : coeff->phs_coeff[i][im][iy] = temp;
1026 : : }
1027 : : }
1028 : : }
1029 : 0 : coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
1030 : 0 : coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
1031 : :
1032 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
1033 : : "IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
1034 : : i, im,
1035 : : coeff->mag_coeff[i][im][0],
1036 : : coeff->phs_coeff[i][im][0]);
1037 : : }
1038 : 0 : }
1039 : :
1040 : 0 : static bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
1041 : : struct coeff *coeff,
1042 : : int iqcal_idx,
1043 : : int nmeasurement)
1044 : : {
1045 : 0 : int i;
1046 : :
1047 : 0 : if ((iqcal_idx + 1) != MAXIQCAL)
1048 : : return false;
1049 : :
1050 [ # # ]: 0 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1051 : 0 : __ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
1052 : : }
1053 : :
1054 : : return true;
1055 : : }
1056 : :
1057 : 21 : static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
1058 : : int iqcal_idx,
1059 : : bool is_reusable)
1060 : : {
1061 [ + - ]: 21 : struct ath_common *common = ath9k_hw_common(ah);
1062 : 42 : const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
1063 [ + - ]: 21 : AR_PHY_TX_IQCAL_STATUS_B0,
1064 : : AR_PHY_TX_IQCAL_STATUS_B1,
1065 : : AR_PHY_TX_IQCAL_STATUS_B2,
1066 : : };
1067 : 21 : const u_int32_t chan_info_tab[] = {
1068 : : AR_PHY_CHAN_INFO_TAB_0,
1069 : : AR_PHY_CHAN_INFO_TAB_1,
1070 : : AR_PHY_CHAN_INFO_TAB_2,
1071 : : };
1072 : 21 : static struct coeff coeff;
1073 : 21 : s32 iq_res[6];
1074 : 21 : int i, im, j;
1075 : 21 : int nmeasurement = 0;
1076 : 21 : bool outlier_detect = true;
1077 : :
1078 [ + + ]: 26 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1079 [ + + ]: 25 : if (!(ah->txchainmask & (1 << i)))
1080 : 1 : continue;
1081 : :
1082 [ + - ]: 48 : nmeasurement = REG_READ_FIELD(ah,
1083 : : AR_PHY_TX_IQCAL_STATUS_B0,
1084 : : AR_PHY_CALIBRATED_GAINS_0);
1085 : 24 : if (nmeasurement > MAX_MEASUREMENT)
1086 : : nmeasurement = MAX_MEASUREMENT;
1087 : :
1088 [ + + ]: 24 : for (im = 0; im < nmeasurement; im++) {
1089 [ - + ]: 20 : ath_dbg(common, CALIBRATE,
1090 : : "Doing Tx IQ Cal for chain %d\n", i);
1091 : :
1092 [ + + ]: 20 : if (REG_READ(ah, txiqcal_status[i]) &
1093 : : AR_PHY_TX_IQCAL_STATUS_FAILED) {
1094 [ - + ]: 10 : ath_dbg(common, CALIBRATE,
1095 : : "Tx IQ Cal failed for chain %d\n", i);
1096 : 10 : goto tx_iqcal_fail;
1097 : : }
1098 : :
1099 [ + + ]: 40 : for (j = 0; j < 3; j++) {
1100 : 30 : u32 idx = 2 * j, offset = 4 * (3 * im + j);
1101 : :
1102 [ + + ]: 54 : REG_RMW_FIELD(ah,
1103 : : AR_PHY_CHAN_INFO_MEMORY,
1104 : : AR_PHY_CHAN_INFO_TAB_S2_READ,
1105 : : 0);
1106 : :
1107 : : /* 32 bits */
1108 : 30 : iq_res[idx] = REG_READ(ah,
1109 : : chan_info_tab[i] +
1110 : : offset);
1111 : :
1112 [ + + ]: 54 : REG_RMW_FIELD(ah,
1113 : : AR_PHY_CHAN_INFO_MEMORY,
1114 : : AR_PHY_CHAN_INFO_TAB_S2_READ,
1115 : : 1);
1116 : :
1117 : : /* 16 bits */
1118 : 30 : iq_res[idx + 1] = 0xffff & REG_READ(ah,
1119 : : chan_info_tab[i] + offset);
1120 : :
1121 [ - + ]: 30 : ath_dbg(common, CALIBRATE,
1122 : : "IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
1123 : : idx, iq_res[idx], idx + 1,
1124 : : iq_res[idx + 1]);
1125 : : }
1126 : :
1127 [ + - ]: 10 : if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
1128 : : coeff.iqc_coeff)) {
1129 [ - + ]: 10 : ath_dbg(common, CALIBRATE,
1130 : : "Failed in calculation of IQ correction\n");
1131 : 10 : goto tx_iqcal_fail;
1132 : : }
1133 : :
1134 : 0 : coeff.phs_coeff[i][im][iqcal_idx] =
1135 : 0 : coeff.iqc_coeff[0] & 0x7f;
1136 : 0 : coeff.mag_coeff[i][im][iqcal_idx] =
1137 : 0 : (coeff.iqc_coeff[0] >> 7) & 0x7f;
1138 : :
1139 [ # # ]: 0 : if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
1140 : 0 : coeff.mag_coeff[i][im][iqcal_idx] -= 128;
1141 [ # # ]: 0 : if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
1142 : 0 : coeff.phs_coeff[i][im][iqcal_idx] -= 128;
1143 : : }
1144 : : }
1145 : :
1146 [ - + ]: 1 : if (AR_SREV_9550(ah))
1147 [ # # ]: 0 : outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
1148 : : iqcal_idx, nmeasurement);
1149 : : if (outlier_detect)
1150 : 1 : ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
1151 : :
1152 : : return;
1153 : :
1154 : 20 : tx_iqcal_fail:
1155 [ - + ]: 20 : ath_dbg(common, CALIBRATE, "Tx IQ Cal failed\n");
1156 : : return;
1157 : : }
1158 : :
1159 : 0 : static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
1160 : : {
1161 : 0 : struct ath9k_hw_cal_data *caldata = ah->caldata;
1162 : 0 : u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
1163 : 0 : int i, im;
1164 : :
1165 : 0 : memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
1166 [ # # ]: 0 : for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
1167 : 0 : tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
1168 [ # # ]: 0 : AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
1169 [ # # ]: 0 : if (!AR_SREV_9485(ah)) {
1170 : 0 : tx_corr_coeff[i * 2][1] =
1171 : 0 : tx_corr_coeff[(i * 2) + 1][1] =
1172 : 0 : AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
1173 : :
1174 : 0 : tx_corr_coeff[i * 2][2] =
1175 : 0 : tx_corr_coeff[(i * 2) + 1][2] =
1176 : 0 : AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
1177 : : }
1178 : : }
1179 : :
1180 [ # # ]: 0 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1181 [ # # ]: 0 : if (!(ah->txchainmask & (1 << i)))
1182 : 0 : continue;
1183 : :
1184 [ # # ]: 0 : for (im = 0; im < caldata->num_measures[i]; im++) {
1185 [ # # ]: 0 : if ((im % 2) == 0)
1186 : 0 : REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
1187 : : AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
1188 : : caldata->tx_corr_coeff[im][i]);
1189 : : else
1190 : 0 : REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
1191 : : AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
1192 : : caldata->tx_corr_coeff[im][i]);
1193 : : }
1194 : : }
1195 : :
1196 : 0 : REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
1197 : : AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
1198 : 0 : REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
1199 : : AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
1200 : 0 : }
1201 : :
1202 : 82 : static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
1203 : : {
1204 : 82 : int offset[8] = {0}, total = 0, test;
1205 : 82 : int agc_out, i, peak_detect_threshold = 0;
1206 : :
1207 [ + - + + ]: 82 : if (AR_SREV_9550(ah) || AR_SREV_9531(ah))
1208 : : peak_detect_threshold = 8;
1209 [ + + ]: 60 : else if (AR_SREV_9561(ah))
1210 : 24 : peak_detect_threshold = 11;
1211 : :
1212 : : /*
1213 : : * Turn off LNA/SW.
1214 : : */
1215 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
1216 : : AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
1217 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
1218 : : AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
1219 : :
1220 [ + + + - : 82 : if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) {
+ - - + ]
1221 [ + - ]: 6 : if (is_2g)
1222 : 6 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
1223 : : AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
1224 : : else
1225 : 0 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
1226 : : AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
1227 : : }
1228 : :
1229 : : /*
1230 : : * Turn off RXON.
1231 : : */
1232 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
1233 : : AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
1234 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
1235 : : AR_PHY_65NM_RXTX2_RXON, 0x0);
1236 : :
1237 : : /*
1238 : : * Turn on AGC for cal.
1239 : : */
1240 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1241 : : AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
1242 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1243 : : AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);
1244 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1245 : : AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
1246 : :
1247 [ - + ]: 82 : if (AR_SREV_9330_11(ah))
1248 : 0 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1249 : : AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
1250 : :
1251 [ + - ]: 82 : if (is_2g)
1252 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1253 : : AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
1254 : : peak_detect_threshold);
1255 : : else
1256 : 0 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1257 : : AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
1258 : : peak_detect_threshold);
1259 : :
1260 [ + + ]: 574 : for (i = 6; i > 0; i--) {
1261 : 492 : offset[i] = BIT(i - 1);
1262 : 492 : test = total + offset[i];
1263 : :
1264 [ + - ]: 492 : if (is_2g)
1265 : 492 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1266 : : AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
1267 : : test);
1268 : : else
1269 : 0 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1270 : : AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
1271 : : test);
1272 : 492 : udelay(100);
1273 : 492 : agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1274 : : AR_PHY_65NM_RXRF_AGC_AGC_OUT);
1275 : 492 : offset[i] = (agc_out) ? 0 : 1;
1276 : 492 : total += (offset[i] << (i - 1));
1277 : : }
1278 : :
1279 [ + - ]: 82 : if (is_2g)
1280 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1281 : : AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total);
1282 : : else
1283 : 0 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1284 : : AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
1285 : :
1286 : : /*
1287 : : * Turn on LNA.
1288 : : */
1289 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
1290 : : AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
1291 : : /*
1292 : : * Turn off RXON.
1293 : : */
1294 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
1295 : : AR_PHY_65NM_RXTX2_RXON_OVR, 0);
1296 : : /*
1297 : : * Turn off peak detect calibration.
1298 : : */
1299 : 82 : REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
1300 : : AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
1301 : 82 : }
1302 : :
1303 : 12 : static void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah,
1304 : : struct ath9k_channel *chan,
1305 : : bool run_rtt_cal)
1306 : : {
1307 : 12 : struct ath9k_hw_cal_data *caldata = ah->caldata;
1308 : 12 : int i;
1309 : :
1310 [ - + + + ]: 12 : if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)
1311 : : return;
1312 : :
1313 [ + + ]: 12 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1314 [ + + ]: 9 : if (!(ah->rxchainmask & (1 << i)))
1315 : 3 : continue;
1316 : 6 : ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
1317 : : }
1318 : :
1319 [ + + ]: 3 : if (caldata)
1320 : 2 : set_bit(SW_PKDET_DONE, &caldata->cal_flags);
1321 : :
1322 [ + - + + ]: 3 : if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {
1323 [ + - ]: 2 : if (IS_CHAN_2GHZ(chan)){
1324 : 2 : caldata->caldac[0] = REG_READ_FIELD(ah,
1325 : : AR_PHY_65NM_RXRF_AGC(0),
1326 : : AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
1327 : 2 : caldata->caldac[1] = REG_READ_FIELD(ah,
1328 : : AR_PHY_65NM_RXRF_AGC(1),
1329 : : AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
1330 : : } else {
1331 : 0 : caldata->caldac[0] = REG_READ_FIELD(ah,
1332 : : AR_PHY_65NM_RXRF_AGC(0),
1333 : : AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
1334 : 0 : caldata->caldac[1] = REG_READ_FIELD(ah,
1335 : : AR_PHY_65NM_RXRF_AGC(1),
1336 : : AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
1337 : : }
1338 : : }
1339 : : }
1340 : :
1341 : 12 : static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
1342 : : {
1343 : 12 : u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
1344 : : AR_PHY_CL_TAB_1,
1345 : : AR_PHY_CL_TAB_2 };
1346 : 12 : struct ath9k_hw_cal_data *caldata = ah->caldata;
1347 : 12 : bool txclcal_done = false;
1348 : 12 : int i, j;
1349 : :
1350 [ + + + + ]: 12 : if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
1351 : 10 : return;
1352 : :
1353 [ - + ]: 2 : txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
1354 : : AR_PHY_AGC_CONTROL_CLC_SUCCESS);
1355 : :
1356 [ - + ]: 2 : if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) {
1357 [ # # ]: 0 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1358 [ # # ]: 0 : if (!(ah->txchainmask & (1 << i)))
1359 : 0 : continue;
1360 [ # # ]: 0 : for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
1361 : 0 : REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
1362 : : caldata->tx_clcal[i][j]);
1363 : : }
1364 [ + - - + ]: 2 : } else if (is_reusable && txclcal_done) {
1365 [ # # ]: 0 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1366 [ # # ]: 0 : if (!(ah->txchainmask & (1 << i)))
1367 : 0 : continue;
1368 [ # # ]: 0 : for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
1369 : 0 : caldata->tx_clcal[i][j] =
1370 : 0 : REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
1371 : : }
1372 : 0 : set_bit(TXCLCAL_DONE, &caldata->cal_flags);
1373 : : }
1374 : : }
1375 : :
1376 : 41 : static void ar9003_hw_init_cal_common(struct ath_hw *ah)
1377 : : {
1378 : 41 : struct ath9k_hw_cal_data *caldata = ah->caldata;
1379 : :
1380 : : /* Initialize list pointers */
1381 : 41 : ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
1382 : :
1383 : 41 : INIT_CAL(&ah->iq_caldata);
1384 : 41 : INSERT_CAL(ah, &ah->iq_caldata);
1385 : :
1386 : : /* Initialize current pointer to first element in list */
1387 : 41 : ah->cal_list_curr = ah->cal_list;
1388 : :
1389 [ + - ]: 41 : if (ah->cal_list_curr)
1390 : 41 : ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
1391 : :
1392 [ + + ]: 41 : if (caldata)
1393 : 37 : caldata->CalValid = 0;
1394 : 41 : }
1395 : :
1396 : 12 : static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
1397 : : struct ath9k_channel *chan)
1398 : : {
1399 : 12 : struct ath_common *common = ath9k_hw_common(ah);
1400 : 12 : struct ath9k_hw_cal_data *caldata = ah->caldata;
1401 : 12 : bool txiqcal_done = false;
1402 : 12 : bool is_reusable = true, status = true;
1403 : 12 : bool run_rtt_cal = false, run_agc_cal;
1404 : 12 : bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
1405 : 12 : u32 rx_delay = 0;
1406 : 12 : u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
1407 : : AR_PHY_AGC_CONTROL_FLTR_CAL |
1408 : : AR_PHY_AGC_CONTROL_PKDET_CAL;
1409 : :
1410 : : /* Use chip chainmask only for calibration */
1411 : 12 : ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
1412 : :
1413 [ + - ]: 12 : if (rtt) {
1414 [ + + ]: 12 : if (!ar9003_hw_rtt_restore(ah, chan))
1415 : 3 : run_rtt_cal = true;
1416 : :
1417 : 3 : if (run_rtt_cal)
1418 [ - + ]: 3 : ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");
1419 : : }
1420 : :
1421 : 12 : run_agc_cal = run_rtt_cal;
1422 : :
1423 [ + + ]: 12 : if (run_rtt_cal) {
1424 : 3 : ar9003_hw_rtt_enable(ah);
1425 : 3 : ar9003_hw_rtt_set_mask(ah, 0x00);
1426 : 3 : ar9003_hw_rtt_clear_hist(ah);
1427 : : }
1428 : :
1429 [ + - ]: 12 : if (rtt) {
1430 [ + + ]: 12 : if (!run_rtt_cal) {
1431 [ - + ]: 9 : agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
1432 : 9 : agc_supp_cals &= agc_ctrl;
1433 : 9 : agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
1434 : : AR_PHY_AGC_CONTROL_FLTR_CAL |
1435 : : AR_PHY_AGC_CONTROL_PKDET_CAL);
1436 [ - + ]: 9 : REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
1437 : : } else {
1438 : : if (ah->ah_flags & AH_FASTCC)
1439 : : run_agc_cal = true;
1440 : : }
1441 : : }
1442 : :
1443 [ + + ]: 12 : if (ah->enabled_cals & TX_CL_CAL) {
1444 [ + - - + ]: 2 : if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags))
1445 : 0 : REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
1446 : : AR_PHY_CL_CAL_ENABLE);
1447 : : else {
1448 : 2 : REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL,
1449 : : AR_PHY_CL_CAL_ENABLE);
1450 : 2 : run_agc_cal = true;
1451 : : }
1452 : : }
1453 : :
1454 [ + - ]: 12 : if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
1455 [ + + ]: 12 : !(ah->enabled_cals & TX_IQ_CAL))
1456 : 8 : goto skip_tx_iqcal;
1457 : :
1458 : : /* Do Tx IQ Calibration */
1459 [ + - ]: 8 : REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
1460 : : AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
1461 : : DELPT);
1462 : :
1463 : : /*
1464 : : * For AR9485 or later chips, TxIQ cal runs as part of
1465 : : * AGC calibration
1466 : : */
1467 [ - + ]: 4 : if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
1468 [ + - + - ]: 4 : if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags))
1469 [ + - ]: 8 : REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
1470 : : AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
1471 : : else
1472 [ # # ]: 0 : REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
1473 : : AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
1474 : : txiqcal_done = run_agc_cal = true;
1475 : : }
1476 : :
1477 : 0 : skip_tx_iqcal:
1478 [ - + - + : 24 : if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
- - - - ]
1479 : 0 : ar9003_mci_init_cal_req(ah, &is_reusable);
1480 : :
1481 [ + + ]: 12 : if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
1482 : 2 : rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);
1483 : : /* Disable BB_active */
1484 : 2 : REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
1485 : 2 : udelay(5);
1486 : 2 : REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY);
1487 : 2 : REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
1488 : : }
1489 : :
1490 [ + + + - ]: 12 : if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
1491 : : /* Calibrate the AGC */
1492 [ - + ]: 12 : REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1493 : : REG_READ(ah, AR_PHY_AGC_CONTROL) |
1494 : : AR_PHY_AGC_CONTROL_CAL);
1495 : :
1496 : : /* Poll for offset calibration complete */
1497 [ - + ]: 12 : status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
1498 : : AR_PHY_AGC_CONTROL_CAL,
1499 : : 0, AH_WAIT_TIMEOUT);
1500 : :
1501 : 12 : ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal);
1502 : : }
1503 : :
1504 [ + + ]: 12 : if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
1505 : 1 : REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay);
1506 : 1 : udelay(5);
1507 : : }
1508 : :
1509 [ - + - + : 24 : if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
- - - - ]
1510 : 0 : ar9003_mci_init_cal_done(ah);
1511 : :
1512 [ + - + + ]: 12 : if (rtt && !run_rtt_cal) {
1513 : 9 : agc_ctrl |= agc_supp_cals;
1514 [ - + ]: 9 : REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
1515 : : }
1516 : :
1517 [ - + ]: 12 : if (!status) {
1518 [ # # ]: 0 : if (run_rtt_cal)
1519 : 0 : ar9003_hw_rtt_disable(ah);
1520 : :
1521 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
1522 : : "offset calibration failed to complete in %d ms; noisy environment?\n",
1523 : : AH_WAIT_TIMEOUT / 1000);
1524 : 0 : return false;
1525 : : }
1526 : :
1527 [ + + ]: 12 : if (txiqcal_done)
1528 : 4 : ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
1529 [ + + - + ]: 8 : else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
1530 : 0 : ar9003_hw_tx_iq_cal_reload(ah);
1531 : :
1532 : 12 : ar9003_hw_cl_cal_post_proc(ah, is_reusable);
1533 : :
1534 [ + + + + ]: 12 : if (run_rtt_cal && caldata) {
1535 [ + - ]: 2 : if (is_reusable) {
1536 [ - + ]: 2 : if (!ath9k_hw_rfbus_req(ah)) {
1537 : 0 : ath_err(ath9k_hw_common(ah),
1538 : : "Could not stop baseband\n");
1539 : : } else {
1540 : 2 : ar9003_hw_rtt_fill_hist(ah);
1541 : :
1542 [ + - ]: 2 : if (test_bit(SW_PKDET_DONE, &caldata->cal_flags))
1543 : 2 : ar9003_hw_rtt_load_hist(ah);
1544 : : }
1545 : :
1546 : 2 : ath9k_hw_rfbus_done(ah);
1547 : : }
1548 : :
1549 : 2 : ar9003_hw_rtt_disable(ah);
1550 : : }
1551 : :
1552 : : /* Revert chainmask to runtime parameters */
1553 : 12 : ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
1554 : :
1555 : 12 : ar9003_hw_init_cal_common(ah);
1556 : :
1557 : 12 : return true;
1558 : : }
1559 : :
1560 : 29 : static bool do_ar9003_agc_cal(struct ath_hw *ah)
1561 : : {
1562 [ - + ]: 29 : struct ath_common *common = ath9k_hw_common(ah);
1563 : 29 : bool status;
1564 : :
1565 [ - + ]: 29 : REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1566 : : REG_READ(ah, AR_PHY_AGC_CONTROL) |
1567 : : AR_PHY_AGC_CONTROL_CAL);
1568 : :
1569 [ - + ]: 29 : status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
1570 : : AR_PHY_AGC_CONTROL_CAL,
1571 : : 0, AH_WAIT_TIMEOUT);
1572 [ - + ]: 29 : if (!status) {
1573 [ # # ]: 0 : ath_dbg(common, CALIBRATE,
1574 : : "offset calibration failed to complete in %d ms,"
1575 : : "noisy environment?\n",
1576 : : AH_WAIT_TIMEOUT / 1000);
1577 : 0 : return false;
1578 : : }
1579 : :
1580 : : return true;
1581 : : }
1582 : :
1583 : 29 : static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
1584 : : struct ath9k_channel *chan)
1585 : : {
1586 : 29 : bool txiqcal_done = false;
1587 : 29 : bool status = true;
1588 : 29 : bool run_agc_cal = false, sep_iq_cal = false;
1589 : 29 : int i = 0;
1590 : :
1591 : : /* Use chip chainmask only for calibration */
1592 : 29 : ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
1593 : :
1594 [ + + ]: 29 : if (ah->enabled_cals & TX_CL_CAL) {
1595 : 4 : REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
1596 : 4 : run_agc_cal = true;
1597 : : }
1598 : :
1599 [ - + ]: 29 : if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
1600 : 0 : goto skip_tx_iqcal;
1601 : :
1602 : : /* Do Tx IQ Calibration */
1603 [ + - ]: 58 : REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
1604 : : AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
1605 : : DELPT);
1606 : :
1607 : : /*
1608 : : * For AR9485 or later chips, TxIQ cal runs as part of
1609 : : * AGC calibration. Specifically, AR9550 in SoC chips.
1610 : : */
1611 [ + + ]: 29 : if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
1612 [ + - + + ]: 38 : if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
1613 : : AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
1614 : : txiqcal_done = true;
1615 : : } else {
1616 : 12 : txiqcal_done = false;
1617 : : }
1618 : : run_agc_cal = true;
1619 : : } else {
1620 : : sep_iq_cal = true;
1621 : : run_agc_cal = true;
1622 : : }
1623 : :
1624 : : /*
1625 : : * In the SoC family, this will run for AR9300, AR9331 and AR9340.
1626 : : */
1627 : 10 : if (sep_iq_cal) {
1628 : 10 : txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
1629 : 10 : REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
1630 : 10 : udelay(5);
1631 : 10 : REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
1632 : : }
1633 : :
1634 [ - + - - ]: 29 : if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) {
1635 [ # # ]: 0 : if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done))
1636 : : return false;
1637 : : }
1638 : :
1639 : 29 : skip_tx_iqcal:
1640 [ # # # # ]: 0 : if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
1641 [ + + ]: 116 : for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1642 [ + + ]: 87 : if (!(ah->rxchainmask & (1 << i)))
1643 : 11 : continue;
1644 : :
1645 : 76 : ar9003_hw_manual_peak_cal(ah, i,
1646 : 76 : IS_CHAN_2GHZ(chan));
1647 : : }
1648 : :
1649 : : /*
1650 : : * For non-AR9550 chips, we just trigger AGC calibration
1651 : : * in the HW, poll for completion and then process
1652 : : * the results.
1653 : : *
1654 : : * For AR955x, we run it multiple times and use
1655 : : * median IQ correction.
1656 : : */
1657 [ + - ]: 29 : if (!AR_SREV_9550(ah)) {
1658 : 29 : status = do_ar9003_agc_cal(ah);
1659 [ + - ]: 29 : if (!status)
1660 : : return false;
1661 : :
1662 [ + + ]: 29 : if (txiqcal_done)
1663 : 17 : ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
1664 : : } else {
1665 [ # # ]: 0 : if (!txiqcal_done) {
1666 : 0 : status = do_ar9003_agc_cal(ah);
1667 [ # # ]: 0 : if (!status)
1668 : : return false;
1669 : : } else {
1670 [ # # ]: 0 : for (i = 0; i < MAXIQCAL; i++) {
1671 : 0 : status = do_ar9003_agc_cal(ah);
1672 [ # # ]: 0 : if (!status)
1673 : : return false;
1674 : 0 : ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
1675 : : }
1676 : : }
1677 : : }
1678 : : }
1679 : :
1680 : : /* Revert chainmask to runtime parameters */
1681 : 29 : ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
1682 : :
1683 : 29 : ar9003_hw_init_cal_common(ah);
1684 : :
1685 : 29 : return true;
1686 : : }
1687 : :
1688 : 5 : void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
1689 : : {
1690 [ + + ]: 5 : struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
1691 [ + + ]: 5 : struct ath_hw_ops *ops = ath9k_hw_ops(ah);
1692 : :
1693 [ + + + - : 5 : if (AR_SREV_9003_PCOEM(ah))
- + ]
1694 : 1 : priv_ops->init_cal = ar9003_hw_init_cal_pcoem;
1695 : : else
1696 : 4 : priv_ops->init_cal = ar9003_hw_init_cal_soc;
1697 : :
1698 : 5 : priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
1699 : 5 : priv_ops->setup_calibration = ar9003_hw_setup_calibration;
1700 : :
1701 : 5 : ops->calibrate = ar9003_hw_calibrate;
1702 : 5 : }
|