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