1 /* 2 * Copyright (c) 2012 Qualcomm Atheros, Inc. 3 * 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. 7 * 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. 15 */ 16 17 #include "ath9k.h" 18 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) 22 { 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); 26 } 27 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) 31 { 32 bool result = false; 33 switch (div_group) { 34 case 0: 35 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) 36 result = true; 37 break; 38 case 1: 39 case 2: 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)))) && 46 (alt_rssi_avg >= 4)) 47 result = true; 48 else 49 result = false; 50 break; 51 } 52 53 return result; 54 } 55 56 static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb, 57 struct ath_hw_antcomb_conf ant_conf, 58 int main_rssi_avg) 59 { 60 antcomb->quick_scan_cnt = 0; 61 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; 66 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; 73 break; 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; 79 break; 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; 86 break; 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; 93 break; 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; 99 break; 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; 105 break; 106 default: 107 break; 108 } 109 } 110 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, 114 int alt_ratio) 115 { 116 /* alt_good */ 117 switch (antcomb->quick_scan_cnt) { 118 case 0: 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; 122 break; 123 case 1: 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; 129 130 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) { 131 /* main is 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; 138 else 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; 147 else 148 antcomb->first_ratio = false; 149 } else { 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; 156 else 157 antcomb->first_ratio = false; 158 } 159 break; 160 case 2: 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; 166 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; 178 } 179 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; 183 else 184 div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1; 185 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; 193 else 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; 202 else 203 antcomb->second_ratio = false; 204 } else { 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; 211 else 212 antcomb->second_ratio = false; 213 } 214 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) { 218 /* first alt*/ 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; 228 else 229 div_ant_conf->alt_lna_conf = 230 ATH_ANT_DIV_COMB_LNA2; 231 else 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; 244 else 245 div_ant_conf->alt_lna_conf = 246 ATH_ANT_DIV_COMB_LNA2; 247 } else { 248 /* Set alt to A+B or A-B */ 249 div_ant_conf->alt_lna_conf = 250 antcomb->second_quick_scan_conf; 251 } 252 } else if (antcomb->first_ratio) { 253 /* first alt */ 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; 263 else 264 div_ant_conf->alt_lna_conf = 265 ATH_ANT_DIV_COMB_LNA2; 266 else 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) { 271 /* second alt */ 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; 281 else 282 div_ant_conf->alt_lna_conf = 283 ATH_ANT_DIV_COMB_LNA2; 284 else 285 /* Set alt to A+B or A-B */ 286 div_ant_conf->alt_lna_conf = 287 antcomb->second_quick_scan_conf; 288 } else { 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; 297 else 298 div_ant_conf->alt_lna_conf = 299 ATH_ANT_DIV_COMB_LNA2; 300 else 301 /* Set alt to A+B or A-B */ 302 div_ant_conf->alt_lna_conf = antcomb->main_conf; 303 } 304 break; 305 default: 306 break; 307 } 308 } 309 310 static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf, 311 struct ath_ant_comb *antcomb, 312 int alt_ratio) 313 { 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; 320 break; 321 case 0x02: /* A-B LNA1 */ 322 ant_conf->fast_div_bias = 0x3d; 323 break; 324 case 0x03: /* A-B A+B */ 325 ant_conf->fast_div_bias = 0x1; 326 break; 327 case 0x10: /* LNA2 A-B */ 328 ant_conf->fast_div_bias = 0x7; 329 break; 330 case 0x12: /* LNA2 LNA1 */ 331 ant_conf->fast_div_bias = 0x2; 332 break; 333 case 0x13: /* LNA2 A+B */ 334 ant_conf->fast_div_bias = 0x7; 335 break; 336 case 0x20: /* LNA1 A-B */ 337 ant_conf->fast_div_bias = 0x6; 338 break; 339 case 0x21: /* LNA1 LNA2 */ 340 ant_conf->fast_div_bias = 0x0; 341 break; 342 case 0x23: /* LNA1 A+B */ 343 ant_conf->fast_div_bias = 0x6; 344 break; 345 case 0x30: /* A+B A-B */ 346 ant_conf->fast_div_bias = 0x1; 347 break; 348 case 0x31: /* A+B LNA2 */ 349 ant_conf->fast_div_bias = 0x3b; 350 break; 351 case 0x32: /* A+B LNA1 */ 352 ant_conf->fast_div_bias = 0x3d; 353 break; 354 default: 355 break; 356 } 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; 365 break; 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; 370 break; 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; 375 break; 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; 380 else 381 ant_conf->fast_div_bias = 0x1; 382 ant_conf->main_gaintb = 0; 383 ant_conf->alt_gaintb = 0; 384 break; 385 case 0x12: /* LNA2 LNA1 */ 386 ant_conf->fast_div_bias = 0x1; 387 ant_conf->main_gaintb = 0; 388 ant_conf->alt_gaintb = 0; 389 break; 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; 394 else 395 ant_conf->fast_div_bias = 0x1; 396 ant_conf->main_gaintb = 0; 397 ant_conf->alt_gaintb = 0; 398 break; 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; 403 else 404 ant_conf->fast_div_bias = 0x1; 405 ant_conf->main_gaintb = 0; 406 ant_conf->alt_gaintb = 0; 407 break; 408 case 0x21: /* LNA1 LNA2 */ 409 ant_conf->fast_div_bias = 0x1; 410 ant_conf->main_gaintb = 0; 411 ant_conf->alt_gaintb = 0; 412 break; 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; 417 else 418 ant_conf->fast_div_bias = 0x1; 419 ant_conf->main_gaintb = 0; 420 ant_conf->alt_gaintb = 0; 421 break; 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; 426 break; 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; 431 break; 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; 436 break; 437 default: 438 break; 439 } 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; 448 break; 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; 453 break; 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; 458 break; 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; 463 else 464 ant_conf->fast_div_bias = 0x2; 465 ant_conf->main_gaintb = 0; 466 ant_conf->alt_gaintb = 0; 467 break; 468 case 0x12: /* LNA2 LNA1 */ 469 ant_conf->fast_div_bias = 0x1; 470 ant_conf->main_gaintb = 0; 471 ant_conf->alt_gaintb = 0; 472 break; 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; 477 else 478 ant_conf->fast_div_bias = 0x2; 479 ant_conf->main_gaintb = 0; 480 ant_conf->alt_gaintb = 0; 481 break; 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; 486 else 487 ant_conf->fast_div_bias = 0x2; 488 ant_conf->main_gaintb = 0; 489 ant_conf->alt_gaintb = 0; 490 break; 491 case 0x21: /* LNA1 LNA2 */ 492 ant_conf->fast_div_bias = 0x1; 493 ant_conf->main_gaintb = 0; 494 ant_conf->alt_gaintb = 0; 495 break; 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; 500 else 501 ant_conf->fast_div_bias = 0x2; 502 ant_conf->main_gaintb = 0; 503 ant_conf->alt_gaintb = 0; 504 break; 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; 509 break; 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; 514 break; 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; 519 break; 520 default: 521 break; 522 } 523 } 524 } 525 526 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) 527 { 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; 531 int curr_main_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; 536 537 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & 538 ATH_ANT_RX_MASK; 539 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & 540 ATH_ANT_RX_MASK; 541 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++; 549 else 550 antcomb->alt_recv_cnt++; 551 } 552 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))) 557 short_scan = true; 558 else 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) 564 short_scan = true; 565 } 566 } 567 568 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || 569 rs->rs_moreaggr) && !short_scan) 570 return; 571 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); 579 } 580 581 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; 585 586 antcomb->count++; 587 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, 591 main_rssi_avg); 592 antcomb->alt_good = true; 593 } else { 594 antcomb->alt_good = false; 595 } 596 597 antcomb->count = 0; 598 antcomb->scan = true; 599 antcomb->scan_not_start = true; 600 } 601 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; 617 } 618 619 goto div_comb_done; 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; 629 630 goto div_comb_done; 631 } 632 633 if ((alt_rssi_avg < (main_rssi_avg + 634 div_ant_conf.lna1_lna2_delta))) 635 goto div_comb_done; 636 } 637 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; 644 /* set to A+B */ 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; 649 break; 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; 654 /* set to A+B */ 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; 658 break; 659 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: 660 antcomb->rssi_add = alt_rssi_avg; 661 antcomb->scan = true; 662 /* set to A-B */ 663 div_ant_conf.alt_lna_conf = 664 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 665 break; 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)) { 675 /* set to A+B */ 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) { 682 /* set to A-B */ 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; 687 } else { 688 /* set to LNA1 */ 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; 693 } 694 } else { 695 /* use LNA1 as main LNA */ 696 if ((antcomb->rssi_add > antcomb->rssi_lna2) && 697 (antcomb->rssi_add > antcomb->rssi_sub)) { 698 /* set to A+B */ 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) { 705 /* set to A-B */ 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; 710 } else { 711 /* set to 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; 716 } 717 } 718 break; 719 default: 720 break; 721 } 722 } else { 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; 736 } 737 goto div_comb_done; 738 } 739 } 740 741 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, 742 main_rssi_avg, alt_rssi_avg, 743 alt_ratio); 744 745 antcomb->quick_scan_cnt++; 746 747 div_comb_done: 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); 750 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; 757 } 758 759 void ath_ant_comb_update(struct ath_softc *sc) 760 { 761 struct ath_hw *ah = sc->sc_ah; 762 struct ath_hw_antcomb_conf div_ant_conf; 763 u8 lna_conf; 764 765 ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); 766 767 if (sc->ant_rx == 1) 768 lna_conf = ATH_ANT_DIV_COMB_LNA1; 769 else 770 lna_conf = ATH_ANT_DIV_COMB_LNA2; 771 772 div_ant_conf.main_lna_conf = lna_conf; 773 div_ant_conf.alt_lna_conf = lna_conf; 774 775 ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); 776 } 777