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 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;
321 case 0x02: /* A-B LNA1 */
322 ant_conf
->fast_div_bias
= 0x3d;
324 case 0x03: /* A-B A+B */
325 ant_conf
->fast_div_bias
= 0x1;
327 case 0x10: /* LNA2 A-B */
328 ant_conf
->fast_div_bias
= 0x7;
330 case 0x12: /* LNA2 LNA1 */
331 ant_conf
->fast_div_bias
= 0x2;
333 case 0x13: /* LNA2 A+B */
334 ant_conf
->fast_div_bias
= 0x7;
336 case 0x20: /* LNA1 A-B */
337 ant_conf
->fast_div_bias
= 0x6;
339 case 0x21: /* LNA1 LNA2 */
340 ant_conf
->fast_div_bias
= 0x0;
342 case 0x23: /* LNA1 A+B */
343 ant_conf
->fast_div_bias
= 0x6;
345 case 0x30: /* A+B A-B */
346 ant_conf
->fast_div_bias
= 0x1;
348 case 0x31: /* A+B LNA2 */
349 ant_conf
->fast_div_bias
= 0x3b;
351 case 0x32: /* A+B LNA1 */
352 ant_conf
->fast_div_bias
= 0x3d;
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;
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;
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;
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;
381 ant_conf
->fast_div_bias
= 0x1;
382 ant_conf
->main_gaintb
= 0;
383 ant_conf
->alt_gaintb
= 0;
385 case 0x12: /* LNA2 LNA1 */
386 ant_conf
->fast_div_bias
= 0x1;
387 ant_conf
->main_gaintb
= 0;
388 ant_conf
->alt_gaintb
= 0;
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;
395 ant_conf
->fast_div_bias
= 0x1;
396 ant_conf
->main_gaintb
= 0;
397 ant_conf
->alt_gaintb
= 0;
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;
404 ant_conf
->fast_div_bias
= 0x1;
405 ant_conf
->main_gaintb
= 0;
406 ant_conf
->alt_gaintb
= 0;
408 case 0x21: /* LNA1 LNA2 */
409 ant_conf
->fast_div_bias
= 0x1;
410 ant_conf
->main_gaintb
= 0;
411 ant_conf
->alt_gaintb
= 0;
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;
418 ant_conf
->fast_div_bias
= 0x1;
419 ant_conf
->main_gaintb
= 0;
420 ant_conf
->alt_gaintb
= 0;
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;
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;
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;
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;
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;
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;
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;
464 ant_conf
->fast_div_bias
= 0x2;
465 ant_conf
->main_gaintb
= 0;
466 ant_conf
->alt_gaintb
= 0;
468 case 0x12: /* LNA2 LNA1 */
469 ant_conf
->fast_div_bias
= 0x1;
470 ant_conf
->main_gaintb
= 0;
471 ant_conf
->alt_gaintb
= 0;
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;
478 ant_conf
->fast_div_bias
= 0x2;
479 ant_conf
->main_gaintb
= 0;
480 ant_conf
->alt_gaintb
= 0;
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;
487 ant_conf
->fast_div_bias
= 0x2;
488 ant_conf
->main_gaintb
= 0;
489 ant_conf
->alt_gaintb
= 0;
491 case 0x21: /* LNA1 LNA2 */
492 ant_conf
->fast_div_bias
= 0x1;
493 ant_conf
->main_gaintb
= 0;
494 ant_conf
->alt_gaintb
= 0;
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;
501 ant_conf
->fast_div_bias
= 0x2;
502 ant_conf
->main_gaintb
= 0;
503 ant_conf
->alt_gaintb
= 0;
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;
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;
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;
526 void ath_ant_comb_scan(struct ath_softc
*sc
, struct ath_rx_status
*rs
)
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
;
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;
537 rx_ant_conf
= (rs
->rs_rssi_ctl2
>> ATH_ANT_RX_CURRENT_SHIFT
) &
539 main_ant_conf
= (rs
->rs_rssi_ctl2
>> ATH_ANT_RX_MAIN_SHIFT
) &
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
++;
550 antcomb
->alt_recv_cnt
++;
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
)))
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
)
568 if (((antcomb
->total_pkt_count
< ATH_ANT_DIV_COMB_MAX_PKTCOUNT
) ||
569 rs
->rs_moreaggr
) && !short_scan
)
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
);
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
;
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
,
592 antcomb
->alt_good
= true;
594 antcomb
->alt_good
= false;
598 antcomb
->scan
= true;
599 antcomb
->scan_not_start
= true;
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
;
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
;
633 if ((alt_rssi_avg
< (main_rssi_avg
+
634 div_ant_conf
.lna1_lna2_delta
)))
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;
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
;
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;
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
;
659 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
:
660 antcomb
->rssi_add
= alt_rssi_avg
;
661 antcomb
->scan
= true;
663 div_ant_conf
.alt_lna_conf
=
664 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
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
)) {
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
) {
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
;
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
;
695 /* use LNA1 as main LNA */
696 if ((antcomb
->rssi_add
> antcomb
->rssi_lna2
) &&
697 (antcomb
->rssi_add
> antcomb
->rssi_sub
)) {
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
) {
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
;
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
;
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
;
741 ath_select_ant_div_from_quick_scan(antcomb
, &div_ant_conf
,
742 main_rssi_avg
, alt_rssi_avg
,
745 antcomb
->quick_scan_cnt
++;
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
);
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;
759 void ath_ant_comb_update(struct ath_softc
*sc
)
761 struct ath_hw
*ah
= sc
->sc_ah
;
762 struct ath_hw_antcomb_conf div_ant_conf
;
765 ath9k_hw_antdiv_comb_conf_get(ah
, &div_ant_conf
);
768 lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
770 lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
772 div_ant_conf
.main_lna_conf
= lna_conf
;
773 div_ant_conf
.alt_lna_conf
= lna_conf
;
775 ath9k_hw_antdiv_comb_conf_set(ah
, &div_ant_conf
);