diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/btcoex.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/btcoex.c | 383 |
1 files changed, 135 insertions, 248 deletions
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index 55f607b7699e..fb4ac15f3b93 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c | |||
@@ -14,10 +14,26 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include "ath9k.h" | 17 | #include "hw.h" |
18 | 18 | ||
19 | static const struct ath_btcoex_config ath_bt_config = { 0, true, true, | 19 | enum ath_bt_mode { |
20 | ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; | 20 | ATH_BT_COEX_MODE_LEGACY, /* legacy rx_clear mode */ |
21 | ATH_BT_COEX_MODE_UNSLOTTED, /* untimed/unslotted mode */ | ||
22 | ATH_BT_COEX_MODE_SLOTTED, /* slotted mode */ | ||
23 | ATH_BT_COEX_MODE_DISALBED, /* coexistence disabled */ | ||
24 | }; | ||
25 | |||
26 | struct ath_btcoex_config { | ||
27 | u8 bt_time_extend; | ||
28 | bool bt_txstate_extend; | ||
29 | bool bt_txframe_extend; | ||
30 | enum ath_bt_mode bt_mode; /* coexistence mode */ | ||
31 | bool bt_quiet_collision; | ||
32 | bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/ | ||
33 | u8 bt_priority_time; | ||
34 | u8 bt_first_slot_time; | ||
35 | bool bt_hold_rx_clear; | ||
36 | }; | ||
21 | 37 | ||
22 | static const u16 ath_subsysid_tbl[] = { | 38 | static const u16 ath_subsysid_tbl[] = { |
23 | AR9280_COEX2WIRE_SUBSYSID, | 39 | AR9280_COEX2WIRE_SUBSYSID, |
@@ -29,141 +45,38 @@ static const u16 ath_subsysid_tbl[] = { | |||
29 | * Checks the subsystem id of the device to see if it | 45 | * Checks the subsystem id of the device to see if it |
30 | * supports btcoex | 46 | * supports btcoex |
31 | */ | 47 | */ |
32 | bool ath_btcoex_supported(u16 subsysid) | 48 | bool ath9k_hw_btcoex_supported(struct ath_hw *ah) |
33 | { | 49 | { |
34 | int i; | 50 | int i; |
35 | 51 | ||
36 | if (!subsysid) | 52 | if (!ah->hw_version.subsysid) |
37 | return false; | 53 | return false; |
38 | 54 | ||
39 | for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) | 55 | for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) |
40 | if (subsysid == ath_subsysid_tbl[i]) | 56 | if (ah->hw_version.subsysid == ath_subsysid_tbl[i]) |
41 | return true; | 57 | return true; |
42 | 58 | ||
43 | return false; | 59 | return false; |
44 | } | 60 | } |
45 | 61 | ||
46 | /* | 62 | void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) |
47 | * Detects if there is any priority bt traffic | ||
48 | */ | ||
49 | static void ath_detect_bt_priority(struct ath_softc *sc) | ||
50 | { | ||
51 | struct ath_btcoex_info *btinfo = &sc->btcoex_info; | ||
52 | |||
53 | if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio)) | ||
54 | btinfo->bt_priority_cnt++; | ||
55 | |||
56 | if (time_after(jiffies, btinfo->bt_priority_time + | ||
57 | msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { | ||
58 | if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { | ||
59 | DPRINTF(sc, ATH_DBG_BTCOEX, | ||
60 | "BT priority traffic detected"); | ||
61 | sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; | ||
62 | } else { | ||
63 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
64 | } | ||
65 | |||
66 | btinfo->bt_priority_cnt = 0; | ||
67 | btinfo->bt_priority_time = jiffies; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Configures appropriate weight based on stomp type. | ||
73 | */ | ||
74 | static void ath_btcoex_bt_stomp(struct ath_softc *sc, | ||
75 | struct ath_btcoex_info *btinfo, | ||
76 | int stomp_type) | ||
77 | { | ||
78 | |||
79 | switch (stomp_type) { | ||
80 | case ATH_BTCOEX_STOMP_ALL: | ||
81 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
82 | AR_STOMP_ALL_WLAN_WGHT); | ||
83 | break; | ||
84 | case ATH_BTCOEX_STOMP_LOW: | ||
85 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
86 | AR_STOMP_LOW_WLAN_WGHT); | ||
87 | break; | ||
88 | case ATH_BTCOEX_STOMP_NONE: | ||
89 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
90 | AR_STOMP_NONE_WLAN_WGHT); | ||
91 | break; | ||
92 | default: | ||
93 | DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); | ||
94 | break; | ||
95 | } | ||
96 | |||
97 | ath9k_hw_btcoex_enable(sc->sc_ah); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * This is the master bt coex timer which runs for every | ||
102 | * 45ms, bt traffic will be given priority during 55% of this | ||
103 | * period while wlan gets remaining 45% | ||
104 | */ | ||
105 | |||
106 | static void ath_btcoex_period_timer(unsigned long data) | ||
107 | { | ||
108 | struct ath_softc *sc = (struct ath_softc *) data; | ||
109 | struct ath_btcoex_info *btinfo = &sc->btcoex_info; | ||
110 | |||
111 | ath_detect_bt_priority(sc); | ||
112 | |||
113 | spin_lock_bh(&btinfo->btcoex_lock); | ||
114 | |||
115 | ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); | ||
116 | |||
117 | spin_unlock_bh(&btinfo->btcoex_lock); | ||
118 | |||
119 | if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) { | ||
120 | if (btinfo->hw_timer_enabled) | ||
121 | ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); | ||
122 | |||
123 | ath_gen_timer_start(sc->sc_ah, | ||
124 | btinfo->no_stomp_timer, | ||
125 | (ath9k_hw_gettsf32(sc->sc_ah) + | ||
126 | btinfo->btcoex_no_stomp), | ||
127 | btinfo->btcoex_no_stomp * 10); | ||
128 | btinfo->hw_timer_enabled = true; | ||
129 | } | ||
130 | |||
131 | mod_timer(&btinfo->period_timer, jiffies + | ||
132 | msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * Generic tsf based hw timer which configures weight | ||
137 | * registers to time slice between wlan and bt traffic | ||
138 | */ | ||
139 | |||
140 | static void ath_btcoex_no_stomp_timer(void *arg) | ||
141 | { | ||
142 | struct ath_softc *sc = (struct ath_softc *)arg; | ||
143 | struct ath_btcoex_info *btinfo = &sc->btcoex_info; | ||
144 | |||
145 | DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n"); | ||
146 | |||
147 | spin_lock_bh(&btinfo->btcoex_lock); | ||
148 | |||
149 | if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) | ||
150 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); | ||
151 | else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) | ||
152 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); | ||
153 | |||
154 | spin_unlock_bh(&btinfo->btcoex_lock); | ||
155 | } | ||
156 | |||
157 | static int ath_init_btcoex_info(struct ath_hw *hw, | ||
158 | struct ath_btcoex_info *btcoex_info) | ||
159 | { | 63 | { |
64 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | ||
65 | const struct ath_btcoex_config ath_bt_config = { | ||
66 | .bt_time_extend = 0, | ||
67 | .bt_txstate_extend = true, | ||
68 | .bt_txframe_extend = true, | ||
69 | .bt_mode = ATH_BT_COEX_MODE_SLOTTED, | ||
70 | .bt_quiet_collision = true, | ||
71 | .bt_rxclear_polarity = true, | ||
72 | .bt_priority_time = 2, | ||
73 | .bt_first_slot_time = 5, | ||
74 | .bt_hold_rx_clear = true, | ||
75 | }; | ||
160 | u32 i; | 76 | u32 i; |
161 | int qnum; | ||
162 | 77 | ||
163 | qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); | 78 | btcoex_hw->bt_coex_mode = |
164 | 79 | (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | | |
165 | btcoex_info->bt_coex_mode = | ||
166 | (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | | ||
167 | SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | | 80 | SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | |
168 | SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | | 81 | SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | |
169 | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | | 82 | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | |
@@ -174,167 +87,141 @@ static int ath_init_btcoex_info(struct ath_hw *hw, | |||
174 | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | | 87 | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | |
175 | SM(qnum, AR_BT_QCU_THRESH); | 88 | SM(qnum, AR_BT_QCU_THRESH); |
176 | 89 | ||
177 | btcoex_info->bt_coex_mode2 = | 90 | btcoex_hw->bt_coex_mode2 = |
178 | SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | | 91 | SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | |
179 | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | | 92 | SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | |
180 | AR_BT_DISABLE_BT_ANT; | 93 | AR_BT_DISABLE_BT_ANT; |
181 | 94 | ||
182 | btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | 95 | for (i = 0; i < 32; i++) |
96 | ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; | ||
97 | } | ||
98 | EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw); | ||
183 | 99 | ||
184 | btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; | 100 | void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) |
101 | { | ||
102 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | ||
185 | 103 | ||
186 | btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * | 104 | /* connect bt_active to baseband */ |
187 | btcoex_info->btcoex_period / 100; | 105 | REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, |
106 | (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | | ||
107 | AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); | ||
188 | 108 | ||
189 | for (i = 0; i < 32; i++) | 109 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, |
190 | hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; | 110 | AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); |
191 | 111 | ||
192 | setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer, | 112 | /* Set input mux for bt_active to gpio pin */ |
193 | (unsigned long) hw->ah_sc); | 113 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, |
114 | AR_GPIO_INPUT_MUX1_BT_ACTIVE, | ||
115 | btcoex_hw->btactive_gpio); | ||
194 | 116 | ||
195 | btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw, | 117 | /* Configure the desired gpio port for input */ |
196 | ath_btcoex_no_stomp_timer, | 118 | ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); |
197 | ath_btcoex_no_stomp_timer, | 119 | } |
198 | (void *)hw->ah_sc, AR_FIRST_NDP_TIMER); | 120 | EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire); |
121 | |||
122 | void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) | ||
123 | { | ||
124 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | ||
199 | 125 | ||
200 | if (btcoex_info->no_stomp_timer == NULL) | 126 | /* btcoex 3-wire */ |
201 | return -ENOMEM; | 127 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, |
128 | (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | | ||
129 | AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); | ||
202 | 130 | ||
203 | spin_lock_init(&btcoex_info->btcoex_lock); | 131 | /* Set input mux for bt_prority_async and |
132 | * bt_active_async to GPIO pins */ | ||
133 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, | ||
134 | AR_GPIO_INPUT_MUX1_BT_ACTIVE, | ||
135 | btcoex_hw->btactive_gpio); | ||
204 | 136 | ||
205 | return 0; | 137 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, |
138 | AR_GPIO_INPUT_MUX1_BT_PRIORITY, | ||
139 | btcoex_hw->btpriority_gpio); | ||
140 | |||
141 | /* Configure the desired GPIO ports for input */ | ||
142 | |||
143 | ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio); | ||
144 | ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio); | ||
206 | } | 145 | } |
146 | EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire); | ||
207 | 147 | ||
208 | int ath9k_hw_btcoex_init(struct ath_hw *ah) | 148 | static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah) |
209 | { | 149 | { |
210 | struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; | 150 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; |
211 | int ret = 0; | ||
212 | |||
213 | if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { | ||
214 | /* connect bt_active to baseband */ | ||
215 | REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, | ||
216 | (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | | ||
217 | AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); | ||
218 | |||
219 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, | ||
220 | AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); | ||
221 | |||
222 | /* Set input mux for bt_active to gpio pin */ | ||
223 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, | ||
224 | AR_GPIO_INPUT_MUX1_BT_ACTIVE, | ||
225 | btcoex_info->btactive_gpio); | ||
226 | |||
227 | /* Configure the desired gpio port for input */ | ||
228 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); | ||
229 | } else { | ||
230 | /* btcoex 3-wire */ | ||
231 | REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, | ||
232 | (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | | ||
233 | AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); | ||
234 | |||
235 | /* Set input mux for bt_prority_async and | ||
236 | * bt_active_async to GPIO pins */ | ||
237 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, | ||
238 | AR_GPIO_INPUT_MUX1_BT_ACTIVE, | ||
239 | btcoex_info->btactive_gpio); | ||
240 | |||
241 | REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, | ||
242 | AR_GPIO_INPUT_MUX1_BT_PRIORITY, | ||
243 | btcoex_info->btpriority_gpio); | ||
244 | |||
245 | /* Configure the desired GPIO ports for input */ | ||
246 | |||
247 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); | ||
248 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); | ||
249 | |||
250 | ret = ath_init_btcoex_info(ah, btcoex_info); | ||
251 | } | ||
252 | 151 | ||
253 | return ret; | 152 | /* Configure the desired GPIO port for TX_FRAME output */ |
153 | ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, | ||
154 | AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); | ||
254 | } | 155 | } |
255 | 156 | ||
256 | void ath9k_hw_btcoex_enable(struct ath_hw *ah) | 157 | void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, |
158 | u32 bt_weight, | ||
159 | u32 wlan_weight) | ||
257 | { | 160 | { |
258 | struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; | 161 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; |
259 | |||
260 | if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { | ||
261 | /* Configure the desired GPIO port for TX_FRAME output */ | ||
262 | ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, | ||
263 | AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); | ||
264 | } else { | ||
265 | /* | ||
266 | * Program coex mode and weight registers to | ||
267 | * enable coex 3-wire | ||
268 | */ | ||
269 | REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); | ||
270 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); | ||
271 | REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); | ||
272 | |||
273 | REG_RMW_FIELD(ah, AR_QUIET1, | ||
274 | AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); | ||
275 | REG_RMW_FIELD(ah, AR_PCU_MISC, | ||
276 | AR_PCU_BT_ANT_PREVENT_RX, 0); | ||
277 | |||
278 | ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, | ||
279 | AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); | ||
280 | } | ||
281 | 162 | ||
282 | REG_RMW(ah, AR_GPIO_PDPU, | 163 | btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | |
283 | (0x2 << (btcoex_info->btactive_gpio * 2)), | 164 | SM(wlan_weight, AR_BTCOEX_WL_WGHT); |
284 | (0x3 << (btcoex_info->btactive_gpio * 2))); | ||
285 | |||
286 | ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; | ||
287 | } | 165 | } |
166 | EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); | ||
288 | 167 | ||
289 | void ath9k_hw_btcoex_disable(struct ath_hw *ah) | 168 | static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) |
290 | { | 169 | { |
291 | struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info; | 170 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; |
292 | 171 | ||
293 | ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); | 172 | /* |
173 | * Program coex mode and weight registers to | ||
174 | * enable coex 3-wire | ||
175 | */ | ||
176 | REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); | ||
177 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); | ||
178 | REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); | ||
294 | 179 | ||
295 | ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, | 180 | REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); |
296 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); | 181 | REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); |
297 | 182 | ||
298 | if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) { | 183 | ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, |
299 | REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); | 184 | AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); |
300 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); | ||
301 | REG_WRITE(ah, AR_BT_COEX_MODE2, 0); | ||
302 | } | ||
303 | |||
304 | ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; | ||
305 | } | 185 | } |
306 | 186 | ||
307 | /* | 187 | void ath9k_hw_btcoex_enable(struct ath_hw *ah) |
308 | * Pause btcoex timer and bt duty cycle timer | ||
309 | */ | ||
310 | void ath_btcoex_timer_pause(struct ath_softc *sc, | ||
311 | struct ath_btcoex_info *btinfo) | ||
312 | { | 188 | { |
189 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | ||
313 | 190 | ||
314 | del_timer_sync(&btinfo->period_timer); | 191 | switch (btcoex_hw->scheme) { |
192 | case ATH_BTCOEX_CFG_NONE: | ||
193 | break; | ||
194 | case ATH_BTCOEX_CFG_2WIRE: | ||
195 | ath9k_hw_btcoex_enable_2wire(ah); | ||
196 | break; | ||
197 | case ATH_BTCOEX_CFG_3WIRE: | ||
198 | ath9k_hw_btcoex_enable_3wire(ah); | ||
199 | break; | ||
200 | } | ||
315 | 201 | ||
316 | if (btinfo->hw_timer_enabled) | 202 | REG_RMW(ah, AR_GPIO_PDPU, |
317 | ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); | 203 | (0x2 << (btcoex_hw->btactive_gpio * 2)), |
204 | (0x3 << (btcoex_hw->btactive_gpio * 2))); | ||
318 | 205 | ||
319 | btinfo->hw_timer_enabled = false; | 206 | ah->btcoex_hw.enabled = true; |
320 | } | 207 | } |
208 | EXPORT_SYMBOL(ath9k_hw_btcoex_enable); | ||
321 | 209 | ||
322 | /* | 210 | void ath9k_hw_btcoex_disable(struct ath_hw *ah) |
323 | * (Re)start btcoex timers | ||
324 | */ | ||
325 | void ath_btcoex_timer_resume(struct ath_softc *sc, | ||
326 | struct ath_btcoex_info *btinfo) | ||
327 | { | 211 | { |
212 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | ||
328 | 213 | ||
329 | DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers"); | 214 | ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0); |
330 | 215 | ||
331 | /* make sure duty cycle timer is also stopped when resuming */ | 216 | ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio, |
332 | if (btinfo->hw_timer_enabled) | 217 | AR_GPIO_OUTPUT_MUX_AS_OUTPUT); |
333 | ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer); | ||
334 | 218 | ||
335 | btinfo->bt_priority_cnt = 0; | 219 | if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { |
336 | btinfo->bt_priority_time = jiffies; | 220 | REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); |
337 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | 221 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); |
222 | REG_WRITE(ah, AR_BT_COEX_MODE2, 0); | ||
223 | } | ||
338 | 224 | ||
339 | mod_timer(&btinfo->period_timer, jiffies); | 225 | ah->btcoex_hw.enabled = false; |
340 | } | 226 | } |
227 | EXPORT_SYMBOL(ath9k_hw_btcoex_disable); | ||