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 ant_conf->main_gaintb = 0; 315 ant_conf->alt_gaintb = 0; 316 317 if (ant_conf->div_group == 0) { 318 /* Adjust the fast_div_bias based on main and alt lna conf */ 319 switch ((ant_conf->main_lna_conf << 4) | 320 ant_conf->alt_lna_conf) { 321 case 0x01: /* A-B LNA2 */ 322 ant_conf->fast_div_bias = 0x3b; 323 break; 324 case 0x02: /* A-B LNA1 */ 325 ant_conf->fast_div_bias = 0x3d; 326 break; 327 case 0x03: /* A-B A+B */ 328 ant_conf->fast_div_bias = 0x1; 329 break; 330 case 0x10: /* LNA2 A-B */ 331 ant_conf->fast_div_bias = 0x7; 332 break; 333 case 0x12: /* LNA2 LNA1 */ 334 ant_conf->fast_div_bias = 0x2; 335 break; 336 case 0x13: /* LNA2 A+B */ 337 ant_conf->fast_div_bias = 0x7; 338 break; 339 case 0x20: /* LNA1 A-B */ 340 ant_conf->fast_div_bias = 0x6; 341 break; 342 case 0x21: /* LNA1 LNA2 */ 343 ant_conf->fast_div_bias = 0x0; 344 break; 345 case 0x23: /* LNA1 A+B */ 346 ant_conf->fast_div_bias = 0x6; 347 break; 348 case 0x30: /* A+B A-B */ 349 ant_conf->fast_div_bias = 0x1; 350 break; 351 case 0x31: /* A+B LNA2 */ 352 ant_conf->fast_div_bias = 0x3b; 353 break; 354 case 0x32: /* A+B LNA1 */ 355 ant_conf->fast_div_bias = 0x3d; 356 break; 357 default: 358 break; 359 } 360 } else if (ant_conf->div_group == 1) { 361 /* Adjust the fast_div_bias based on main and alt_lna_conf */ 362 switch ((ant_conf->main_lna_conf << 4) | 363 ant_conf->alt_lna_conf) { 364 case 0x01: /* A-B LNA2 */ 365 ant_conf->fast_div_bias = 0x1; 366 break; 367 case 0x02: /* A-B LNA1 */ 368 ant_conf->fast_div_bias = 0x1; 369 break; 370 case 0x03: /* A-B A+B */ 371 ant_conf->fast_div_bias = 0x1; 372 break; 373 case 0x10: /* LNA2 A-B */ 374 if (!(antcomb->scan) && 375 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 376 ant_conf->fast_div_bias = 0x3f; 377 else 378 ant_conf->fast_div_bias = 0x1; 379 break; 380 case 0x12: /* LNA2 LNA1 */ 381 ant_conf->fast_div_bias = 0x1; 382 break; 383 case 0x13: /* LNA2 A+B */ 384 if (!(antcomb->scan) && 385 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 386 ant_conf->fast_div_bias = 0x3f; 387 else 388 ant_conf->fast_div_bias = 0x1; 389 break; 390 case 0x20: /* LNA1 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 break; 397 case 0x21: /* LNA1 LNA2 */ 398 ant_conf->fast_div_bias = 0x1; 399 break; 400 case 0x23: /* LNA1 A+B */ 401 if (!(antcomb->scan) && 402 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 403 ant_conf->fast_div_bias = 0x3f; 404 else 405 ant_conf->fast_div_bias = 0x1; 406 break; 407 case 0x30: /* A+B A-B */ 408 ant_conf->fast_div_bias = 0x1; 409 break; 410 case 0x31: /* A+B LNA2 */ 411 ant_conf->fast_div_bias = 0x1; 412 break; 413 case 0x32: /* A+B LNA1 */ 414 ant_conf->fast_div_bias = 0x1; 415 break; 416 default: 417 break; 418 } 419 } else if (ant_conf->div_group == 2) { 420 /* Adjust the fast_div_bias based on main and alt_lna_conf */ 421 switch ((ant_conf->main_lna_conf << 4) | 422 ant_conf->alt_lna_conf) { 423 case 0x01: /* A-B LNA2 */ 424 ant_conf->fast_div_bias = 0x1; 425 break; 426 case 0x02: /* A-B LNA1 */ 427 ant_conf->fast_div_bias = 0x1; 428 break; 429 case 0x03: /* A-B A+B */ 430 ant_conf->fast_div_bias = 0x1; 431 break; 432 case 0x10: /* LNA2 A-B */ 433 if (!(antcomb->scan) && 434 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 435 ant_conf->fast_div_bias = 0x1; 436 else 437 ant_conf->fast_div_bias = 0x2; 438 break; 439 case 0x12: /* LNA2 LNA1 */ 440 ant_conf->fast_div_bias = 0x1; 441 break; 442 case 0x13: /* LNA2 A+B */ 443 if (!(antcomb->scan) && 444 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 445 ant_conf->fast_div_bias = 0x1; 446 else 447 ant_conf->fast_div_bias = 0x2; 448 break; 449 case 0x20: /* LNA1 A-B */ 450 if (!(antcomb->scan) && 451 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) 452 ant_conf->fast_div_bias = 0x1; 453 else 454 ant_conf->fast_div_bias = 0x2; 455 break; 456 case 0x21: /* LNA1 LNA2 */ 457 ant_conf->fast_div_bias = 0x1; 458 break; 459 case 0x23: /* LNA1 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 break; 466 case 0x30: /* A+B A-B */ 467 ant_conf->fast_div_bias = 0x1; 468 break; 469 case 0x31: /* A+B LNA2 */ 470 ant_conf->fast_div_bias = 0x1; 471 break; 472 case 0x32: /* A+B LNA1 */ 473 ant_conf->fast_div_bias = 0x1; 474 break; 475 default: 476 break; 477 } 478 } else if (ant_conf->div_group == 3) { 479 switch ((ant_conf->main_lna_conf << 4) | 480 ant_conf->alt_lna_conf) { 481 case 0x01: /* A-B LNA2 */ 482 ant_conf->fast_div_bias = 0x1; 483 break; 484 case 0x02: /* A-B LNA1 */ 485 ant_conf->fast_div_bias = 0x39; 486 break; 487 case 0x03: /* A-B A+B */ 488 ant_conf->fast_div_bias = 0x1; 489 break; 490 case 0x10: /* LNA2 A-B */ 491 if ((antcomb->scan == 0) && 492 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 493 ant_conf->fast_div_bias = 0x3f; 494 } else { 495 ant_conf->fast_div_bias = 0x1; 496 } 497 break; 498 case 0x12: /* LNA2 LNA1 */ 499 ant_conf->fast_div_bias = 0x39; 500 break; 501 case 0x13: /* LNA2 A+B */ 502 if ((antcomb->scan == 0) && 503 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 504 ant_conf->fast_div_bias = 0x3f; 505 } else { 506 ant_conf->fast_div_bias = 0x1; 507 } 508 break; 509 case 0x20: /* LNA1 A-B */ 510 if ((antcomb->scan == 0) && 511 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 512 ant_conf->fast_div_bias = 0x3f; 513 } else { 514 ant_conf->fast_div_bias = 0x4; 515 } 516 break; 517 case 0x21: /* LNA1 LNA2 */ 518 ant_conf->fast_div_bias = 0x6; 519 break; 520 case 0x23: /* LNA1 A+B */ 521 if ((antcomb->scan == 0) && 522 (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) { 523 ant_conf->fast_div_bias = 0x3f; 524 } else { 525 ant_conf->fast_div_bias = 0x6; 526 } 527 break; 528 case 0x30: /* A+B A-B */ 529 ant_conf->fast_div_bias = 0x1; 530 break; 531 case 0x31: /* A+B LNA2 */ 532 ant_conf->fast_div_bias = 0x6; 533 break; 534 case 0x32: /* A+B LNA1 */ 535 ant_conf->fast_div_bias = 0x1; 536 break; 537 default: 538 break; 539 } 540 } 541 } 542 543 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) 544 { 545 struct ath_hw_antcomb_conf div_ant_conf; 546 struct ath_ant_comb *antcomb = &sc->ant_comb; 547 int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; 548 int curr_main_set; 549 int main_rssi = rs->rs_rssi_ctl0; 550 int alt_rssi = rs->rs_rssi_ctl1; 551 int rx_ant_conf, main_ant_conf; 552 bool short_scan = false; 553 554 rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) & 555 ATH_ANT_RX_MASK; 556 main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) & 557 ATH_ANT_RX_MASK; 558 559 /* Record packet only when both main_rssi and alt_rssi is positive */ 560 if (main_rssi > 0 && alt_rssi > 0) { 561 antcomb->total_pkt_count++; 562 antcomb->main_total_rssi += main_rssi; 563 antcomb->alt_total_rssi += alt_rssi; 564 if (main_ant_conf == rx_ant_conf) 565 antcomb->main_recv_cnt++; 566 else 567 antcomb->alt_recv_cnt++; 568 } 569 570 /* Short scan check */ 571 if (antcomb->scan && antcomb->alt_good) { 572 if (time_after(jiffies, antcomb->scan_start_time + 573 msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR))) 574 short_scan = true; 575 else 576 if (antcomb->total_pkt_count == 577 ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) { 578 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 579 antcomb->total_pkt_count); 580 if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO) 581 short_scan = true; 582 } 583 } 584 585 if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) || 586 rs->rs_moreaggr) && !short_scan) 587 return; 588 589 if (antcomb->total_pkt_count) { 590 alt_ratio = ((antcomb->alt_recv_cnt * 100) / 591 antcomb->total_pkt_count); 592 main_rssi_avg = (antcomb->main_total_rssi / 593 antcomb->total_pkt_count); 594 alt_rssi_avg = (antcomb->alt_total_rssi / 595 antcomb->total_pkt_count); 596 } 597 598 599 ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); 600 curr_alt_set = div_ant_conf.alt_lna_conf; 601 curr_main_set = div_ant_conf.main_lna_conf; 602 603 antcomb->count++; 604 605 if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) { 606 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) { 607 ath_lnaconf_alt_good_scan(antcomb, div_ant_conf, 608 main_rssi_avg); 609 antcomb->alt_good = true; 610 } else { 611 antcomb->alt_good = false; 612 } 613 614 antcomb->count = 0; 615 antcomb->scan = true; 616 antcomb->scan_not_start = true; 617 } 618 619 if (!antcomb->scan) { 620 if (ath_ant_div_comb_alt_check(div_ant_conf.div_group, 621 alt_ratio, curr_main_set, curr_alt_set, 622 alt_rssi_avg, main_rssi_avg)) { 623 if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) { 624 /* Switch main and alt LNA */ 625 div_ant_conf.main_lna_conf = 626 ATH_ANT_DIV_COMB_LNA2; 627 div_ant_conf.alt_lna_conf = 628 ATH_ANT_DIV_COMB_LNA1; 629 } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) { 630 div_ant_conf.main_lna_conf = 631 ATH_ANT_DIV_COMB_LNA1; 632 div_ant_conf.alt_lna_conf = 633 ATH_ANT_DIV_COMB_LNA2; 634 } 635 636 goto div_comb_done; 637 } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) && 638 (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) { 639 /* Set alt to another LNA */ 640 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) 641 div_ant_conf.alt_lna_conf = 642 ATH_ANT_DIV_COMB_LNA1; 643 else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) 644 div_ant_conf.alt_lna_conf = 645 ATH_ANT_DIV_COMB_LNA2; 646 647 goto div_comb_done; 648 } 649 650 if ((alt_rssi_avg < (main_rssi_avg + 651 div_ant_conf.lna1_lna2_delta))) 652 goto div_comb_done; 653 } 654 655 if (!antcomb->scan_not_start) { 656 switch (curr_alt_set) { 657 case ATH_ANT_DIV_COMB_LNA2: 658 antcomb->rssi_lna2 = alt_rssi_avg; 659 antcomb->rssi_lna1 = main_rssi_avg; 660 antcomb->scan = true; 661 /* set to A+B */ 662 div_ant_conf.main_lna_conf = 663 ATH_ANT_DIV_COMB_LNA1; 664 div_ant_conf.alt_lna_conf = 665 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 666 break; 667 case ATH_ANT_DIV_COMB_LNA1: 668 antcomb->rssi_lna1 = alt_rssi_avg; 669 antcomb->rssi_lna2 = main_rssi_avg; 670 antcomb->scan = true; 671 /* set to A+B */ 672 div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2; 673 div_ant_conf.alt_lna_conf = 674 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 675 break; 676 case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2: 677 antcomb->rssi_add = alt_rssi_avg; 678 antcomb->scan = true; 679 /* set to A-B */ 680 div_ant_conf.alt_lna_conf = 681 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 682 break; 683 case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2: 684 antcomb->rssi_sub = alt_rssi_avg; 685 antcomb->scan = false; 686 if (antcomb->rssi_lna2 > 687 (antcomb->rssi_lna1 + 688 ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) { 689 /* use LNA2 as main LNA */ 690 if ((antcomb->rssi_add > antcomb->rssi_lna1) && 691 (antcomb->rssi_add > antcomb->rssi_sub)) { 692 /* set to A+B */ 693 div_ant_conf.main_lna_conf = 694 ATH_ANT_DIV_COMB_LNA2; 695 div_ant_conf.alt_lna_conf = 696 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 697 } else if (antcomb->rssi_sub > 698 antcomb->rssi_lna1) { 699 /* set to A-B */ 700 div_ant_conf.main_lna_conf = 701 ATH_ANT_DIV_COMB_LNA2; 702 div_ant_conf.alt_lna_conf = 703 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 704 } else { 705 /* set to LNA1 */ 706 div_ant_conf.main_lna_conf = 707 ATH_ANT_DIV_COMB_LNA2; 708 div_ant_conf.alt_lna_conf = 709 ATH_ANT_DIV_COMB_LNA1; 710 } 711 } else { 712 /* use LNA1 as main LNA */ 713 if ((antcomb->rssi_add > antcomb->rssi_lna2) && 714 (antcomb->rssi_add > antcomb->rssi_sub)) { 715 /* set to A+B */ 716 div_ant_conf.main_lna_conf = 717 ATH_ANT_DIV_COMB_LNA1; 718 div_ant_conf.alt_lna_conf = 719 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2; 720 } else if (antcomb->rssi_sub > 721 antcomb->rssi_lna1) { 722 /* set to A-B */ 723 div_ant_conf.main_lna_conf = 724 ATH_ANT_DIV_COMB_LNA1; 725 div_ant_conf.alt_lna_conf = 726 ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2; 727 } else { 728 /* set to LNA2 */ 729 div_ant_conf.main_lna_conf = 730 ATH_ANT_DIV_COMB_LNA1; 731 div_ant_conf.alt_lna_conf = 732 ATH_ANT_DIV_COMB_LNA2; 733 } 734 } 735 break; 736 default: 737 break; 738 } 739 } else { 740 if (!antcomb->alt_good) { 741 antcomb->scan_not_start = false; 742 /* Set alt to another LNA */ 743 if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) { 744 div_ant_conf.main_lna_conf = 745 ATH_ANT_DIV_COMB_LNA2; 746 div_ant_conf.alt_lna_conf = 747 ATH_ANT_DIV_COMB_LNA1; 748 } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) { 749 div_ant_conf.main_lna_conf = 750 ATH_ANT_DIV_COMB_LNA1; 751 div_ant_conf.alt_lna_conf = 752 ATH_ANT_DIV_COMB_LNA2; 753 } 754 goto div_comb_done; 755 } 756 } 757 758 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf, 759 main_rssi_avg, alt_rssi_avg, 760 alt_ratio); 761 762 antcomb->quick_scan_cnt++; 763 764 div_comb_done: 765 ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio); 766 ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf); 767 768 antcomb->scan_start_time = jiffies; 769 antcomb->total_pkt_count = 0; 770 antcomb->main_total_rssi = 0; 771 antcomb->alt_total_rssi = 0; 772 antcomb->main_recv_cnt = 0; 773 antcomb->alt_recv_cnt = 0; 774 } 775 776 void ath_ant_comb_update(struct ath_softc *sc) 777 { 778 struct ath_hw *ah = sc->sc_ah; 779 struct ath_common *common = ath9k_hw_common(ah); 780 struct ath_hw_antcomb_conf div_ant_conf; 781 u8 lna_conf; 782 783 ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf); 784 785 if (sc->ant_rx == 1) 786 lna_conf = ATH_ANT_DIV_COMB_LNA1; 787 else 788 lna_conf = ATH_ANT_DIV_COMB_LNA2; 789 790 div_ant_conf.main_lna_conf = lna_conf; 791 div_ant_conf.alt_lna_conf = lna_conf; 792 793 ath9k_hw_antdiv_comb_conf_set(ah, &div_ant_conf); 794 795 if (common->antenna_diversity) 796 ath9k_hw_antctrl_shared_chain_lnadiv(ah, true); 797 } 798