Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2012 Qualcomm Atheros, 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 "ath9k.h"
18 : :
19 : : /*
20 : : * AR9285
21 : : * ======
22 : : *
23 : : * EEPROM has 2 4-bit fields containing the card configuration.
24 : : *
25 : : * antdiv_ctl1:
26 : : * ------------
27 : : * bb_enable_ant_div_lnadiv : 1
28 : : * bb_ant_div_alt_gaintb : 1
29 : : * bb_ant_div_main_gaintb : 1
30 : : * bb_enable_ant_fast_div : 1
31 : : *
32 : : * antdiv_ctl2:
33 : : * -----------
34 : : * bb_ant_div_alt_lnaconf : 2
35 : : * bb_ant_div_main_lnaconf : 2
36 : : *
37 : : * The EEPROM bits are used as follows:
38 : : * ------------------------------------
39 : : *
40 : : * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining.
41 : : * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
42 : : *
43 : : * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0
44 : : * 1 -> Antenna config Alt/Main uses gaintable 1
45 : : * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
46 : : *
47 : : * bb_enable_ant_fast_div - Enable fast antenna diversity.
48 : : * Set in AR_PHY_CCK_DETECT.
49 : : *
50 : : * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
51 : : * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
52 : : * 10=LNA1
53 : : * 01=LNA2
54 : : * 11=LNA1+LNA2
55 : : * 00=LNA1-LNA2
56 : : *
57 : : * AR9485 / AR9565 / AR9331
58 : : * ========================
59 : : *
60 : : * The same bits are present in the EEPROM, but the location in the
61 : : * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
62 : : *
63 : : * ant_div_alt_lnaconf ==> bit 0~1
64 : : * ant_div_main_lnaconf ==> bit 2~3
65 : : * ant_div_alt_gaintb ==> bit 4
66 : : * ant_div_main_gaintb ==> bit 5
67 : : * enable_ant_div_lnadiv ==> bit 6
68 : : * enable_ant_fast_div ==> bit 7
69 : : */
70 : :
71 : 0 : static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb,
72 : : int alt_ratio, int maxdelta,
73 : : int mindelta, int main_rssi_avg,
74 : : int alt_rssi_avg, int pkt_count)
75 : : {
76 : 0 : if (pkt_count <= 50)
77 : : return false;
78 : :
79 [ # # # # : 0 : if (alt_rssi_avg > main_rssi_avg + mindelta)
# # # # #
# # # ]
80 : : return true;
81 : :
82 [ # # # # : 0 : if (alt_ratio >= antcomb->ant_ratio2 &&
# # # # #
# # # ]
83 [ # # # # : 0 : alt_rssi_avg >= antcomb->low_rssi_thresh &&
# # # # #
# # # ]
84 [ # # # # : 0 : (alt_rssi_avg > main_rssi_avg + maxdelta))
# # # # #
# # # ]
85 : : return true;
86 : :
87 : : return false;
88 : : }
89 : :
90 : : static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
91 : : struct ath_ant_comb *antcomb,
92 : : int alt_ratio, int alt_rssi_avg,
93 : : int main_rssi_avg)
94 : : {
95 : : bool result, set1, set2;
96 : :
97 : : result = set1 = set2 = false;
98 : :
99 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
100 : : conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
101 : : set1 = true;
102 : :
103 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
104 : : conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
105 : : set2 = true;
106 : :
107 : : switch (conf->div_group) {
108 : : case 0:
109 : : if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
110 : : result = true;
111 : : break;
112 : : case 1:
113 : : case 2:
114 : : if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
115 : : break;
116 : :
117 : : if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
118 : : (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) ||
119 : : (alt_ratio > antcomb->ant_ratio))
120 : : result = true;
121 : :
122 : : break;
123 : : case 3:
124 : : if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
125 : : break;
126 : :
127 : : if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
128 : : (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) ||
129 : : (alt_ratio > antcomb->ant_ratio))
130 : : result = true;
131 : :
132 : : break;
133 : : }
134 : :
135 : : return result;
136 : : }
137 : :
138 : : static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
139 : : struct ath_hw_antcomb_conf ant_conf,
140 : : int main_rssi_avg)
141 : : {
142 : : antcomb->quick_scan_cnt = 0;
143 : :
144 : : if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
145 : : antcomb->rssi_lna2 = main_rssi_avg;
146 : : else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
147 : : antcomb->rssi_lna1 = main_rssi_avg;
148 : :
149 : : switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
150 : : case 0x10: /* LNA2 A-B */
151 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
152 : : antcomb->first_quick_scan_conf =
153 : : ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
154 : : antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
155 : : break;
156 : : case 0x20: /* LNA1 A-B */
157 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
158 : : antcomb->first_quick_scan_conf =
159 : : ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
160 : : antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
161 : : break;
162 : : case 0x21: /* LNA1 LNA2 */
163 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
164 : : antcomb->first_quick_scan_conf =
165 : : ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
166 : : antcomb->second_quick_scan_conf =
167 : : ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
168 : : break;
169 : : case 0x12: /* LNA2 LNA1 */
170 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
171 : : antcomb->first_quick_scan_conf =
172 : : ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
173 : : antcomb->second_quick_scan_conf =
174 : : ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
175 : : break;
176 : : case 0x13: /* LNA2 A+B */
177 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
178 : : antcomb->first_quick_scan_conf =
179 : : ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
180 : : antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
181 : : break;
182 : : case 0x23: /* LNA1 A+B */
183 : : antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
184 : : antcomb->first_quick_scan_conf =
185 : : ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
186 : : antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
187 : : break;
188 : : default:
189 : : break;
190 : : }
191 : : }
192 : :
193 : : static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
194 : : struct ath_hw_antcomb_conf *conf)
195 : : {
196 : : /* set alt to the conf with maximun ratio */
197 : : if (antcomb->first_ratio && antcomb->second_ratio) {
198 : : if (antcomb->rssi_second > antcomb->rssi_third) {
199 : : /* first alt*/
200 : : if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
201 : : (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
202 : : /* Set alt LNA1 or LNA2*/
203 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
204 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
205 : : else
206 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
207 : : else
208 : : /* Set alt to A+B or A-B */
209 : : conf->alt_lna_conf =
210 : : antcomb->first_quick_scan_conf;
211 : : } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
212 : : (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
213 : : /* Set alt LNA1 or LNA2 */
214 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
215 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
216 : : else
217 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
218 : : } else {
219 : : /* Set alt to A+B or A-B */
220 : : conf->alt_lna_conf = antcomb->second_quick_scan_conf;
221 : : }
222 : : } else if (antcomb->first_ratio) {
223 : : /* first alt */
224 : : if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
225 : : (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
226 : : /* Set alt LNA1 or LNA2 */
227 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
228 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
229 : : else
230 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
231 : : else
232 : : /* Set alt to A+B or A-B */
233 : : conf->alt_lna_conf = antcomb->first_quick_scan_conf;
234 : : } else if (antcomb->second_ratio) {
235 : : /* second alt */
236 : : if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
237 : : (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
238 : : /* Set alt LNA1 or LNA2 */
239 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
240 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
241 : : else
242 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
243 : : else
244 : : /* Set alt to A+B or A-B */
245 : : conf->alt_lna_conf = antcomb->second_quick_scan_conf;
246 : : } else {
247 : : /* main is largest */
248 : : if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
249 : : (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
250 : : /* Set alt LNA1 or LNA2 */
251 : : if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
252 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
253 : : else
254 : : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
255 : : else
256 : : /* Set alt to A+B or A-B */
257 : : conf->alt_lna_conf = antcomb->main_conf;
258 : : }
259 : : }
260 : :
261 : 0 : static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
262 : : struct ath_hw_antcomb_conf *div_ant_conf,
263 : : int main_rssi_avg, int alt_rssi_avg,
264 : : int alt_ratio)
265 : : {
266 : : /* alt_good */
267 [ # # # # ]: 0 : switch (antcomb->quick_scan_cnt) {
268 : 0 : case 0:
269 : : /* set alt to main, and alt to first conf */
270 : 0 : div_ant_conf->main_lna_conf = antcomb->main_conf;
271 : 0 : div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
272 : 0 : break;
273 : 0 : case 1:
274 : : /* set alt to main, and alt to first conf */
275 : 0 : div_ant_conf->main_lna_conf = antcomb->main_conf;
276 : 0 : div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
277 : 0 : antcomb->rssi_first = main_rssi_avg;
278 : 0 : antcomb->rssi_second = alt_rssi_avg;
279 : :
280 [ # # ]: 0 : if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
281 : : /* main is LNA1 */
282 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
283 : : ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
284 : : ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
285 : : main_rssi_avg, alt_rssi_avg,
286 [ # # ]: 0 : antcomb->total_pkt_count))
287 : 0 : antcomb->first_ratio = true;
288 : : else
289 : 0 : antcomb->first_ratio = false;
290 [ # # ]: 0 : } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
291 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
292 : : ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
293 : : ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
294 : : main_rssi_avg, alt_rssi_avg,
295 [ # # ]: 0 : antcomb->total_pkt_count))
296 : 0 : antcomb->first_ratio = true;
297 : : else
298 : 0 : antcomb->first_ratio = false;
299 : : } else {
300 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
301 : : ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
302 : : 0,
303 : : main_rssi_avg, alt_rssi_avg,
304 [ # # ]: 0 : antcomb->total_pkt_count))
305 : 0 : antcomb->first_ratio = true;
306 : : else
307 : 0 : antcomb->first_ratio = false;
308 : : }
309 : : break;
310 : 0 : case 2:
311 : 0 : antcomb->alt_good = false;
312 : 0 : antcomb->scan_not_start = false;
313 : 0 : antcomb->scan = false;
314 : 0 : antcomb->rssi_first = main_rssi_avg;
315 : 0 : antcomb->rssi_third = alt_rssi_avg;
316 : :
317 [ # # # # ]: 0 : switch(antcomb->second_quick_scan_conf) {
318 : 0 : case ATH_ANT_DIV_COMB_LNA1:
319 : 0 : antcomb->rssi_lna1 = alt_rssi_avg;
320 : 0 : break;
321 : 0 : case ATH_ANT_DIV_COMB_LNA2:
322 : 0 : antcomb->rssi_lna2 = alt_rssi_avg;
323 : 0 : break;
324 : 0 : case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
325 [ # # ]: 0 : if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
326 : 0 : antcomb->rssi_lna2 = main_rssi_avg;
327 [ # # ]: 0 : else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
328 : 0 : antcomb->rssi_lna1 = main_rssi_avg;
329 : : break;
330 : : default:
331 : : break;
332 : : }
333 : :
334 : 0 : if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
335 [ # # ]: 0 : div_ant_conf->lna1_lna2_switch_delta)
336 : 0 : div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
337 : : else
338 : 0 : div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
339 : :
340 [ # # ]: 0 : if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
341 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
342 : : ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
343 : : ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
344 : : main_rssi_avg, alt_rssi_avg,
345 [ # # ]: 0 : antcomb->total_pkt_count))
346 : 0 : antcomb->second_ratio = true;
347 : : else
348 : 0 : antcomb->second_ratio = false;
349 [ # # ]: 0 : } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
350 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
351 : : ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
352 : : ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
353 : : main_rssi_avg, alt_rssi_avg,
354 [ # # ]: 0 : antcomb->total_pkt_count))
355 : 0 : antcomb->second_ratio = true;
356 : : else
357 : 0 : antcomb->second_ratio = false;
358 : : } else {
359 : 0 : if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
360 : : ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
361 : : 0,
362 : : main_rssi_avg, alt_rssi_avg,
363 [ # # ]: 0 : antcomb->total_pkt_count))
364 : 0 : antcomb->second_ratio = true;
365 : : else
366 : 0 : antcomb->second_ratio = false;
367 : : }
368 : :
369 : 0 : ath_ant_set_alt_ratio(antcomb, div_ant_conf);
370 : :
371 : 0 : break;
372 : : default:
373 : : break;
374 : : }
375 : 0 : }
376 : :
377 : 0 : static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
378 : : struct ath_ant_comb *antcomb,
379 : : int alt_ratio)
380 : : {
381 : 0 : ant_conf->main_gaintb = 0;
382 : 0 : ant_conf->alt_gaintb = 0;
383 : :
384 [ # # ]: 0 : if (ant_conf->div_group == 0) {
385 : : /* Adjust the fast_div_bias based on main and alt lna conf */
386 : 0 : switch ((ant_conf->main_lna_conf << 4) |
387 [ # # # # : 0 : ant_conf->alt_lna_conf) {
# # # # #
# # # # ]
388 : 0 : case 0x01: /* A-B LNA2 */
389 : 0 : ant_conf->fast_div_bias = 0x3b;
390 : 0 : break;
391 : 0 : case 0x02: /* A-B LNA1 */
392 : 0 : ant_conf->fast_div_bias = 0x3d;
393 : 0 : break;
394 : 0 : case 0x03: /* A-B A+B */
395 : 0 : ant_conf->fast_div_bias = 0x1;
396 : 0 : break;
397 : 0 : case 0x10: /* LNA2 A-B */
398 : 0 : ant_conf->fast_div_bias = 0x7;
399 : 0 : break;
400 : 0 : case 0x12: /* LNA2 LNA1 */
401 : 0 : ant_conf->fast_div_bias = 0x2;
402 : 0 : break;
403 : 0 : case 0x13: /* LNA2 A+B */
404 : 0 : ant_conf->fast_div_bias = 0x7;
405 : 0 : break;
406 : 0 : case 0x20: /* LNA1 A-B */
407 : 0 : ant_conf->fast_div_bias = 0x6;
408 : 0 : break;
409 : 0 : case 0x21: /* LNA1 LNA2 */
410 : 0 : ant_conf->fast_div_bias = 0x0;
411 : 0 : break;
412 : 0 : case 0x23: /* LNA1 A+B */
413 : 0 : ant_conf->fast_div_bias = 0x6;
414 : 0 : break;
415 : 0 : case 0x30: /* A+B A-B */
416 : 0 : ant_conf->fast_div_bias = 0x1;
417 : 0 : break;
418 : 0 : case 0x31: /* A+B LNA2 */
419 : 0 : ant_conf->fast_div_bias = 0x3b;
420 : 0 : break;
421 : 0 : case 0x32: /* A+B LNA1 */
422 : 0 : ant_conf->fast_div_bias = 0x3d;
423 : 0 : break;
424 : : default:
425 : : break;
426 : : }
427 [ # # ]: 0 : } else if (ant_conf->div_group == 1) {
428 : : /* Adjust the fast_div_bias based on main and alt_lna_conf */
429 : 0 : switch ((ant_conf->main_lna_conf << 4) |
430 [ # # # # : 0 : ant_conf->alt_lna_conf) {
# # # # #
# # # # ]
431 : 0 : case 0x01: /* A-B LNA2 */
432 : 0 : ant_conf->fast_div_bias = 0x1;
433 : 0 : break;
434 : 0 : case 0x02: /* A-B LNA1 */
435 : 0 : ant_conf->fast_div_bias = 0x1;
436 : 0 : break;
437 : 0 : case 0x03: /* A-B A+B */
438 : 0 : ant_conf->fast_div_bias = 0x1;
439 : 0 : break;
440 : 0 : case 0x10: /* LNA2 A-B */
441 [ # # # # ]: 0 : if (!(antcomb->scan) &&
442 : : (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
443 : 0 : ant_conf->fast_div_bias = 0x3f;
444 : : else
445 : 0 : ant_conf->fast_div_bias = 0x1;
446 : : break;
447 : 0 : case 0x12: /* LNA2 LNA1 */
448 : 0 : ant_conf->fast_div_bias = 0x1;
449 : 0 : break;
450 : 0 : case 0x13: /* LNA2 A+B */
451 [ # # # # ]: 0 : if (!(antcomb->scan) &&
452 : : (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
453 : 0 : ant_conf->fast_div_bias = 0x3f;
454 : : else
455 : 0 : ant_conf->fast_div_bias = 0x1;
456 : : break;
457 : 0 : case 0x20: /* LNA1 A-B */
458 [ # # # # ]: 0 : if (!(antcomb->scan) &&
459 : : (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
460 : 0 : ant_conf->fast_div_bias = 0x3f;
461 : : else
462 : 0 : ant_conf->fast_div_bias = 0x1;
463 : : break;
464 : 0 : case 0x21: /* LNA1 LNA2 */
465 : 0 : ant_conf->fast_div_bias = 0x1;
466 : 0 : break;
467 : 0 : case 0x23: /* LNA1 A+B */
468 [ # # # # ]: 0 : if (!(antcomb->scan) &&
469 : : (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
470 : 0 : ant_conf->fast_div_bias = 0x3f;
471 : : else
472 : 0 : ant_conf->fast_div_bias = 0x1;
473 : : break;
474 : 0 : case 0x30: /* A+B A-B */
475 : 0 : ant_conf->fast_div_bias = 0x1;
476 : 0 : break;
477 : 0 : case 0x31: /* A+B LNA2 */
478 : 0 : ant_conf->fast_div_bias = 0x1;
479 : 0 : break;
480 : 0 : case 0x32: /* A+B LNA1 */
481 : 0 : ant_conf->fast_div_bias = 0x1;
482 : 0 : break;
483 : : default:
484 : : break;
485 : : }
486 [ # # ]: 0 : } else if (ant_conf->div_group == 2) {
487 : : /* Adjust the fast_div_bias based on main and alt_lna_conf */
488 : 0 : switch ((ant_conf->main_lna_conf << 4) |
489 [ # # # # : 0 : ant_conf->alt_lna_conf) {
# # # # #
# # # # ]
490 : 0 : case 0x01: /* A-B LNA2 */
491 : 0 : ant_conf->fast_div_bias = 0x1;
492 : 0 : break;
493 : 0 : case 0x02: /* A-B LNA1 */
494 : 0 : ant_conf->fast_div_bias = 0x1;
495 : 0 : break;
496 : 0 : case 0x03: /* A-B A+B */
497 : 0 : ant_conf->fast_div_bias = 0x1;
498 : 0 : break;
499 : 0 : case 0x10: /* LNA2 A-B */
500 [ # # # # ]: 0 : if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
501 : 0 : ant_conf->fast_div_bias = 0x1;
502 : : else
503 : 0 : ant_conf->fast_div_bias = 0x2;
504 : : break;
505 : 0 : case 0x12: /* LNA2 LNA1 */
506 : 0 : ant_conf->fast_div_bias = 0x1;
507 : 0 : break;
508 : 0 : case 0x13: /* LNA2 A+B */
509 [ # # # # ]: 0 : if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
510 : 0 : ant_conf->fast_div_bias = 0x1;
511 : : else
512 : 0 : ant_conf->fast_div_bias = 0x2;
513 : : break;
514 : 0 : case 0x20: /* LNA1 A-B */
515 [ # # # # ]: 0 : if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
516 : 0 : ant_conf->fast_div_bias = 0x1;
517 : : else
518 : 0 : ant_conf->fast_div_bias = 0x2;
519 : : break;
520 : 0 : case 0x21: /* LNA1 LNA2 */
521 : 0 : ant_conf->fast_div_bias = 0x1;
522 : 0 : break;
523 : 0 : case 0x23: /* LNA1 A+B */
524 [ # # # # ]: 0 : if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
525 : 0 : ant_conf->fast_div_bias = 0x1;
526 : : else
527 : 0 : ant_conf->fast_div_bias = 0x2;
528 : : break;
529 : 0 : case 0x30: /* A+B A-B */
530 : 0 : ant_conf->fast_div_bias = 0x1;
531 : 0 : break;
532 : 0 : case 0x31: /* A+B LNA2 */
533 : 0 : ant_conf->fast_div_bias = 0x1;
534 : 0 : break;
535 : 0 : case 0x32: /* A+B LNA1 */
536 : 0 : ant_conf->fast_div_bias = 0x1;
537 : 0 : break;
538 : : default:
539 : : break;
540 : : }
541 : :
542 [ # # ]: 0 : if (antcomb->fast_div_bias)
543 : 0 : ant_conf->fast_div_bias = antcomb->fast_div_bias;
544 [ # # ]: 0 : } else if (ant_conf->div_group == 3) {
545 : 0 : switch ((ant_conf->main_lna_conf << 4) |
546 [ # # # # : 0 : ant_conf->alt_lna_conf) {
# # # # #
# # # # ]
547 : 0 : case 0x01: /* A-B LNA2 */
548 : 0 : ant_conf->fast_div_bias = 0x1;
549 : 0 : break;
550 : 0 : case 0x02: /* A-B LNA1 */
551 : 0 : ant_conf->fast_div_bias = 0x39;
552 : 0 : break;
553 : 0 : case 0x03: /* A-B A+B */
554 : 0 : ant_conf->fast_div_bias = 0x1;
555 : 0 : break;
556 : 0 : case 0x10: /* LNA2 A-B */
557 : 0 : ant_conf->fast_div_bias = 0x2;
558 : 0 : break;
559 : 0 : case 0x12: /* LNA2 LNA1 */
560 : 0 : ant_conf->fast_div_bias = 0x3f;
561 : 0 : break;
562 : 0 : case 0x13: /* LNA2 A+B */
563 : 0 : ant_conf->fast_div_bias = 0x2;
564 : 0 : break;
565 : 0 : case 0x20: /* LNA1 A-B */
566 : 0 : ant_conf->fast_div_bias = 0x3;
567 : 0 : break;
568 : 0 : case 0x21: /* LNA1 LNA2 */
569 : 0 : ant_conf->fast_div_bias = 0x3;
570 : 0 : break;
571 : 0 : case 0x23: /* LNA1 A+B */
572 : 0 : ant_conf->fast_div_bias = 0x3;
573 : 0 : break;
574 : 0 : case 0x30: /* A+B A-B */
575 : 0 : ant_conf->fast_div_bias = 0x1;
576 : 0 : break;
577 : 0 : case 0x31: /* A+B LNA2 */
578 : 0 : ant_conf->fast_div_bias = 0x6;
579 : 0 : break;
580 : 0 : case 0x32: /* A+B LNA1 */
581 : 0 : ant_conf->fast_div_bias = 0x1;
582 : 0 : break;
583 : : default:
584 : : break;
585 : : }
586 : 0 : }
587 : 0 : }
588 : :
589 : 0 : static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
590 : : struct ath_hw_antcomb_conf *conf,
591 : : int curr_alt_set, int alt_rssi_avg,
592 : : int main_rssi_avg)
593 : : {
594 [ # # # # : 0 : switch (curr_alt_set) {
# ]
595 : 0 : case ATH_ANT_DIV_COMB_LNA2:
596 : 0 : antcomb->rssi_lna2 = alt_rssi_avg;
597 : 0 : antcomb->rssi_lna1 = main_rssi_avg;
598 : 0 : antcomb->scan = true;
599 : : /* set to A+B */
600 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
601 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
602 : 0 : break;
603 : 0 : case ATH_ANT_DIV_COMB_LNA1:
604 : 0 : antcomb->rssi_lna1 = alt_rssi_avg;
605 : 0 : antcomb->rssi_lna2 = main_rssi_avg;
606 : 0 : antcomb->scan = true;
607 : : /* set to A+B */
608 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
609 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
610 : 0 : break;
611 : 0 : case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
612 : 0 : antcomb->rssi_add = alt_rssi_avg;
613 : 0 : antcomb->scan = true;
614 : : /* set to A-B */
615 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
616 : 0 : break;
617 : 0 : case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
618 : 0 : antcomb->rssi_sub = alt_rssi_avg;
619 : 0 : antcomb->scan = false;
620 : 0 : if (antcomb->rssi_lna2 >
621 [ # # ]: 0 : (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
622 : : /* use LNA2 as main LNA */
623 [ # # # # ]: 0 : if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
624 : : (antcomb->rssi_add > antcomb->rssi_sub)) {
625 : : /* set to A+B */
626 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
627 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
628 [ # # ]: 0 : } else if (antcomb->rssi_sub >
629 : : antcomb->rssi_lna1) {
630 : : /* set to A-B */
631 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
632 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
633 : : } else {
634 : : /* set to LNA1 */
635 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
636 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
637 : : }
638 : : } else {
639 : : /* use LNA1 as main LNA */
640 [ # # # # ]: 0 : if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
641 : : (antcomb->rssi_add > antcomb->rssi_sub)) {
642 : : /* set to A+B */
643 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
644 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
645 [ # # ]: 0 : } else if (antcomb->rssi_sub >
646 : : antcomb->rssi_lna1) {
647 : : /* set to A-B */
648 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
649 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
650 : : } else {
651 : : /* set to LNA2 */
652 : 0 : conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
653 : 0 : conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
654 : : }
655 : : }
656 : : break;
657 : : default:
658 : : break;
659 : : }
660 : 0 : }
661 : :
662 : 0 : static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
663 : : struct ath_ant_comb *antcomb,
664 : : int alt_ratio, int alt_rssi_avg,
665 : : int main_rssi_avg, int curr_main_set,
666 : : int curr_alt_set)
667 : : {
668 : 0 : bool ret = false;
669 : :
670 [ # # ]: 0 : if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
671 : : alt_rssi_avg, main_rssi_avg)) {
672 [ # # ]: 0 : if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
673 : : /*
674 : : * Switch main and alt LNA.
675 : : */
676 : 0 : div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
677 : 0 : div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
678 [ # # ]: 0 : } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
679 : 0 : div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
680 : 0 : div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
681 : : }
682 : :
683 : : ret = true;
684 [ # # ]: 0 : } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
685 : : (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
686 : : /*
687 : : Set alt to another LNA.
688 : : */
689 [ # # ]: 0 : if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
690 : 0 : div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
691 [ # # ]: 0 : else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
692 : 0 : div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
693 : :
694 : : ret = true;
695 : : }
696 : :
697 : 0 : return ret;
698 : : }
699 : :
700 : 0 : static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
701 : : {
702 : 0 : int alt_ratio;
703 : :
704 [ # # # # ]: 0 : if (!antcomb->scan || !antcomb->alt_good)
705 : : return false;
706 : :
707 [ # # ]: 0 : if (time_after(jiffies, antcomb->scan_start_time +
708 : : msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
709 : : return true;
710 : :
711 [ # # ]: 0 : if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
712 : 0 : alt_ratio = ((antcomb->alt_recv_cnt * 100) /
713 : : antcomb->total_pkt_count);
714 [ # # ]: 0 : if (alt_ratio < antcomb->ant_ratio)
715 : 0 : return true;
716 : : }
717 : :
718 : : return false;
719 : : }
720 : :
721 : 0 : void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
722 : : {
723 : 0 : struct ath_hw_antcomb_conf div_ant_conf;
724 : 0 : struct ath_ant_comb *antcomb = &sc->ant_comb;
725 : 0 : int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
726 : 0 : int curr_main_set;
727 : 0 : int main_rssi = rs->rs_rssi_ctl[0];
728 : 0 : int alt_rssi = rs->rs_rssi_ctl[1];
729 : 0 : int rx_ant_conf, main_ant_conf;
730 : 0 : bool short_scan = false, ret;
731 : :
732 : 0 : rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
733 : : ATH_ANT_RX_MASK;
734 : 0 : main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
735 : : ATH_ANT_RX_MASK;
736 : :
737 [ # # ]: 0 : if (alt_rssi >= antcomb->low_rssi_thresh) {
738 : 0 : antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
739 : 0 : antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
740 : : } else {
741 : 0 : antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
742 : 0 : antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
743 : : }
744 : :
745 : : /* Record packet only when both main_rssi and alt_rssi is positive */
746 [ # # # # ]: 0 : if (main_rssi > 0 && alt_rssi > 0) {
747 : 0 : antcomb->total_pkt_count++;
748 : 0 : antcomb->main_total_rssi += main_rssi;
749 : 0 : antcomb->alt_total_rssi += alt_rssi;
750 : :
751 [ # # ]: 0 : if (main_ant_conf == rx_ant_conf)
752 : 0 : antcomb->main_recv_cnt++;
753 : : else
754 : 0 : antcomb->alt_recv_cnt++;
755 : : }
756 : :
757 [ # # ]: 0 : if (main_ant_conf == rx_ant_conf) {
758 : 0 : ANT_STAT_INC(sc, ANT_MAIN, recv_cnt);
759 : 0 : ANT_LNA_INC(sc, ANT_MAIN, rx_ant_conf);
760 : : } else {
761 : 0 : ANT_STAT_INC(sc, ANT_ALT, recv_cnt);
762 : 0 : ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf);
763 : : }
764 : :
765 : : /* Short scan check */
766 : 0 : short_scan = ath_ant_short_scan_check(antcomb);
767 : :
768 [ # # ]: 0 : if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
769 [ # # # # ]: 0 : rs->rs_moreaggr) && !short_scan)
770 : 0 : return;
771 : :
772 [ # # ]: 0 : if (antcomb->total_pkt_count) {
773 : 0 : alt_ratio = ((antcomb->alt_recv_cnt * 100) /
774 : 0 : antcomb->total_pkt_count);
775 : 0 : main_rssi_avg = (antcomb->main_total_rssi /
776 : : antcomb->total_pkt_count);
777 : 0 : alt_rssi_avg = (antcomb->alt_total_rssi /
778 : : antcomb->total_pkt_count);
779 : : }
780 : :
781 : 0 : ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
782 : 0 : curr_alt_set = div_ant_conf.alt_lna_conf;
783 : 0 : curr_main_set = div_ant_conf.main_lna_conf;
784 : 0 : antcomb->count++;
785 : :
786 [ # # ]: 0 : if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
787 [ # # ]: 0 : if (alt_ratio > antcomb->ant_ratio) {
788 : 0 : ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
789 : : main_rssi_avg);
790 : 0 : antcomb->alt_good = true;
791 : : } else {
792 : 0 : antcomb->alt_good = false;
793 : : }
794 : :
795 : 0 : antcomb->count = 0;
796 : 0 : antcomb->scan = true;
797 : 0 : antcomb->scan_not_start = true;
798 : : }
799 : :
800 [ # # ]: 0 : if (!antcomb->scan) {
801 : 0 : ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
802 : : alt_rssi_avg, main_rssi_avg,
803 : : curr_main_set, curr_alt_set);
804 [ # # ]: 0 : if (ret)
805 : 0 : goto div_comb_done;
806 : : }
807 : :
808 [ # # ]: 0 : if (!antcomb->scan &&
809 [ # # ]: 0 : (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
810 : 0 : goto div_comb_done;
811 : :
812 [ # # ]: 0 : if (!antcomb->scan_not_start) {
813 : 0 : ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
814 : : alt_rssi_avg, main_rssi_avg);
815 : : } else {
816 [ # # ]: 0 : if (!antcomb->alt_good) {
817 : 0 : antcomb->scan_not_start = false;
818 : : /* Set alt to another LNA */
819 [ # # ]: 0 : if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
820 : 0 : div_ant_conf.main_lna_conf =
821 : : ATH_ANT_DIV_COMB_LNA2;
822 : 0 : div_ant_conf.alt_lna_conf =
823 : : ATH_ANT_DIV_COMB_LNA1;
824 [ # # ]: 0 : } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
825 : 0 : div_ant_conf.main_lna_conf =
826 : : ATH_ANT_DIV_COMB_LNA1;
827 : 0 : div_ant_conf.alt_lna_conf =
828 : : ATH_ANT_DIV_COMB_LNA2;
829 : : }
830 : 0 : goto div_comb_done;
831 : : }
832 : 0 : ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
833 : : main_rssi_avg, alt_rssi_avg,
834 : : alt_ratio);
835 : 0 : antcomb->quick_scan_cnt++;
836 : : }
837 : :
838 : 0 : div_comb_done:
839 : 0 : ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
840 : 0 : ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
841 : 0 : ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
842 : :
843 : 0 : antcomb->scan_start_time = jiffies;
844 : 0 : antcomb->total_pkt_count = 0;
845 : 0 : antcomb->main_total_rssi = 0;
846 : 0 : antcomb->alt_total_rssi = 0;
847 : 0 : antcomb->main_recv_cnt = 0;
848 : 0 : antcomb->alt_recv_cnt = 0;
849 : : }
|