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 div_ant_conf->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 ant_conf->fast_div_bias = 0x2;
558 break;
559 case 0x12:
560 ant_conf->fast_div_bias = 0x3f;
561 break;
562 case 0x13:
563 ant_conf->fast_div_bias = 0x2;
564 break;
565 case 0x20:
566 ant_conf->fast_div_bias = 0x3;
567 break;
568 case 0x21:
569 ant_conf->fast_div_bias = 0x3;
570 break;
571 case 0x23:
572 ant_conf->fast_div_bias = 0x3;
573 break;
574 case 0x30:
575 ant_conf->fast_div_bias = 0x1;
576 break;
577 case 0x31:
578 ant_conf->fast_div_bias = 0x6;
579 break;
580 case 0x32:
581 ant_conf->fast_div_bias = 0x1;
582 break;
583 default:
584 break;
585 }
586 }
587}
588
589static 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 switch (curr_alt_set) {
595 case ATH_ANT_DIV_COMB_LNA2:
596 antcomb->rssi_lna2 = alt_rssi_avg;
597 antcomb->rssi_lna1 = main_rssi_avg;
598 antcomb->scan = true;
599
600 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
601 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
602 break;
603 case ATH_ANT_DIV_COMB_LNA1:
604 antcomb->rssi_lna1 = alt_rssi_avg;
605 antcomb->rssi_lna2 = main_rssi_avg;
606 antcomb->scan = true;
607
608 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
609 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
610 break;
611 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
612 antcomb->rssi_add = alt_rssi_avg;
613 antcomb->scan = true;
614
615 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
616 break;
617 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
618 antcomb->rssi_sub = alt_rssi_avg;
619 antcomb->scan = false;
620 if (antcomb->rssi_lna2 >
621 (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
622
623 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
624 (antcomb->rssi_add > antcomb->rssi_sub)) {
625
626 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
627 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
628 } else if (antcomb->rssi_sub >
629 antcomb->rssi_lna1) {
630
631 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
632 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
633 } else {
634
635 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
636 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
637 }
638 } else {
639
640 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
641 (antcomb->rssi_add > antcomb->rssi_sub)) {
642
643 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
644 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
645 } else if (antcomb->rssi_sub >
646 antcomb->rssi_lna1) {
647
648 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
649 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
650 } else {
651
652 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
653 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
654 }
655 }
656 break;
657 default:
658 break;
659 }
660}
661
662static 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 bool ret = false;
669
670 if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
671 alt_rssi_avg, main_rssi_avg)) {
672 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
673
674
675
676 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
677 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
678 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
679 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
680 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
681 }
682
683 ret = true;
684 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
685 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
686
687
688
689 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
690 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
691 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
692 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
693
694 ret = true;
695 }
696
697 return ret;
698}
699
700static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
701{
702 int alt_ratio;
703
704 if (!antcomb->scan || !antcomb->alt_good)
705 return false;
706
707 if (time_after(jiffies, antcomb->scan_start_time +
708 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
709 return true;
710
711 if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
712 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
713 antcomb->total_pkt_count);
714 if (alt_ratio < antcomb->ant_ratio)
715 return true;
716 }
717
718 return false;
719}
720
721void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
722{
723 struct ath_hw_antcomb_conf div_ant_conf;
724 struct ath_ant_comb *antcomb = &sc->ant_comb;
725 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
726 int curr_main_set;
727 int main_rssi = rs->rs_rssi_ctl[0];
728 int alt_rssi = rs->rs_rssi_ctl[1];
729 int rx_ant_conf, main_ant_conf;
730 bool short_scan = false, ret;
731
732 rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
733 ATH_ANT_RX_MASK;
734 main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
735 ATH_ANT_RX_MASK;
736
737 if (alt_rssi >= antcomb->low_rssi_thresh) {
738 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
739 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
740 } else {
741 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
742 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
743 }
744
745
746 if (main_rssi > 0 && alt_rssi > 0) {
747 antcomb->total_pkt_count++;
748 antcomb->main_total_rssi += main_rssi;
749 antcomb->alt_total_rssi += alt_rssi;
750
751 if (main_ant_conf == rx_ant_conf)
752 antcomb->main_recv_cnt++;
753 else
754 antcomb->alt_recv_cnt++;
755 }
756
757 if (main_ant_conf == rx_ant_conf) {
758 ANT_STAT_INC(ANT_MAIN, recv_cnt);
759 ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
760 } else {
761 ANT_STAT_INC(ANT_ALT, recv_cnt);
762 ANT_LNA_INC(ANT_ALT, rx_ant_conf);
763 }
764
765
766 short_scan = ath_ant_short_scan_check(antcomb);
767
768 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
769 rs->rs_moreaggr) && !short_scan)
770 return;
771
772 if (antcomb->total_pkt_count) {
773 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
774 antcomb->total_pkt_count);
775 main_rssi_avg = (antcomb->main_total_rssi /
776 antcomb->total_pkt_count);
777 alt_rssi_avg = (antcomb->alt_total_rssi /
778 antcomb->total_pkt_count);
779 }
780
781 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
782 curr_alt_set = div_ant_conf.alt_lna_conf;
783 curr_main_set = div_ant_conf.main_lna_conf;
784 antcomb->count++;
785
786 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
787 if (alt_ratio > antcomb->ant_ratio) {
788 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
789 main_rssi_avg);
790 antcomb->alt_good = true;
791 } else {
792 antcomb->alt_good = false;
793 }
794
795 antcomb->count = 0;
796 antcomb->scan = true;
797 antcomb->scan_not_start = true;
798 }
799
800 if (!antcomb->scan) {
801 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 if (ret)
805 goto div_comb_done;
806 }
807
808 if (!antcomb->scan &&
809 (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
810 goto div_comb_done;
811
812 if (!antcomb->scan_not_start) {
813 ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
814 alt_rssi_avg, main_rssi_avg);
815 } else {
816 if (!antcomb->alt_good) {
817 antcomb->scan_not_start = false;
818
819 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
820 div_ant_conf.main_lna_conf =
821 ATH_ANT_DIV_COMB_LNA2;
822 div_ant_conf.alt_lna_conf =
823 ATH_ANT_DIV_COMB_LNA1;
824 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
825 div_ant_conf.main_lna_conf =
826 ATH_ANT_DIV_COMB_LNA1;
827 div_ant_conf.alt_lna_conf =
828 ATH_ANT_DIV_COMB_LNA2;
829 }
830 goto div_comb_done;
831 }
832 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
833 main_rssi_avg, alt_rssi_avg,
834 alt_ratio);
835 antcomb->quick_scan_cnt++;
836 }
837
838div_comb_done:
839 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
840 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
841 ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
842
843 antcomb->scan_start_time = jiffies;
844 antcomb->total_pkt_count = 0;
845 antcomb->main_total_rssi = 0;
846 antcomb->alt_total_rssi = 0;
847 antcomb->main_recv_cnt = 0;
848 antcomb->alt_recv_cnt = 0;
849}
850