2 * Copyright (c) 2010 Atheros Communications Inc.
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.
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.
19 #include "ar9003_phy.h"
21 static void ar9003_hw_setup_calibration(struct ath_hw
*ah
,
22 struct ath9k_cal_list
*currCal
)
27 static bool ar9003_hw_calibrate(struct ath_hw
*ah
,
28 struct ath9k_channel
*chan
,
36 static bool ar9003_hw_init_cal(struct ath_hw
*ah
,
37 struct ath9k_channel
*chan
)
43 static void ar9003_hw_iqcal_collect(struct ath_hw
*ah
)
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
]);
63 static void ar9003_hw_iqcalibrate(struct ath_hw
*ah
, u8 numChains
)
65 struct ath_common
*common
= ath9k_hw_common(ah
);
66 u32 powerMeasQ
, powerMeasI
, iqCorrMeas
;
67 u32 qCoffDenom
, iCoffDenom
;
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
,
76 for (i
= 0; i
< numChains
; i
++) {
77 powerMeasI
= ah
->totalPowerMeasI
[i
];
78 powerMeasQ
= ah
->totalPowerMeasQ
[i
];
79 iqCorrMeas
= ah
->totalIqCorrMeas
[i
];
81 ath_print(common
, ATH_DBG_CALIBRATE
,
82 "Starting IQ Cal and Correction for Chain %d\n",
85 ath_print(common
, ATH_DBG_CALIBRATE
,
86 "Orignal: Chn %diq_corr_meas = 0x%08x\n",
87 i
, ah
->totalIqCorrMeas
[i
]);
91 if (iqCorrMeas
> 0x80000000) {
92 iqCorrMeas
= (0xffffffff - iqCorrMeas
) + 1;
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",
103 iCoffDenom
= (powerMeasI
/ 2 + powerMeasQ
/ 2) / 256;
104 qCoffDenom
= powerMeasQ
/ 64;
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
);
114 /* Force bounds on iCoff */
117 else if (iCoff
<= -63)
120 /* Negate iCoff if iqCorrNeg == 0 */
121 if (iqCorrNeg
== 0x0)
124 /* Force bounds on qCoff */
127 else if (qCoff
<= -63)
130 iCoff
= iCoff
& 0x7f;
131 qCoff
= qCoff
& 0x7f;
133 ath_print(common
, ATH_DBG_CALIBRATE
,
134 "Chn %d : iCoff = 0x%x qCoff = 0x%x\n",
136 ath_print(common
, ATH_DBG_CALIBRATE
,
137 "Register offset (0x%04x) "
138 "before update = 0x%x\n",
140 REG_READ(ah
, offset_array
[i
]));
142 REG_RMW_FIELD(ah
, offset_array
[i
],
143 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF
,
145 REG_RMW_FIELD(ah
, offset_array
[i
],
146 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
,
148 ath_print(common
, ATH_DBG_CALIBRATE
,
149 "Register offset (0x%04x) QI COFF "
150 "(bitfields 0x%08x) after update = 0x%x\n",
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",
158 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF
,
159 REG_READ(ah
, offset_array
[i
]));
161 ath_print(common
, ATH_DBG_CALIBRATE
,
162 "IQ Cal and Correction done for Chain %d\n",
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
));
177 static const struct ath9k_percal_data iq_cal_single_sample
= {
181 ar9003_hw_iqcal_collect
,
182 ar9003_hw_iqcalibrate
185 static void ar9003_hw_init_cal_settings(struct ath_hw
*ah
)
187 ah
->iq_caldata
.calData
= &iq_cal_single_sample
;
188 ah
->supp_cals
= IQ_MISMATCH_CAL
;
191 static bool ar9003_hw_iscal_supported(struct ath_hw
*ah
,
192 enum ath9k_cal_types calType
)
198 void ar9003_hw_attach_calib_ops(struct ath_hw
*ah
)
200 struct ath_hw_private_ops
*priv_ops
= ath9k_hw_private_ops(ah
);
201 struct ath_hw_ops
*ops
= ath9k_hw_ops(ah
);
203 priv_ops
->init_cal_settings
= ar9003_hw_init_cal_settings
;
204 priv_ops
->init_cal
= ar9003_hw_init_cal
;
205 priv_ops
->setup_calibration
= ar9003_hw_setup_calibration
;
206 priv_ops
->iscal_supported
= ar9003_hw_iscal_supported
;
208 ops
->calibrate
= ar9003_hw_calibrate
;