123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849 |
- /*
- * Copyright (c) 2012 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "ath9k.h"
- /*
- * AR9285
- * ======
- *
- * EEPROM has 2 4-bit fields containing the card configuration.
- *
- * antdiv_ctl1:
- * ------------
- * bb_enable_ant_div_lnadiv : 1
- * bb_ant_div_alt_gaintb : 1
- * bb_ant_div_main_gaintb : 1
- * bb_enable_ant_fast_div : 1
- *
- * antdiv_ctl2:
- * -----------
- * bb_ant_div_alt_lnaconf : 2
- * bb_ant_div_main_lnaconf : 2
- *
- * The EEPROM bits are used as follows:
- * ------------------------------------
- *
- * bb_enable_ant_div_lnadiv - Enable LNA path rx antenna diversity/combining.
- * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
- *
- * bb_ant_div_[alt/main]_gaintb - 0 -> Antenna config Alt/Main uses gaintable 0
- * 1 -> Antenna config Alt/Main uses gaintable 1
- * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
- *
- * bb_enable_ant_fast_div - Enable fast antenna diversity.
- * Set in AR_PHY_CCK_DETECT.
- *
- * bb_ant_div_[alt/main]_lnaconf - Alt/Main LNA diversity/combining input config.
- * Set in AR_PHY_MULTICHAIN_GAIN_CTL.
- * 10=LNA1
- * 01=LNA2
- * 11=LNA1+LNA2
- * 00=LNA1-LNA2
- *
- * AR9485 / AR9565 / AR9331
- * ========================
- *
- * The same bits are present in the EEPROM, but the location in the
- * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).
- *
- * ant_div_alt_lnaconf ==> bit 0~1
- * ant_div_main_lnaconf ==> bit 2~3
- * ant_div_alt_gaintb ==> bit 4
- * ant_div_main_gaintb ==> bit 5
- * enable_ant_div_lnadiv ==> bit 6
- * enable_ant_fast_div ==> bit 7
- */
- static inline bool ath_is_alt_ant_ratio_better(struct ath_ant_comb *antcomb,
- int alt_ratio, int maxdelta,
- int mindelta, int main_rssi_avg,
- int alt_rssi_avg, int pkt_count)
- {
- if (pkt_count <= 50)
- return false;
- if (alt_rssi_avg > main_rssi_avg + mindelta)
- return true;
- if (alt_ratio >= antcomb->ant_ratio2 &&
- alt_rssi_avg >= antcomb->low_rssi_thresh &&
- (alt_rssi_avg > main_rssi_avg + maxdelta))
- return true;
- return false;
- }
- static inline bool ath_ant_div_comb_alt_check(struct ath_hw_antcomb_conf *conf,
- struct ath_ant_comb *antcomb,
- int alt_ratio, int alt_rssi_avg,
- int main_rssi_avg)
- {
- bool result, set1, set2;
- result = set1 = set2 = false;
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2 &&
- conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA1)
- set1 = true;
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA1 &&
- conf->alt_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- set2 = true;
- switch (conf->div_group) {
- case 0:
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
- result = true;
- break;
- case 1:
- case 2:
- if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
- break;
- if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 5))) ||
- (set2 && (alt_rssi_avg >= (main_rssi_avg - 2))) ||
- (alt_ratio > antcomb->ant_ratio))
- result = true;
- break;
- case 3:
- if (alt_rssi_avg < 4 || alt_rssi_avg < antcomb->low_rssi_thresh)
- break;
- if ((set1 && (alt_rssi_avg >= (main_rssi_avg - 3))) ||
- (set2 && (alt_rssi_avg >= (main_rssi_avg + 3))) ||
- (alt_ratio > antcomb->ant_ratio))
- result = true;
- break;
- }
- return result;
- }
- static void ath_lnaconf_alt_good_scan(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf ant_conf,
- int main_rssi_avg)
- {
- antcomb->quick_scan_cnt = 0;
- if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (ant_conf.main_lna_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
- switch ((ant_conf.main_lna_conf << 4) | ant_conf.alt_lna_conf) {
- case 0x10: /* LNA2 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case 0x20: /* LNA1 A-B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- case 0x21: /* LNA1 LNA2 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case 0x12: /* LNA2 LNA1 */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case 0x13: /* LNA2 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA1;
- break;
- case 0x23: /* LNA1 A+B */
- antcomb->main_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- antcomb->first_quick_scan_conf =
- ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- antcomb->second_quick_scan_conf = ATH_ANT_DIV_COMB_LNA2;
- break;
- default:
- break;
- }
- }
- static void ath_ant_set_alt_ratio(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf *conf)
- {
- /* set alt to the conf with maximun ratio */
- if (antcomb->first_ratio && antcomb->second_ratio) {
- if (antcomb->rssi_second > antcomb->rssi_third) {
- /* first alt*/
- if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2*/
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- conf->alt_lna_conf =
- antcomb->first_quick_scan_conf;
- } else if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2)) {
- /* Set alt LNA1 or LNA2 */
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- } else {
- /* Set alt to A+B or A-B */
- conf->alt_lna_conf = antcomb->second_quick_scan_conf;
- }
- } else if (antcomb->first_ratio) {
- /* first alt */
- if ((antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->first_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- conf->alt_lna_conf = antcomb->first_quick_scan_conf;
- } else if (antcomb->second_ratio) {
- /* second alt */
- if ((antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->second_quick_scan_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- conf->alt_lna_conf = antcomb->second_quick_scan_conf;
- } else {
- /* main is largest */
- if ((antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) ||
- (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2))
- /* Set alt LNA1 or LNA2 */
- if (conf->main_lna_conf == ATH_ANT_DIV_COMB_LNA2)
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- /* Set alt to A+B or A-B */
- conf->alt_lna_conf = antcomb->main_conf;
- }
- }
- static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf *div_ant_conf,
- int main_rssi_avg, int alt_rssi_avg,
- int alt_ratio)
- {
- /* alt_good */
- switch (antcomb->quick_scan_cnt) {
- case 0:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->first_quick_scan_conf;
- break;
- case 1:
- /* set alt to main, and alt to first conf */
- div_ant_conf->main_lna_conf = antcomb->main_conf;
- div_ant_conf->alt_lna_conf = antcomb->second_quick_scan_conf;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_second = alt_rssi_avg;
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- /* main is LNA1 */
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- } else {
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- 0,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->first_ratio = true;
- else
- antcomb->first_ratio = false;
- }
- break;
- case 2:
- antcomb->alt_good = false;
- antcomb->scan_not_start = false;
- antcomb->scan = false;
- antcomb->rssi_first = main_rssi_avg;
- antcomb->rssi_third = alt_rssi_avg;
- switch(antcomb->second_quick_scan_conf) {
- case ATH_ANT_DIV_COMB_LNA1:
- antcomb->rssi_lna1 = alt_rssi_avg;
- break;
- case ATH_ANT_DIV_COMB_LNA2:
- antcomb->rssi_lna2 = alt_rssi_avg;
- break;
- case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
- antcomb->rssi_lna2 = main_rssi_avg;
- else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
- antcomb->rssi_lna1 = main_rssi_avg;
- break;
- default:
- break;
- }
- if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
- div_ant_conf->lna1_lna2_switch_delta)
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- else
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- } else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_MID,
- ATH_ANT_DIV_COMB_LNA1_DELTA_LOW,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- } else {
- if (ath_is_alt_ant_ratio_better(antcomb, alt_ratio,
- ATH_ANT_DIV_COMB_LNA1_DELTA_HI,
- 0,
- main_rssi_avg, alt_rssi_avg,
- antcomb->total_pkt_count))
- antcomb->second_ratio = true;
- else
- antcomb->second_ratio = false;
- }
- ath_ant_set_alt_ratio(antcomb, div_ant_conf);
- break;
- default:
- break;
- }
- }
- static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
- struct ath_ant_comb *antcomb,
- int alt_ratio)
- {
- ant_conf->main_gaintb = 0;
- ant_conf->alt_gaintb = 0;
- if (ant_conf->div_group == 0) {
- /* Adjust the fast_div_bias based on main and alt lna conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x10: /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x13: /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case 0x20: /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x0;
- break;
- case 0x23: /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- default:
- break;
- }
- } else if (ant_conf->div_group == 1) {
- /* Adjust the fast_div_bias based on main and alt_lna_conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x10: /* LNA2 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x13: /* LNA2 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x20: /* LNA1 A-B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x23: /* LNA1 A+B */
- if (!(antcomb->scan) &&
- (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
- ant_conf->fast_div_bias = 0x3f;
- else
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- default:
- break;
- }
- } else if (ant_conf->div_group == 2) {
- /* Adjust the fast_div_bias based on main and alt_lna_conf */
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x10: /* LNA2 A-B */
- if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x13: /* LNA2 A+B */
- if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x20: /* LNA1 A-B */
- if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x23: /* LNA1 A+B */
- if (!antcomb->scan && (alt_ratio > antcomb->ant_ratio))
- ant_conf->fast_div_bias = 0x1;
- else
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- default:
- break;
- }
- if (antcomb->fast_div_bias)
- ant_conf->fast_div_bias = antcomb->fast_div_bias;
- } else if (ant_conf->div_group == 3) {
- switch ((ant_conf->main_lna_conf << 4) |
- ant_conf->alt_lna_conf) {
- case 0x01: /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x02: /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x39;
- break;
- case 0x03: /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x10: /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x12: /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x3f;
- break;
- case 0x13: /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x2;
- break;
- case 0x20: /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x3;
- break;
- case 0x21: /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x3;
- break;
- case 0x23: /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x3;
- break;
- case 0x30: /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case 0x31: /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x6;
- break;
- case 0x32: /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x1;
- break;
- default:
- break;
- }
- }
- }
- static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
- struct ath_hw_antcomb_conf *conf,
- int curr_alt_set, int alt_rssi_avg,
- int main_rssi_avg)
- {
- switch (curr_alt_set) {
- case ATH_ANT_DIV_COMB_LNA2:
- antcomb->rssi_lna2 = alt_rssi_avg;
- antcomb->rssi_lna1 = main_rssi_avg;
- antcomb->scan = true;
- /* set to A+B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1:
- antcomb->rssi_lna1 = alt_rssi_avg;
- antcomb->rssi_lna2 = main_rssi_avg;
- antcomb->scan = true;
- /* set to A+B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
- antcomb->rssi_add = alt_rssi_avg;
- antcomb->scan = true;
- /* set to A-B */
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- break;
- case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
- antcomb->rssi_sub = alt_rssi_avg;
- antcomb->scan = false;
- if (antcomb->rssi_lna2 >
- (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
- /* use LNA2 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA1 */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- }
- } else {
- /* use LNA1 as main LNA */
- if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
- (antcomb->rssi_add > antcomb->rssi_sub)) {
- /* set to A+B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
- } else if (antcomb->rssi_sub >
- antcomb->rssi_lna1) {
- /* set to A-B */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
- } else {
- /* set to LNA2 */
- conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- }
- }
- break;
- default:
- break;
- }
- }
- static bool ath_ant_try_switch(struct ath_hw_antcomb_conf *div_ant_conf,
- struct ath_ant_comb *antcomb,
- int alt_ratio, int alt_rssi_avg,
- int main_rssi_avg, int curr_main_set,
- int curr_alt_set)
- {
- bool ret = false;
- if (ath_ant_div_comb_alt_check(div_ant_conf, antcomb, alt_ratio,
- alt_rssi_avg, main_rssi_avg)) {
- if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
- /*
- * Switch main and alt LNA.
- */
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- }
- ret = true;
- } else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
- (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
- /*
- Set alt to another LNA.
- */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
- div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA1;
- else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
- div_ant_conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;
- ret = true;
- }
- return ret;
- }
- static bool ath_ant_short_scan_check(struct ath_ant_comb *antcomb)
- {
- int alt_ratio;
- if (!antcomb->scan || !antcomb->alt_good)
- return false;
- if (time_after(jiffies, antcomb->scan_start_time +
- msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
- return true;
- if (antcomb->total_pkt_count == ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- if (alt_ratio < antcomb->ant_ratio)
- return true;
- }
- return false;
- }
- void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
- {
- struct ath_hw_antcomb_conf div_ant_conf;
- struct ath_ant_comb *antcomb = &sc->ant_comb;
- int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
- int curr_main_set;
- int main_rssi = rs->rs_rssi_ctl[0];
- int alt_rssi = rs->rs_rssi_ctl[1];
- int rx_ant_conf, main_ant_conf;
- bool short_scan = false, ret;
- rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
- ATH_ANT_RX_MASK;
- main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
- ATH_ANT_RX_MASK;
- if (alt_rssi >= antcomb->low_rssi_thresh) {
- antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO;
- antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2;
- } else {
- antcomb->ant_ratio = ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI;
- antcomb->ant_ratio2 = ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI;
- }
- /* Record packet only when both main_rssi and alt_rssi is positive */
- if (main_rssi > 0 && alt_rssi > 0) {
- antcomb->total_pkt_count++;
- antcomb->main_total_rssi += main_rssi;
- antcomb->alt_total_rssi += alt_rssi;
- if (main_ant_conf == rx_ant_conf)
- antcomb->main_recv_cnt++;
- else
- antcomb->alt_recv_cnt++;
- }
- if (main_ant_conf == rx_ant_conf) {
- ANT_STAT_INC(ANT_MAIN, recv_cnt);
- ANT_LNA_INC(ANT_MAIN, rx_ant_conf);
- } else {
- ANT_STAT_INC(ANT_ALT, recv_cnt);
- ANT_LNA_INC(ANT_ALT, rx_ant_conf);
- }
- /* Short scan check */
- short_scan = ath_ant_short_scan_check(antcomb);
- if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
- rs->rs_moreaggr) && !short_scan)
- return;
- if (antcomb->total_pkt_count) {
- alt_ratio = ((antcomb->alt_recv_cnt * 100) /
- antcomb->total_pkt_count);
- main_rssi_avg = (antcomb->main_total_rssi /
- antcomb->total_pkt_count);
- alt_rssi_avg = (antcomb->alt_total_rssi /
- antcomb->total_pkt_count);
- }
- ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
- curr_alt_set = div_ant_conf.alt_lna_conf;
- curr_main_set = div_ant_conf.main_lna_conf;
- antcomb->count++;
- if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
- if (alt_ratio > antcomb->ant_ratio) {
- ath_lnaconf_alt_good_scan(antcomb, div_ant_conf,
- main_rssi_avg);
- antcomb->alt_good = true;
- } else {
- antcomb->alt_good = false;
- }
- antcomb->count = 0;
- antcomb->scan = true;
- antcomb->scan_not_start = true;
- }
- if (!antcomb->scan) {
- ret = ath_ant_try_switch(&div_ant_conf, antcomb, alt_ratio,
- alt_rssi_avg, main_rssi_avg,
- curr_main_set, curr_alt_set);
- if (ret)
- goto div_comb_done;
- }
- if (!antcomb->scan &&
- (alt_rssi_avg < (main_rssi_avg + div_ant_conf.lna1_lna2_delta)))
- goto div_comb_done;
- if (!antcomb->scan_not_start) {
- ath_ant_try_scan(antcomb, &div_ant_conf, curr_alt_set,
- alt_rssi_avg, main_rssi_avg);
- } else {
- if (!antcomb->alt_good) {
- antcomb->scan_not_start = false;
- /* Set alt to another LNA */
- if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- } else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
- div_ant_conf.main_lna_conf =
- ATH_ANT_DIV_COMB_LNA1;
- div_ant_conf.alt_lna_conf =
- ATH_ANT_DIV_COMB_LNA2;
- }
- goto div_comb_done;
- }
- ath_select_ant_div_from_quick_scan(antcomb, &div_ant_conf,
- main_rssi_avg, alt_rssi_avg,
- alt_ratio);
- antcomb->quick_scan_cnt++;
- }
- div_comb_done:
- ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
- ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
- ath9k_debug_stat_ant(sc, &div_ant_conf, main_rssi_avg, alt_rssi_avg);
- antcomb->scan_start_time = jiffies;
- antcomb->total_pkt_count = 0;
- antcomb->main_total_rssi = 0;
- antcomb->alt_total_rssi = 0;
- antcomb->main_recv_cnt = 0;
- antcomb->alt_recv_cnt = 0;
- }
|