2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 static 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)
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);
28 static 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)
35 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
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)))) &&
56 static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
57 struct ath_hw_antcomb_conf ant_conf,
60 antcomb->quick_scan_cnt = 0;
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;
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;
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;
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;
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;
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;
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;
111 static 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,
117 switch (antcomb->quick_scan_cnt) {
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;
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;
130 if (antcomb->main_conf == ATH_ANT_DIV_COMB_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;
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;
148 antcomb->first_ratio = false;
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;
157 antcomb->first_ratio = false;
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;
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;
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;
184 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
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;
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;
203 antcomb->second_ratio = false;
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;
212 antcomb->second_ratio = false;
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) {
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;
229 div_ant_conf->alt_lna_conf =
230 ATH_ANT_DIV_COMB_LNA2;
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;
245 div_ant_conf->alt_lna_conf =
246 ATH_ANT_DIV_COMB_LNA2;
248 /* Set alt to A+B or A-B */
249 div_ant_conf->alt_lna_conf =
250 antcomb->second_quick_scan_conf;
252 } else if (antcomb->first_ratio) {
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;
264 div_ant_conf->alt_lna_conf =
265 ATH_ANT_DIV_COMB_LNA2;
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) {
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;
282 div_ant_conf->alt_lna_conf =
283 ATH_ANT_DIV_COMB_LNA2;
285 /* Set alt to A+B or A-B */
286 div_ant_conf->alt_lna_conf =
287 antcomb->second_quick_scan_conf;
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;
298 div_ant_conf->alt_lna_conf =
299 ATH_ANT_DIV_COMB_LNA2;
301 /* Set alt to A+B or A-B */
302 div_ant_conf->alt_lna_conf = antcomb->main_conf;
310 static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
311 struct ath_ant_comb *antcomb,
314 ant_conf->main_gaintb = 0;
315 ant_conf->alt_gaintb = 0;
317 if (ant_conf->div_group == 0) {
318 /* Adjust the fast_div_bias based on main and alt lna conf */
319 switch ((ant_conf->main_lna_conf << 4) |
320 ant_conf->alt_lna_conf) {
321 case 0x01: /* A-B LNA2 */
322 ant_conf->fast_div_bias = 0x3b;
324 case 0x02: /* A-B LNA1 */
325 ant_conf->fast_div_bias = 0x3d;
327 case 0x03: /* A-B A+B */
328 ant_conf->fast_div_bias = 0x1;
330 case 0x10: /* LNA2 A-B */
331 ant_conf->fast_div_bias = 0x7;
333 case 0x12: /* LNA2 LNA1 */
334 ant_conf->fast_div_bias = 0x2;
336 case 0x13: /* LNA2 A+B */
337 ant_conf->fast_div_bias = 0x7;
339 case 0x20: /* LNA1 A-B */
340 ant_conf->fast_div_bias = 0x6;
342 case 0x21: /* LNA1 LNA2 */
343 ant_conf->fast_div_bias = 0x0;
345 case 0x23: /* LNA1 A+B */
346 ant_conf->fast_div_bias = 0x6;
348 case 0x30: /* A+B A-B */
349 ant_conf->fast_div_bias = 0x1;
351 case 0x31: /* A+B LNA2 */
352 ant_conf->fast_div_bias = 0x3b;
354 case 0x32: /* A+B LNA1 */
355 ant_conf->fast_div_bias = 0x3d;
360 } else if (ant_conf->div_group == 1) {
361 /* Adjust the fast_div_bias based on main and alt_lna_conf */
362 switch ((ant_conf->main_lna_conf << 4) |
363 ant_conf->alt_lna_conf) {
364 case 0x01: /* A-B LNA2 */
365 ant_conf->fast_div_bias = 0x1;
367 case 0x02: /* A-B LNA1 */
368 ant_conf->fast_div_bias = 0x1;
370 case 0x03: /* A-B A+B */
371 ant_conf->fast_div_bias = 0x1;
373 case 0x10: /* LNA2 A-B */
374 if (!(antcomb->scan) &&
375 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
376 ant_conf->fast_div_bias = 0x3f;
378 ant_conf->fast_div_bias = 0x1;
380 case 0x12: /* LNA2 LNA1 */
381 ant_conf->fast_div_bias = 0x1;
383 case 0x13: /* LNA2 A+B */
384 if (!(antcomb->scan) &&
385 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
386 ant_conf->fast_div_bias = 0x3f;
388 ant_conf->fast_div_bias = 0x1;
390 case 0x20: /* LNA1 A-B */
391 if (!(antcomb->scan) &&
392 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
393 ant_conf->fast_div_bias = 0x3f;
395 ant_conf->fast_div_bias = 0x1;
397 case 0x21: /* LNA1 LNA2 */
398 ant_conf->fast_div_bias = 0x1;
400 case 0x23: /* LNA1 A+B */
401 if (!(antcomb->scan) &&
402 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
403 ant_conf->fast_div_bias = 0x3f;
405 ant_conf->fast_div_bias = 0x1;
407 case 0x30: /* A+B A-B */
408 ant_conf->fast_div_bias = 0x1;
410 case 0x31: /* A+B LNA2 */
411 ant_conf->fast_div_bias = 0x1;
413 case 0x32: /* A+B LNA1 */
414 ant_conf->fast_div_bias = 0x1;
419 } else if (ant_conf->div_group == 2) {
420 /* Adjust the fast_div_bias based on main and alt_lna_conf */
421 switch ((ant_conf->main_lna_conf << 4) |
422 ant_conf->alt_lna_conf) {
423 case 0x01: /* A-B LNA2 */
424 ant_conf->fast_div_bias = 0x1;
426 case 0x02: /* A-B LNA1 */
427 ant_conf->fast_div_bias = 0x1;
429 case 0x03: /* A-B A+B */
430 ant_conf->fast_div_bias = 0x1;
432 case 0x10: /* LNA2 A-B */
433 if (!(antcomb->scan) &&
434 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
435 ant_conf->fast_div_bias = 0x1;
437 ant_conf->fast_div_bias = 0x2;
439 case 0x12: /* LNA2 LNA1 */
440 ant_conf->fast_div_bias = 0x1;
442 case 0x13: /* LNA2 A+B */
443 if (!(antcomb->scan) &&
444 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
445 ant_conf->fast_div_bias = 0x1;
447 ant_conf->fast_div_bias = 0x2;
449 case 0x20: /* LNA1 A-B */
450 if (!(antcomb->scan) &&
451 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
452 ant_conf->fast_div_bias = 0x1;
454 ant_conf->fast_div_bias = 0x2;
456 case 0x21: /* LNA1 LNA2 */
457 ant_conf->fast_div_bias = 0x1;
459 case 0x23: /* LNA1 A+B */
460 if (!(antcomb->scan) &&
461 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
462 ant_conf->fast_div_bias = 0x1;
464 ant_conf->fast_div_bias = 0x2;
466 case 0x30: /* A+B A-B */
467 ant_conf->fast_div_bias = 0x1;
469 case 0x31: /* A+B LNA2 */
470 ant_conf->fast_div_bias = 0x1;
472 case 0x32: /* A+B LNA1 */
473 ant_conf->fast_div_bias = 0x1;
478 } else if (ant_conf->div_group == 3) {
479 switch ((ant_conf->main_lna_conf << 4) |
480 ant_conf->alt_lna_conf) {
481 case 0x01: /* A-B LNA2 */
482 ant_conf->fast_div_bias = 0x1;
484 case 0x02: /* A-B LNA1 */
485 ant_conf->fast_div_bias = 0x39;
487 case 0x03: /* A-B A+B */
488 ant_conf->fast_div_bias = 0x1;
490 case 0x10: /* LNA2 A-B */
491 if ((antcomb->scan == 0) &&
492 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
493 ant_conf->fast_div_bias = 0x3f;
495 ant_conf->fast_div_bias = 0x1;
498 case 0x12: /* LNA2 LNA1 */
499 ant_conf->fast_div_bias = 0x39;
501 case 0x13: /* LNA2 A+B */
502 if ((antcomb->scan == 0) &&
503 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
504 ant_conf->fast_div_bias = 0x3f;
506 ant_conf->fast_div_bias = 0x1;
509 case 0x20: /* LNA1 A-B */
510 if ((antcomb->scan == 0) &&
511 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
512 ant_conf->fast_div_bias = 0x3f;
514 ant_conf->fast_div_bias = 0x4;
517 case 0x21: /* LNA1 LNA2 */
518 ant_conf->fast_div_bias = 0x6;
520 case 0x23: /* LNA1 A+B */
521 if ((antcomb->scan == 0) &&
522 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
523 ant_conf->fast_div_bias = 0x3f;
525 ant_conf->fast_div_bias = 0x6;
528 case 0x30: /* A+B A-B */
529 ant_conf->fast_div_bias = 0x1;
531 case 0x31: /* A+B LNA2 */
532 ant_conf->fast_div_bias = 0x6;
534 case 0x32: /* A+B LNA1 */
535 ant_conf->fast_div_bias = 0x1;
543 static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
547 if (!antcomb->scan || !antcomb->alt_good)
550 if (time_after(jiffies, antcomb->scan_start_time +
551 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
554 if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
555 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
556 antcomb->total_pkt_count);
557 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
564 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
566 struct ath_hw_antcomb_conf div_ant_conf;
567 struct ath_ant_comb *antcomb = &sc->ant_comb;
568 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
570 int main_rssi = rs->rs_rssi_ctl0;
571 int alt_rssi = rs->rs_rssi_ctl1;
572 int rx_ant_conf, main_ant_conf;
573 bool short_scan = false;
575 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
577 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
580 /* Record packet only when both main_rssi and alt_rssi is positive */
581 if (main_rssi > 0 && alt_rssi > 0) {
582 antcomb->total_pkt_count++;
583 antcomb->main_total_rssi += main_rssi;
584 antcomb->alt_total_rssi += alt_rssi;
586 if (main_ant_conf == rx_ant_conf) {
587 antcomb->main_recv_cnt++;
588 ANT_STAT_INC(ANT_MAIN, recv_cnt);
589 ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
591 antcomb->alt_recv_cnt++;
592 ANT_STAT_INC(ANT_ALT, recv_cnt);
593 ANT_LNA_INC(ANT_ALT, rx_ant_conf);
597 /* Short scan check */
598 short_scan = ath_ant_short_scan_check(antcomb);
600 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
601 rs->rs_moreaggr) && !short_scan)
604 if (antcomb->total_pkt_count) {
605 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
606 antcomb->total_pkt_count);
607 main_rssi_avg = (antcomb->main_total_rssi /
608 antcomb->total_pkt_count);
609 alt_rssi_avg = (antcomb->alt_total_rssi /
610 antcomb->total_pkt_count);
614 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
615 curr_alt_set = div_ant_conf.alt_lna_conf;
616 curr_main_set = div_ant_conf.main_lna_conf;
620 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
621 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
622 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
624 antcomb->alt_good = true;
626 antcomb->alt_good = false;
630 antcomb->scan = true;
631 antcomb->scan_not_start = true;
634 if (!antcomb->scan) {
635 if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
636 alt_ratio, curr_main_set, curr_alt_set,
637 alt_rssi_avg, main_rssi_avg)) {
638 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
639 /* Switch main and alt LNA */
640 div_ant_conf.main_lna_conf =
641 ATH_ANT_DIV_COMB_LNA2;
642 div_ant_conf.alt_lna_conf =
643 ATH_ANT_DIV_COMB_LNA1;
644 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
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_LNA2;
652 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
653 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
654 /* Set alt to another LNA */
655 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
656 div_ant_conf.alt_lna_conf =
657 ATH_ANT_DIV_COMB_LNA1;
658 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
659 div_ant_conf.alt_lna_conf =
660 ATH_ANT_DIV_COMB_LNA2;
665 if ((alt_rssi_avg < (main_rssi_avg +
666 div_ant_conf.lna1_lna2_delta)))
670 if (!antcomb->scan_not_start) {
671 switch (curr_alt_set) {
672 case ATH_ANT_DIV_COMB_LNA2:
673 antcomb->rssi_lna2 = alt_rssi_avg;
674 antcomb->rssi_lna1 = main_rssi_avg;
675 antcomb->scan = true;
677 div_ant_conf.main_lna_conf =
678 ATH_ANT_DIV_COMB_LNA1;
679 div_ant_conf.alt_lna_conf =
680 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
682 case ATH_ANT_DIV_COMB_LNA1:
683 antcomb->rssi_lna1 = alt_rssi_avg;
684 antcomb->rssi_lna2 = main_rssi_avg;
685 antcomb->scan = true;
687 div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
688 div_ant_conf.alt_lna_conf =
689 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
691 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
692 antcomb->rssi_add = alt_rssi_avg;
693 antcomb->scan = true;
695 div_ant_conf.alt_lna_conf =
696 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
698 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
699 antcomb->rssi_sub = alt_rssi_avg;
700 antcomb->scan = false;
701 if (antcomb->rssi_lna2 >
702 (antcomb->rssi_lna1 +
703 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
704 /* use LNA2 as main LNA */
705 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
706 (antcomb->rssi_add > antcomb->rssi_sub)) {
708 div_ant_conf.main_lna_conf =
709 ATH_ANT_DIV_COMB_LNA2;
710 div_ant_conf.alt_lna_conf =
711 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
712 } else if (antcomb->rssi_sub >
713 antcomb->rssi_lna1) {
715 div_ant_conf.main_lna_conf =
716 ATH_ANT_DIV_COMB_LNA2;
717 div_ant_conf.alt_lna_conf =
718 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
721 div_ant_conf.main_lna_conf =
722 ATH_ANT_DIV_COMB_LNA2;
723 div_ant_conf.alt_lna_conf =
724 ATH_ANT_DIV_COMB_LNA1;
727 /* use LNA1 as main LNA */
728 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
729 (antcomb->rssi_add > antcomb->rssi_sub)) {
731 div_ant_conf.main_lna_conf =
732 ATH_ANT_DIV_COMB_LNA1;
733 div_ant_conf.alt_lna_conf =
734 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
735 } else if (antcomb->rssi_sub >
736 antcomb->rssi_lna1) {
738 div_ant_conf.main_lna_conf =
739 ATH_ANT_DIV_COMB_LNA1;
740 div_ant_conf.alt_lna_conf =
741 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
744 div_ant_conf.main_lna_conf =
745 ATH_ANT_DIV_COMB_LNA1;
746 div_ant_conf.alt_lna_conf =
747 ATH_ANT_DIV_COMB_LNA2;
755 if (!antcomb->alt_good) {
756 antcomb->scan_not_start = false;
757 /* Set alt to another LNA */
758 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
759 div_ant_conf.main_lna_conf =
760 ATH_ANT_DIV_COMB_LNA2;
761 div_ant_conf.alt_lna_conf =
762 ATH_ANT_DIV_COMB_LNA1;
763 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
764 div_ant_conf.main_lna_conf =
765 ATH_ANT_DIV_COMB_LNA1;
766 div_ant_conf.alt_lna_conf =
767 ATH_ANT_DIV_COMB_LNA2;
771 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
772 main_rssi_avg, alt_rssi_avg,
774 antcomb->quick_scan_cnt++;
778 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
779 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
781 antcomb->scan_start_time = jiffies;
782 antcomb->total_pkt_count = 0;
783 antcomb->main_total_rssi = 0;
784 antcomb->alt_total_rssi = 0;
785 antcomb->main_recv_cnt = 0;
786 antcomb->alt_recv_cnt = 0;
789 void ath_ant_comb_update(struct ath_softc *sc)
791 struct ath_hw *ah = sc->sc_ah;
792 struct ath_common *common = ath9k_hw_common(ah);
793 struct ath_hw_antcomb_conf div_ant_conf;
796 ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
799 lna_conf = ATH_ANT_DIV_COMB_LNA1;
801 lna_conf = ATH_ANT_DIV_COMB_LNA2;
803 div_ant_conf.main_lna_conf = lna_conf;
804 div_ant_conf.alt_lna_conf = lna_conf;
806 ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf);
808 if (common->antenna_diversity)
809 ath9k_hw_antctrl_shared_chain_lnadiv(ah, true);