1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "ath9k.h"
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71static 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 if (pkt_count <= 50)
77 return false;
78
79 if (alt_rssi_avg > main_rssi_avg + mindelta)
80 return true;
81
82 if (alt_ratio >= antcomb->ant_ratio2 &&
83 alt_rssi_avg >= antcomb->low_rssi_thresh &&
84 (alt_rssi_avg > main_rssi_avg + maxdelta))
85 return true;
86
87 return false;
88}
89
90static 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
138static 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:
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:
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:
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:
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:
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:
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
193static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
194 struct ath_hw_antcomb_conf *conf)
195{
196
197 if (antcomb->first_ratio && antcomb->second_ratio) {
198 if (antcomb->rssi_second > antcomb->rssi_third) {
199
200 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
201 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
202
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
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
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
220 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
221 }
222 } else if (antcomb->first_ratio) {
223
224 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
225 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
226
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
233 conf->alt_lna_conf = antcomb->first_quick_scan_conf;
234 } else if (antcomb->second_ratio) {
235
236 if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
237 (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
238
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
245 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
246 } else {
247
248 if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
249 (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
250
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
257 conf->alt_lna_conf = antcomb->main_conf;
258 }
259}
260
261static 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
267 switch (antcomb->quick_scan_cnt) {
268 case 0:
269
270 div_ant_conf->main_lna_conf = antcomb->main_conf;
271 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
272 break;
273 case 1:
274
275 div_ant_conf->main_lna_conf = antcomb->main_conf;
276 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
277 antcomb->rssi_first = main_rssi_avg;
278 antcomb->rssi_second = alt_rssi_avg;
279
280 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
281
282 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 antcomb->total_pkt_count))
287 antcomb->first_ratio = true;
288 else
289 antcomb->first_ratio = false;
290 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
291 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 antcomb->total_pkt_count))
296 antcomb->first_ratio = true;
297 else
298 antcomb->first_ratio = false;
299 } else {
300 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 antcomb->total_pkt_count))
305 antcomb->first_ratio = true;
306 else
307 antcomb->first_ratio = false;
308 }
309 break;
310 case 2:
311 antcomb->alt_good = false;
312 antcomb->scan_not_start = false;
313 antcomb->scan = false;
314 antcomb->rssi_first = main_rssi_avg;
315 antcomb->rssi_third = alt_rssi_avg;
316
317 switch(antcomb->second_quick_scan_conf) {
318 case ATH_ANT_DIV_COMB_LNA1:
319 antcomb->rssi_lna1 = alt_rssi_avg;
320 break;
321 case ATH_ANT_DIV_COMB_LNA2:
322 antcomb->rssi_lna2 = alt_rssi_avg;
323 break;
324 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
325 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
326 antcomb->rssi_lna2 = main_rssi_avg;
327 else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
328 antcomb->rssi_lna1 = main_rssi_avg;
329 break;
330 default:
331 break;
332 }
333
334 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
335 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
336 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
337 else
338 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
339
340 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
341 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 antcomb->total_pkt_count))
346 antcomb->second_ratio = true;
347 else
348 antcomb->second_ratio = false;
349 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
350 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 antcomb->total_pkt_count))
355 antcomb->second_ratio = true;
356 else
357 antcomb->second_ratio = false;
358 } else {
359 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 antcomb->total_pkt_count))
364 antcomb->second_ratio = true;
365 else
366 antcomb->second_ratio = false;
367 }
368
369 ath_ant_set_alt_ratio(antcomb, div_ant_conf);
370
371 break;
372 default:
373 break;
374 }
375}
376
377static 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 ant_conf->main_gaintb = 0;
382 ant_conf->alt_gaintb = 0;
383
384 if (ant_conf->div_group == 0) {
385
386 switch ((ant_conf->main_lna_conf << 4) |
387 ant_conf->alt_lna_conf) {
388 case 0x01:
389 ant_conf->fast_div_bias = 0x3b;
390 break;
391 case 0x02:
392 ant_conf->fast_div_bias = 0x3d;
393 break;
394 case 0x03:
395 ant_conf->fast_div_bias = 0x1;
396 break;
397 case 0x10:
398 ant_conf->fast_div_bias = 0x7;
399 break;
400 case 0x12:
401 ant_conf->fast_div_bias = 0x2;
402 break;
403 case 0x13:
404 ant_conf->fast_div_bias = 0x7;
405 break;
406 case 0x20:
407 ant_conf->fast_div_bias = 0x6;
408 break;
409 case 0x21:
410 ant_conf->fast_div_bias = 0x0;
411 break;
412 case 0x23:
413 ant_conf->fast_div_bias = 0x6;
414 break;
415 case 0x30:
416 ant_conf->fast_div_bias = 0x1;
417 break;
418 case 0x31:
419 ant_conf->fast_div_bias = 0x3b;
420 break;
421 case 0x32:
422 ant_conf->fast_div_bias = 0x3d;
423 break;
424 default:
425 break;
426 }
427 } else if (ant_conf->div_group == 1) {
428
429 switch ((ant_conf->main_lna_conf << 4) |
430 ant_conf->alt_lna_conf) {
431 case 0x01:
432 ant_conf->fast_div_bias = 0x1;
433 break;
434 case 0x02:
435 ant_conf->fast_div_bias = 0x1;
436 break;
437 case 0x03:
438 ant_conf->fast_div_bias = 0x1;
439 break;
440 case 0x10:
441 if (!(antcomb->scan) &&
442 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
443 ant_conf->fast_div_bias = 0x3f;
444 else
445 ant_conf->fast_div_bias = 0x1;
446 break;
447 case 0x12:
448 ant_conf->fast_div_bias = 0x1;
449 break;
450 case 0x13:
451 if (!(antcomb->scan) &&
452 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
453 ant_conf->fast_div_bias = 0x3f;
454 else
455 ant_conf->fast_div_bias = 0x1;
456 break;
457 case 0x20:
458 if (!(antcomb->scan) &&
459 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
460 ant_conf->fast_div_bias = 0x3f;
461 else
462 ant_conf->fast_div_bias = 0x1;
463 break;
464 case 0x21:
465 ant_conf->fast_div_bias = 0x1;
466 break;
467 case 0x23:
468 if (!(antcomb->scan) &&
469 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
470 ant_conf->fast_div_bias = 0x3f;
471 else
472 ant_conf->fast_div_bias = 0x1;
473 break;
474 case 0x30:
475 ant_conf->fast_div_bias = 0x1;
476 break;
477 case 0x31:
478 ant_conf->fast_div_bias = 0x1;
479 break;
480 case 0x32:
481 ant_conf->fast_div_bias = 0x1;
482 break;
483 default:
484 break;
485 }
486 } else if (ant_conf->div_group == 2) {
487
488 switch ((ant_conf->main_lna_conf << 4) |
489 ant_conf->alt_lna_conf) {
490 case 0x01:
491 ant_conf->fast_div_bias = 0x1;
492 break;
493 case 0x02:
494 ant_conf->fast_div_bias = 0x1;
495 break;
496 case 0x03:
497 ant_conf->fast_div_bias = 0x1;
498 break;
499 case 0x10:
500 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
501 ant_conf->fast_div_bias = 0x1;
502 else
503 ant_conf->fast_div_bias = 0x2;
504 break;
505 case 0x12:
506 ant_conf->fast_div_bias = 0x1;
507 break;
508 case 0x13:
509 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
510 ant_conf->fast_div_bias = 0x1;
511 else
512 ant_conf->fast_div_bias = 0x2;
513 break;
514 case 0x20:
515 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
516 ant_conf->fast_div_bias = 0x1;
517 else
518 ant_conf->fast_div_bias = 0x2;
519 break;
520 case 0x21:
521 ant_conf->fast_div_bias = 0x1;
522 break;
523 case 0x23:
524 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
525 ant_conf->fast_div_bias = 0x1;
526 else
527 ant_conf->fast_div_bias = 0x2;
528 break;
529 case 0x30:
530 ant_conf->fast_div_bias = 0x1;
531 break;
532 case 0x31:
533 ant_conf->fast_div_bias = 0x1;
534 break;
535 case 0x32:
536 ant_conf->fast_div_bias = 0x1;
537 break;
538 default:
539 break;
540 }
541
542 if (antcomb->fast_div_bias)
543 ant_conf->fast_div_bias = antcomb->fast_div_bias;
544 } else if (ant_conf->div_group == 3) {
545 switch ((ant_conf->main_lna_conf << 4) |
546 ant_conf->alt_lna_conf) {
547 case 0x01:
548 ant_conf->fast_div_bias = 0x1;
549 break;
550 case 0x02:
551 ant_conf->fast_div_bias = 0x39;
552 break;
553 case 0x03:
554 ant_conf->fast_div_bias = 0x1;
555 break;
556 case 0x10:
557 if ((antcomb->scan == 0) &&
558 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
559 ant_conf->fast_div_bias = 0x3f;
560 } else {
561 ant_conf->fast_div_bias = 0x1;
562 }
563 break;
564 case 0x12:
565 ant_conf->fast_div_bias = 0x39;
566 break;
567 case 0x13:
568 if ((antcomb->scan == 0) &&
569 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
570 ant_conf->fast_div_bias = 0x3f;
571 } else {
572 ant_conf->fast_div_bias = 0x1;
573 }
574 break;
575 case 0x20:
576 if ((antcomb->scan == 0) &&
577 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
578 ant_conf->fast_div_bias = 0x3f;
579 } else {
580 ant_conf->fast_div_bias = 0x4;
581 }
582 break;
583 case 0x21:
584 ant_conf->fast_div_bias = 0x6;
585 break;
586 case 0x23:
587 if ((antcomb->scan == 0) &&
588 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
589 ant_conf->fast_div_bias = 0x3f;
590 } else {
591 ant_conf->fast_div_bias = 0x6;
592 }
593 break;
594 case 0x30:
595 ant_conf->fast_div_bias = 0x1;
596 break;
597 case 0x31:
598 ant_conf->fast_div_bias = 0x6;
599 break;
600 case 0x32:
601 ant_conf->fast_div_bias = 0x1;
602 break;
603 default:
604 break;
605 }
606 }
607}
608
609static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
610 struct ath_hw_antcomb_conf *conf,
611 int curr_alt_set, int alt_rssi_avg,
612 int main_rssi_avg)
613{
614 switch (curr_alt_set) {
615 case ATH_ANT_DIV_COMB_LNA2:
616 antcomb->rssi_lna2 = alt_rssi_avg;
617 antcomb->rssi_lna1 = main_rssi_avg;
618 antcomb->scan = true;
619
620 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
621 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
622 break;
623 case ATH_ANT_DIV_COMB_LNA1:
624 antcomb->rssi_lna1 = alt_rssi_avg;
625 antcomb->rssi_lna2 = main_rssi_avg;
626 antcomb->scan = true;
627
628 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
629 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
630 break;
631 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
632 antcomb->rssi_add = alt_rssi_avg;
633 antcomb->scan = true;
634
635 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
636 break;
637 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
638 antcomb->rssi_sub = alt_rssi_avg;
639 antcomb->scan = false;
640 if (antcomb->rssi_lna2 >
641 (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
642
643 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
644 (antcomb->rssi_add > antcomb->rssi_sub)) {
645
646 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
647 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
648 } else if (antcomb->rssi_sub >
649 antcomb->rssi_lna1) {
650
651 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
652 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
653 } else {
654
655 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
656 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
657 }
658 } else {
659
660 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
661 (antcomb->rssi_add > antcomb->rssi_sub)) {
662
663 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
664 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
665 } else if (antcomb->rssi_sub >
666 antcomb->rssi_lna1) {
667
668 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
669 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
670 } else {
671
672 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
673 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
674 }
675 }
676 break;
677 default:
678 break;
679 }
680}
681
682static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
683 struct ath_ant_comb *antcomb,
684 int alt_ratio, int alt_rssi_avg,
685 int main_rssi_avg, int curr_main_set,
686 int curr_alt_set)
687{
688 bool ret = false;
689
690 if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
691 alt_rssi_avg, main_rssi_avg)) {
692 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
693
694
695
696 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
697 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
698 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
699 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
700 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
701 }
702
703 ret = true;
704 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
705 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
706
707
708
709 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
710 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
711 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
712 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
713
714 ret = true;
715 }
716
717 return ret;
718}
719
720static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
721{
722 int alt_ratio;
723
724 if (!antcomb->scan || !antcomb->alt_good)
725 return false;
726
727 if (time_after(jiffies, antcomb->scan_start_time +
728 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
729 return true;
730
731 if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
732 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
733 antcomb->total_pkt_count);
734 if (alt_ratio < antcomb->ant_ratio)
735 return true;
736 }
737
738 return false;
739}
740
741void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
742{
743 struct ath_hw_antcomb_conf div_ant_conf;
744 struct ath_ant_comb *antcomb = &sc->ant_comb;
745 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
746 int curr_main_set;
747 int main_rssi = rs->rs_rssi_ctl0;
748 int alt_rssi = rs->rs_rssi_ctl1;
749 int rx_ant_conf, main_ant_conf;
750 bool short_scan = false, ret;
751
752 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
753 ATH_ANT_RX_MASK;
754 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
755 ATH_ANT_RX_MASK;
756
757 if (alt_rssi >= antcomb->low_rssi_thresh) {
758 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
759 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
760 } else {
761 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
762 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
763 }
764
765
766 if (main_rssi > 0 && alt_rssi > 0) {
767 antcomb->total_pkt_count++;
768 antcomb->main_total_rssi += main_rssi;
769 antcomb->alt_total_rssi += alt_rssi;
770
771 if (main_ant_conf == rx_ant_conf)
772 antcomb->main_recv_cnt++;
773 else
774 antcomb->alt_recv_cnt++;
775 }
776
777 if (main_ant_conf == rx_ant_conf) {
778 ANT_STAT_INC(ANT_MAIN, recv_cnt);
779 ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
780 } else {
781 ANT_STAT_INC(ANT_ALT, recv_cnt);
782 ANT_LNA_INC(ANT_ALT, rx_ant_conf);
783 }
784
785
786 short_scan = ath_ant_short_scan_check(antcomb);
787
788 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
789 rs->rs_moreaggr) && !short_scan)
790 return;
791
792 if (antcomb->total_pkt_count) {
793 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
794 antcomb->total_pkt_count);
795 main_rssi_avg = (antcomb->main_total_rssi /
796 antcomb->total_pkt_count);
797 alt_rssi_avg = (antcomb->alt_total_rssi /
798 antcomb->total_pkt_count);
799 }
800
801 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
802 curr_alt_set = div_ant_conf.alt_lna_conf;
803 curr_main_set = div_ant_conf.main_lna_conf;
804 antcomb->count++;
805
806 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
807 if (alt_ratio > antcomb->ant_ratio) {
808 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
809 main_rssi_avg);
810 antcomb->alt_good = true;
811 } else {
812 antcomb->alt_good = false;
813 }
814
815 antcomb->count = 0;
816 antcomb->scan = true;
817 antcomb->scan_not_start = true;
818 }
819
820 if (!antcomb->scan) {
821 ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
822 alt_rssi_avg, main_rssi_avg,
823 curr_main_set, curr_alt_set);
824 if (ret)
825 goto div_comb_done;
826 }
827
828 if (!antcomb->scan &&
829 (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
830 goto div_comb_done;
831
832 if (!antcomb->scan_not_start) {
833 ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
834 alt_rssi_avg, main_rssi_avg);
835 } else {
836 if (!antcomb->alt_good) {
837 antcomb->scan_not_start = false;
838
839 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
840 div_ant_conf.main_lna_conf =
841 ATH_ANT_DIV_COMB_LNA2;
842 div_ant_conf.alt_lna_conf =
843 ATH_ANT_DIV_COMB_LNA1;
844 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
845 div_ant_conf.main_lna_conf =
846 ATH_ANT_DIV_COMB_LNA1;
847 div_ant_conf.alt_lna_conf =
848 ATH_ANT_DIV_COMB_LNA2;
849 }
850 goto div_comb_done;
851 }
852 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
853 main_rssi_avg, alt_rssi_avg,
854 alt_ratio);
855 antcomb->quick_scan_cnt++;
856 }
857
858div_comb_done:
859 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
860 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
861 ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
862
863 antcomb->scan_start_time = jiffies;
864 antcomb->total_pkt_count = 0;
865 antcomb->main_total_rssi = 0;
866 antcomb->alt_total_rssi = 0;
867 antcomb->main_recv_cnt = 0;
868 antcomb->alt_recv_cnt = 0;
869}
870