brintos

brintos / linux-shallow public Read only

0
0
Text · 24.6 KiB · acc84e6 Raw
850 lines · c
1/*2 * Copyright (c) 2012 Qualcomm Atheros, Inc.3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#include "ath9k.h"18 19/*20 * AR928521 * ======22 *23 * EEPROM has 2 4-bit fields containing the card configuration.24 *25 * antdiv_ctl1:26 * ------------27 * bb_enable_ant_div_lnadiv : 128 * bb_ant_div_alt_gaintb    : 129 * bb_ant_div_main_gaintb   : 130 * bb_enable_ant_fast_div   : 131 *32 * antdiv_ctl2:33 * -----------34 * bb_ant_div_alt_lnaconf  : 235 * bb_ant_div_main_lnaconf : 236 *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 044 *                                 1 -> Antenna config Alt/Main uses gaintable 145 *                                 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=LNA153 *                                 01=LNA254 *                                 11=LNA1+LNA255 *                                 00=LNA1-LNA256 *57 * AR9485 / AR9565 / AR933158 * ========================59 *60 * The same bits are present in the EEPROM, but the location in the61 * EEPROM is different (ant_div_control in ar9300_BaseExtension_1).62 *63 * ant_div_alt_lnaconf      ==> bit 0~164 * ant_div_main_lnaconf     ==> bit 2~365 * ant_div_alt_gaintb       ==> bit 466 * ant_div_main_gaintb      ==> bit 567 * enable_ant_div_lnadiv    ==> bit 668 * enable_ant_fast_div      ==> bit 769 */70 71static 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 90static 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 138static 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 193static 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				else206					conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;207			else208				/* 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			else217				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			else230				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;231		else232			/* 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			else242				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;243		else244			/* 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			else254				conf->alt_lna_conf = ATH_ANT_DIV_COMB_LNA2;255		else256			/* Set alt to A+B or A-B */257			conf->alt_lna_conf = antcomb->main_conf;258	}259}260 261static 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			else289				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			else298				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			else307				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		else338			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			else348				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			else357				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			else366				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 377static 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			else445				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			else455				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			else462				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			else472				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			else503				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			else512				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			else518				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			else527				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 589static 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_lna2) {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 662static 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 700static 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 721void 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		else754			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 838div_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}850