xref: /freebsd/sys/dev/ath/ath_hal/ar9002/ar9285_btcoex.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
1 /*
2  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
3  * Copyright (c) 2002-2005 Atheros Communications, Inc.
4  * Copyright (c) 2008-2010, Atheros Communications Inc.
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * $FreeBSD$
19  */
20 
21 #include "opt_ah.h"
22 
23 #include "ah.h"
24 #include "ah_internal.h"
25 #include "ah_devid.h"
26 #ifdef AH_DEBUG
27 #include "ah_desc.h"		    /* NB: for HAL_PHYERR* */
28 #endif
29 
30 #include "ar5416/ar5416.h"
31 #include "ar5416/ar5416reg.h"
32 #include "ar5416/ar5416phy.h"
33 #include "ar5416/ar5416desc.h" /* AR5416_CONTTXMODE */
34 
35 #include "ar9002/ar9285phy.h"
36 #include "ar9002/ar9285.h"
37 
38 /*
39  * This is specific to Kite.
40  *
41  * Kiwi and others don't have antenna diversity like this.
42  */
43 void
44 ar9285BTCoexAntennaDiversity(struct ath_hal *ah)
45 {
46 	struct ath_hal_5416 *ahp = AH5416(ah);
47 	u_int32_t regVal;
48 	u_int8_t ant_div_control1, ant_div_control2;
49 
50 	if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ALLOW) ||
51 	    (AH5212(ah)->ah_diversity != HAL_ANT_VARIABLE)) {
52 	if ((ahp->ah_btCoexFlag & HAL_BT_COEX_FLAG_ANT_DIV_ENABLE) &&
53 	     (AH5212(ah)->ah_antControl == HAL_ANT_VARIABLE)) {
54 		/* Enable antenna diversity */
55 		ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_ENABLE;
56 		ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_ENABLE;
57 
58 		/* Don't disable BT ant to allow BB to control SWCOM */
59 		ahp->ah_btCoexMode2 &= (~(AR_BT_DISABLE_BT_ANT));
60 		OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
61 
62 		/* Program the correct SWCOM table */
63 		OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
64 		    HAL_BT_COEX_ANT_DIV_SWITCH_COM);
65 		OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
66 	} else if (AH5212(ah)->ah_antControl == HAL_ANT_FIXED_B) {
67 		/* Disable antenna diversity. Use antenna B(LNA2) only. */
68 		ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_B;
69 		ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_B;
70 
71 		/* Disable BT ant to allow concurrent BT and WLAN receive */
72 		ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
73 		OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
74 
75 		/*
76 		 * Program SWCOM table to make sure RF switch always parks
77 		 * at WLAN side
78 		 */
79 		OS_REG_WRITE(ah, AR_PHY_SWITCH_COM,
80 		    HAL_BT_COEX_ANT_DIV_SWITCH_COM);
81 		OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0x60000000, 0xf0000000);
82 	} else {
83 		/* Disable antenna diversity. Use antenna A(LNA1) only */
84 		ant_div_control1 = HAL_BT_COEX_ANTDIV_CONTROL1_FIXED_A;
85 		ant_div_control2 = HAL_BT_COEX_ANTDIV_CONTROL2_FIXED_A;
86 
87 		/* Disable BT ant to allow concurrent BT and WLAN receive */
88 		ahp->ah_btCoexMode2 |= AR_BT_DISABLE_BT_ANT;
89 		OS_REG_WRITE(ah, AR_BT_COEX_MODE2, ahp->ah_btCoexMode2);
90 
91 		/*
92 		 * Program SWCOM table to make sure RF switch always
93 		 * parks at BT side
94 		 */
95 		OS_REG_WRITE(ah, AR_PHY_SWITCH_COM, 0);
96 		OS_REG_RMW(ah, AR_PHY_SWITCH_CHAIN_0, 0, 0xf0000000);
97 	}
98 
99 	regVal = OS_REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
100 	regVal &= (~(AR_PHY_9285_ANT_DIV_CTL_ALL));
101 	/*
102 	 * Clear ant_fast_div_bias [14:9] since for Janus the main LNA is
103 	 * always LNA1.
104 	 */
105 	regVal &= (~(AR_PHY_9285_FAST_DIV_BIAS));
106 
107 	regVal |= SM(ant_div_control1, AR_PHY_9285_ANT_DIV_CTL);
108 	regVal |= SM(ant_div_control2, AR_PHY_9285_ANT_DIV_ALT_LNACONF);
109 	regVal |= SM((ant_div_control2 >> 2), AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
110 	regVal |= SM((ant_div_control1 >> 1), AR_PHY_9285_ANT_DIV_ALT_GAINTB);
111 	regVal |= SM((ant_div_control1 >> 2), AR_PHY_9285_ANT_DIV_MAIN_GAINTB);
112 	OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regVal);
113 
114 	regVal = OS_REG_READ(ah, AR_PHY_CCK_DETECT);
115 	regVal &= (~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
116 	regVal |= SM((ant_div_control1 >> 3),
117 	    AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
118 	OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regVal);
119     }
120 }
121 
122 void
123 ar9285BTCoexSetParameter(struct ath_hal *ah, u_int32_t type, u_int32_t value)
124 {
125 	struct ath_hal_5416 *ahp = AH5416(ah);
126 
127 	switch (type) {
128 	case HAL_BT_COEX_ANTENNA_DIVERSITY:
129 		if (AR_SREV_KITE(ah)) {
130 			ahp->ah_btCoexFlag |= HAL_BT_COEX_FLAG_ANT_DIV_ALLOW;
131 			if (value)
132 				ahp->ah_btCoexFlag |=
133 				    HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
134 			else
135 				ahp->ah_btCoexFlag &=
136 				    ~HAL_BT_COEX_FLAG_ANT_DIV_ENABLE;
137 			ar9285BTCoexAntennaDiversity(ah);
138 		}
139 		break;
140 	default:
141 		ar5416BTCoexSetParameter(ah, type, value);
142 		break;
143 	}
144 }
145 
146 
147