blob: f0e8f639ecfd4646f2e2efa9d99752ebc5391568 [file] [log] [blame]
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -04001/*
2 * Copyright (c) 2010 Atheros Communications Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "hw.h"
18#include "hw-ops.h"
19#include "ar9003_phy.h"
20
21static void ar9003_hw_setup_calibration(struct ath_hw *ah,
22 struct ath9k_cal_list *currCal)
23{
Luis R. Rodriguez4b019312010-04-15 17:39:10 -040024 struct ath_common *common = ath9k_hw_common(ah);
25
26 /* Select calibration to run */
27 switch (currCal->calData->calType) {
28 case IQ_MISMATCH_CAL:
29 /*
30 * Start calibration with
31 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
32 */
33 REG_RMW_FIELD(ah, AR_PHY_TIMING4,
34 AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
35 currCal->calData->calCountMax);
36 REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
37
38 ath_print(common, ATH_DBG_CALIBRATE,
39 "starting IQ Mismatch Calibration\n");
40
41 /* Kick-off cal */
42 REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
43 break;
44 case TEMP_COMP_CAL:
45 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
46 AR_PHY_65NM_CH0_THERM_LOCAL, 1);
47 REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
48 AR_PHY_65NM_CH0_THERM_START, 1);
49
50 ath_print(common, ATH_DBG_CALIBRATE,
51 "starting Temperature Compensation Calibration\n");
52 break;
53 case ADC_DC_INIT_CAL:
54 case ADC_GAIN_CAL:
55 case ADC_DC_CAL:
56 /* Not yet */
57 break;
58 }
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -040059}
60
61static bool ar9003_hw_calibrate(struct ath_hw *ah,
62 struct ath9k_channel *chan,
63 u8 rxchainmask,
64 bool longcal)
65{
66 /* TODO */
67 return false;
68}
69
70static bool ar9003_hw_init_cal(struct ath_hw *ah,
71 struct ath9k_channel *chan)
72{
73 /* TODO */
74 return false;
75}
76
Luis R. Rodriguez590b7d22010-04-15 17:39:01 -040077static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
78{
79 int i;
80
81 /* Accumulate IQ cal measures for active chains */
82 for (i = 0; i < AR5416_MAX_CHAINS; i++) {
83 ah->totalPowerMeasI[i] +=
84 REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
85 ah->totalPowerMeasQ[i] +=
86 REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
87 ah->totalIqCorrMeas[i] +=
88 (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
89 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
90 "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
91 ah->cal_samples, i, ah->totalPowerMeasI[i],
92 ah->totalPowerMeasQ[i],
93 ah->totalIqCorrMeas[i]);
94 }
95}
96
97static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
98{
99 struct ath_common *common = ath9k_hw_common(ah);
100 u32 powerMeasQ, powerMeasI, iqCorrMeas;
101 u32 qCoffDenom, iCoffDenom;
102 int32_t qCoff, iCoff;
103 int iqCorrNeg, i;
104 const u_int32_t offset_array[3] = {
105 AR_PHY_RX_IQCAL_CORR_B0,
106 AR_PHY_RX_IQCAL_CORR_B1,
107 AR_PHY_RX_IQCAL_CORR_B2,
108 };
109
110 for (i = 0; i < numChains; i++) {
111 powerMeasI = ah->totalPowerMeasI[i];
112 powerMeasQ = ah->totalPowerMeasQ[i];
113 iqCorrMeas = ah->totalIqCorrMeas[i];
114
115 ath_print(common, ATH_DBG_CALIBRATE,
116 "Starting IQ Cal and Correction for Chain %d\n",
117 i);
118
119 ath_print(common, ATH_DBG_CALIBRATE,
120 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
121 i, ah->totalIqCorrMeas[i]);
122
123 iqCorrNeg = 0;
124
125 if (iqCorrMeas > 0x80000000) {
126 iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
127 iqCorrNeg = 1;
128 }
129
130 ath_print(common, ATH_DBG_CALIBRATE,
131 "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
132 ath_print(common, ATH_DBG_CALIBRATE,
133 "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
134 ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
135 iqCorrNeg);
136
137 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
138 qCoffDenom = powerMeasQ / 64;
139
140 if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
141 iCoff = iqCorrMeas / iCoffDenom;
142 qCoff = powerMeasI / qCoffDenom - 64;
143 ath_print(common, ATH_DBG_CALIBRATE,
144 "Chn %d iCoff = 0x%08x\n", i, iCoff);
145 ath_print(common, ATH_DBG_CALIBRATE,
146 "Chn %d qCoff = 0x%08x\n", i, qCoff);
147
148 /* Force bounds on iCoff */
149 if (iCoff >= 63)
150 iCoff = 63;
151 else if (iCoff <= -63)
152 iCoff = -63;
153
154 /* Negate iCoff if iqCorrNeg == 0 */
155 if (iqCorrNeg == 0x0)
156 iCoff = -iCoff;
157
158 /* Force bounds on qCoff */
159 if (qCoff >= 63)
160 qCoff = 63;
161 else if (qCoff <= -63)
162 qCoff = -63;
163
164 iCoff = iCoff & 0x7f;
165 qCoff = qCoff & 0x7f;
166
167 ath_print(common, ATH_DBG_CALIBRATE,
168 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
169 i, iCoff, qCoff);
170 ath_print(common, ATH_DBG_CALIBRATE,
171 "Register offset (0x%04x) "
172 "before update = 0x%x\n",
173 offset_array[i],
174 REG_READ(ah, offset_array[i]));
175
176 REG_RMW_FIELD(ah, offset_array[i],
177 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
178 iCoff);
179 REG_RMW_FIELD(ah, offset_array[i],
180 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
181 qCoff);
182 ath_print(common, ATH_DBG_CALIBRATE,
183 "Register offset (0x%04x) QI COFF "
184 "(bitfields 0x%08x) after update = 0x%x\n",
185 offset_array[i],
186 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
187 REG_READ(ah, offset_array[i]));
188 ath_print(common, ATH_DBG_CALIBRATE,
189 "Register offset (0x%04x) QQ COFF "
190 "(bitfields 0x%08x) after update = 0x%x\n",
191 offset_array[i],
192 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
193 REG_READ(ah, offset_array[i]));
194
195 ath_print(common, ATH_DBG_CALIBRATE,
196 "IQ Cal and Correction done for Chain %d\n",
197 i);
198 }
199 }
200
201 REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
202 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
203 ath_print(common, ATH_DBG_CALIBRATE,
204 "IQ Cal and Correction (offset 0x%04x) enabled "
205 "(bit position 0x%08x). New Value 0x%08x\n",
206 (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
207 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
208 REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
209}
210
211static const struct ath9k_percal_data iq_cal_single_sample = {
212 IQ_MISMATCH_CAL,
213 MIN_CAL_SAMPLES,
214 PER_MAX_LOG_COUNT,
215 ar9003_hw_iqcal_collect,
216 ar9003_hw_iqcalibrate
217};
218
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -0400219static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
220{
Luis R. Rodriguez590b7d22010-04-15 17:39:01 -0400221 ah->iq_caldata.calData = &iq_cal_single_sample;
222 ah->supp_cals = IQ_MISMATCH_CAL;
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -0400223}
224
225static bool ar9003_hw_iscal_supported(struct ath_hw *ah,
226 enum ath9k_cal_types calType)
227{
228 /* TODO */
229 return false;
230}
231
Luis R. Rodriguez77d6d392010-04-15 17:39:09 -0400232static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
233{
234 /* TODO */
235}
236
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -0400237void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
238{
239 struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
240 struct ath_hw_ops *ops = ath9k_hw_ops(ah);
241
242 priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
243 priv_ops->init_cal = ar9003_hw_init_cal;
244 priv_ops->setup_calibration = ar9003_hw_setup_calibration;
245 priv_ops->iscal_supported = ar9003_hw_iscal_supported;
Luis R. Rodriguez77d6d392010-04-15 17:39:09 -0400246 priv_ops->loadnf = ar9003_hw_loadnf;
Luis R. Rodriguez795f5e22010-04-15 17:39:00 -0400247
248 ops->calibrate = ar9003_hw_calibrate;
249}