blob: eba85adb7cd37157d0ee5df8eeaeaa1fa883cc94 [file] [log] [blame]
Sujithf1dc5602008-10-29 10:16:30 +05301/*
Sujithcee075a2009-03-13 09:07:23 +05302 * Copyright (c) 2008-2009 Atheros Communications Inc.
Sujithf1dc5602008-10-29 10:16:30 +05303 *
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
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070017#include "hw.h"
Luis R. Rodriguez8fe65362010-04-15 17:38:14 -040018#include "ar9002_phy.h"
Sujithf1dc5602008-10-29 10:16:30 +053019
Sujithf1dc5602008-10-29 10:16:30 +053020/* We can tune this as we go by monitoring really low values */
21#define ATH9K_NF_TOO_LOW -60
Vivek Natarajan53bc7aa2010-04-05 14:48:04 +053022#define AR9285_CLCAL_REDO_THRESH 1
Sujithf1dc5602008-10-29 10:16:30 +053023
24/* AR5416 may return very high value (like -31 dBm), in those cases the nf
25 * is incorrect and we should use the static NF value. Later we can try to
26 * find out why they are reporting these values */
27
Sujithcbe61d82009-02-09 13:27:12 +053028static bool ath9k_hw_nf_in_range(struct ath_hw *ah, s16 nf)
Sujithf1dc5602008-10-29 10:16:30 +053029{
30 if (nf > ATH9K_NF_TOO_LOW) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070031 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
32 "noise floor value detected (%d) is "
33 "lower than what we think is a "
34 "reasonable value (%d)\n",
35 nf, ATH9K_NF_TOO_LOW);
Sujithf1dc5602008-10-29 10:16:30 +053036 return false;
37 }
38 return true;
39}
40
41static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer)
42{
43 int16_t nfval;
44 int16_t sort[ATH9K_NF_CAL_HIST_MAX];
45 int i, j;
46
47 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++)
48 sort[i] = nfCalBuffer[i];
49
50 for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) {
51 for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) {
52 if (sort[j] > sort[j - 1]) {
53 nfval = sort[j];
54 sort[j] = sort[j - 1];
55 sort[j - 1] = nfval;
56 }
57 }
58 }
59 nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1];
60
61 return nfval;
62}
63
64static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
65 int16_t *nfarray)
66{
67 int i;
68
69 for (i = 0; i < NUM_NF_READINGS; i++) {
70 h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
71
72 if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
73 h[i].currIndex = 0;
74
75 if (h[i].invalidNFcount > 0) {
76 if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
77 nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
78 h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
79 } else {
80 h[i].invalidNFcount--;
81 h[i].privNF = nfarray[i];
82 }
83 } else {
84 h[i].privNF =
85 ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
86 }
87 }
88 return;
89}
90
Sujithcbe61d82009-02-09 13:27:12 +053091static void ath9k_hw_do_getnf(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +053092 int16_t nfarray[NUM_NF_READINGS])
93{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -070094 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +053095 int16_t nf;
96
97 if (AR_SREV_9280_10_OR_LATER(ah))
98 nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
99 else
100 nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
101
102 if (nf & 0x100)
103 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700104 ath_print(common, ATH_DBG_CALIBRATE,
105 "NF calibrated [ctl] [chain 0] is %d\n", nf);
Sujith2cbfaea2010-03-17 14:25:20 +0530106
107 if (AR_SREV_9271(ah) && (nf >= -114))
108 nf = -116;
109
Sujithf1dc5602008-10-29 10:16:30 +0530110 nfarray[0] = nf;
111
Sujith6398dc02010-03-17 14:25:19 +0530112 if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530113 if (AR_SREV_9280_10_OR_LATER(ah))
114 nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
115 AR9280_PHY_CH1_MINCCA_PWR);
116 else
117 nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
118 AR_PHY_CH1_MINCCA_PWR);
Sujithf1dc5602008-10-29 10:16:30 +0530119
Sujithf1dc5602008-10-29 10:16:30 +0530120 if (nf & 0x100)
121 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700122 ath_print(common, ATH_DBG_CALIBRATE,
123 "NF calibrated [ctl] [chain 1] is %d\n", nf);
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530124 nfarray[1] = nf;
125
Vivek Natarajanac88b6e2009-07-23 10:59:57 +0530126 if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530127 nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
128 AR_PHY_CH2_MINCCA_PWR);
129 if (nf & 0x100)
130 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700131 ath_print(common, ATH_DBG_CALIBRATE,
132 "NF calibrated [ctl] [chain 2] is %d\n", nf);
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530133 nfarray[2] = nf;
134 }
Sujithf1dc5602008-10-29 10:16:30 +0530135 }
136
137 if (AR_SREV_9280_10_OR_LATER(ah))
138 nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
139 AR9280_PHY_EXT_MINCCA_PWR);
140 else
141 nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
142 AR_PHY_EXT_MINCCA_PWR);
143
144 if (nf & 0x100)
145 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700146 ath_print(common, ATH_DBG_CALIBRATE,
147 "NF calibrated [ext] [chain 0] is %d\n", nf);
Sujith2cbfaea2010-03-17 14:25:20 +0530148
149 if (AR_SREV_9271(ah) && (nf >= -114))
150 nf = -116;
151
Sujithf1dc5602008-10-29 10:16:30 +0530152 nfarray[3] = nf;
153
Sujith6398dc02010-03-17 14:25:19 +0530154 if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530155 if (AR_SREV_9280_10_OR_LATER(ah))
156 nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
157 AR9280_PHY_CH1_EXT_MINCCA_PWR);
158 else
159 nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
160 AR_PHY_CH1_EXT_MINCCA_PWR);
Sujithf1dc5602008-10-29 10:16:30 +0530161
Sujithf1dc5602008-10-29 10:16:30 +0530162 if (nf & 0x100)
163 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700164 ath_print(common, ATH_DBG_CALIBRATE,
165 "NF calibrated [ext] [chain 1] is %d\n", nf);
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530166 nfarray[4] = nf;
167
Vivek Natarajanac88b6e2009-07-23 10:59:57 +0530168 if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530169 nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
170 AR_PHY_CH2_EXT_MINCCA_PWR);
171 if (nf & 0x100)
172 nf = 0 - ((nf ^ 0x1ff) + 1);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700173 ath_print(common, ATH_DBG_CALIBRATE,
174 "NF calibrated [ext] [chain 2] is %d\n", nf);
Senthil Balasubramanian793c5922009-01-26 20:28:14 +0530175 nfarray[5] = nf;
176 }
Sujithf1dc5602008-10-29 10:16:30 +0530177 }
178}
179
Sujithcbe61d82009-02-09 13:27:12 +0530180static bool getNoiseFloorThresh(struct ath_hw *ah,
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800181 enum ieee80211_band band,
Sujithf1dc5602008-10-29 10:16:30 +0530182 int16_t *nft)
183{
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800184 switch (band) {
185 case IEEE80211_BAND_5GHZ:
Sujithf74df6f2009-02-09 13:27:24 +0530186 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_5);
Sujithf1dc5602008-10-29 10:16:30 +0530187 break;
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800188 case IEEE80211_BAND_2GHZ:
Sujithf74df6f2009-02-09 13:27:24 +0530189 *nft = (int8_t)ah->eep_ops->get_eeprom(ah, EEP_NFTHRESH_2);
Sujithf1dc5602008-10-29 10:16:30 +0530190 break;
191 default:
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800192 BUG_ON(1);
Sujithf1dc5602008-10-29 10:16:30 +0530193 return false;
194 }
195
196 return true;
197}
198
Sujithcbe61d82009-02-09 13:27:12 +0530199static void ath9k_hw_setup_calibration(struct ath_hw *ah,
Sujithcbfe9462009-04-13 21:56:56 +0530200 struct ath9k_cal_list *currCal)
Sujithf1dc5602008-10-29 10:16:30 +0530201{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700202 struct ath_common *common = ath9k_hw_common(ah);
203
Sujithf1dc5602008-10-29 10:16:30 +0530204 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
205 AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
206 currCal->calData->calCountMax);
207
208 switch (currCal->calData->calType) {
209 case IQ_MISMATCH_CAL:
210 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700211 ath_print(common, ATH_DBG_CALIBRATE,
212 "starting IQ Mismatch Calibration\n");
Sujithf1dc5602008-10-29 10:16:30 +0530213 break;
214 case ADC_GAIN_CAL:
215 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700216 ath_print(common, ATH_DBG_CALIBRATE,
217 "starting ADC Gain Calibration\n");
Sujithf1dc5602008-10-29 10:16:30 +0530218 break;
219 case ADC_DC_CAL:
220 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700221 ath_print(common, ATH_DBG_CALIBRATE,
222 "starting ADC DC Calibration\n");
Sujithf1dc5602008-10-29 10:16:30 +0530223 break;
224 case ADC_DC_INIT_CAL:
225 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700226 ath_print(common, ATH_DBG_CALIBRATE,
227 "starting Init ADC DC Calibration\n");
Sujithf1dc5602008-10-29 10:16:30 +0530228 break;
229 }
230
231 REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
232 AR_PHY_TIMING_CTRL4_DO_CAL);
233}
234
Sujithcbe61d82009-02-09 13:27:12 +0530235static void ath9k_hw_reset_calibration(struct ath_hw *ah,
Sujithcbfe9462009-04-13 21:56:56 +0530236 struct ath9k_cal_list *currCal)
Sujithf1dc5602008-10-29 10:16:30 +0530237{
Sujithf1dc5602008-10-29 10:16:30 +0530238 int i;
239
240 ath9k_hw_setup_calibration(ah, currCal);
241
242 currCal->calState = CAL_RUNNING;
243
244 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
Sujith2660b812009-02-09 13:27:26 +0530245 ah->meas0.sign[i] = 0;
246 ah->meas1.sign[i] = 0;
247 ah->meas2.sign[i] = 0;
248 ah->meas3.sign[i] = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530249 }
250
Sujith2660b812009-02-09 13:27:26 +0530251 ah->cal_samples = 0;
Sujithf1dc5602008-10-29 10:16:30 +0530252}
253
Sujith379f0442009-04-13 21:56:48 +0530254static bool ath9k_hw_per_calibration(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530255 struct ath9k_channel *ichan,
256 u8 rxchainmask,
Sujithcbfe9462009-04-13 21:56:56 +0530257 struct ath9k_cal_list *currCal)
Sujithf1dc5602008-10-29 10:16:30 +0530258{
Sujith379f0442009-04-13 21:56:48 +0530259 bool iscaldone = false;
Sujithf1dc5602008-10-29 10:16:30 +0530260
261 if (currCal->calState == CAL_RUNNING) {
262 if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
263 AR_PHY_TIMING_CTRL4_DO_CAL)) {
264
265 currCal->calData->calCollect(ah);
Sujith2660b812009-02-09 13:27:26 +0530266 ah->cal_samples++;
Sujithf1dc5602008-10-29 10:16:30 +0530267
Sujith2660b812009-02-09 13:27:26 +0530268 if (ah->cal_samples >= currCal->calData->calNumSamples) {
Sujithf1dc5602008-10-29 10:16:30 +0530269 int i, numChains = 0;
270 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
271 if (rxchainmask & (1 << i))
272 numChains++;
273 }
274
275 currCal->calData->calPostProc(ah, numChains);
276 ichan->CalValid |= currCal->calData->calType;
277 currCal->calState = CAL_DONE;
Sujith379f0442009-04-13 21:56:48 +0530278 iscaldone = true;
Sujithf1dc5602008-10-29 10:16:30 +0530279 } else {
280 ath9k_hw_setup_calibration(ah, currCal);
281 }
282 }
283 } else if (!(ichan->CalValid & currCal->calData->calType)) {
284 ath9k_hw_reset_calibration(ah, currCal);
285 }
Sujith379f0442009-04-13 21:56:48 +0530286
287 return iscaldone;
Sujithf1dc5602008-10-29 10:16:30 +0530288}
289
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800290/* Assumes you are talking about the currently configured channel */
Sujithcbe61d82009-02-09 13:27:12 +0530291static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
Sujithcbfe9462009-04-13 21:56:56 +0530292 enum ath9k_cal_types calType)
Sujithf1dc5602008-10-29 10:16:30 +0530293{
Luis R. Rodriguezb002a4a2009-09-13 00:03:27 -0700294 struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
Sujithf1dc5602008-10-29 10:16:30 +0530295
Sujith2660b812009-02-09 13:27:26 +0530296 switch (calType & ah->supp_cals) {
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800297 case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
298 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530299 case ADC_GAIN_CAL:
300 case ADC_DC_CAL:
Sujitha451aa62009-04-13 21:56:43 +0530301 if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
302 conf_is_ht20(conf)))
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800303 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530304 break;
305 }
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800306 return false;
Sujithf1dc5602008-10-29 10:16:30 +0530307}
308
Sujithcbe61d82009-02-09 13:27:12 +0530309static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530310{
Sujithf1dc5602008-10-29 10:16:30 +0530311 int i;
312
313 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
Sujith2660b812009-02-09 13:27:26 +0530314 ah->totalPowerMeasI[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530315 REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
Sujith2660b812009-02-09 13:27:26 +0530316 ah->totalPowerMeasQ[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530317 REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
Sujith2660b812009-02-09 13:27:26 +0530318 ah->totalIqCorrMeas[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530319 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700320 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
321 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
322 ah->cal_samples, i, ah->totalPowerMeasI[i],
323 ah->totalPowerMeasQ[i],
324 ah->totalIqCorrMeas[i]);
Sujithf1dc5602008-10-29 10:16:30 +0530325 }
326}
327
Sujithcbe61d82009-02-09 13:27:12 +0530328static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530329{
Sujithf1dc5602008-10-29 10:16:30 +0530330 int i;
331
332 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
Sujith2660b812009-02-09 13:27:26 +0530333 ah->totalAdcIOddPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530334 REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
Sujith2660b812009-02-09 13:27:26 +0530335 ah->totalAdcIEvenPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530336 REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
Sujith2660b812009-02-09 13:27:26 +0530337 ah->totalAdcQOddPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530338 REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
Sujith2660b812009-02-09 13:27:26 +0530339 ah->totalAdcQEvenPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530340 REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
341
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700342 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
343 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
344 "oddq=0x%08x; evenq=0x%08x;\n",
345 ah->cal_samples, i,
346 ah->totalAdcIOddPhase[i],
347 ah->totalAdcIEvenPhase[i],
348 ah->totalAdcQOddPhase[i],
349 ah->totalAdcQEvenPhase[i]);
Sujithf1dc5602008-10-29 10:16:30 +0530350 }
351}
352
Sujithcbe61d82009-02-09 13:27:12 +0530353static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530354{
Sujithf1dc5602008-10-29 10:16:30 +0530355 int i;
356
357 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
Sujith2660b812009-02-09 13:27:26 +0530358 ah->totalAdcDcOffsetIOddPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530359 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
Sujith2660b812009-02-09 13:27:26 +0530360 ah->totalAdcDcOffsetIEvenPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530361 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
Sujith2660b812009-02-09 13:27:26 +0530362 ah->totalAdcDcOffsetQOddPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530363 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
Sujith2660b812009-02-09 13:27:26 +0530364 ah->totalAdcDcOffsetQEvenPhase[i] +=
Sujithf1dc5602008-10-29 10:16:30 +0530365 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
366
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700367 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
368 "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
369 "oddq=0x%08x; evenq=0x%08x;\n",
370 ah->cal_samples, i,
371 ah->totalAdcDcOffsetIOddPhase[i],
372 ah->totalAdcDcOffsetIEvenPhase[i],
373 ah->totalAdcDcOffsetQOddPhase[i],
374 ah->totalAdcDcOffsetQEvenPhase[i]);
Sujithf1dc5602008-10-29 10:16:30 +0530375 }
376}
377
Sujithcbe61d82009-02-09 13:27:12 +0530378static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
Sujithf1dc5602008-10-29 10:16:30 +0530379{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700380 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530381 u32 powerMeasQ, powerMeasI, iqCorrMeas;
382 u32 qCoffDenom, iCoffDenom;
383 int32_t qCoff, iCoff;
384 int iqCorrNeg, i;
385
386 for (i = 0; i < numChains; i++) {
Sujith2660b812009-02-09 13:27:26 +0530387 powerMeasI = ah->totalPowerMeasI[i];
388 powerMeasQ = ah->totalPowerMeasQ[i];
389 iqCorrMeas = ah->totalIqCorrMeas[i];
Sujithf1dc5602008-10-29 10:16:30 +0530390
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700391 ath_print(common, ATH_DBG_CALIBRATE,
392 "Starting IQ Cal and Correction for Chain %d\n",
393 i);
Sujithf1dc5602008-10-29 10:16:30 +0530394
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700395 ath_print(common, ATH_DBG_CALIBRATE,
396 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
397 i, ah->totalIqCorrMeas[i]);
Sujithf1dc5602008-10-29 10:16:30 +0530398
399 iqCorrNeg = 0;
400
401 if (iqCorrMeas > 0x80000000) {
402 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
403 iqCorrNeg = 1;
404 }
405
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700406 ath_print(common, ATH_DBG_CALIBRATE,
407 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
408 ath_print(common, ATH_DBG_CALIBRATE,
409 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
410 ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
411 iqCorrNeg);
Sujithf1dc5602008-10-29 10:16:30 +0530412
413 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
414 qCoffDenom = powerMeasQ / 64;
415
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530416 if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
417 (qCoffDenom != 0)) {
Sujithf1dc5602008-10-29 10:16:30 +0530418 iCoff = iqCorrMeas / iCoffDenom;
419 qCoff = powerMeasI / qCoffDenom - 64;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700420 ath_print(common, ATH_DBG_CALIBRATE,
421 "Chn %d iCoff = 0x%08x\n", i, iCoff);
422 ath_print(common, ATH_DBG_CALIBRATE,
423 "Chn %d qCoff = 0x%08x\n", i, qCoff);
Sujithf1dc5602008-10-29 10:16:30 +0530424
425 iCoff = iCoff & 0x3f;
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700426 ath_print(common, ATH_DBG_CALIBRATE,
427 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
Sujithf1dc5602008-10-29 10:16:30 +0530428 if (iqCorrNeg == 0x0)
429 iCoff = 0x40 - iCoff;
430
431 if (qCoff > 15)
432 qCoff = 15;
433 else if (qCoff <= -16)
434 qCoff = 16;
435
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700436 ath_print(common, ATH_DBG_CALIBRATE,
437 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
438 i, iCoff, qCoff);
Sujithf1dc5602008-10-29 10:16:30 +0530439
440 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
441 AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
442 iCoff);
443 REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
444 AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
445 qCoff);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700446 ath_print(common, ATH_DBG_CALIBRATE,
447 "IQ Cal and Correction done for Chain %d\n",
448 i);
Sujithf1dc5602008-10-29 10:16:30 +0530449 }
450 }
451
452 REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
453 AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
454}
455
Sujithcbe61d82009-02-09 13:27:12 +0530456static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
Sujithf1dc5602008-10-29 10:16:30 +0530457{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700458 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530459 u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
460 u32 qGainMismatch, iGainMismatch, val, i;
461
462 for (i = 0; i < numChains; i++) {
Sujith2660b812009-02-09 13:27:26 +0530463 iOddMeasOffset = ah->totalAdcIOddPhase[i];
464 iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
465 qOddMeasOffset = ah->totalAdcQOddPhase[i];
466 qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
Sujithf1dc5602008-10-29 10:16:30 +0530467
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700468 ath_print(common, ATH_DBG_CALIBRATE,
469 "Starting ADC Gain Cal for Chain %d\n", i);
Sujithf1dc5602008-10-29 10:16:30 +0530470
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700471 ath_print(common, ATH_DBG_CALIBRATE,
472 "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
473 iOddMeasOffset);
474 ath_print(common, ATH_DBG_CALIBRATE,
475 "Chn %d pwr_meas_even_i = 0x%08x\n", i,
476 iEvenMeasOffset);
477 ath_print(common, ATH_DBG_CALIBRATE,
478 "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
479 qOddMeasOffset);
480 ath_print(common, ATH_DBG_CALIBRATE,
481 "Chn %d pwr_meas_even_q = 0x%08x\n", i,
482 qEvenMeasOffset);
Sujithf1dc5602008-10-29 10:16:30 +0530483
484 if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
485 iGainMismatch =
486 ((iEvenMeasOffset * 32) /
487 iOddMeasOffset) & 0x3f;
488 qGainMismatch =
489 ((qOddMeasOffset * 32) /
490 qEvenMeasOffset) & 0x3f;
491
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700492 ath_print(common, ATH_DBG_CALIBRATE,
493 "Chn %d gain_mismatch_i = 0x%08x\n", i,
494 iGainMismatch);
495 ath_print(common, ATH_DBG_CALIBRATE,
496 "Chn %d gain_mismatch_q = 0x%08x\n", i,
497 qGainMismatch);
Sujithf1dc5602008-10-29 10:16:30 +0530498
499 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
500 val &= 0xfffff000;
501 val |= (qGainMismatch) | (iGainMismatch << 6);
502 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
503
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700504 ath_print(common, ATH_DBG_CALIBRATE,
505 "ADC Gain Cal done for Chain %d\n", i);
Sujithf1dc5602008-10-29 10:16:30 +0530506 }
507 }
508
509 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
510 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
511 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
512}
513
Sujithcbe61d82009-02-09 13:27:12 +0530514static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
Sujithf1dc5602008-10-29 10:16:30 +0530515{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700516 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530517 u32 iOddMeasOffset, iEvenMeasOffset, val, i;
518 int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
Sujithcbfe9462009-04-13 21:56:56 +0530519 const struct ath9k_percal_data *calData =
Sujith2660b812009-02-09 13:27:26 +0530520 ah->cal_list_curr->calData;
Sujithf1dc5602008-10-29 10:16:30 +0530521 u32 numSamples =
522 (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
523
524 for (i = 0; i < numChains; i++) {
Sujith2660b812009-02-09 13:27:26 +0530525 iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
526 iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
527 qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
528 qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
Sujithf1dc5602008-10-29 10:16:30 +0530529
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700530 ath_print(common, ATH_DBG_CALIBRATE,
531 "Starting ADC DC Offset Cal for Chain %d\n", i);
Sujithf1dc5602008-10-29 10:16:30 +0530532
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700533 ath_print(common, ATH_DBG_CALIBRATE,
534 "Chn %d pwr_meas_odd_i = %d\n", i,
535 iOddMeasOffset);
536 ath_print(common, ATH_DBG_CALIBRATE,
537 "Chn %d pwr_meas_even_i = %d\n", i,
538 iEvenMeasOffset);
539 ath_print(common, ATH_DBG_CALIBRATE,
540 "Chn %d pwr_meas_odd_q = %d\n", i,
541 qOddMeasOffset);
542 ath_print(common, ATH_DBG_CALIBRATE,
543 "Chn %d pwr_meas_even_q = %d\n", i,
544 qEvenMeasOffset);
Sujithf1dc5602008-10-29 10:16:30 +0530545
546 iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
547 numSamples) & 0x1ff;
548 qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
549 numSamples) & 0x1ff;
550
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700551 ath_print(common, ATH_DBG_CALIBRATE,
552 "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
553 iDcMismatch);
554 ath_print(common, ATH_DBG_CALIBRATE,
555 "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
556 qDcMismatch);
Sujithf1dc5602008-10-29 10:16:30 +0530557
558 val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
559 val &= 0xc0000fff;
560 val |= (qDcMismatch << 12) | (iDcMismatch << 21);
561 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
562
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700563 ath_print(common, ATH_DBG_CALIBRATE,
564 "ADC DC Offset Cal done for Chain %d\n", i);
Sujithf1dc5602008-10-29 10:16:30 +0530565 }
566
567 REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
568 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
569 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
570}
571
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800572/* This is done for the currently configured channel */
Sujithcbe61d82009-02-09 13:27:12 +0530573bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530574{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700575 struct ath_common *common = ath9k_hw_common(ah);
576 struct ieee80211_conf *conf = &common->hw->conf;
Sujithcbfe9462009-04-13 21:56:56 +0530577 struct ath9k_cal_list *currCal = ah->cal_list_curr;
Sujithf1dc5602008-10-29 10:16:30 +0530578
Sujith2660b812009-02-09 13:27:26 +0530579 if (!ah->curchan)
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800580 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530581
582 if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah))
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800583 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530584
585 if (currCal == NULL)
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800586 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530587
588 if (currCal->calState != CAL_DONE) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700589 ath_print(common, ATH_DBG_CALIBRATE,
590 "Calibration state incorrect, %d\n",
591 currCal->calState);
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800592 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530593 }
594
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800595 if (!ath9k_hw_iscal_supported(ah, currCal->calData->calType))
596 return true;
Sujithf1dc5602008-10-29 10:16:30 +0530597
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700598 ath_print(common, ATH_DBG_CALIBRATE,
599 "Resetting Cal %d state for channel %u\n",
600 currCal->calData->calType, conf->channel->center_freq);
Sujithf1dc5602008-10-29 10:16:30 +0530601
Sujith2660b812009-02-09 13:27:26 +0530602 ah->curchan->CalValid &= ~currCal->calData->calType;
Sujithf1dc5602008-10-29 10:16:30 +0530603 currCal->calState = CAL_WAITING;
604
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -0800605 return false;
Sujithf1dc5602008-10-29 10:16:30 +0530606}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400607EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
Sujithf1dc5602008-10-29 10:16:30 +0530608
Sujithcbe61d82009-02-09 13:27:12 +0530609void ath9k_hw_start_nfcal(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530610{
611 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
612 AR_PHY_AGC_CONTROL_ENABLE_NF);
613 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
614 AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
615 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
616}
617
Sujithcbe61d82009-02-09 13:27:12 +0530618void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
Sujithf1dc5602008-10-29 10:16:30 +0530619{
620 struct ath9k_nfcal_hist *h;
621 int i, j;
622 int32_t val;
623 const u32 ar5416_cca_regs[6] = {
624 AR_PHY_CCA,
625 AR_PHY_CH1_CCA,
626 AR_PHY_CH2_CCA,
627 AR_PHY_EXT_CCA,
628 AR_PHY_CH1_EXT_CCA,
629 AR_PHY_CH2_EXT_CCA
630 };
Senthil Balasubramaniance143bb2009-09-17 09:27:33 +0530631 u8 chainmask, rx_chain_status;
Sujithf1dc5602008-10-29 10:16:30 +0530632
Senthil Balasubramaniance143bb2009-09-17 09:27:33 +0530633 rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
Sujith6398dc02010-03-17 14:25:19 +0530634 if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
Sujith5dad40c2009-01-23 11:20:55 +0530635 chainmask = 0x9;
Senthil Balasubramaniance143bb2009-09-17 09:27:33 +0530636 else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
637 if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
638 chainmask = 0x1B;
639 else
640 chainmask = 0x09;
641 } else {
642 if (rx_chain_status & 0x4)
643 chainmask = 0x3F;
644 else if (rx_chain_status & 0x2)
645 chainmask = 0x1B;
646 else
647 chainmask = 0x09;
648 }
Sujithf1dc5602008-10-29 10:16:30 +0530649
Sujithf1dc5602008-10-29 10:16:30 +0530650 h = ah->nfCalHist;
Sujithf1dc5602008-10-29 10:16:30 +0530651
652 for (i = 0; i < NUM_NF_READINGS; i++) {
653 if (chainmask & (1 << i)) {
654 val = REG_READ(ah, ar5416_cca_regs[i]);
655 val &= 0xFFFFFE00;
656 val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
657 REG_WRITE(ah, ar5416_cca_regs[i], val);
658 }
659 }
660
661 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
662 AR_PHY_AGC_CONTROL_ENABLE_NF);
663 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
664 AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
665 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
666
Senthil Balasubramanian63a75b92009-09-18 15:07:03 +0530667 for (j = 0; j < 5; j++) {
Sujithf1dc5602008-10-29 10:16:30 +0530668 if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
669 AR_PHY_AGC_CONTROL_NF) == 0)
670 break;
Senthil Balasubramanian63a75b92009-09-18 15:07:03 +0530671 udelay(50);
Sujithf1dc5602008-10-29 10:16:30 +0530672 }
673
674 for (i = 0; i < NUM_NF_READINGS; i++) {
675 if (chainmask & (1 << i)) {
676 val = REG_READ(ah, ar5416_cca_regs[i]);
677 val &= 0xFFFFFE00;
678 val |= (((u32) (-50) << 1) & 0x1ff);
679 REG_WRITE(ah, ar5416_cca_regs[i], val);
680 }
681 }
682}
683
Sujithcbe61d82009-02-09 13:27:12 +0530684int16_t ath9k_hw_getnf(struct ath_hw *ah,
Sujithf1dc5602008-10-29 10:16:30 +0530685 struct ath9k_channel *chan)
686{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700687 struct ath_common *common = ath9k_hw_common(ah);
Sujithf1dc5602008-10-29 10:16:30 +0530688 int16_t nf, nfThresh;
689 int16_t nfarray[NUM_NF_READINGS] = { 0 };
690 struct ath9k_nfcal_hist *h;
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800691 struct ieee80211_channel *c = chan->chan;
Sujithf1dc5602008-10-29 10:16:30 +0530692
693 chan->channelFlags &= (~CHANNEL_CW_INT);
694 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700695 ath_print(common, ATH_DBG_CALIBRATE,
696 "NF did not complete in calibration window\n");
Sujithf1dc5602008-10-29 10:16:30 +0530697 nf = 0;
698 chan->rawNoiseFloor = nf;
699 return chan->rawNoiseFloor;
700 } else {
701 ath9k_hw_do_getnf(ah, nfarray);
702 nf = nfarray[0];
Luis R. Rodriguez76061ab2008-12-23 15:58:41 -0800703 if (getNoiseFloorThresh(ah, c->band, &nfThresh)
Sujithf1dc5602008-10-29 10:16:30 +0530704 && nf > nfThresh) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700705 ath_print(common, ATH_DBG_CALIBRATE,
706 "noise floor failed detected; "
707 "detected %d, threshold %d\n",
708 nf, nfThresh);
Sujithf1dc5602008-10-29 10:16:30 +0530709 chan->channelFlags |= CHANNEL_CW_INT;
710 }
711 }
712
Sujithf1dc5602008-10-29 10:16:30 +0530713 h = ah->nfCalHist;
Sujithf1dc5602008-10-29 10:16:30 +0530714
715 ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
716 chan->rawNoiseFloor = h[0].privNF;
717
718 return chan->rawNoiseFloor;
719}
720
Sujithcbe61d82009-02-09 13:27:12 +0530721void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
Sujithf1dc5602008-10-29 10:16:30 +0530722{
723 int i, j;
Senthil Balasubramaniana59b5a52009-07-14 20:17:07 -0400724 s16 noise_floor;
725
726 if (AR_SREV_9280(ah))
727 noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
Sujith6398dc02010-03-17 14:25:19 +0530728 else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
Senthil Balasubramaniana59b5a52009-07-14 20:17:07 -0400729 noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
Vivek Natarajan6170cd52009-09-17 09:24:24 +0530730 else if (AR_SREV_9287(ah))
731 noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
Senthil Balasubramaniana59b5a52009-07-14 20:17:07 -0400732 else
733 noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
Sujithf1dc5602008-10-29 10:16:30 +0530734
735 for (i = 0; i < NUM_NF_READINGS; i++) {
736 ah->nfCalHist[i].currIndex = 0;
Senthil Balasubramaniana59b5a52009-07-14 20:17:07 -0400737 ah->nfCalHist[i].privNF = noise_floor;
Sujithf1dc5602008-10-29 10:16:30 +0530738 ah->nfCalHist[i].invalidNFcount =
739 AR_PHY_CCA_FILTERWINDOW_LENGTH;
740 for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
Senthil Balasubramaniana59b5a52009-07-14 20:17:07 -0400741 ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
Sujithf1dc5602008-10-29 10:16:30 +0530742 }
743 }
Sujithf1dc5602008-10-29 10:16:30 +0530744}
745
Sujithcbe61d82009-02-09 13:27:12 +0530746s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
Sujithf1dc5602008-10-29 10:16:30 +0530747{
Sujithf1dc5602008-10-29 10:16:30 +0530748 s16 nf;
749
Luis R. Rodriguez5f8e0772009-01-22 15:16:48 -0800750 if (chan->rawNoiseFloor == 0)
Luis R. Rodrigueze56db712008-12-23 15:58:47 -0800751 nf = -96;
752 else
Luis R. Rodriguez5f8e0772009-01-22 15:16:48 -0800753 nf = chan->rawNoiseFloor;
Sujithf1dc5602008-10-29 10:16:30 +0530754
755 if (!ath9k_hw_nf_in_range(ah, nf))
756 nf = ATH_DEFAULT_NOISE_FLOOR;
757
758 return nf;
759}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -0400760EXPORT_SYMBOL(ath9k_hw_getchan_noise);
Sujithf1dc5602008-10-29 10:16:30 +0530761
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530762static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530763{
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530764 u32 rddata;
765 int32_t delta, currPDADC, slope;
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530766
767 rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530768 currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
769
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530770 if (ah->initPDADC == 0 || currPDADC == 0) {
771 /*
772 * Zero value indicates that no frames have been transmitted yet,
773 * can't do temperature compensation until frames are transmitted.
774 */
775 return;
776 } else {
777 slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
778
779 if (slope == 0) { /* to avoid divide by zero case */
780 delta = 0;
781 } else {
782 delta = ((currPDADC - ah->initPDADC)*4) / slope;
783 }
784 REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
785 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
786 REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
787 AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
788 }
789}
790
791static void ath9k_olc_temp_compensation(struct ath_hw *ah)
792{
793 u32 rddata, i;
794 int delta, currPDADC, regval;
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530795
Vivek Natarajandb91f2e2009-08-14 11:27:16 +0530796 if (OLC_FOR_AR9287_10_LATER) {
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530797 ath9k_olc_temp_compensation_9287(ah);
798 } else {
799 rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
800 currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
801
Vivek Natarajandb91f2e2009-08-14 11:27:16 +0530802 if (ah->initPDADC == 0 || currPDADC == 0) {
803 return;
804 } else {
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530805 if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
806 delta = (currPDADC - ah->initPDADC + 4) / 8;
Vivek Natarajandb91f2e2009-08-14 11:27:16 +0530807 else
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530808 delta = (currPDADC - ah->initPDADC + 5) / 10;
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530809
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530810 if (delta != ah->PDADCdelta) {
811 ah->PDADCdelta = delta;
812 for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
813 regval = ah->originalGain[i] - delta;
814 if (regval < 0)
815 regval = 0;
Vivek Natarajandb91f2e2009-08-14 11:27:16 +0530816
Vivek Natarajan0b98eaa2009-09-18 15:03:42 +0530817 REG_RMW_FIELD(ah,
818 AR_PHY_TX_GAIN_TBL1 + i * 4,
819 AR_PHY_TX_GAIN, regval);
820 }
Vivek Natarajandb91f2e2009-08-14 11:27:16 +0530821 }
Senthil Balasubramanian8bd1d072009-02-12 13:57:03 +0530822 }
823 }
824}
825
Luis R. Rodriguez62268112009-10-07 16:22:19 -0400826static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -0400827{
828 u32 regVal;
829 unsigned int i;
830 u32 regList [][2] = {
831 { 0x786c, 0 },
832 { 0x7854, 0 },
833 { 0x7820, 0 },
834 { 0x7824, 0 },
835 { 0x7868, 0 },
836 { 0x783c, 0 },
837 { 0x7838, 0 } ,
838 { 0x7828, 0 } ,
839 };
840
841 for (i = 0; i < ARRAY_SIZE(regList); i++)
842 regList[i][1] = REG_READ(ah, regList[i][0]);
843
844 regVal = REG_READ(ah, 0x7834);
845 regVal &= (~(0x1));
846 REG_WRITE(ah, 0x7834, regVal);
847 regVal = REG_READ(ah, 0x9808);
848 regVal |= (0x1 << 27);
849 REG_WRITE(ah, 0x9808, regVal);
850
851 /* 786c,b23,1, pwddac=1 */
852 REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
853 /* 7854, b5,1, pdrxtxbb=1 */
854 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
855 /* 7854, b7,1, pdv2i=1 */
856 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
857 /* 7854, b8,1, pddacinterface=1 */
858 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
859 /* 7824,b12,0, offcal=0 */
860 REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
861 /* 7838, b1,0, pwddb=0 */
862 REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
863 /* 7820,b11,0, enpacal=0 */
864 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
865 /* 7820,b25,1, pdpadrv1=0 */
866 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
867 /* 7820,b24,0, pdpadrv2=0 */
868 REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0);
869 /* 7820,b23,0, pdpaout=0 */
870 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
871 /* 783c,b14-16,7, padrvgn2tab_0=7 */
872 REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
873 /*
874 * 7838,b29-31,0, padrvgn1tab_0=0
875 * does not matter since we turn it off
876 */
877 REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
878
879 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
880
881 /* Set:
882 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
883 * txon=1,paon=1,oscon=1,synthon_force=1
884 */
885 REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
886 udelay(30);
887 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
888
889 /* find off_6_1; */
Luis R. Rodriguez1d9c1852009-10-27 12:59:37 -0400890 for (i = 6; i > 0; i--) {
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -0400891 regVal = REG_READ(ah, 0x7834);
892 regVal |= (1 << (20 + i));
893 REG_WRITE(ah, 0x7834, regVal);
894 udelay(1);
895 //regVal = REG_READ(ah, 0x7834);
896 regVal &= (~(0x1 << (20 + i)));
897 regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
898 << (20 + i));
899 REG_WRITE(ah, 0x7834, regVal);
900 }
901
Luis R. Rodriguez62268112009-10-07 16:22:19 -0400902 regVal = (regVal >>20) & 0x7f;
903
904 /* Update PA cal info */
905 if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
906 if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
907 ah->pacal_info.max_skipcount =
908 2 * ah->pacal_info.max_skipcount;
909 ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
910 } else {
911 ah->pacal_info.max_skipcount = 1;
912 ah->pacal_info.skipcount = 0;
913 ah->pacal_info.prev_offset = regVal;
914 }
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -0400915
916 regVal = REG_READ(ah, 0x7834);
917 regVal |= 0x1;
918 REG_WRITE(ah, 0x7834, regVal);
919 regVal = REG_READ(ah, 0x9808);
920 regVal &= (~(0x1 << 27));
921 REG_WRITE(ah, 0x9808, regVal);
922
923 for (i = 0; i < ARRAY_SIZE(regList); i++)
924 REG_WRITE(ah, regList[i][0], regList[i][1]);
925}
926
Sujitha13883b2009-08-26 08:39:40 +0530927static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530928{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700929 struct ath_common *common = ath9k_hw_common(ah);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530930 u32 regVal;
931 int i, offset, offs_6_1, offs_0;
932 u32 ccomp_org, reg_field;
933 u32 regList[][2] = {
934 { 0x786c, 0 },
935 { 0x7854, 0 },
936 { 0x7820, 0 },
937 { 0x7824, 0 },
938 { 0x7868, 0 },
939 { 0x783c, 0 },
940 { 0x7838, 0 },
941 };
942
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -0700943 ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
Sujitha13883b2009-08-26 08:39:40 +0530944
Sujith20caf0d2009-08-26 08:39:52 +0530945 /* PA CAL is not needed for high power solution */
946 if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
947 AR5416_EEP_TXGAIN_HIGH_POWER)
948 return;
949
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530950 if (AR_SREV_9285_11(ah)) {
951 REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
952 udelay(10);
953 }
954
955 for (i = 0; i < ARRAY_SIZE(regList); i++)
956 regList[i][1] = REG_READ(ah, regList[i][0]);
957
958 regVal = REG_READ(ah, 0x7834);
959 regVal &= (~(0x1));
960 REG_WRITE(ah, 0x7834, regVal);
961 regVal = REG_READ(ah, 0x9808);
962 regVal |= (0x1 << 27);
963 REG_WRITE(ah, 0x9808, regVal);
964
965 REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
966 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
967 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
968 REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
969 REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
970 REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
971 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
Sujith0abb0962009-08-26 08:39:50 +0530972 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530973 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
974 REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
975 REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
976 REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
977 ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
Sujith0abb0962009-08-26 08:39:50 +0530978 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530979
980 REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
981 udelay(30);
982 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
983 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
984
985 for (i = 6; i > 0; i--) {
986 regVal = REG_READ(ah, 0x7834);
987 regVal |= (1 << (19 + i));
988 REG_WRITE(ah, 0x7834, regVal);
989 udelay(1);
Sujithedbf51f2009-09-17 09:28:41 +0530990 regVal = REG_READ(ah, 0x7834);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +0530991 regVal &= (~(0x1 << (19 + i)));
992 reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
993 regVal |= (reg_field << (19 + i));
994 REG_WRITE(ah, 0x7834, regVal);
995 }
996
997 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
998 udelay(1);
999 reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
1000 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
1001 offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
1002 offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
1003
1004 offset = (offs_6_1<<1) | offs_0;
1005 offset = offset - 0;
1006 offs_6_1 = offset>>1;
1007 offs_0 = offset & 1;
1008
Sujitha13883b2009-08-26 08:39:40 +05301009 if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
1010 if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
1011 ah->pacal_info.max_skipcount =
1012 2 * ah->pacal_info.max_skipcount;
1013 ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
1014 } else {
1015 ah->pacal_info.max_skipcount = 1;
1016 ah->pacal_info.skipcount = 0;
1017 ah->pacal_info.prev_offset = offset;
1018 }
1019
Senthil Balasubramaniane7594072008-12-08 19:43:48 +05301020 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
1021 REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
1022
1023 regVal = REG_READ(ah, 0x7834);
1024 regVal |= 0x1;
1025 REG_WRITE(ah, 0x7834, regVal);
1026 regVal = REG_READ(ah, 0x9808);
1027 regVal &= (~(0x1 << 27));
1028 REG_WRITE(ah, 0x9808, regVal);
1029
1030 for (i = 0; i < ARRAY_SIZE(regList); i++)
1031 REG_WRITE(ah, regList[i][0], regList[i][1]);
1032
1033 REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
1034
1035 if (AR_SREV_9285_11(ah))
1036 REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
1037
1038}
1039
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301040bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
Sujith379f0442009-04-13 21:56:48 +05301041 u8 rxchainmask, bool longcal)
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301042{
Sujith379f0442009-04-13 21:56:48 +05301043 bool iscaldone = true;
Sujithcbfe9462009-04-13 21:56:56 +05301044 struct ath9k_cal_list *currCal = ah->cal_list_curr;
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301045
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301046 if (currCal &&
1047 (currCal->calState == CAL_RUNNING ||
1048 currCal->calState == CAL_WAITING)) {
Sujith379f0442009-04-13 21:56:48 +05301049 iscaldone = ath9k_hw_per_calibration(ah, chan,
1050 rxchainmask, currCal);
1051 if (iscaldone) {
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301052 ah->cal_list_curr = currCal = currCal->calNext;
1053
1054 if (currCal->calState == CAL_WAITING) {
Sujith379f0442009-04-13 21:56:48 +05301055 iscaldone = false;
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301056 ath9k_hw_reset_calibration(ah, currCal);
1057 }
1058 }
1059 }
1060
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -04001061 /* Do NF cal only at longer intervals */
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301062 if (longcal) {
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -04001063 /* Do periodic PAOffset Cal */
Sujith02afa2a2010-03-17 14:25:21 +05301064 if (AR_SREV_9271(ah)) {
1065 if (!ah->pacal_info.skipcount)
1066 ath9k_hw_9271_pa_cal(ah, false);
1067 else
1068 ah->pacal_info.skipcount--;
1069 } else if (AR_SREV_9285_11_OR_LATER(ah)) {
Sujitha13883b2009-08-26 08:39:40 +05301070 if (!ah->pacal_info.skipcount)
1071 ath9k_hw_9285_pa_cal(ah, false);
1072 else
1073 ah->pacal_info.skipcount--;
1074 }
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301075
Vivek Natarajanac88b6e2009-07-23 10:59:57 +05301076 if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301077 ath9k_olc_temp_compensation(ah);
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -04001078
1079 /* Get the value from the previous NF cal and update history buffer */
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301080 ath9k_hw_getnf(ah, chan);
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -04001081
1082 /*
1083 * Load the NF from history buffer of the current channel.
1084 * NF is slow time-variant, so it is OK to use a historical value.
1085 */
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301086 ath9k_hw_loadnf(ah, ah->curchan);
Luis R. Rodriguezd7e7d222009-08-03 23:14:12 -04001087
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301088 ath9k_hw_start_nfcal(ah);
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301089 }
1090
Sujith379f0442009-04-13 21:56:48 +05301091 return iscaldone;
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301092}
Luis R. Rodriguez7322fd12009-09-23 23:07:00 -04001093EXPORT_SYMBOL(ath9k_hw_calibrate);
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301094
Luis R. Rodriguezb57df122009-10-07 16:22:18 -04001095/* Carrier leakage Calibration fix */
Vivek Natarajan53bc7aa2010-04-05 14:48:04 +05301096static bool ar9285_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301097{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001098 struct ath_common *common = ath9k_hw_common(ah);
1099
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301100 REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
Sujithdb2f63f2009-04-13 21:56:41 +05301101 if (IS_CHAN_HT20(chan)) {
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301102 REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
1103 REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
1104 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
1105 AR_PHY_AGC_CONTROL_FLTR_CAL);
1106 REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
1107 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
1108 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
1109 AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001110 ath_print(common, ATH_DBG_CALIBRATE, "offset "
1111 "calibration failed to complete in "
1112 "1ms; noisy ??\n");
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301113 return false;
1114 }
1115 REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
1116 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
1117 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
1118 }
1119 REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
1120 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
1121 REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
1122 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
1123 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
1124 0, AH_WAIT_TIMEOUT)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001125 ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
1126 "failed to complete in 1ms; noisy ??\n");
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301127 return false;
1128 }
1129
1130 REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
1131 REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
1132 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
1133
1134 return true;
1135}
1136
Vivek Natarajan53bc7aa2010-04-05 14:48:04 +05301137static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
1138{
1139 int i;
1140 u_int32_t txgain_max;
1141 u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
1142 u_int32_t reg_clc_I0, reg_clc_Q0;
1143 u_int32_t i0_num = 0;
1144 u_int32_t q0_num = 0;
1145 u_int32_t total_num = 0;
1146 u_int32_t reg_rf2g5_org;
1147 bool retv = true;
1148
1149 if (!(ar9285_cl_cal(ah, chan)))
1150 return false;
1151
1152 txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
1153 AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
1154
1155 for (i = 0; i < (txgain_max+1); i++) {
1156 clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
1157 AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
1158 if (!(gain_mask & (1 << clc_gain))) {
1159 gain_mask |= (1 << clc_gain);
1160 clc_num++;
1161 }
1162 }
1163
1164 for (i = 0; i < clc_num; i++) {
1165 reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
1166 & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
1167 reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
1168 & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
1169 if (reg_clc_I0 == 0)
1170 i0_num++;
1171
1172 if (reg_clc_Q0 == 0)
1173 q0_num++;
1174 }
1175 total_num = i0_num + q0_num;
1176 if (total_num > AR9285_CLCAL_REDO_THRESH) {
1177 reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
1178 if (AR_SREV_9285E_20(ah)) {
1179 REG_WRITE(ah, AR9285_RF2G5,
1180 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
1181 AR9285_RF2G5_IC50TX_XE_SET);
1182 } else {
1183 REG_WRITE(ah, AR9285_RF2G5,
1184 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
1185 AR9285_RF2G5_IC50TX_SET);
1186 }
1187 retv = ar9285_cl_cal(ah, chan);
1188 REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
1189 }
1190 return retv;
1191}
1192
Sujith04d19dd2009-04-13 21:56:59 +05301193bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
Sujithf1dc5602008-10-29 10:16:30 +05301194{
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001195 struct ath_common *common = ath9k_hw_common(ah);
1196
Luis R. Rodriguezb57df122009-10-07 16:22:18 -04001197 if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
Senthil Balasubramanian4e845162009-03-06 11:24:10 +05301198 if (!ar9285_clc(ah, chan))
1199 return false;
Sujith04d19dd2009-04-13 21:56:59 +05301200 } else {
1201 if (AR_SREV_9280_10_OR_LATER(ah)) {
Vivek Natarajanac88b6e2009-07-23 10:59:57 +05301202 if (!AR_SREV_9287_10_OR_LATER(ah))
1203 REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
1204 AR_PHY_ADC_CTL_OFF_PWDADC);
1205 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
1206 AR_PHY_AGC_CONTROL_FLTR_CAL);
Sujith04d19dd2009-04-13 21:56:59 +05301207 }
Sujithedf7c062009-02-12 10:06:49 +05301208
Sujith04d19dd2009-04-13 21:56:59 +05301209 /* Calibrate the AGC */
Sujithedf7c062009-02-12 10:06:49 +05301210 REG_WRITE(ah, AR_PHY_AGC_CONTROL,
Sujith04d19dd2009-04-13 21:56:59 +05301211 REG_READ(ah, AR_PHY_AGC_CONTROL) |
1212 AR_PHY_AGC_CONTROL_CAL);
Sujithedf7c062009-02-12 10:06:49 +05301213
Sujith04d19dd2009-04-13 21:56:59 +05301214 /* Poll for offset calibration complete */
1215 if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
1216 0, AH_WAIT_TIMEOUT)) {
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001217 ath_print(common, ATH_DBG_CALIBRATE,
1218 "offset calibration failed to "
1219 "complete in 1ms; noisy environment?\n");
Sujithedf7c062009-02-12 10:06:49 +05301220 return false;
1221 }
1222
Sujith04d19dd2009-04-13 21:56:59 +05301223 if (AR_SREV_9280_10_OR_LATER(ah)) {
Vivek Natarajanac88b6e2009-07-23 10:59:57 +05301224 if (!AR_SREV_9287_10_OR_LATER(ah))
1225 REG_SET_BIT(ah, AR_PHY_ADC_CTL,
1226 AR_PHY_ADC_CTL_OFF_PWDADC);
1227 REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
1228 AR_PHY_AGC_CONTROL_FLTR_CAL);
Sujith04d19dd2009-04-13 21:56:59 +05301229 }
Sujithedf7c062009-02-12 10:06:49 +05301230 }
1231
1232 /* Do PA Calibration */
Luis R. Rodriguez62268112009-10-07 16:22:19 -04001233 if (AR_SREV_9271(ah))
1234 ath9k_hw_9271_pa_cal(ah, true);
1235 else if (AR_SREV_9285_11_OR_LATER(ah))
Sujitha13883b2009-08-26 08:39:40 +05301236 ath9k_hw_9285_pa_cal(ah, true);
Senthil Balasubramaniane7594072008-12-08 19:43:48 +05301237
Sujith04d19dd2009-04-13 21:56:59 +05301238 /* Do NF Calibration after DC offset and other calibrations */
Sujithf1dc5602008-10-29 10:16:30 +05301239 REG_WRITE(ah, AR_PHY_AGC_CONTROL,
Sujith04d19dd2009-04-13 21:56:59 +05301240 REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
Sujithf1dc5602008-10-29 10:16:30 +05301241
Sujith2660b812009-02-09 13:27:26 +05301242 ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
Sujithf1dc5602008-10-29 10:16:30 +05301243
Sujith04d19dd2009-04-13 21:56:59 +05301244 /* Enable IQ, ADC Gain and ADC DC offset CALs */
Sujithf1dc5602008-10-29 10:16:30 +05301245 if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -08001246 if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
Sujith2660b812009-02-09 13:27:26 +05301247 INIT_CAL(&ah->adcgain_caldata);
1248 INSERT_CAL(ah, &ah->adcgain_caldata);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001249 ath_print(common, ATH_DBG_CALIBRATE,
1250 "enabling ADC Gain Calibration.\n");
Sujithf1dc5602008-10-29 10:16:30 +05301251 }
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -08001252 if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
Sujith2660b812009-02-09 13:27:26 +05301253 INIT_CAL(&ah->adcdc_caldata);
1254 INSERT_CAL(ah, &ah->adcdc_caldata);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001255 ath_print(common, ATH_DBG_CALIBRATE,
1256 "enabling ADC DC Calibration.\n");
Sujithf1dc5602008-10-29 10:16:30 +05301257 }
Luis R. Rodriguezc9e27d92008-12-23 15:58:42 -08001258 if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
Sujith2660b812009-02-09 13:27:26 +05301259 INIT_CAL(&ah->iq_caldata);
1260 INSERT_CAL(ah, &ah->iq_caldata);
Luis R. Rodriguezc46917b2009-09-13 02:42:02 -07001261 ath_print(common, ATH_DBG_CALIBRATE,
1262 "enabling IQ Calibration.\n");
Sujithf1dc5602008-10-29 10:16:30 +05301263 }
1264
Sujith2660b812009-02-09 13:27:26 +05301265 ah->cal_list_curr = ah->cal_list;
Sujithf1dc5602008-10-29 10:16:30 +05301266
Sujith2660b812009-02-09 13:27:26 +05301267 if (ah->cal_list_curr)
1268 ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
Sujithf1dc5602008-10-29 10:16:30 +05301269 }
1270
Luis R. Rodriguez5f8e0772009-01-22 15:16:48 -08001271 chan->CalValid = 0;
Sujithf1dc5602008-10-29 10:16:30 +05301272
1273 return true;
1274}
1275
Sujithcbfe9462009-04-13 21:56:56 +05301276const struct ath9k_percal_data iq_cal_multi_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301277 IQ_MISMATCH_CAL,
1278 MAX_CAL_SAMPLES,
1279 PER_MIN_LOG_COUNT,
1280 ath9k_hw_iqcal_collect,
1281 ath9k_hw_iqcalibrate
1282};
Sujithcbfe9462009-04-13 21:56:56 +05301283const struct ath9k_percal_data iq_cal_single_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301284 IQ_MISMATCH_CAL,
1285 MIN_CAL_SAMPLES,
1286 PER_MAX_LOG_COUNT,
1287 ath9k_hw_iqcal_collect,
1288 ath9k_hw_iqcalibrate
1289};
Sujithcbfe9462009-04-13 21:56:56 +05301290const struct ath9k_percal_data adc_gain_cal_multi_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301291 ADC_GAIN_CAL,
1292 MAX_CAL_SAMPLES,
1293 PER_MIN_LOG_COUNT,
1294 ath9k_hw_adc_gaincal_collect,
1295 ath9k_hw_adc_gaincal_calibrate
1296};
Sujithcbfe9462009-04-13 21:56:56 +05301297const struct ath9k_percal_data adc_gain_cal_single_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301298 ADC_GAIN_CAL,
1299 MIN_CAL_SAMPLES,
1300 PER_MAX_LOG_COUNT,
1301 ath9k_hw_adc_gaincal_collect,
1302 ath9k_hw_adc_gaincal_calibrate
1303};
Sujithcbfe9462009-04-13 21:56:56 +05301304const struct ath9k_percal_data adc_dc_cal_multi_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301305 ADC_DC_CAL,
1306 MAX_CAL_SAMPLES,
1307 PER_MIN_LOG_COUNT,
1308 ath9k_hw_adc_dccal_collect,
1309 ath9k_hw_adc_dccal_calibrate
1310};
Sujithcbfe9462009-04-13 21:56:56 +05301311const struct ath9k_percal_data adc_dc_cal_single_sample = {
Sujithf1dc5602008-10-29 10:16:30 +05301312 ADC_DC_CAL,
1313 MIN_CAL_SAMPLES,
1314 PER_MAX_LOG_COUNT,
1315 ath9k_hw_adc_dccal_collect,
1316 ath9k_hw_adc_dccal_calibrate
1317};
Sujithcbfe9462009-04-13 21:56:56 +05301318const struct ath9k_percal_data adc_init_dc_cal = {
Sujithf1dc5602008-10-29 10:16:30 +05301319 ADC_DC_INIT_CAL,
1320 MIN_CAL_SAMPLES,
1321 INIT_LOG_COUNT,
1322 ath9k_hw_adc_dccal_collect,
1323 ath9k_hw_adc_dccal_calibrate
1324};