root/drivers/net/wireless/ath/ath9k/antenna.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ath_is_alt_ant_ratio_better
  2. ath_ant_div_comb_alt_check
  3. ath_lnaconf_alt_good_scan
  4. ath_ant_set_alt_ratio
  5. ath_select_ant_div_from_quick_scan
  6. ath_ant_div_conf_fast_divbias
  7. ath_ant_try_scan
  8. ath_ant_try_switch
  9. ath_ant_short_scan_check
  10. ath_ant_comb_scan

   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 /*
  20  * AR9285
  21  * ======
  22  *
  23  * EEPROM has 2 4-bit fields containing the card configuration.
  24  *
  25  * antdiv_ctl1:
  26  * ------------
  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
  31  *
  32  * antdiv_ctl2:
  33  * -----------
  34  * bb_ant_div_alt_lnaconf  : 2
  35  * bb_ant_div_main_lnaconf : 2
  36  *
  37  * The EEPROM bits are used as follows:
  38  * ------------------------------------
  39  *
  40  * bb_enable_ant_div_lnadiv      - Enable LNA path rx antenna diversity/combining.
  41  *                                 Set in AR_PHY_MULTICHAIN_GAIN_CTL.
  42  *
  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.
  46  *
  47  * bb_enable_ant_fast_div        - Enable fast antenna diversity.
  48  *                                 Set in AR_PHY_CCK_DETECT.
  49  *
  50  * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
  51  *                                 Set in AR_PHY_MULTICHAIN_GAIN_CTL.
  52  *                                 10=LNA1
  53  *                                 01=LNA2
  54  *                                 11=LNA1+LNA2
  55  *                                 00=LNA1-LNA2
  56  *
  57  * AR9485 / AR9565 / AR9331
  58  * ========================
  59  *
  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).
  62  *
  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
  69  */
  70 
  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)
  75 {
  76         if (pkt_count <= 50)
  77                 return false;
  78 
  79         if (alt_rssi_avg > main_rssi_avg + mindelta)
  80                 return true;
  81 
  82         if (alt_ratio >= antcomb->ant_ratio2 &&
  83             alt_rssi_avg >= antcomb->low_rssi_thresh &&
  84             (alt_rssi_avg > main_rssi_avg + maxdelta))
  85                 return true;
  86 
  87         return false;
  88 }
  89 
  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,
  93                                               int main_rssi_avg)
  94 {
  95         bool result, set1, set2;
  96 
  97         result = set1 = set2 = false;
  98 
  99         if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
 100             conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
 101                 set1 = true;
 102 
 103         if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
 104             conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
 105                 set2 = true;
 106 
 107         switch (conf->div_group) {
 108         case 0:
 109                 if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
 110                         result = true;
 111                 break;
 112         case 1:
 113         case 2:
 114                 if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
 115                         break;
 116 
 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))
 120                         result = true;
 121 
 122                 break;
 123         case 3:
 124                 if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
 125                         break;
 126 
 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))
 130                         result = true;
 131 
 132                 break;
 133         }
 134 
 135         return result;
 136 }
 137 
 138 static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
 139                                       struct ath_hw_antcomb_conf ant_conf,
 140                                       int main_rssi_avg)
 141 {
 142         antcomb->quick_scan_cnt = 0;
 143 
 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;
 148 
 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;
 155                 break;
 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;
 161                 break;
 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;
 168                 break;
 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;
 175                 break;
 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;
 181                 break;
 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;
 187                 break;
 188         default:
 189                 break;
 190         }
 191 }
 192 
 193 static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
 194                                   struct ath_hw_antcomb_conf *conf)
 195 {
 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) {
 199                         /* first alt*/
 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;
 205                                 else
 206                                         conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 207                         else
 208                                 /* Set alt to A+B or A-B */
 209                                 conf->alt_lna_conf =
 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;
 216                         else
 217                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 218                 } else {
 219                         /* Set alt to A+B or A-B */
 220                         conf->alt_lna_conf = antcomb->second_quick_scan_conf;
 221                 }
 222         } else if (antcomb->first_ratio) {
 223                 /* first alt */
 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;
 229                         else
 230                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 231                 else
 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) {
 235                 /* second alt */
 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;
 241                         else
 242                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 243                 else
 244                         /* Set alt to A+B or A-B */
 245                         conf->alt_lna_conf = antcomb->second_quick_scan_conf;
 246         } else {
 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;
 253                         else
 254                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 255                 else
 256                         /* Set alt to A+B or A-B */
 257                         conf->alt_lna_conf = antcomb->main_conf;
 258         }
 259 }
 260 
 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,
 264                                        int alt_ratio)
 265 {
 266         /* alt_good */
 267         switch (antcomb->quick_scan_cnt) {
 268         case 0:
 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;
 272                 break;
 273         case 1:
 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;
 279 
 280                 if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
 281                         /* main is 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;
 288                         else
 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;
 297                         else
 298                                 antcomb->first_ratio = false;
 299                 } else {
 300                         if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
 301                                                 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
 302                                                 0,
 303                                                 main_rssi_avg, alt_rssi_avg,
 304                                                 antcomb->total_pkt_count))
 305                                 antcomb->first_ratio = true;
 306                         else
 307                                 antcomb->first_ratio = false;
 308                 }
 309                 break;
 310         case 2:
 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;
 316 
 317                 switch(antcomb->second_quick_scan_conf) {
 318                 case ATH_ANT_DIV_COMB_LNA1:
 319                         antcomb->rssi_lna1 = alt_rssi_avg;
 320                         break;
 321                 case ATH_ANT_DIV_COMB_LNA2:
 322                         antcomb->rssi_lna2 = alt_rssi_avg;
 323                         break;
 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;
 329                         break;
 330                 default:
 331                         break;
 332                 }
 333 
 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;
 337                 else
 338                         div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
 339 
 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;
 347                         else
 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;
 356                         else
 357                                 antcomb->second_ratio = false;
 358                 } else {
 359                         if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
 360                                                 ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
 361                                                 0,
 362                                                 main_rssi_avg, alt_rssi_avg,
 363                                                 antcomb->total_pkt_count))
 364                                 antcomb->second_ratio = true;
 365                         else
 366                                 antcomb->second_ratio = false;
 367                 }
 368 
 369                 ath_ant_set_alt_ratio(antcomb, div_ant_conf);
 370 
 371                 break;
 372         default:
 373                 break;
 374         }
 375 }
 376 
 377 static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
 378                                           struct ath_ant_comb *antcomb,
 379                                           int alt_ratio)
 380 {
 381         ant_conf->main_gaintb = 0;
 382         ant_conf->alt_gaintb = 0;
 383 
 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;
 390                         break;
 391                 case 0x02: /* A-B LNA1 */
 392                         ant_conf->fast_div_bias = 0x3d;
 393                         break;
 394                 case 0x03: /* A-B A+B */
 395                         ant_conf->fast_div_bias = 0x1;
 396                         break;
 397                 case 0x10: /* LNA2 A-B */
 398                         ant_conf->fast_div_bias = 0x7;
 399                         break;
 400                 case 0x12: /* LNA2 LNA1 */
 401                         ant_conf->fast_div_bias = 0x2;
 402                         break;
 403                 case 0x13: /* LNA2 A+B */
 404                         ant_conf->fast_div_bias = 0x7;
 405                         break;
 406                 case 0x20: /* LNA1 A-B */
 407                         ant_conf->fast_div_bias = 0x6;
 408                         break;
 409                 case 0x21: /* LNA1 LNA2 */
 410                         ant_conf->fast_div_bias = 0x0;
 411                         break;
 412                 case 0x23: /* LNA1 A+B */
 413                         ant_conf->fast_div_bias = 0x6;
 414                         break;
 415                 case 0x30: /* A+B A-B */
 416                         ant_conf->fast_div_bias = 0x1;
 417                         break;
 418                 case 0x31: /* A+B LNA2 */
 419                         ant_conf->fast_div_bias = 0x3b;
 420                         break;
 421                 case 0x32: /* A+B LNA1 */
 422                         ant_conf->fast_div_bias = 0x3d;
 423                         break;
 424                 default:
 425                         break;
 426                 }
 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;
 433                         break;
 434                 case 0x02: /* A-B LNA1 */
 435                         ant_conf->fast_div_bias = 0x1;
 436                         break;
 437                 case 0x03: /* A-B A+B */
 438                         ant_conf->fast_div_bias = 0x1;
 439                         break;
 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;
 444                         else
 445                                 ant_conf->fast_div_bias = 0x1;
 446                         break;
 447                 case 0x12: /* LNA2 LNA1 */
 448                         ant_conf->fast_div_bias = 0x1;
 449                         break;
 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;
 454                         else
 455                                 ant_conf->fast_div_bias = 0x1;
 456                         break;
 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;
 461                         else
 462                                 ant_conf->fast_div_bias = 0x1;
 463                         break;
 464                 case 0x21: /* LNA1 LNA2 */
 465                         ant_conf->fast_div_bias = 0x1;
 466                         break;
 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;
 471                         else
 472                                 ant_conf->fast_div_bias = 0x1;
 473                         break;
 474                 case 0x30: /* A+B A-B */
 475                         ant_conf->fast_div_bias = 0x1;
 476                         break;
 477                 case 0x31: /* A+B LNA2 */
 478                         ant_conf->fast_div_bias = 0x1;
 479                         break;
 480                 case 0x32: /* A+B LNA1 */
 481                         ant_conf->fast_div_bias = 0x1;
 482                         break;
 483                 default:
 484                         break;
 485                 }
 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;
 492                         break;
 493                 case 0x02: /* A-B LNA1 */
 494                         ant_conf->fast_div_bias = 0x1;
 495                         break;
 496                 case 0x03: /* A-B A+B */
 497                         ant_conf->fast_div_bias = 0x1;
 498                         break;
 499                 case 0x10: /* LNA2 A-B */
 500                         if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
 501                                 ant_conf->fast_div_bias = 0x1;
 502                         else
 503                                 ant_conf->fast_div_bias = 0x2;
 504                         break;
 505                 case 0x12: /* LNA2 LNA1 */
 506                         ant_conf->fast_div_bias = 0x1;
 507                         break;
 508                 case 0x13: /* LNA2 A+B */
 509                         if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
 510                                 ant_conf->fast_div_bias = 0x1;
 511                         else
 512                                 ant_conf->fast_div_bias = 0x2;
 513                         break;
 514                 case 0x20: /* LNA1 A-B */
 515                         if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
 516                                 ant_conf->fast_div_bias = 0x1;
 517                         else
 518                                 ant_conf->fast_div_bias = 0x2;
 519                         break;
 520                 case 0x21: /* LNA1 LNA2 */
 521                         ant_conf->fast_div_bias = 0x1;
 522                         break;
 523                 case 0x23: /* LNA1 A+B */
 524                         if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
 525                                 ant_conf->fast_div_bias = 0x1;
 526                         else
 527                                 ant_conf->fast_div_bias = 0x2;
 528                         break;
 529                 case 0x30: /* A+B A-B */
 530                         ant_conf->fast_div_bias = 0x1;
 531                         break;
 532                 case 0x31: /* A+B LNA2 */
 533                         ant_conf->fast_div_bias = 0x1;
 534                         break;
 535                 case 0x32: /* A+B LNA1 */
 536                         ant_conf->fast_div_bias = 0x1;
 537                         break;
 538                 default:
 539                         break;
 540                 }
 541 
 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;
 549                         break;
 550                 case 0x02: /* A-B LNA1 */
 551                         ant_conf->fast_div_bias = 0x39;
 552                         break;
 553                 case 0x03: /* A-B A+B */
 554                         ant_conf->fast_div_bias = 0x1;
 555                         break;
 556                 case 0x10: /* LNA2 A-B */
 557                         ant_conf->fast_div_bias = 0x2;
 558                         break;
 559                 case 0x12: /* LNA2 LNA1 */
 560                         ant_conf->fast_div_bias = 0x3f;
 561                         break;
 562                 case 0x13: /* LNA2 A+B */
 563                         ant_conf->fast_div_bias = 0x2;
 564                         break;
 565                 case 0x20: /* LNA1 A-B */
 566                         ant_conf->fast_div_bias = 0x3;
 567                         break;
 568                 case 0x21: /* LNA1 LNA2 */
 569                         ant_conf->fast_div_bias = 0x3;
 570                         break;
 571                 case 0x23: /* LNA1 A+B */
 572                         ant_conf->fast_div_bias = 0x3;
 573                         break;
 574                 case 0x30: /* A+B A-B */
 575                         ant_conf->fast_div_bias = 0x1;
 576                         break;
 577                 case 0x31: /* A+B LNA2 */
 578                         ant_conf->fast_div_bias = 0x6;
 579                         break;
 580                 case 0x32: /* A+B LNA1 */
 581                         ant_conf->fast_div_bias = 0x1;
 582                         break;
 583                 default:
 584                         break;
 585                 }
 586         }
 587 }
 588 
 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,
 592                              int main_rssi_avg)
 593 {
 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;
 599                 /* set to A+B */
 600                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
 601                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
 602                 break;
 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;
 607                 /* set to A+B */
 608                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 609                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
 610                 break;
 611         case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
 612                 antcomb->rssi_add = alt_rssi_avg;
 613                 antcomb->scan = true;
 614                 /* set to A-B */
 615                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
 616                 break;
 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)) {
 625                                 /* set to A+B */
 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) {
 630                                 /* set to A-B */
 631                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 632                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
 633                         } else {
 634                                 /* set to LNA1 */
 635                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 636                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
 637                         }
 638                 } else {
 639                         /* use LNA1 as main LNA */
 640                         if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
 641                             (antcomb->rssi_add > antcomb->rssi_sub)) {
 642                                 /* set to A+B */
 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) {
 647                                 /* set to A-B */
 648                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
 649                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
 650                         } else {
 651                                 /* set to LNA2 */
 652                                 conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
 653                                 conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
 654                         }
 655                 }
 656                 break;
 657         default:
 658                 break;
 659         }
 660 }
 661 
 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,
 666                                int curr_alt_set)
 667 {
 668         bool ret = false;
 669 
 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) {
 673                         /*
 674                          * Switch main and alt LNA.
 675                          */
 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;
 681                 }
 682 
 683                 ret = true;
 684         } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
 685                    (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
 686                 /*
 687                   Set alt to another LNA.
 688                 */
 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;
 693 
 694                 ret = true;
 695         }
 696 
 697         return ret;
 698 }
 699 
 700 static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
 701 {
 702         int alt_ratio;
 703 
 704         if (!antcomb->scan || !antcomb->alt_good)
 705                 return false;
 706 
 707         if (time_after(jiffies, antcomb->scan_start_time +
 708                        msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
 709                 return true;
 710 
 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)
 715                         return true;
 716         }
 717 
 718         return false;
 719 }
 720 
 721 void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
 722 {
 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;
 726         int curr_main_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;
 731 
 732         rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
 733                        ATH_ANT_RX_MASK;
 734         main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
 735                          ATH_ANT_RX_MASK;
 736 
 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;
 740         } else {
 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;
 743         }
 744 
 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;
 750 
 751                 if (main_ant_conf == rx_ant_conf)
 752                         antcomb->main_recv_cnt++;
 753                 else
 754                         antcomb->alt_recv_cnt++;
 755         }
 756 
 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);
 760         } else {
 761                 ANT_STAT_INC(sc, ANT_ALT, recv_cnt);
 762                 ANT_LNA_INC(sc, ANT_ALT, rx_ant_conf);
 763         }
 764 
 765         /* Short scan check */
 766         short_scan = ath_ant_short_scan_check(antcomb);
 767 
 768         if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
 769              rs->rs_moreaggr) && !short_scan)
 770                 return;
 771 
 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);
 779         }
 780 
 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;
 784         antcomb->count++;
 785 
 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,
 789                                                   main_rssi_avg);
 790                         antcomb->alt_good = true;
 791                 } else {
 792                         antcomb->alt_good = false;
 793                 }
 794 
 795                 antcomb->count = 0;
 796                 antcomb->scan = true;
 797                 antcomb->scan_not_start = true;
 798         }
 799 
 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);
 804                 if (ret)
 805                         goto div_comb_done;
 806         }
 807 
 808         if (!antcomb->scan &&
 809             (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
 810                 goto div_comb_done;
 811 
 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);
 815         } else {
 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;
 829                         }
 830                         goto div_comb_done;
 831                 }
 832                 ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
 833                                                    main_rssi_avg, alt_rssi_avg,
 834                                                    alt_ratio);
 835                 antcomb->quick_scan_cnt++;
 836         }
 837 
 838 div_comb_done:
 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);
 842 
 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;
 849 }

/* [<][>][^][v][top][bottom][index][help] */