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.
23 * EEPROM has 2 4-bit fields containing the card configuration.
27 * bb_enable_ant_div_lnadiv : 1
28 * bb_ant_div_alt_gaintb : 1
29 * bb_ant_div_main_gaintb : 1
30 * bb_enable_ant_fast_div : 1
34 * bb_ant_div_alt_lnaconf : 2
35 * bb_ant_div_main_lnaconf : 2
37 * The EEPROM bits are used as follows:
38 * ------------------------------------
40 * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining.
41 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
43 * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0
44 * 1 -> Antenna config Alt/Main uses gaintable 1
45 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
47 * bb_enable_ant_fast_div - Enable fast antenna diversity.
48 * Set in AR_PHY_CCK_DETECT.
50 * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
51 * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
57 * AR9485 / AR9565 / AR9331
58 * ========================
60 * The same bits are present in the EEPROM, but the location in the
61 * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
63 * ant_div_alt_lnaconf ==> bit 0~1
64 * ant_div_main_lnaconf ==> bit 2~3
65 * ant_div_alt_gaintb ==> bit 4
66 * ant_div_main_gaintb ==> bit 5
67 * enable_ant_div_lnadiv ==> bit 6
68 * enable_ant_fast_div ==> bit 7
71 static 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
)
79 if (alt_rssi_avg
> main_rssi_avg
+ mindelta
)
82 if (alt_ratio
>= antcomb
->ant_ratio2
&&
83 alt_rssi_avg
>= antcomb
->low_rssi_thresh
&&
84 (alt_rssi_avg
> main_rssi_avg
+ maxdelta
))
90 static 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
,
95 bool result
, set1
, set2
;
97 result
= set1
= set2
= false;
99 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
&&
100 conf
->alt_lna_conf
== ATH_ANT_DIV_COMB_LNA1
)
103 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA1
&&
104 conf
->alt_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
107 switch (conf
->div_group
) {
109 if (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
)
114 if (alt_rssi_avg
< 4 || alt_rssi_avg
< antcomb
->low_rssi_thresh
)
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
))
124 if (alt_rssi_avg
< 4 || alt_rssi_avg
< antcomb
->low_rssi_thresh
)
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
))
138 static void ath_lnaconf_alt_good_scan(struct ath_ant_comb
*antcomb
,
139 struct ath_hw_antcomb_conf ant_conf
,
142 antcomb
->quick_scan_cnt
= 0;
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
;
149 switch ((ant_conf
.main_lna_conf
<< 4) | ant_conf
.alt_lna_conf
) {
150 case 0x10: /* LNA2 A-B */
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
;
156 case 0x20: /* LNA1 A-B */
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
;
162 case 0x21: /* LNA1 LNA2 */
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
;
169 case 0x12: /* LNA2 LNA1 */
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
;
176 case 0x13: /* LNA2 A+B */
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
;
182 case 0x23: /* LNA1 A+B */
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
;
193 static void ath_ant_set_alt_ratio(struct ath_ant_comb
*antcomb
,
194 struct ath_hw_antcomb_conf
*conf
)
196 /* set alt to the conf with maximun ratio */
197 if (antcomb
->first_ratio
&& antcomb
->second_ratio
) {
198 if (antcomb
->rssi_second
> antcomb
->rssi_third
) {
200 if ((antcomb
->first_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA1
) ||
201 (antcomb
->first_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA2
))
202 /* Set alt LNA1 or LNA2*/
203 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
204 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
206 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
208 /* Set alt to A+B or A-B */
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 /* Set alt LNA1 or LNA2 */
214 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
215 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
217 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
219 /* Set alt to A+B or A-B */
220 conf
->alt_lna_conf
= antcomb
->second_quick_scan_conf
;
222 } else if (antcomb
->first_ratio
) {
224 if ((antcomb
->first_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA1
) ||
225 (antcomb
->first_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA2
))
226 /* Set alt LNA1 or LNA2 */
227 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
228 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
230 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
232 /* Set alt to A+B or A-B */
233 conf
->alt_lna_conf
= antcomb
->first_quick_scan_conf
;
234 } else if (antcomb
->second_ratio
) {
236 if ((antcomb
->second_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA1
) ||
237 (antcomb
->second_quick_scan_conf
== ATH_ANT_DIV_COMB_LNA2
))
238 /* Set alt LNA1 or LNA2 */
239 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
240 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
242 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
244 /* Set alt to A+B or A-B */
245 conf
->alt_lna_conf
= antcomb
->second_quick_scan_conf
;
247 /* main is largest */
248 if ((antcomb
->main_conf
== ATH_ANT_DIV_COMB_LNA1
) ||
249 (antcomb
->main_conf
== ATH_ANT_DIV_COMB_LNA2
))
250 /* Set alt LNA1 or LNA2 */
251 if (conf
->main_lna_conf
== ATH_ANT_DIV_COMB_LNA2
)
252 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
254 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
256 /* Set alt to A+B or A-B */
257 conf
->alt_lna_conf
= antcomb
->main_conf
;
261 static 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
,
267 switch (antcomb
->quick_scan_cnt
) {
269 /* set alt to main, and alt to first conf */
270 div_ant_conf
->main_lna_conf
= antcomb
->main_conf
;
271 div_ant_conf
->alt_lna_conf
= antcomb
->first_quick_scan_conf
;
274 /* set alt to main, and alt to first conf */
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
;
280 if (antcomb
->main_conf
== ATH_ANT_DIV_COMB_LNA1
) {
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;
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;
298 antcomb
->first_ratio
= false;
300 if (ath_is_alt_ant_ratio_better(antcomb
, alt_ratio
,
301 ATH_ANT_DIV_COMB_LNA1_DELTA_HI
,
303 main_rssi_avg
, alt_rssi_avg
,
304 antcomb
->total_pkt_count
))
305 antcomb
->first_ratio
= true;
307 antcomb
->first_ratio
= false;
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
;
317 switch(antcomb
->second_quick_scan_conf
) {
318 case ATH_ANT_DIV_COMB_LNA1
:
319 antcomb
->rssi_lna1
= alt_rssi_avg
;
321 case ATH_ANT_DIV_COMB_LNA2
:
322 antcomb
->rssi_lna2
= alt_rssi_avg
;
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
;
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
;
338 div_ant_conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
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;
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;
357 antcomb
->second_ratio
= false;
359 if (ath_is_alt_ant_ratio_better(antcomb
, alt_ratio
,
360 ATH_ANT_DIV_COMB_LNA1_DELTA_HI
,
362 main_rssi_avg
, alt_rssi_avg
,
363 antcomb
->total_pkt_count
))
364 antcomb
->second_ratio
= true;
366 antcomb
->second_ratio
= false;
369 ath_ant_set_alt_ratio(antcomb
, div_ant_conf
);
377 static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf
*ant_conf
,
378 struct ath_ant_comb
*antcomb
,
381 ant_conf
->main_gaintb
= 0;
382 ant_conf
->alt_gaintb
= 0;
384 if (ant_conf
->div_group
== 0) {
385 /* Adjust the fast_div_bias based on main and alt lna conf */
386 switch ((ant_conf
->main_lna_conf
<< 4) |
387 ant_conf
->alt_lna_conf
) {
388 case 0x01: /* A-B LNA2 */
389 ant_conf
->fast_div_bias
= 0x3b;
391 case 0x02: /* A-B LNA1 */
392 ant_conf
->fast_div_bias
= 0x3d;
394 case 0x03: /* A-B A+B */
395 ant_conf
->fast_div_bias
= 0x1;
397 case 0x10: /* LNA2 A-B */
398 ant_conf
->fast_div_bias
= 0x7;
400 case 0x12: /* LNA2 LNA1 */
401 ant_conf
->fast_div_bias
= 0x2;
403 case 0x13: /* LNA2 A+B */
404 ant_conf
->fast_div_bias
= 0x7;
406 case 0x20: /* LNA1 A-B */
407 ant_conf
->fast_div_bias
= 0x6;
409 case 0x21: /* LNA1 LNA2 */
410 ant_conf
->fast_div_bias
= 0x0;
412 case 0x23: /* LNA1 A+B */
413 ant_conf
->fast_div_bias
= 0x6;
415 case 0x30: /* A+B A-B */
416 ant_conf
->fast_div_bias
= 0x1;
418 case 0x31: /* A+B LNA2 */
419 ant_conf
->fast_div_bias
= 0x3b;
421 case 0x32: /* A+B LNA1 */
422 ant_conf
->fast_div_bias
= 0x3d;
427 } else if (ant_conf
->div_group
== 1) {
428 /* Adjust the fast_div_bias based on main and alt_lna_conf */
429 switch ((ant_conf
->main_lna_conf
<< 4) |
430 ant_conf
->alt_lna_conf
) {
431 case 0x01: /* A-B LNA2 */
432 ant_conf
->fast_div_bias
= 0x1;
434 case 0x02: /* A-B LNA1 */
435 ant_conf
->fast_div_bias
= 0x1;
437 case 0x03: /* A-B A+B */
438 ant_conf
->fast_div_bias
= 0x1;
440 case 0x10: /* LNA2 A-B */
441 if (!(antcomb
->scan
) &&
442 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
))
443 ant_conf
->fast_div_bias
= 0x3f;
445 ant_conf
->fast_div_bias
= 0x1;
447 case 0x12: /* LNA2 LNA1 */
448 ant_conf
->fast_div_bias
= 0x1;
450 case 0x13: /* LNA2 A+B */
451 if (!(antcomb
->scan
) &&
452 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
))
453 ant_conf
->fast_div_bias
= 0x3f;
455 ant_conf
->fast_div_bias
= 0x1;
457 case 0x20: /* LNA1 A-B */
458 if (!(antcomb
->scan
) &&
459 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
))
460 ant_conf
->fast_div_bias
= 0x3f;
462 ant_conf
->fast_div_bias
= 0x1;
464 case 0x21: /* LNA1 LNA2 */
465 ant_conf
->fast_div_bias
= 0x1;
467 case 0x23: /* LNA1 A+B */
468 if (!(antcomb
->scan
) &&
469 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
))
470 ant_conf
->fast_div_bias
= 0x3f;
472 ant_conf
->fast_div_bias
= 0x1;
474 case 0x30: /* A+B A-B */
475 ant_conf
->fast_div_bias
= 0x1;
477 case 0x31: /* A+B LNA2 */
478 ant_conf
->fast_div_bias
= 0x1;
480 case 0x32: /* A+B LNA1 */
481 ant_conf
->fast_div_bias
= 0x1;
486 } else if (ant_conf
->div_group
== 2) {
487 /* Adjust the fast_div_bias based on main and alt_lna_conf */
488 switch ((ant_conf
->main_lna_conf
<< 4) |
489 ant_conf
->alt_lna_conf
) {
490 case 0x01: /* A-B LNA2 */
491 ant_conf
->fast_div_bias
= 0x1;
493 case 0x02: /* A-B LNA1 */
494 ant_conf
->fast_div_bias
= 0x1;
496 case 0x03: /* A-B A+B */
497 ant_conf
->fast_div_bias
= 0x1;
499 case 0x10: /* LNA2 A-B */
500 if (!antcomb
->scan
&& (alt_ratio
> antcomb
->ant_ratio
))
501 ant_conf
->fast_div_bias
= 0x1;
503 ant_conf
->fast_div_bias
= 0x2;
505 case 0x12: /* LNA2 LNA1 */
506 ant_conf
->fast_div_bias
= 0x1;
508 case 0x13: /* LNA2 A+B */
509 if (!antcomb
->scan
&& (alt_ratio
> antcomb
->ant_ratio
))
510 ant_conf
->fast_div_bias
= 0x1;
512 ant_conf
->fast_div_bias
= 0x2;
514 case 0x20: /* LNA1 A-B */
515 if (!antcomb
->scan
&& (alt_ratio
> antcomb
->ant_ratio
))
516 ant_conf
->fast_div_bias
= 0x1;
518 ant_conf
->fast_div_bias
= 0x2;
520 case 0x21: /* LNA1 LNA2 */
521 ant_conf
->fast_div_bias
= 0x1;
523 case 0x23: /* LNA1 A+B */
524 if (!antcomb
->scan
&& (alt_ratio
> antcomb
->ant_ratio
))
525 ant_conf
->fast_div_bias
= 0x1;
527 ant_conf
->fast_div_bias
= 0x2;
529 case 0x30: /* A+B A-B */
530 ant_conf
->fast_div_bias
= 0x1;
532 case 0x31: /* A+B LNA2 */
533 ant_conf
->fast_div_bias
= 0x1;
535 case 0x32: /* A+B LNA1 */
536 ant_conf
->fast_div_bias
= 0x1;
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: /* A-B LNA2 */
548 ant_conf
->fast_div_bias
= 0x1;
550 case 0x02: /* A-B LNA1 */
551 ant_conf
->fast_div_bias
= 0x39;
553 case 0x03: /* A-B A+B */
554 ant_conf
->fast_div_bias
= 0x1;
556 case 0x10: /* LNA2 A-B */
557 if ((antcomb
->scan
== 0) &&
558 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
)) {
559 ant_conf
->fast_div_bias
= 0x3f;
561 ant_conf
->fast_div_bias
= 0x1;
564 case 0x12: /* LNA2 LNA1 */
565 ant_conf
->fast_div_bias
= 0x39;
567 case 0x13: /* LNA2 A+B */
568 if ((antcomb
->scan
== 0) &&
569 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
)) {
570 ant_conf
->fast_div_bias
= 0x3f;
572 ant_conf
->fast_div_bias
= 0x1;
575 case 0x20: /* LNA1 A-B */
576 if ((antcomb
->scan
== 0) &&
577 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
)) {
578 ant_conf
->fast_div_bias
= 0x3f;
580 ant_conf
->fast_div_bias
= 0x4;
583 case 0x21: /* LNA1 LNA2 */
584 ant_conf
->fast_div_bias
= 0x6;
586 case 0x23: /* LNA1 A+B */
587 if ((antcomb
->scan
== 0) &&
588 (alt_ratio
> ATH_ANT_DIV_COMB_ALT_ANT_RATIO
)) {
589 ant_conf
->fast_div_bias
= 0x3f;
591 ant_conf
->fast_div_bias
= 0x6;
594 case 0x30: /* A+B A-B */
595 ant_conf
->fast_div_bias
= 0x1;
597 case 0x31: /* A+B LNA2 */
598 ant_conf
->fast_div_bias
= 0x6;
600 case 0x32: /* A+B LNA1 */
601 ant_conf
->fast_div_bias
= 0x1;
609 static 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
,
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;
620 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
621 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
;
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;
628 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
629 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
;
631 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
:
632 antcomb
->rssi_add
= alt_rssi_avg
;
633 antcomb
->scan
= true;
635 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
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 /* use LNA2 as main LNA */
643 if ((antcomb
->rssi_add
> antcomb
->rssi_lna1
) &&
644 (antcomb
->rssi_add
> antcomb
->rssi_sub
)) {
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
) {
651 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
652 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
655 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
656 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
659 /* use LNA1 as main LNA */
660 if ((antcomb
->rssi_add
> antcomb
->rssi_lna2
) &&
661 (antcomb
->rssi_add
> antcomb
->rssi_sub
)) {
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
) {
668 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
669 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
672 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
673 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
682 static 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
,
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
) {
694 * Switch main and alt LNA.
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
;
704 } else if ((curr_alt_set
!= ATH_ANT_DIV_COMB_LNA1
) &&
705 (curr_alt_set
!= ATH_ANT_DIV_COMB_LNA2
)) {
707 Set alt to another LNA.
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
;
720 static bool ath_ant_short_scan_check(struct ath_ant_comb
*antcomb
)
724 if (!antcomb
->scan
|| !antcomb
->alt_good
)
727 if (time_after(jiffies
, antcomb
->scan_start_time
+
728 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR
)))
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
)
741 void ath_ant_comb_scan(struct ath_softc
*sc
, struct ath_rx_status
*rs
)
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
;
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
;
752 rx_ant_conf
= (rs
->rs_rssi_ctl2
>> ATH_ANT_RX_CURRENT_SHIFT
) &
754 main_ant_conf
= (rs
->rs_rssi_ctl2
>> ATH_ANT_RX_MAIN_SHIFT
) &
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
;
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
;
765 /* Record packet only when both main_rssi and alt_rssi is positive */
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
;
771 if (main_ant_conf
== rx_ant_conf
)
772 antcomb
->main_recv_cnt
++;
774 antcomb
->alt_recv_cnt
++;
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
);
781 ANT_STAT_INC(ANT_ALT
, recv_cnt
);
782 ANT_LNA_INC(ANT_ALT
, rx_ant_conf
);
785 /* Short scan check */
786 short_scan
= ath_ant_short_scan_check(antcomb
);
788 if (((antcomb
->total_pkt_count
< ATH_ANT_DIV_COMB_MAX_PKTCOUNT
) ||
789 rs
->rs_moreaggr
) && !short_scan
)
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
);
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
;
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
,
810 antcomb
->alt_good
= true;
812 antcomb
->alt_good
= false;
816 antcomb
->scan
= true;
817 antcomb
->scan_not_start
= true;
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
);
828 if (!antcomb
->scan
&&
829 (alt_rssi_avg
< (main_rssi_avg
+ div_ant_conf
.lna1_lna2_delta
)))
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
);
836 if (!antcomb
->alt_good
) {
837 antcomb
->scan_not_start
= false;
838 /* Set alt to another LNA */
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
;
852 ath_select_ant_div_from_quick_scan(antcomb
, &div_ant_conf
,
853 main_rssi_avg
, alt_rssi_avg
,
855 antcomb
->quick_scan_cnt
++;
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
);
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;