0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "ath9k.h"
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb,
0072 int alt_ratio, int maxdelta,
0073 int mindelta, int main_rssi_avg,
0074 int alt_rssi_avg, int pkt_count)
0075 {
0076 if (pkt_count <= 50)
0077 return false;
0078
0079 if (alt_rssi_avg > main_rssi_avg + mindelta)
0080 return true;
0081
0082 if (alt_ratio >= antcomb->ant_ratio2 &&
0083 alt_rssi_avg >= antcomb->low_rssi_thresh &&
0084 (alt_rssi_avg > main_rssi_avg + maxdelta))
0085 return true;
0086
0087 return false;
0088 }
0089
0090 static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
0091 struct ath_ant_comb *antcomb,
0092 int alt_ratio, int alt_rssi_avg,
0093 int main_rssi_avg)
0094 {
0095 bool result, set1, set2;
0096
0097 result = set1 = set2 = false;
0098
0099 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
0100 conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
0101 set1 = true;
0102
0103 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
0104 conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0105 set2 = true;
0106
0107 switch (conf->div_group) {
0108 case 0:
0109 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
0110 result = true;
0111 break;
0112 case 1:
0113 case 2:
0114 if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
0115 break;
0116
0117 if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
0118 (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) ||
0119 (alt_ratio > antcomb->ant_ratio))
0120 result = true;
0121
0122 break;
0123 case 3:
0124 if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
0125 break;
0126
0127 if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
0128 (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) ||
0129 (alt_ratio > antcomb->ant_ratio))
0130 result = true;
0131
0132 break;
0133 }
0134
0135 return result;
0136 }
0137
0138 static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
0139 struct ath_hw_antcomb_conf ant_conf,
0140 int main_rssi_avg)
0141 {
0142 antcomb->quick_scan_cnt = 0;
0143
0144 if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0145 antcomb->rssi_lna2 = main_rssi_avg;
0146 else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
0147 antcomb->rssi_lna1 = main_rssi_avg;
0148
0149 switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
0150 case 0x10:
0151 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0152 antcomb->first_quick_scan_conf =
0153 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0154 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
0155 break;
0156 case 0x20:
0157 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0158 antcomb->first_quick_scan_conf =
0159 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0160 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
0161 break;
0162 case 0x21:
0163 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
0164 antcomb->first_quick_scan_conf =
0165 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0166 antcomb->second_quick_scan_conf =
0167 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0168 break;
0169 case 0x12:
0170 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
0171 antcomb->first_quick_scan_conf =
0172 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0173 antcomb->second_quick_scan_conf =
0174 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0175 break;
0176 case 0x13:
0177 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0178 antcomb->first_quick_scan_conf =
0179 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0180 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
0181 break;
0182 case 0x23:
0183 antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0184 antcomb->first_quick_scan_conf =
0185 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0186 antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
0187 break;
0188 default:
0189 break;
0190 }
0191 }
0192
0193 static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
0194 struct ath_hw_antcomb_conf *conf)
0195 {
0196
0197 if (antcomb->first_ratio && antcomb->second_ratio) {
0198 if (antcomb->rssi_second > antcomb->rssi_third) {
0199
0200 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
0201 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
0202
0203 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0204 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0205 else
0206 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0207 else
0208
0209 conf->alt_lna_conf =
0210 antcomb->first_quick_scan_conf;
0211 } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
0212 (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
0213
0214 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0215 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0216 else
0217 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0218 } else {
0219
0220 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
0221 }
0222 } else if (antcomb->first_ratio) {
0223
0224 if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
0225 (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
0226
0227 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0228 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0229 else
0230 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0231 else
0232
0233 conf->alt_lna_conf = antcomb->first_quick_scan_conf;
0234 } else if (antcomb->second_ratio) {
0235
0236 if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
0237 (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
0238
0239 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0240 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0241 else
0242 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0243 else
0244
0245 conf->alt_lna_conf = antcomb->second_quick_scan_conf;
0246 } else {
0247
0248 if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
0249 (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
0250
0251 if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
0252 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0253 else
0254 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0255 else
0256
0257 conf->alt_lna_conf = antcomb->main_conf;
0258 }
0259 }
0260
0261 static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
0262 struct ath_hw_antcomb_conf *div_ant_conf,
0263 int main_rssi_avg, int alt_rssi_avg,
0264 int alt_ratio)
0265 {
0266
0267 switch (antcomb->quick_scan_cnt) {
0268 case 0:
0269
0270 div_ant_conf->main_lna_conf = antcomb->main_conf;
0271 div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
0272 break;
0273 case 1:
0274
0275 div_ant_conf->main_lna_conf = antcomb->main_conf;
0276 div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
0277 antcomb->rssi_first = main_rssi_avg;
0278 antcomb->rssi_second = alt_rssi_avg;
0279
0280 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
0281
0282 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0283 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
0284 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
0285 main_rssi_avg, alt_rssi_avg,
0286 antcomb->total_pkt_count))
0287 antcomb->first_ratio = true;
0288 else
0289 antcomb->first_ratio = false;
0290 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
0291 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0292 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
0293 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
0294 main_rssi_avg, alt_rssi_avg,
0295 antcomb->total_pkt_count))
0296 antcomb->first_ratio = true;
0297 else
0298 antcomb->first_ratio = false;
0299 } else {
0300 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0301 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
0302 0,
0303 main_rssi_avg, alt_rssi_avg,
0304 antcomb->total_pkt_count))
0305 antcomb->first_ratio = true;
0306 else
0307 antcomb->first_ratio = false;
0308 }
0309 break;
0310 case 2:
0311 antcomb->alt_good = false;
0312 antcomb->scan_not_start = false;
0313 antcomb->scan = false;
0314 antcomb->rssi_first = main_rssi_avg;
0315 antcomb->rssi_third = alt_rssi_avg;
0316
0317 switch(antcomb->second_quick_scan_conf) {
0318 case ATH_ANT_DIV_COMB_LNA1:
0319 antcomb->rssi_lna1 = alt_rssi_avg;
0320 break;
0321 case ATH_ANT_DIV_COMB_LNA2:
0322 antcomb->rssi_lna2 = alt_rssi_avg;
0323 break;
0324 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
0325 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
0326 antcomb->rssi_lna2 = main_rssi_avg;
0327 else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
0328 antcomb->rssi_lna1 = main_rssi_avg;
0329 break;
0330 default:
0331 break;
0332 }
0333
0334 if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
0335 div_ant_conf->lna1_lna2_switch_delta)
0336 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0337 else
0338 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0339
0340 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
0341 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0342 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
0343 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
0344 main_rssi_avg, alt_rssi_avg,
0345 antcomb->total_pkt_count))
0346 antcomb->second_ratio = true;
0347 else
0348 antcomb->second_ratio = false;
0349 } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
0350 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0351 ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
0352 ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
0353 main_rssi_avg, alt_rssi_avg,
0354 antcomb->total_pkt_count))
0355 antcomb->second_ratio = true;
0356 else
0357 antcomb->second_ratio = false;
0358 } else {
0359 if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
0360 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
0361 0,
0362 main_rssi_avg, alt_rssi_avg,
0363 antcomb->total_pkt_count))
0364 antcomb->second_ratio = true;
0365 else
0366 antcomb->second_ratio = false;
0367 }
0368
0369 ath_ant_set_alt_ratio(antcomb, div_ant_conf);
0370
0371 break;
0372 default:
0373 break;
0374 }
0375 }
0376
0377 static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
0378 struct ath_ant_comb *antcomb,
0379 int alt_ratio)
0380 {
0381 ant_conf->main_gaintb = 0;
0382 ant_conf->alt_gaintb = 0;
0383
0384 if (ant_conf->div_group == 0) {
0385
0386 switch ((ant_conf->main_lna_conf << 4) |
0387 ant_conf->alt_lna_conf) {
0388 case 0x01:
0389 ant_conf->fast_div_bias = 0x3b;
0390 break;
0391 case 0x02:
0392 ant_conf->fast_div_bias = 0x3d;
0393 break;
0394 case 0x03:
0395 ant_conf->fast_div_bias = 0x1;
0396 break;
0397 case 0x10:
0398 ant_conf->fast_div_bias = 0x7;
0399 break;
0400 case 0x12:
0401 ant_conf->fast_div_bias = 0x2;
0402 break;
0403 case 0x13:
0404 ant_conf->fast_div_bias = 0x7;
0405 break;
0406 case 0x20:
0407 ant_conf->fast_div_bias = 0x6;
0408 break;
0409 case 0x21:
0410 ant_conf->fast_div_bias = 0x0;
0411 break;
0412 case 0x23:
0413 ant_conf->fast_div_bias = 0x6;
0414 break;
0415 case 0x30:
0416 ant_conf->fast_div_bias = 0x1;
0417 break;
0418 case 0x31:
0419 ant_conf->fast_div_bias = 0x3b;
0420 break;
0421 case 0x32:
0422 ant_conf->fast_div_bias = 0x3d;
0423 break;
0424 default:
0425 break;
0426 }
0427 } else if (ant_conf->div_group == 1) {
0428
0429 switch ((ant_conf->main_lna_conf << 4) |
0430 ant_conf->alt_lna_conf) {
0431 case 0x01:
0432 ant_conf->fast_div_bias = 0x1;
0433 break;
0434 case 0x02:
0435 ant_conf->fast_div_bias = 0x1;
0436 break;
0437 case 0x03:
0438 ant_conf->fast_div_bias = 0x1;
0439 break;
0440 case 0x10:
0441 if (!(antcomb->scan) &&
0442 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
0443 ant_conf->fast_div_bias = 0x3f;
0444 else
0445 ant_conf->fast_div_bias = 0x1;
0446 break;
0447 case 0x12:
0448 ant_conf->fast_div_bias = 0x1;
0449 break;
0450 case 0x13:
0451 if (!(antcomb->scan) &&
0452 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
0453 ant_conf->fast_div_bias = 0x3f;
0454 else
0455 ant_conf->fast_div_bias = 0x1;
0456 break;
0457 case 0x20:
0458 if (!(antcomb->scan) &&
0459 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
0460 ant_conf->fast_div_bias = 0x3f;
0461 else
0462 ant_conf->fast_div_bias = 0x1;
0463 break;
0464 case 0x21:
0465 ant_conf->fast_div_bias = 0x1;
0466 break;
0467 case 0x23:
0468 if (!(antcomb->scan) &&
0469 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
0470 ant_conf->fast_div_bias = 0x3f;
0471 else
0472 ant_conf->fast_div_bias = 0x1;
0473 break;
0474 case 0x30:
0475 ant_conf->fast_div_bias = 0x1;
0476 break;
0477 case 0x31:
0478 ant_conf->fast_div_bias = 0x1;
0479 break;
0480 case 0x32:
0481 ant_conf->fast_div_bias = 0x1;
0482 break;
0483 default:
0484 break;
0485 }
0486 } else if (ant_conf->div_group == 2) {
0487
0488 switch ((ant_conf->main_lna_conf << 4) |
0489 ant_conf->alt_lna_conf) {
0490 case 0x01:
0491 ant_conf->fast_div_bias = 0x1;
0492 break;
0493 case 0x02:
0494 ant_conf->fast_div_bias = 0x1;
0495 break;
0496 case 0x03:
0497 ant_conf->fast_div_bias = 0x1;
0498 break;
0499 case 0x10:
0500 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
0501 ant_conf->fast_div_bias = 0x1;
0502 else
0503 ant_conf->fast_div_bias = 0x2;
0504 break;
0505 case 0x12:
0506 ant_conf->fast_div_bias = 0x1;
0507 break;
0508 case 0x13:
0509 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
0510 ant_conf->fast_div_bias = 0x1;
0511 else
0512 ant_conf->fast_div_bias = 0x2;
0513 break;
0514 case 0x20:
0515 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
0516 ant_conf->fast_div_bias = 0x1;
0517 else
0518 ant_conf->fast_div_bias = 0x2;
0519 break;
0520 case 0x21:
0521 ant_conf->fast_div_bias = 0x1;
0522 break;
0523 case 0x23:
0524 if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
0525 ant_conf->fast_div_bias = 0x1;
0526 else
0527 ant_conf->fast_div_bias = 0x2;
0528 break;
0529 case 0x30:
0530 ant_conf->fast_div_bias = 0x1;
0531 break;
0532 case 0x31:
0533 ant_conf->fast_div_bias = 0x1;
0534 break;
0535 case 0x32:
0536 ant_conf->fast_div_bias = 0x1;
0537 break;
0538 default:
0539 break;
0540 }
0541
0542 if (antcomb->fast_div_bias)
0543 ant_conf->fast_div_bias = antcomb->fast_div_bias;
0544 } else if (ant_conf->div_group == 3) {
0545 switch ((ant_conf->main_lna_conf << 4) |
0546 ant_conf->alt_lna_conf) {
0547 case 0x01:
0548 ant_conf->fast_div_bias = 0x1;
0549 break;
0550 case 0x02:
0551 ant_conf->fast_div_bias = 0x39;
0552 break;
0553 case 0x03:
0554 ant_conf->fast_div_bias = 0x1;
0555 break;
0556 case 0x10:
0557 ant_conf->fast_div_bias = 0x2;
0558 break;
0559 case 0x12:
0560 ant_conf->fast_div_bias = 0x3f;
0561 break;
0562 case 0x13:
0563 ant_conf->fast_div_bias = 0x2;
0564 break;
0565 case 0x20:
0566 ant_conf->fast_div_bias = 0x3;
0567 break;
0568 case 0x21:
0569 ant_conf->fast_div_bias = 0x3;
0570 break;
0571 case 0x23:
0572 ant_conf->fast_div_bias = 0x3;
0573 break;
0574 case 0x30:
0575 ant_conf->fast_div_bias = 0x1;
0576 break;
0577 case 0x31:
0578 ant_conf->fast_div_bias = 0x6;
0579 break;
0580 case 0x32:
0581 ant_conf->fast_div_bias = 0x1;
0582 break;
0583 default:
0584 break;
0585 }
0586 }
0587 }
0588
0589 static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
0590 struct ath_hw_antcomb_conf *conf,
0591 int curr_alt_set, int alt_rssi_avg,
0592 int main_rssi_avg)
0593 {
0594 switch (curr_alt_set) {
0595 case ATH_ANT_DIV_COMB_LNA2:
0596 antcomb->rssi_lna2 = alt_rssi_avg;
0597 antcomb->rssi_lna1 = main_rssi_avg;
0598 antcomb->scan = true;
0599
0600 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0601 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0602 break;
0603 case ATH_ANT_DIV_COMB_LNA1:
0604 antcomb->rssi_lna1 = alt_rssi_avg;
0605 antcomb->rssi_lna2 = main_rssi_avg;
0606 antcomb->scan = true;
0607
0608 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0609 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0610 break;
0611 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
0612 antcomb->rssi_add = alt_rssi_avg;
0613 antcomb->scan = true;
0614
0615 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0616 break;
0617 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
0618 antcomb->rssi_sub = alt_rssi_avg;
0619 antcomb->scan = false;
0620 if (antcomb->rssi_lna2 >
0621 (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
0622
0623 if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
0624 (antcomb->rssi_add > antcomb->rssi_sub)) {
0625
0626 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0627 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0628 } else if (antcomb->rssi_sub >
0629 antcomb->rssi_lna1) {
0630
0631 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0632 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0633 } else {
0634
0635 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0636 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0637 }
0638 } else {
0639
0640 if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
0641 (antcomb->rssi_add > antcomb->rssi_sub)) {
0642
0643 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0644 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
0645 } else if (antcomb->rssi_sub >
0646 antcomb->rssi_lna1) {
0647
0648 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0649 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
0650 } else {
0651
0652 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0653 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0654 }
0655 }
0656 break;
0657 default:
0658 break;
0659 }
0660 }
0661
0662 static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
0663 struct ath_ant_comb *antcomb,
0664 int alt_ratio, int alt_rssi_avg,
0665 int main_rssi_avg, int curr_main_set,
0666 int curr_alt_set)
0667 {
0668 bool ret = false;
0669
0670 if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
0671 alt_rssi_avg, main_rssi_avg)) {
0672 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
0673
0674
0675
0676 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0677 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0678 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
0679 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0680 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0681 }
0682
0683 ret = true;
0684 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
0685 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
0686
0687
0688
0689 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
0690 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
0691 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
0692 div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
0693
0694 ret = true;
0695 }
0696
0697 return ret;
0698 }
0699
0700 static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
0701 {
0702 int alt_ratio;
0703
0704 if (!antcomb->scan || !antcomb->alt_good)
0705 return false;
0706
0707 if (time_after(jiffies, antcomb->scan_start_time +
0708 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
0709 return true;
0710
0711 if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
0712 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
0713 antcomb->total_pkt_count);
0714 if (alt_ratio < antcomb->ant_ratio)
0715 return true;
0716 }
0717
0718 return false;
0719 }
0720
0721 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
0722 {
0723 struct ath_hw_antcomb_conf div_ant_conf;
0724 struct ath_ant_comb *antcomb = &sc->ant_comb;
0725 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
0726 int curr_main_set;
0727 int main_rssi = rs->rs_rssi_ctl[0];
0728 int alt_rssi = rs->rs_rssi_ctl[1];
0729 int rx_ant_conf, main_ant_conf;
0730 bool short_scan = false, ret;
0731
0732 rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
0733 ATH_ANT_RX_MASK;
0734 main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
0735 ATH_ANT_RX_MASK;
0736
0737 if (alt_rssi >= antcomb->low_rssi_thresh) {
0738 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
0739 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
0740 } else {
0741 antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
0742 antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
0743 }
0744
0745
0746 if (main_rssi > 0 && alt_rssi > 0) {
0747 antcomb->total_pkt_count++;
0748 antcomb->main_total_rssi += main_rssi;
0749 antcomb->alt_total_rssi += alt_rssi;
0750
0751 if (main_ant_conf == rx_ant_conf)
0752 antcomb->main_recv_cnt++;
0753 else
0754 antcomb->alt_recv_cnt++;
0755 }
0756
0757 if (main_ant_conf == rx_ant_conf) {
0758 ANT_STAT_INC(sc, ANT_MAIN, recv_cnt);
0759 ANT_LNA_INC(sc, ANT_MAIN, rx_ant_conf);
0760 } else {
0761 ANT_STAT_INC(sc, ANT_ALT, recv_cnt);
0762 ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf);
0763 }
0764
0765
0766 short_scan = ath_ant_short_scan_check(antcomb);
0767
0768 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
0769 rs->rs_moreaggr) && !short_scan)
0770 return;
0771
0772 if (antcomb->total_pkt_count) {
0773 alt_ratio = ((antcomb->alt_recv_cnt * 100) /
0774 antcomb->total_pkt_count);
0775 main_rssi_avg = (antcomb->main_total_rssi /
0776 antcomb->total_pkt_count);
0777 alt_rssi_avg = (antcomb->alt_total_rssi /
0778 antcomb->total_pkt_count);
0779 }
0780
0781 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
0782 curr_alt_set = div_ant_conf.alt_lna_conf;
0783 curr_main_set = div_ant_conf.main_lna_conf;
0784 antcomb->count++;
0785
0786 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
0787 if (alt_ratio > antcomb->ant_ratio) {
0788 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
0789 main_rssi_avg);
0790 antcomb->alt_good = true;
0791 } else {
0792 antcomb->alt_good = false;
0793 }
0794
0795 antcomb->count = 0;
0796 antcomb->scan = true;
0797 antcomb->scan_not_start = true;
0798 }
0799
0800 if (!antcomb->scan) {
0801 ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
0802 alt_rssi_avg, main_rssi_avg,
0803 curr_main_set, curr_alt_set);
0804 if (ret)
0805 goto div_comb_done;
0806 }
0807
0808 if (!antcomb->scan &&
0809 (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
0810 goto div_comb_done;
0811
0812 if (!antcomb->scan_not_start) {
0813 ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
0814 alt_rssi_avg, main_rssi_avg);
0815 } else {
0816 if (!antcomb->alt_good) {
0817 antcomb->scan_not_start = false;
0818
0819 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
0820 div_ant_conf.main_lna_conf =
0821 ATH_ANT_DIV_COMB_LNA2;
0822 div_ant_conf.alt_lna_conf =
0823 ATH_ANT_DIV_COMB_LNA1;
0824 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
0825 div_ant_conf.main_lna_conf =
0826 ATH_ANT_DIV_COMB_LNA1;
0827 div_ant_conf.alt_lna_conf =
0828 ATH_ANT_DIV_COMB_LNA2;
0829 }
0830 goto div_comb_done;
0831 }
0832 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
0833 main_rssi_avg, alt_rssi_avg,
0834 alt_ratio);
0835 antcomb->quick_scan_cnt++;
0836 }
0837
0838 div_comb_done:
0839 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
0840 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
0841 ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
0842
0843 antcomb->scan_start_time = jiffies;
0844 antcomb->total_pkt_count = 0;
0845 antcomb->main_total_rssi = 0;
0846 antcomb->alt_total_rssi = 0;
0847 antcomb->main_recv_cnt = 0;
0848 antcomb->alt_recv_cnt = 0;
0849 }