Commit | Line | Data |
---|---|---|
f1dc5600 | 1 | /* |
cee075a2 | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
f1dc5600 S |
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 | ||
394cf0a1 | 17 | #include "ath9k.h" |
f1dc5600 | 18 | |
f1dc5600 S |
19 | /* We can tune this as we go by monitoring really low values */ |
20 | #define ATH9K_NF_TOO_LOW -60 | |
21 | ||
22 | /* AR5416 may return very high value (like -31 dBm), in those cases the nf | |
23 | * is incorrect and we should use the static NF value. Later we can try to | |
24 | * find out why they are reporting these values */ | |
25 | ||
cbe61d8a | 26 | static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf) |
f1dc5600 S |
27 | { |
28 | if (nf > ATH9K_NF_TOO_LOW) { | |
04bd4638 S |
29 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
30 | "noise floor value detected (%d) is " | |
f1dc5600 S |
31 | "lower than what we think is a " |
32 | "reasonable value (%d)\n", | |
04bd4638 | 33 | nf, ATH9K_NF_TOO_LOW); |
f1dc5600 S |
34 | return false; |
35 | } | |
36 | return true; | |
37 | } | |
38 | ||
39 | static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) | |
40 | { | |
41 | int16_t nfval; | |
42 | int16_t sort[ATH9K_NF_CAL_HIST_MAX]; | |
43 | int i, j; | |
44 | ||
45 | for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) | |
46 | sort[i] = nfCalBuffer[i]; | |
47 | ||
48 | for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { | |
49 | for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { | |
50 | if (sort[j] > sort[j - 1]) { | |
51 | nfval = sort[j]; | |
52 | sort[j] = sort[j - 1]; | |
53 | sort[j - 1] = nfval; | |
54 | } | |
55 | } | |
56 | } | |
57 | nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; | |
58 | ||
59 | return nfval; | |
60 | } | |
61 | ||
62 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, | |
63 | int16_t *nfarray) | |
64 | { | |
65 | int i; | |
66 | ||
67 | for (i = 0; i < NUM_NF_READINGS; i++) { | |
68 | h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; | |
69 | ||
70 | if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) | |
71 | h[i].currIndex = 0; | |
72 | ||
73 | if (h[i].invalidNFcount > 0) { | |
74 | if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || | |
75 | nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { | |
76 | h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; | |
77 | } else { | |
78 | h[i].invalidNFcount--; | |
79 | h[i].privNF = nfarray[i]; | |
80 | } | |
81 | } else { | |
82 | h[i].privNF = | |
83 | ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); | |
84 | } | |
85 | } | |
86 | return; | |
87 | } | |
88 | ||
cbe61d8a | 89 | static void ath9k_hw_do_getnf(struct ath_hw *ah, |
f1dc5600 S |
90 | int16_t nfarray[NUM_NF_READINGS]) |
91 | { | |
92 | int16_t nf; | |
93 | ||
94 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
95 | nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); | |
96 | else | |
97 | nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); | |
98 | ||
99 | if (nf & 0x100) | |
100 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
101 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
102 | "NF calibrated [ctl] [chain 0] is %d\n", nf); | |
103 | nfarray[0] = nf; | |
104 | ||
793c5929 SB |
105 | if (!AR_SREV_9285(ah)) { |
106 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
107 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), | |
108 | AR9280_PHY_CH1_MINCCA_PWR); | |
109 | else | |
110 | nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), | |
111 | AR_PHY_CH1_MINCCA_PWR); | |
f1dc5600 | 112 | |
f1dc5600 S |
113 | if (nf & 0x100) |
114 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
04bd4638 | 115 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
793c5929 SB |
116 | "NF calibrated [ctl] [chain 1] is %d\n", nf); |
117 | nfarray[1] = nf; | |
118 | ||
ac88b6ec | 119 | if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { |
793c5929 SB |
120 | nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), |
121 | AR_PHY_CH2_MINCCA_PWR); | |
122 | if (nf & 0x100) | |
123 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
124 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
125 | "NF calibrated [ctl] [chain 2] is %d\n", nf); | |
126 | nfarray[2] = nf; | |
127 | } | |
f1dc5600 S |
128 | } |
129 | ||
130 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
131 | nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), | |
132 | AR9280_PHY_EXT_MINCCA_PWR); | |
133 | else | |
134 | nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), | |
135 | AR_PHY_EXT_MINCCA_PWR); | |
136 | ||
137 | if (nf & 0x100) | |
138 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
04bd4638 | 139 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
f1dc5600 S |
140 | "NF calibrated [ext] [chain 0] is %d\n", nf); |
141 | nfarray[3] = nf; | |
142 | ||
793c5929 SB |
143 | if (!AR_SREV_9285(ah)) { |
144 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
145 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), | |
146 | AR9280_PHY_CH1_EXT_MINCCA_PWR); | |
147 | else | |
148 | nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), | |
149 | AR_PHY_CH1_EXT_MINCCA_PWR); | |
f1dc5600 | 150 | |
f1dc5600 S |
151 | if (nf & 0x100) |
152 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
04bd4638 | 153 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
793c5929 SB |
154 | "NF calibrated [ext] [chain 1] is %d\n", nf); |
155 | nfarray[4] = nf; | |
156 | ||
ac88b6ec | 157 | if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) { |
793c5929 SB |
158 | nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), |
159 | AR_PHY_CH2_EXT_MINCCA_PWR); | |
160 | if (nf & 0x100) | |
161 | nf = 0 - ((nf ^ 0x1ff) + 1); | |
162 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
163 | "NF calibrated [ext] [chain 2] is %d\n", nf); | |
164 | nfarray[5] = nf; | |
165 | } | |
f1dc5600 S |
166 | } |
167 | } | |
168 | ||
cbe61d8a | 169 | static bool getNoiseFloorThresh(struct ath_hw *ah, |
76061abb | 170 | enum ieee80211_band band, |
f1dc5600 S |
171 | int16_t *nft) |
172 | { | |
76061abb LR |
173 | switch (band) { |
174 | case IEEE80211_BAND_5GHZ: | |
f74df6fb | 175 | *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5); |
f1dc5600 | 176 | break; |
76061abb | 177 | case IEEE80211_BAND_2GHZ: |
f74df6fb | 178 | *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2); |
f1dc5600 S |
179 | break; |
180 | default: | |
76061abb | 181 | BUG_ON(1); |
f1dc5600 S |
182 | return false; |
183 | } | |
184 | ||
185 | return true; | |
186 | } | |
187 | ||
cbe61d8a | 188 | static void ath9k_hw_setup_calibration(struct ath_hw *ah, |
cbfe9468 | 189 | struct ath9k_cal_list *currCal) |
f1dc5600 S |
190 | { |
191 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), | |
192 | AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, | |
193 | currCal->calData->calCountMax); | |
194 | ||
195 | switch (currCal->calData->calType) { | |
196 | case IQ_MISMATCH_CAL: | |
197 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); | |
198 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 | 199 | "starting IQ Mismatch Calibration\n"); |
f1dc5600 S |
200 | break; |
201 | case ADC_GAIN_CAL: | |
202 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); | |
203 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 | 204 | "starting ADC Gain Calibration\n"); |
f1dc5600 S |
205 | break; |
206 | case ADC_DC_CAL: | |
207 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); | |
208 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 | 209 | "starting ADC DC Calibration\n"); |
f1dc5600 S |
210 | break; |
211 | case ADC_DC_INIT_CAL: | |
212 | REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); | |
213 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 | 214 | "starting Init ADC DC Calibration\n"); |
f1dc5600 S |
215 | break; |
216 | } | |
217 | ||
218 | REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), | |
219 | AR_PHY_TIMING_CTRL4_DO_CAL); | |
220 | } | |
221 | ||
cbe61d8a | 222 | static void ath9k_hw_reset_calibration(struct ath_hw *ah, |
cbfe9468 | 223 | struct ath9k_cal_list *currCal) |
f1dc5600 | 224 | { |
f1dc5600 S |
225 | int i; |
226 | ||
227 | ath9k_hw_setup_calibration(ah, currCal); | |
228 | ||
229 | currCal->calState = CAL_RUNNING; | |
230 | ||
231 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | |
2660b81a S |
232 | ah->meas0.sign[i] = 0; |
233 | ah->meas1.sign[i] = 0; | |
234 | ah->meas2.sign[i] = 0; | |
235 | ah->meas3.sign[i] = 0; | |
f1dc5600 S |
236 | } |
237 | ||
2660b81a | 238 | ah->cal_samples = 0; |
f1dc5600 S |
239 | } |
240 | ||
379f0440 | 241 | static bool ath9k_hw_per_calibration(struct ath_hw *ah, |
f1dc5600 S |
242 | struct ath9k_channel *ichan, |
243 | u8 rxchainmask, | |
cbfe9468 | 244 | struct ath9k_cal_list *currCal) |
f1dc5600 | 245 | { |
379f0440 | 246 | bool iscaldone = false; |
f1dc5600 S |
247 | |
248 | if (currCal->calState == CAL_RUNNING) { | |
249 | if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & | |
250 | AR_PHY_TIMING_CTRL4_DO_CAL)) { | |
251 | ||
252 | currCal->calData->calCollect(ah); | |
2660b81a | 253 | ah->cal_samples++; |
f1dc5600 | 254 | |
2660b81a | 255 | if (ah->cal_samples >= currCal->calData->calNumSamples) { |
f1dc5600 S |
256 | int i, numChains = 0; |
257 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | |
258 | if (rxchainmask & (1 << i)) | |
259 | numChains++; | |
260 | } | |
261 | ||
262 | currCal->calData->calPostProc(ah, numChains); | |
263 | ichan->CalValid |= currCal->calData->calType; | |
264 | currCal->calState = CAL_DONE; | |
379f0440 | 265 | iscaldone = true; |
f1dc5600 S |
266 | } else { |
267 | ath9k_hw_setup_calibration(ah, currCal); | |
268 | } | |
269 | } | |
270 | } else if (!(ichan->CalValid & currCal->calData->calType)) { | |
271 | ath9k_hw_reset_calibration(ah, currCal); | |
272 | } | |
379f0440 S |
273 | |
274 | return iscaldone; | |
f1dc5600 S |
275 | } |
276 | ||
c9e27d94 | 277 | /* Assumes you are talking about the currently configured channel */ |
cbe61d8a | 278 | static bool ath9k_hw_iscal_supported(struct ath_hw *ah, |
cbfe9468 | 279 | enum ath9k_cal_types calType) |
f1dc5600 | 280 | { |
c9e27d94 | 281 | struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; |
f1dc5600 | 282 | |
2660b81a | 283 | switch (calType & ah->supp_cals) { |
c9e27d94 LR |
284 | case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */ |
285 | return true; | |
f1dc5600 S |
286 | case ADC_GAIN_CAL: |
287 | case ADC_DC_CAL: | |
a451aa66 S |
288 | if (!(conf->channel->band == IEEE80211_BAND_2GHZ && |
289 | conf_is_ht20(conf))) | |
c9e27d94 | 290 | return true; |
f1dc5600 S |
291 | break; |
292 | } | |
c9e27d94 | 293 | return false; |
f1dc5600 S |
294 | } |
295 | ||
cbe61d8a | 296 | static void ath9k_hw_iqcal_collect(struct ath_hw *ah) |
f1dc5600 | 297 | { |
f1dc5600 S |
298 | int i; |
299 | ||
300 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | |
2660b81a | 301 | ah->totalPowerMeasI[i] += |
f1dc5600 | 302 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); |
2660b81a | 303 | ah->totalPowerMeasQ[i] += |
f1dc5600 | 304 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); |
2660b81a | 305 | ah->totalIqCorrMeas[i] += |
f1dc5600 S |
306 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); |
307 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
308 | "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", | |
2660b81a S |
309 | ah->cal_samples, i, ah->totalPowerMeasI[i], |
310 | ah->totalPowerMeasQ[i], | |
311 | ah->totalIqCorrMeas[i]); | |
f1dc5600 S |
312 | } |
313 | } | |
314 | ||
cbe61d8a | 315 | static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah) |
f1dc5600 | 316 | { |
f1dc5600 S |
317 | int i; |
318 | ||
319 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | |
2660b81a | 320 | ah->totalAdcIOddPhase[i] += |
f1dc5600 | 321 | REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); |
2660b81a | 322 | ah->totalAdcIEvenPhase[i] += |
f1dc5600 | 323 | REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); |
2660b81a | 324 | ah->totalAdcQOddPhase[i] += |
f1dc5600 | 325 | REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); |
2660b81a | 326 | ah->totalAdcQEvenPhase[i] += |
f1dc5600 S |
327 | REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); |
328 | ||
329 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
330 | "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " | |
331 | "oddq=0x%08x; evenq=0x%08x;\n", | |
2660b81a S |
332 | ah->cal_samples, i, |
333 | ah->totalAdcIOddPhase[i], | |
334 | ah->totalAdcIEvenPhase[i], | |
335 | ah->totalAdcQOddPhase[i], | |
336 | ah->totalAdcQEvenPhase[i]); | |
f1dc5600 S |
337 | } |
338 | } | |
339 | ||
cbe61d8a | 340 | static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah) |
f1dc5600 | 341 | { |
f1dc5600 S |
342 | int i; |
343 | ||
344 | for (i = 0; i < AR5416_MAX_CHAINS; i++) { | |
2660b81a | 345 | ah->totalAdcDcOffsetIOddPhase[i] += |
f1dc5600 | 346 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); |
2660b81a | 347 | ah->totalAdcDcOffsetIEvenPhase[i] += |
f1dc5600 | 348 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); |
2660b81a | 349 | ah->totalAdcDcOffsetQOddPhase[i] += |
f1dc5600 | 350 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); |
2660b81a | 351 | ah->totalAdcDcOffsetQEvenPhase[i] += |
f1dc5600 S |
352 | (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); |
353 | ||
354 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
355 | "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " | |
356 | "oddq=0x%08x; evenq=0x%08x;\n", | |
2660b81a S |
357 | ah->cal_samples, i, |
358 | ah->totalAdcDcOffsetIOddPhase[i], | |
359 | ah->totalAdcDcOffsetIEvenPhase[i], | |
360 | ah->totalAdcDcOffsetQOddPhase[i], | |
361 | ah->totalAdcDcOffsetQEvenPhase[i]); | |
f1dc5600 S |
362 | } |
363 | } | |
364 | ||
cbe61d8a | 365 | static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) |
f1dc5600 | 366 | { |
f1dc5600 S |
367 | u32 powerMeasQ, powerMeasI, iqCorrMeas; |
368 | u32 qCoffDenom, iCoffDenom; | |
369 | int32_t qCoff, iCoff; | |
370 | int iqCorrNeg, i; | |
371 | ||
372 | for (i = 0; i < numChains; i++) { | |
2660b81a S |
373 | powerMeasI = ah->totalPowerMeasI[i]; |
374 | powerMeasQ = ah->totalPowerMeasQ[i]; | |
375 | iqCorrMeas = ah->totalIqCorrMeas[i]; | |
f1dc5600 S |
376 | |
377 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
378 | "Starting IQ Cal and Correction for Chain %d\n", | |
379 | i); | |
380 | ||
381 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
382 | "Orignal: Chn %diq_corr_meas = 0x%08x\n", | |
2660b81a | 383 | i, ah->totalIqCorrMeas[i]); |
f1dc5600 S |
384 | |
385 | iqCorrNeg = 0; | |
386 | ||
387 | if (iqCorrMeas > 0x80000000) { | |
388 | iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; | |
389 | iqCorrNeg = 1; | |
390 | } | |
391 | ||
392 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
393 | "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); | |
394 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
395 | "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); | |
396 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", | |
397 | iqCorrNeg); | |
398 | ||
399 | iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; | |
400 | qCoffDenom = powerMeasQ / 64; | |
401 | ||
402 | if (powerMeasQ != 0) { | |
403 | iCoff = iqCorrMeas / iCoffDenom; | |
404 | qCoff = powerMeasI / qCoffDenom - 64; | |
405 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
406 | "Chn %d iCoff = 0x%08x\n", i, iCoff); | |
407 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
408 | "Chn %d qCoff = 0x%08x\n", i, qCoff); | |
409 | ||
410 | iCoff = iCoff & 0x3f; | |
411 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
412 | "New: Chn %d iCoff = 0x%08x\n", i, iCoff); | |
413 | if (iqCorrNeg == 0x0) | |
414 | iCoff = 0x40 - iCoff; | |
415 | ||
416 | if (qCoff > 15) | |
417 | qCoff = 15; | |
418 | else if (qCoff <= -16) | |
419 | qCoff = 16; | |
420 | ||
421 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
422 | "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", | |
423 | i, iCoff, qCoff); | |
424 | ||
425 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), | |
426 | AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, | |
427 | iCoff); | |
428 | REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), | |
429 | AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, | |
430 | qCoff); | |
431 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
432 | "IQ Cal and Correction done for Chain %d\n", | |
433 | i); | |
434 | } | |
435 | } | |
436 | ||
437 | REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), | |
438 | AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); | |
439 | } | |
440 | ||
cbe61d8a | 441 | static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) |
f1dc5600 | 442 | { |
f1dc5600 S |
443 | u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; |
444 | u32 qGainMismatch, iGainMismatch, val, i; | |
445 | ||
446 | for (i = 0; i < numChains; i++) { | |
2660b81a S |
447 | iOddMeasOffset = ah->totalAdcIOddPhase[i]; |
448 | iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; | |
449 | qOddMeasOffset = ah->totalAdcQOddPhase[i]; | |
450 | qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; | |
f1dc5600 S |
451 | |
452 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
453 | "Starting ADC Gain Cal for Chain %d\n", i); | |
454 | ||
455 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
456 | "Chn %d pwr_meas_odd_i = 0x%08x\n", i, | |
457 | iOddMeasOffset); | |
458 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
459 | "Chn %d pwr_meas_even_i = 0x%08x\n", i, | |
460 | iEvenMeasOffset); | |
461 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
462 | "Chn %d pwr_meas_odd_q = 0x%08x\n", i, | |
463 | qOddMeasOffset); | |
464 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
465 | "Chn %d pwr_meas_even_q = 0x%08x\n", i, | |
466 | qEvenMeasOffset); | |
467 | ||
468 | if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { | |
469 | iGainMismatch = | |
470 | ((iEvenMeasOffset * 32) / | |
471 | iOddMeasOffset) & 0x3f; | |
472 | qGainMismatch = | |
473 | ((qOddMeasOffset * 32) / | |
474 | qEvenMeasOffset) & 0x3f; | |
475 | ||
476 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
477 | "Chn %d gain_mismatch_i = 0x%08x\n", i, | |
478 | iGainMismatch); | |
479 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
480 | "Chn %d gain_mismatch_q = 0x%08x\n", i, | |
481 | qGainMismatch); | |
482 | ||
483 | val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); | |
484 | val &= 0xfffff000; | |
485 | val |= (qGainMismatch) | (iGainMismatch << 6); | |
486 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); | |
487 | ||
488 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
489 | "ADC Gain Cal done for Chain %d\n", i); | |
490 | } | |
491 | } | |
492 | ||
493 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), | |
494 | REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | | |
495 | AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); | |
496 | } | |
497 | ||
cbe61d8a | 498 | static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) |
f1dc5600 | 499 | { |
f1dc5600 S |
500 | u32 iOddMeasOffset, iEvenMeasOffset, val, i; |
501 | int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; | |
cbfe9468 | 502 | const struct ath9k_percal_data *calData = |
2660b81a | 503 | ah->cal_list_curr->calData; |
f1dc5600 S |
504 | u32 numSamples = |
505 | (1 << (calData->calCountMax + 5)) * calData->calNumSamples; | |
506 | ||
507 | for (i = 0; i < numChains; i++) { | |
2660b81a S |
508 | iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; |
509 | iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; | |
510 | qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; | |
511 | qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; | |
f1dc5600 S |
512 | |
513 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
514 | "Starting ADC DC Offset Cal for Chain %d\n", i); | |
515 | ||
516 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
517 | "Chn %d pwr_meas_odd_i = %d\n", i, | |
518 | iOddMeasOffset); | |
519 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
520 | "Chn %d pwr_meas_even_i = %d\n", i, | |
521 | iEvenMeasOffset); | |
522 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
523 | "Chn %d pwr_meas_odd_q = %d\n", i, | |
524 | qOddMeasOffset); | |
525 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
526 | "Chn %d pwr_meas_even_q = %d\n", i, | |
527 | qEvenMeasOffset); | |
528 | ||
529 | iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / | |
530 | numSamples) & 0x1ff; | |
531 | qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / | |
532 | numSamples) & 0x1ff; | |
533 | ||
534 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
535 | "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, | |
536 | iDcMismatch); | |
537 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
538 | "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, | |
539 | qDcMismatch); | |
540 | ||
541 | val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); | |
542 | val &= 0xc0000fff; | |
543 | val |= (qDcMismatch << 12) | (iDcMismatch << 21); | |
544 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); | |
545 | ||
546 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
547 | "ADC DC Offset Cal done for Chain %d\n", i); | |
548 | } | |
549 | ||
550 | REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), | |
551 | REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | | |
552 | AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); | |
553 | } | |
554 | ||
c9e27d94 | 555 | /* This is done for the currently configured channel */ |
cbe61d8a | 556 | bool ath9k_hw_reset_calvalid(struct ath_hw *ah) |
f1dc5600 | 557 | { |
c9e27d94 | 558 | struct ieee80211_conf *conf = &ah->ah_sc->hw->conf; |
cbfe9468 | 559 | struct ath9k_cal_list *currCal = ah->cal_list_curr; |
f1dc5600 | 560 | |
2660b81a | 561 | if (!ah->curchan) |
c9e27d94 | 562 | return true; |
f1dc5600 S |
563 | |
564 | if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) | |
c9e27d94 | 565 | return true; |
f1dc5600 S |
566 | |
567 | if (currCal == NULL) | |
c9e27d94 | 568 | return true; |
f1dc5600 S |
569 | |
570 | if (currCal->calState != CAL_DONE) { | |
571 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 S |
572 | "Calibration state incorrect, %d\n", |
573 | currCal->calState); | |
c9e27d94 | 574 | return true; |
f1dc5600 S |
575 | } |
576 | ||
c9e27d94 LR |
577 | if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType)) |
578 | return true; | |
f1dc5600 S |
579 | |
580 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
c9e27d94 LR |
581 | "Resetting Cal %d state for channel %u\n", |
582 | currCal->calData->calType, conf->channel->center_freq); | |
f1dc5600 | 583 | |
2660b81a | 584 | ah->curchan->CalValid &= ~currCal->calData->calType; |
f1dc5600 S |
585 | currCal->calState = CAL_WAITING; |
586 | ||
c9e27d94 | 587 | return false; |
f1dc5600 S |
588 | } |
589 | ||
cbe61d8a | 590 | void ath9k_hw_start_nfcal(struct ath_hw *ah) |
f1dc5600 S |
591 | { |
592 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | |
593 | AR_PHY_AGC_CONTROL_ENABLE_NF); | |
594 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | |
595 | AR_PHY_AGC_CONTROL_NO_UPDATE_NF); | |
596 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | |
597 | } | |
598 | ||
cbe61d8a | 599 | void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) |
f1dc5600 S |
600 | { |
601 | struct ath9k_nfcal_hist *h; | |
602 | int i, j; | |
603 | int32_t val; | |
604 | const u32 ar5416_cca_regs[6] = { | |
605 | AR_PHY_CCA, | |
606 | AR_PHY_CH1_CCA, | |
607 | AR_PHY_CH2_CCA, | |
608 | AR_PHY_EXT_CCA, | |
609 | AR_PHY_CH1_EXT_CCA, | |
610 | AR_PHY_CH2_EXT_CCA | |
611 | }; | |
ce143bb0 | 612 | u8 chainmask, rx_chain_status; |
f1dc5600 | 613 | |
ce143bb0 | 614 | rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK); |
5dad40c1 S |
615 | if (AR_SREV_9285(ah)) |
616 | chainmask = 0x9; | |
ce143bb0 SB |
617 | else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) { |
618 | if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4)) | |
619 | chainmask = 0x1B; | |
620 | else | |
621 | chainmask = 0x09; | |
622 | } else { | |
623 | if (rx_chain_status & 0x4) | |
624 | chainmask = 0x3F; | |
625 | else if (rx_chain_status & 0x2) | |
626 | chainmask = 0x1B; | |
627 | else | |
628 | chainmask = 0x09; | |
629 | } | |
f1dc5600 | 630 | |
f1dc5600 | 631 | h = ah->nfCalHist; |
f1dc5600 S |
632 | |
633 | for (i = 0; i < NUM_NF_READINGS; i++) { | |
634 | if (chainmask & (1 << i)) { | |
635 | val = REG_READ(ah, ar5416_cca_regs[i]); | |
636 | val &= 0xFFFFFE00; | |
637 | val |= (((u32) (h[i].privNF) << 1) & 0x1ff); | |
638 | REG_WRITE(ah, ar5416_cca_regs[i], val); | |
639 | } | |
640 | } | |
641 | ||
642 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | |
643 | AR_PHY_AGC_CONTROL_ENABLE_NF); | |
644 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | |
645 | AR_PHY_AGC_CONTROL_NO_UPDATE_NF); | |
646 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | |
647 | ||
648 | for (j = 0; j < 1000; j++) { | |
649 | if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & | |
650 | AR_PHY_AGC_CONTROL_NF) == 0) | |
651 | break; | |
652 | udelay(10); | |
653 | } | |
654 | ||
655 | for (i = 0; i < NUM_NF_READINGS; i++) { | |
656 | if (chainmask & (1 << i)) { | |
657 | val = REG_READ(ah, ar5416_cca_regs[i]); | |
658 | val &= 0xFFFFFE00; | |
659 | val |= (((u32) (-50) << 1) & 0x1ff); | |
660 | REG_WRITE(ah, ar5416_cca_regs[i], val); | |
661 | } | |
662 | } | |
663 | } | |
664 | ||
cbe61d8a | 665 | int16_t ath9k_hw_getnf(struct ath_hw *ah, |
f1dc5600 S |
666 | struct ath9k_channel *chan) |
667 | { | |
668 | int16_t nf, nfThresh; | |
669 | int16_t nfarray[NUM_NF_READINGS] = { 0 }; | |
670 | struct ath9k_nfcal_hist *h; | |
76061abb | 671 | struct ieee80211_channel *c = chan->chan; |
f1dc5600 S |
672 | |
673 | chan->channelFlags &= (~CHANNEL_CW_INT); | |
674 | if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { | |
675 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 | 676 | "NF did not complete in calibration window\n"); |
f1dc5600 S |
677 | nf = 0; |
678 | chan->rawNoiseFloor = nf; | |
679 | return chan->rawNoiseFloor; | |
680 | } else { | |
681 | ath9k_hw_do_getnf(ah, nfarray); | |
682 | nf = nfarray[0]; | |
76061abb | 683 | if (getNoiseFloorThresh(ah, c->band, &nfThresh) |
f1dc5600 S |
684 | && nf > nfThresh) { |
685 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | |
04bd4638 S |
686 | "noise floor failed detected; " |
687 | "detected %d, threshold %d\n", | |
f1dc5600 S |
688 | nf, nfThresh); |
689 | chan->channelFlags |= CHANNEL_CW_INT; | |
690 | } | |
691 | } | |
692 | ||
f1dc5600 | 693 | h = ah->nfCalHist; |
f1dc5600 S |
694 | |
695 | ath9k_hw_update_nfcal_hist_buffer(h, nfarray); | |
696 | chan->rawNoiseFloor = h[0].privNF; | |
697 | ||
698 | return chan->rawNoiseFloor; | |
699 | } | |
700 | ||
cbe61d8a | 701 | void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah) |
f1dc5600 S |
702 | { |
703 | int i, j; | |
a59b5a5e SB |
704 | s16 noise_floor; |
705 | ||
706 | if (AR_SREV_9280(ah)) | |
707 | noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE; | |
708 | else if (AR_SREV_9285(ah)) | |
709 | noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE; | |
6170cd5c VN |
710 | else if (AR_SREV_9287(ah)) |
711 | noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE; | |
a59b5a5e SB |
712 | else |
713 | noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE; | |
f1dc5600 S |
714 | |
715 | for (i = 0; i < NUM_NF_READINGS; i++) { | |
716 | ah->nfCalHist[i].currIndex = 0; | |
a59b5a5e | 717 | ah->nfCalHist[i].privNF = noise_floor; |
f1dc5600 S |
718 | ah->nfCalHist[i].invalidNFcount = |
719 | AR_PHY_CCA_FILTERWINDOW_LENGTH; | |
720 | for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { | |
a59b5a5e | 721 | ah->nfCalHist[i].nfCalBuffer[j] = noise_floor; |
f1dc5600 S |
722 | } |
723 | } | |
f1dc5600 S |
724 | } |
725 | ||
cbe61d8a | 726 | s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) |
f1dc5600 | 727 | { |
f1dc5600 S |
728 | s16 nf; |
729 | ||
5f8e077c | 730 | if (chan->rawNoiseFloor == 0) |
e56db718 LR |
731 | nf = -96; |
732 | else | |
5f8e077c | 733 | nf = chan->rawNoiseFloor; |
f1dc5600 S |
734 | |
735 | if (!ath9k_hw_nf_in_range(ah, nf)) | |
736 | nf = ATH_DEFAULT_NOISE_FLOOR; | |
737 | ||
738 | return nf; | |
739 | } | |
740 | ||
8bd1d07f SB |
741 | static void ath9k_olc_temp_compensation(struct ath_hw *ah) |
742 | { | |
743 | u32 rddata, i; | |
db91f2e4 | 744 | int delta, currPDADC, regval, slope; |
8bd1d07f SB |
745 | |
746 | rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); | |
8bd1d07f SB |
747 | currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); |
748 | ||
8bd1d07f | 749 | |
db91f2e4 VN |
750 | if (OLC_FOR_AR9287_10_LATER) { |
751 | if (ah->initPDADC == 0 || currPDADC == 0) { | |
752 | return; | |
753 | } else { | |
754 | slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); | |
755 | if (slope == 0) | |
756 | delta = 0; | |
757 | else | |
758 | delta = ((currPDADC - ah->initPDADC)*4) / slope; | |
759 | REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, | |
760 | AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); | |
761 | REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, | |
762 | AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); | |
763 | } | |
764 | } else { | |
765 | if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) | |
766 | delta = (currPDADC - ah->initPDADC + 4) / 8; | |
767 | else | |
768 | delta = (currPDADC - ah->initPDADC + 5) / 10; | |
769 | ||
770 | if (delta != ah->PDADCdelta) { | |
771 | ah->PDADCdelta = delta; | |
772 | for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { | |
773 | regval = ah->originalGain[i] - delta; | |
774 | if (regval < 0) | |
775 | regval = 0; | |
8bd1d07f | 776 | |
db91f2e4 VN |
777 | REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, |
778 | AR_PHY_TX_GAIN, regval); | |
779 | } | |
8bd1d07f SB |
780 | } |
781 | } | |
782 | } | |
783 | ||
d7e7d229 LR |
784 | static void ath9k_hw_9271_pa_cal(struct ath_hw *ah) |
785 | { | |
786 | u32 regVal; | |
787 | unsigned int i; | |
788 | u32 regList [][2] = { | |
789 | { 0x786c, 0 }, | |
790 | { 0x7854, 0 }, | |
791 | { 0x7820, 0 }, | |
792 | { 0x7824, 0 }, | |
793 | { 0x7868, 0 }, | |
794 | { 0x783c, 0 }, | |
795 | { 0x7838, 0 } , | |
796 | { 0x7828, 0 } , | |
797 | }; | |
798 | ||
799 | for (i = 0; i < ARRAY_SIZE(regList); i++) | |
800 | regList[i][1] = REG_READ(ah, regList[i][0]); | |
801 | ||
802 | regVal = REG_READ(ah, 0x7834); | |
803 | regVal &= (~(0x1)); | |
804 | REG_WRITE(ah, 0x7834, regVal); | |
805 | regVal = REG_READ(ah, 0x9808); | |
806 | regVal |= (0x1 << 27); | |
807 | REG_WRITE(ah, 0x9808, regVal); | |
808 | ||
809 | /* 786c,b23,1, pwddac=1 */ | |
810 | REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); | |
811 | /* 7854, b5,1, pdrxtxbb=1 */ | |
812 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); | |
813 | /* 7854, b7,1, pdv2i=1 */ | |
814 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); | |
815 | /* 7854, b8,1, pddacinterface=1 */ | |
816 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); | |
817 | /* 7824,b12,0, offcal=0 */ | |
818 | REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); | |
819 | /* 7838, b1,0, pwddb=0 */ | |
820 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); | |
821 | /* 7820,b11,0, enpacal=0 */ | |
822 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); | |
823 | /* 7820,b25,1, pdpadrv1=0 */ | |
824 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); | |
825 | /* 7820,b24,0, pdpadrv2=0 */ | |
826 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0); | |
827 | /* 7820,b23,0, pdpaout=0 */ | |
828 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); | |
829 | /* 783c,b14-16,7, padrvgn2tab_0=7 */ | |
830 | REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7); | |
831 | /* | |
832 | * 7838,b29-31,0, padrvgn1tab_0=0 | |
833 | * does not matter since we turn it off | |
834 | */ | |
835 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0); | |
836 | ||
837 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); | |
838 | ||
839 | /* Set: | |
840 | * localmode=1,bmode=1,bmoderxtx=1,synthon=1, | |
841 | * txon=1,paon=1,oscon=1,synthon_force=1 | |
842 | */ | |
843 | REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); | |
844 | udelay(30); | |
845 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); | |
846 | ||
847 | /* find off_6_1; */ | |
848 | for (i = 6; i >= 0; i--) { | |
849 | regVal = REG_READ(ah, 0x7834); | |
850 | regVal |= (1 << (20 + i)); | |
851 | REG_WRITE(ah, 0x7834, regVal); | |
852 | udelay(1); | |
853 | //regVal = REG_READ(ah, 0x7834); | |
854 | regVal &= (~(0x1 << (20 + i))); | |
855 | regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) | |
856 | << (20 + i)); | |
857 | REG_WRITE(ah, 0x7834, regVal); | |
858 | } | |
859 | ||
860 | /* Empirical offset correction */ | |
861 | #if 0 | |
862 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0x20); | |
863 | #endif | |
864 | ||
865 | regVal = REG_READ(ah, 0x7834); | |
866 | regVal |= 0x1; | |
867 | REG_WRITE(ah, 0x7834, regVal); | |
868 | regVal = REG_READ(ah, 0x9808); | |
869 | regVal &= (~(0x1 << 27)); | |
870 | REG_WRITE(ah, 0x9808, regVal); | |
871 | ||
872 | for (i = 0; i < ARRAY_SIZE(regList); i++) | |
873 | REG_WRITE(ah, regList[i][0], regList[i][1]); | |
874 | } | |
875 | ||
a13883b0 | 876 | static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset) |
e7594072 SB |
877 | { |
878 | ||
879 | u32 regVal; | |
880 | int i, offset, offs_6_1, offs_0; | |
881 | u32 ccomp_org, reg_field; | |
882 | u32 regList[][2] = { | |
883 | { 0x786c, 0 }, | |
884 | { 0x7854, 0 }, | |
885 | { 0x7820, 0 }, | |
886 | { 0x7824, 0 }, | |
887 | { 0x7868, 0 }, | |
888 | { 0x783c, 0 }, | |
889 | { 0x7838, 0 }, | |
890 | }; | |
891 | ||
a13883b0 S |
892 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); |
893 | ||
20caf0dd S |
894 | /* PA CAL is not needed for high power solution */ |
895 | if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == | |
896 | AR5416_EEP_TXGAIN_HIGH_POWER) | |
897 | return; | |
898 | ||
e7594072 SB |
899 | if (AR_SREV_9285_11(ah)) { |
900 | REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); | |
901 | udelay(10); | |
902 | } | |
903 | ||
904 | for (i = 0; i < ARRAY_SIZE(regList); i++) | |
905 | regList[i][1] = REG_READ(ah, regList[i][0]); | |
906 | ||
907 | regVal = REG_READ(ah, 0x7834); | |
908 | regVal &= (~(0x1)); | |
909 | REG_WRITE(ah, 0x7834, regVal); | |
910 | regVal = REG_READ(ah, 0x9808); | |
911 | regVal |= (0x1 << 27); | |
912 | REG_WRITE(ah, 0x9808, regVal); | |
913 | ||
914 | REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); | |
915 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); | |
916 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); | |
917 | REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); | |
918 | REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); | |
919 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); | |
920 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); | |
0abb0968 | 921 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); |
e7594072 SB |
922 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); |
923 | REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); | |
924 | REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); | |
925 | REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); | |
926 | ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); | |
0abb0968 | 927 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); |
e7594072 SB |
928 | |
929 | REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); | |
930 | udelay(30); | |
931 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); | |
932 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); | |
933 | ||
934 | for (i = 6; i > 0; i--) { | |
935 | regVal = REG_READ(ah, 0x7834); | |
936 | regVal |= (1 << (19 + i)); | |
937 | REG_WRITE(ah, 0x7834, regVal); | |
938 | udelay(1); | |
edbf51f6 | 939 | regVal = REG_READ(ah, 0x7834); |
e7594072 SB |
940 | regVal &= (~(0x1 << (19 + i))); |
941 | reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); | |
942 | regVal |= (reg_field << (19 + i)); | |
943 | REG_WRITE(ah, 0x7834, regVal); | |
944 | } | |
945 | ||
946 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); | |
947 | udelay(1); | |
948 | reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); | |
949 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); | |
950 | offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); | |
951 | offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); | |
952 | ||
953 | offset = (offs_6_1<<1) | offs_0; | |
954 | offset = offset - 0; | |
955 | offs_6_1 = offset>>1; | |
956 | offs_0 = offset & 1; | |
957 | ||
a13883b0 S |
958 | if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { |
959 | if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) | |
960 | ah->pacal_info.max_skipcount = | |
961 | 2 * ah->pacal_info.max_skipcount; | |
962 | ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; | |
963 | } else { | |
964 | ah->pacal_info.max_skipcount = 1; | |
965 | ah->pacal_info.skipcount = 0; | |
966 | ah->pacal_info.prev_offset = offset; | |
967 | } | |
968 | ||
e7594072 SB |
969 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); |
970 | REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); | |
971 | ||
972 | regVal = REG_READ(ah, 0x7834); | |
973 | regVal |= 0x1; | |
974 | REG_WRITE(ah, 0x7834, regVal); | |
975 | regVal = REG_READ(ah, 0x9808); | |
976 | regVal &= (~(0x1 << 27)); | |
977 | REG_WRITE(ah, 0x9808, regVal); | |
978 | ||
979 | for (i = 0; i < ARRAY_SIZE(regList); i++) | |
980 | REG_WRITE(ah, regList[i][0], regList[i][1]); | |
981 | ||
982 | REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); | |
983 | ||
984 | if (AR_SREV_9285_11(ah)) | |
985 | REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); | |
986 | ||
987 | } | |
988 | ||
4e845168 | 989 | bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, |
379f0440 | 990 | u8 rxchainmask, bool longcal) |
4e845168 | 991 | { |
379f0440 | 992 | bool iscaldone = true; |
cbfe9468 | 993 | struct ath9k_cal_list *currCal = ah->cal_list_curr; |
4e845168 | 994 | |
4e845168 SB |
995 | if (currCal && |
996 | (currCal->calState == CAL_RUNNING || | |
997 | currCal->calState == CAL_WAITING)) { | |
379f0440 S |
998 | iscaldone = ath9k_hw_per_calibration(ah, chan, |
999 | rxchainmask, currCal); | |
1000 | if (iscaldone) { | |
4e845168 SB |
1001 | ah->cal_list_curr = currCal = currCal->calNext; |
1002 | ||
1003 | if (currCal->calState == CAL_WAITING) { | |
379f0440 | 1004 | iscaldone = false; |
4e845168 SB |
1005 | ath9k_hw_reset_calibration(ah, currCal); |
1006 | } | |
1007 | } | |
1008 | } | |
1009 | ||
d7e7d229 | 1010 | /* Do NF cal only at longer intervals */ |
4e845168 | 1011 | if (longcal) { |
d7e7d229 LR |
1012 | /* Do periodic PAOffset Cal */ |
1013 | if (AR_SREV_9271(ah)) | |
1014 | ath9k_hw_9271_pa_cal(ah); | |
a13883b0 S |
1015 | else if (AR_SREV_9285_11_OR_LATER(ah)) { |
1016 | if (!ah->pacal_info.skipcount) | |
1017 | ath9k_hw_9285_pa_cal(ah, false); | |
1018 | else | |
1019 | ah->pacal_info.skipcount--; | |
1020 | } | |
4e845168 | 1021 | |
ac88b6ec | 1022 | if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER) |
4e845168 | 1023 | ath9k_olc_temp_compensation(ah); |
d7e7d229 LR |
1024 | |
1025 | /* Get the value from the previous NF cal and update history buffer */ | |
4e845168 | 1026 | ath9k_hw_getnf(ah, chan); |
d7e7d229 LR |
1027 | |
1028 | /* | |
1029 | * Load the NF from history buffer of the current channel. | |
1030 | * NF is slow time-variant, so it is OK to use a historical value. | |
1031 | */ | |
4e845168 | 1032 | ath9k_hw_loadnf(ah, ah->curchan); |
d7e7d229 | 1033 | |
4e845168 | 1034 | ath9k_hw_start_nfcal(ah); |
4e845168 SB |
1035 | } |
1036 | ||
379f0440 | 1037 | return iscaldone; |
4e845168 SB |
1038 | } |
1039 | ||
15cc0f1a | 1040 | static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan) |
4e845168 SB |
1041 | { |
1042 | REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); | |
db2f63f6 | 1043 | if (IS_CHAN_HT20(chan)) { |
4e845168 SB |
1044 | REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); |
1045 | REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); | |
1046 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | |
1047 | AR_PHY_AGC_CONTROL_FLTR_CAL); | |
1048 | REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); | |
1049 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); | |
1050 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | |
1051 | AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { | |
1052 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset " | |
1053 | "calibration failed to complete in " | |
1054 | "1ms; noisy ??\n"); | |
1055 | return false; | |
1056 | } | |
1057 | REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); | |
1058 | REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); | |
1059 | REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); | |
1060 | } | |
1061 | REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); | |
1062 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); | |
1063 | REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); | |
1064 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); | |
1065 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, | |
1066 | 0, AH_WAIT_TIMEOUT)) { | |
1067 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration " | |
1068 | "failed to complete in 1ms; noisy ??\n"); | |
1069 | return false; | |
1070 | } | |
1071 | ||
1072 | REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); | |
1073 | REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); | |
1074 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); | |
1075 | ||
1076 | return true; | |
1077 | } | |
1078 | ||
04d19ddd | 1079 | bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) |
f1dc5600 | 1080 | { |
f9dd6b52 | 1081 | if (AR_SREV_9285_12_OR_LATER(ah)) { |
4e845168 SB |
1082 | if (!ar9285_clc(ah, chan)) |
1083 | return false; | |
04d19ddd S |
1084 | } else { |
1085 | if (AR_SREV_9280_10_OR_LATER(ah)) { | |
ac88b6ec VN |
1086 | if (!AR_SREV_9287_10_OR_LATER(ah)) |
1087 | REG_CLR_BIT(ah, AR_PHY_ADC_CTL, | |
1088 | AR_PHY_ADC_CTL_OFF_PWDADC); | |
1089 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | |
1090 | AR_PHY_AGC_CONTROL_FLTR_CAL); | |
04d19ddd | 1091 | } |
edf7c060 | 1092 | |
04d19ddd | 1093 | /* Calibrate the AGC */ |
edf7c060 | 1094 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
04d19ddd S |
1095 | REG_READ(ah, AR_PHY_AGC_CONTROL) | |
1096 | AR_PHY_AGC_CONTROL_CAL); | |
edf7c060 | 1097 | |
04d19ddd S |
1098 | /* Poll for offset calibration complete */ |
1099 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, | |
1100 | 0, AH_WAIT_TIMEOUT)) { | |
edf7c060 S |
1101 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
1102 | "offset calibration failed to complete in 1ms; " | |
1103 | "noisy environment?\n"); | |
1104 | return false; | |
1105 | } | |
1106 | ||
04d19ddd | 1107 | if (AR_SREV_9280_10_OR_LATER(ah)) { |
ac88b6ec VN |
1108 | if (!AR_SREV_9287_10_OR_LATER(ah)) |
1109 | REG_SET_BIT(ah, AR_PHY_ADC_CTL, | |
1110 | AR_PHY_ADC_CTL_OFF_PWDADC); | |
1111 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, | |
1112 | AR_PHY_AGC_CONTROL_FLTR_CAL); | |
04d19ddd | 1113 | } |
edf7c060 S |
1114 | } |
1115 | ||
1116 | /* Do PA Calibration */ | |
f9dd6b52 | 1117 | if (AR_SREV_9285_11_OR_LATER(ah)) |
a13883b0 | 1118 | ath9k_hw_9285_pa_cal(ah, true); |
e7594072 | 1119 | |
04d19ddd | 1120 | /* Do NF Calibration after DC offset and other calibrations */ |
f1dc5600 | 1121 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
04d19ddd | 1122 | REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); |
f1dc5600 | 1123 | |
2660b81a | 1124 | ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; |
f1dc5600 | 1125 | |
04d19ddd | 1126 | /* Enable IQ, ADC Gain and ADC DC offset CALs */ |
f1dc5600 | 1127 | if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { |
c9e27d94 | 1128 | if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) { |
2660b81a S |
1129 | INIT_CAL(&ah->adcgain_caldata); |
1130 | INSERT_CAL(ah, &ah->adcgain_caldata); | |
f1dc5600 | 1131 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
04d19ddd | 1132 | "enabling ADC Gain Calibration.\n"); |
f1dc5600 | 1133 | } |
c9e27d94 | 1134 | if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) { |
2660b81a S |
1135 | INIT_CAL(&ah->adcdc_caldata); |
1136 | INSERT_CAL(ah, &ah->adcdc_caldata); | |
f1dc5600 | 1137 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
04d19ddd | 1138 | "enabling ADC DC Calibration.\n"); |
f1dc5600 | 1139 | } |
c9e27d94 | 1140 | if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) { |
2660b81a S |
1141 | INIT_CAL(&ah->iq_caldata); |
1142 | INSERT_CAL(ah, &ah->iq_caldata); | |
f1dc5600 | 1143 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
04d19ddd | 1144 | "enabling IQ Calibration.\n"); |
f1dc5600 S |
1145 | } |
1146 | ||
2660b81a | 1147 | ah->cal_list_curr = ah->cal_list; |
f1dc5600 | 1148 | |
2660b81a S |
1149 | if (ah->cal_list_curr) |
1150 | ath9k_hw_reset_calibration(ah, ah->cal_list_curr); | |
f1dc5600 S |
1151 | } |
1152 | ||
5f8e077c | 1153 | chan->CalValid = 0; |
f1dc5600 S |
1154 | |
1155 | return true; | |
1156 | } | |
1157 | ||
cbfe9468 | 1158 | const struct ath9k_percal_data iq_cal_multi_sample = { |
f1dc5600 S |
1159 | IQ_MISMATCH_CAL, |
1160 | MAX_CAL_SAMPLES, | |
1161 | PER_MIN_LOG_COUNT, | |
1162 | ath9k_hw_iqcal_collect, | |
1163 | ath9k_hw_iqcalibrate | |
1164 | }; | |
cbfe9468 | 1165 | const struct ath9k_percal_data iq_cal_single_sample = { |
f1dc5600 S |
1166 | IQ_MISMATCH_CAL, |
1167 | MIN_CAL_SAMPLES, | |
1168 | PER_MAX_LOG_COUNT, | |
1169 | ath9k_hw_iqcal_collect, | |
1170 | ath9k_hw_iqcalibrate | |
1171 | }; | |
cbfe9468 | 1172 | const struct ath9k_percal_data adc_gain_cal_multi_sample = { |
f1dc5600 S |
1173 | ADC_GAIN_CAL, |
1174 | MAX_CAL_SAMPLES, | |
1175 | PER_MIN_LOG_COUNT, | |
1176 | ath9k_hw_adc_gaincal_collect, | |
1177 | ath9k_hw_adc_gaincal_calibrate | |
1178 | }; | |
cbfe9468 | 1179 | const struct ath9k_percal_data adc_gain_cal_single_sample = { |
f1dc5600 S |
1180 | ADC_GAIN_CAL, |
1181 | MIN_CAL_SAMPLES, | |
1182 | PER_MAX_LOG_COUNT, | |
1183 | ath9k_hw_adc_gaincal_collect, | |
1184 | ath9k_hw_adc_gaincal_calibrate | |
1185 | }; | |
cbfe9468 | 1186 | const struct ath9k_percal_data adc_dc_cal_multi_sample = { |
f1dc5600 S |
1187 | ADC_DC_CAL, |
1188 | MAX_CAL_SAMPLES, | |
1189 | PER_MIN_LOG_COUNT, | |
1190 | ath9k_hw_adc_dccal_collect, | |
1191 | ath9k_hw_adc_dccal_calibrate | |
1192 | }; | |
cbfe9468 | 1193 | const struct ath9k_percal_data adc_dc_cal_single_sample = { |
f1dc5600 S |
1194 | ADC_DC_CAL, |
1195 | MIN_CAL_SAMPLES, | |
1196 | PER_MAX_LOG_COUNT, | |
1197 | ath9k_hw_adc_dccal_collect, | |
1198 | ath9k_hw_adc_dccal_calibrate | |
1199 | }; | |
cbfe9468 | 1200 | const struct ath9k_percal_data adc_init_dc_cal = { |
f1dc5600 S |
1201 | ADC_DC_INIT_CAL, |
1202 | MIN_CAL_SAMPLES, | |
1203 | INIT_LOG_COUNT, | |
1204 | ath9k_hw_adc_dccal_collect, | |
1205 | ath9k_hw_adc_dccal_calibrate | |
1206 | }; |