OSDN Git Service

ath9k_hw: abstract loading noisefloor
[uclinux-h8/linux.git] / drivers / net / wireless / ath / ath9k / ar9003_calib.c
1 /*
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
21 static void ar9003_hw_setup_calibration(struct ath_hw *ah,
22                                         struct ath9k_cal_list *currCal)
23 {
24         /* TODO */
25 }
26
27 static bool ar9003_hw_calibrate(struct ath_hw *ah,
28                                 struct ath9k_channel *chan,
29                                 u8 rxchainmask,
30                                 bool longcal)
31 {
32         /* TODO */
33         return false;
34 }
35
36 static bool ar9003_hw_init_cal(struct ath_hw *ah,
37                                struct ath9k_channel *chan)
38 {
39         /* TODO */
40         return false;
41 }
42
43 static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
44 {
45         int i;
46
47         /* Accumulate IQ cal measures for active chains */
48         for (i = 0; i < AR5416_MAX_CHAINS; i++) {
49                 ah->totalPowerMeasI[i] +=
50                         REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
51                 ah->totalPowerMeasQ[i] +=
52                         REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
53                 ah->totalIqCorrMeas[i] +=
54                         (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
55                 ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
56                           "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
57                           ah->cal_samples, i, ah->totalPowerMeasI[i],
58                           ah->totalPowerMeasQ[i],
59                           ah->totalIqCorrMeas[i]);
60         }
61 }
62
63 static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
64 {
65         struct ath_common *common = ath9k_hw_common(ah);
66         u32 powerMeasQ, powerMeasI, iqCorrMeas;
67         u32 qCoffDenom, iCoffDenom;
68         int32_t qCoff, iCoff;
69         int iqCorrNeg, i;
70         const u_int32_t offset_array[3] = {
71                 AR_PHY_RX_IQCAL_CORR_B0,
72                 AR_PHY_RX_IQCAL_CORR_B1,
73                 AR_PHY_RX_IQCAL_CORR_B2,
74         };
75
76         for (i = 0; i < numChains; i++) {
77                 powerMeasI = ah->totalPowerMeasI[i];
78                 powerMeasQ = ah->totalPowerMeasQ[i];
79                 iqCorrMeas = ah->totalIqCorrMeas[i];
80
81                 ath_print(common, ATH_DBG_CALIBRATE,
82                           "Starting IQ Cal and Correction for Chain %d\n",
83                           i);
84
85                 ath_print(common, ATH_DBG_CALIBRATE,
86                           "Orignal: Chn %diq_corr_meas = 0x%08x\n",
87                           i, ah->totalIqCorrMeas[i]);
88
89                 iqCorrNeg = 0;
90
91                 if (iqCorrMeas > 0x80000000) {
92                         iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
93                         iqCorrNeg = 1;
94                 }
95
96                 ath_print(common, ATH_DBG_CALIBRATE,
97                           "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
98                 ath_print(common, ATH_DBG_CALIBRATE,
99                           "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
100                 ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
101                           iqCorrNeg);
102
103                 iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
104                 qCoffDenom = powerMeasQ / 64;
105
106                 if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
107                         iCoff = iqCorrMeas / iCoffDenom;
108                         qCoff = powerMeasI / qCoffDenom - 64;
109                         ath_print(common, ATH_DBG_CALIBRATE,
110                                   "Chn %d iCoff = 0x%08x\n", i, iCoff);
111                         ath_print(common, ATH_DBG_CALIBRATE,
112                                   "Chn %d qCoff = 0x%08x\n", i, qCoff);
113
114                         /* Force bounds on iCoff */
115                         if (iCoff >= 63)
116                                 iCoff = 63;
117                         else if (iCoff <= -63)
118                                 iCoff = -63;
119
120                         /* Negate iCoff if iqCorrNeg == 0 */
121                         if (iqCorrNeg == 0x0)
122                                 iCoff = -iCoff;
123
124                         /* Force bounds on qCoff */
125                         if (qCoff >= 63)
126                                 qCoff = 63;
127                         else if (qCoff <= -63)
128                                 qCoff = -63;
129
130                         iCoff = iCoff & 0x7f;
131                         qCoff = qCoff & 0x7f;
132
133                         ath_print(common, ATH_DBG_CALIBRATE,
134                                   "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
135                                   i, iCoff, qCoff);
136                         ath_print(common, ATH_DBG_CALIBRATE,
137                                   "Register offset (0x%04x) "
138                                   "before update = 0x%x\n",
139                                   offset_array[i],
140                                   REG_READ(ah, offset_array[i]));
141
142                         REG_RMW_FIELD(ah, offset_array[i],
143                                       AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
144                                       iCoff);
145                         REG_RMW_FIELD(ah, offset_array[i],
146                                       AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
147                                       qCoff);
148                         ath_print(common, ATH_DBG_CALIBRATE,
149                                   "Register offset (0x%04x) QI COFF "
150                                   "(bitfields 0x%08x) after update = 0x%x\n",
151                                   offset_array[i],
152                                   AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
153                                   REG_READ(ah, offset_array[i]));
154                         ath_print(common, ATH_DBG_CALIBRATE,
155                                   "Register offset (0x%04x) QQ COFF "
156                                   "(bitfields 0x%08x) after update = 0x%x\n",
157                                   offset_array[i],
158                                   AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
159                                   REG_READ(ah, offset_array[i]));
160
161                         ath_print(common, ATH_DBG_CALIBRATE,
162                                   "IQ Cal and Correction done for Chain %d\n",
163                                   i);
164                 }
165         }
166
167         REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
168                     AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
169         ath_print(common, ATH_DBG_CALIBRATE,
170                   "IQ Cal and Correction (offset 0x%04x) enabled "
171                   "(bit position 0x%08x). New Value 0x%08x\n",
172                   (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
173                   AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
174                   REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
175 }
176
177 static const struct ath9k_percal_data iq_cal_single_sample = {
178         IQ_MISMATCH_CAL,
179         MIN_CAL_SAMPLES,
180         PER_MAX_LOG_COUNT,
181         ar9003_hw_iqcal_collect,
182         ar9003_hw_iqcalibrate
183 };
184
185 static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
186 {
187         ah->iq_caldata.calData = &iq_cal_single_sample;
188         ah->supp_cals = IQ_MISMATCH_CAL;
189 }
190
191 static bool ar9003_hw_iscal_supported(struct ath_hw *ah,
192                                       enum ath9k_cal_types calType)
193 {
194         /* TODO */
195         return false;
196 }
197
198 static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
199 {
200         /* TODO */
201 }
202
203 void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
204 {
205         struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
206         struct ath_hw_ops *ops = ath9k_hw_ops(ah);
207
208         priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
209         priv_ops->init_cal = ar9003_hw_init_cal;
210         priv_ops->setup_calibration = ar9003_hw_setup_calibration;
211         priv_ops->iscal_supported = ar9003_hw_iscal_supported;
212         priv_ops->loadnf = ar9003_hw_loadnf;
213
214         ops->calibrate = ar9003_hw_calibrate;
215 }