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 div_ant_conf
->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 ant_conf
->fast_div_bias
= 0x2;
559 case 0x12: /* LNA2 LNA1 */
560 ant_conf
->fast_div_bias
= 0x3f;
562 case 0x13: /* LNA2 A+B */
563 ant_conf
->fast_div_bias
= 0x2;
565 case 0x20: /* LNA1 A-B */
566 ant_conf
->fast_div_bias
= 0x3;
568 case 0x21: /* LNA1 LNA2 */
569 ant_conf
->fast_div_bias
= 0x3;
571 case 0x23: /* LNA1 A+B */
572 ant_conf
->fast_div_bias
= 0x3;
574 case 0x30: /* A+B A-B */
575 ant_conf
->fast_div_bias
= 0x1;
577 case 0x31: /* A+B LNA2 */
578 ant_conf
->fast_div_bias
= 0x6;
580 case 0x32: /* A+B LNA1 */
581 ant_conf
->fast_div_bias
= 0x1;
589 static 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
,
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;
600 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
601 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
;
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;
608 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
609 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
;
611 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2
:
612 antcomb
->rssi_add
= alt_rssi_avg
;
613 antcomb
->scan
= true;
615 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
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 /* use LNA2 as main LNA */
623 if ((antcomb
->rssi_add
> antcomb
->rssi_lna1
) &&
624 (antcomb
->rssi_add
> antcomb
->rssi_sub
)) {
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
) {
631 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
632 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
635 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
636 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
639 /* use LNA1 as main LNA */
640 if ((antcomb
->rssi_add
> antcomb
->rssi_lna2
) &&
641 (antcomb
->rssi_add
> antcomb
->rssi_sub
)) {
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
) {
648 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
649 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2
;
652 conf
->main_lna_conf
= ATH_ANT_DIV_COMB_LNA1
;
653 conf
->alt_lna_conf
= ATH_ANT_DIV_COMB_LNA2
;
662 static 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
,
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
) {
674 * Switch main and alt LNA.
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
;
684 } else if ((curr_alt_set
!= ATH_ANT_DIV_COMB_LNA1
) &&
685 (curr_alt_set
!= ATH_ANT_DIV_COMB_LNA2
)) {
687 Set alt to another LNA.
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
;
700 static bool ath_ant_short_scan_check(struct ath_ant_comb
*antcomb
)
704 if (!antcomb
->scan
|| !antcomb
->alt_good
)
707 if (time_after(jiffies
, antcomb
->scan_start_time
+
708 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR
)))
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
)
721 void ath_ant_comb_scan(struct ath_softc
*sc
, struct ath_rx_status
*rs
)
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
;
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
;
732 rx_ant_conf
= (rs
->rs_rssi_ctl
[2] >> ATH_ANT_RX_CURRENT_SHIFT
) &
734 main_ant_conf
= (rs
->rs_rssi_ctl
[2] >> ATH_ANT_RX_MAIN_SHIFT
) &
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
;
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
;
745 /* Record packet only when both main_rssi and alt_rssi is positive */
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
;
751 if (main_ant_conf
== rx_ant_conf
)
752 antcomb
->main_recv_cnt
++;
754 antcomb
->alt_recv_cnt
++;
757 if (main_ant_conf
== rx_ant_conf
) {
758 ANT_STAT_INC(sc
, ANT_MAIN
, recv_cnt
);
759 ANT_LNA_INC(sc
, ANT_MAIN
, rx_ant_conf
);
761 ANT_STAT_INC(sc
, ANT_ALT
, recv_cnt
);
762 ANT_LNA_INC(sc
, ANT_ALT
, rx_ant_conf
);
765 /* Short scan check */
766 short_scan
= ath_ant_short_scan_check(antcomb
);
768 if (((antcomb
->total_pkt_count
< ATH_ANT_DIV_COMB_MAX_PKTCOUNT
) ||
769 rs
->rs_moreaggr
) && !short_scan
)
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
);
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
;
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
,
790 antcomb
->alt_good
= true;
792 antcomb
->alt_good
= false;
796 antcomb
->scan
= true;
797 antcomb
->scan_not_start
= true;
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
);
808 if (!antcomb
->scan
&&
809 (alt_rssi_avg
< (main_rssi_avg
+ div_ant_conf
.lna1_lna2_delta
)))
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
);
816 if (!antcomb
->alt_good
) {
817 antcomb
->scan_not_start
= false;
818 /* Set alt to another LNA */
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
;
832 ath_select_ant_div_from_quick_scan(antcomb
, &div_ant_conf
,
833 main_rssi_avg
, alt_rssi_avg
,
835 antcomb
->quick_scan_cnt
++;
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
);
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;