diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/btcoex.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/btcoex.c | 132 |
1 files changed, 105 insertions, 27 deletions
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index fb4ac15f3b93..41ce0b139886 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2009 Atheros Communications Inc. | 2 | * Copyright (c) 2009-2011 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 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 | 5 | * purpose with or without fee is hereby granted, provided that the above |
@@ -35,29 +35,6 @@ struct ath_btcoex_config { | |||
35 | bool bt_hold_rx_clear; | 35 | bool bt_hold_rx_clear; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static const u16 ath_subsysid_tbl[] = { | ||
39 | AR9280_COEX2WIRE_SUBSYSID, | ||
40 | AT9285_COEX3WIRE_SA_SUBSYSID, | ||
41 | AT9285_COEX3WIRE_DA_SUBSYSID | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * Checks the subsystem id of the device to see if it | ||
46 | * supports btcoex | ||
47 | */ | ||
48 | bool ath9k_hw_btcoex_supported(struct ath_hw *ah) | ||
49 | { | ||
50 | int i; | ||
51 | |||
52 | if (!ah->hw_version.subsysid) | ||
53 | return false; | ||
54 | |||
55 | for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) | ||
56 | if (ah->hw_version.subsysid == ath_subsysid_tbl[i]) | ||
57 | return true; | ||
58 | |||
59 | return false; | ||
60 | } | ||
61 | 38 | ||
62 | void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) | 39 | void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) |
63 | { | 40 | { |
@@ -74,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) | |||
74 | .bt_hold_rx_clear = true, | 51 | .bt_hold_rx_clear = true, |
75 | }; | 52 | }; |
76 | u32 i; | 53 | u32 i; |
54 | bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; | ||
55 | |||
56 | if (AR_SREV_9300_20_OR_LATER(ah)) | ||
57 | rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; | ||
77 | 58 | ||
78 | btcoex_hw->bt_coex_mode = | 59 | btcoex_hw->bt_coex_mode = |
79 | (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | | 60 | (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | |
@@ -82,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) | |||
82 | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | | 63 | SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | |
83 | SM(ath_bt_config.bt_mode, AR_BT_MODE) | | 64 | SM(ath_bt_config.bt_mode, AR_BT_MODE) | |
84 | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | | 65 | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | |
85 | SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | | 66 | SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | |
86 | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | | 67 | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | |
87 | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | | 68 | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | |
88 | SM(qnum, AR_BT_QCU_THRESH); | 69 | SM(qnum, AR_BT_QCU_THRESH); |
@@ -165,18 +146,39 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, | |||
165 | } | 146 | } |
166 | EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); | 147 | EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); |
167 | 148 | ||
149 | |||
168 | static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) | 150 | static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) |
169 | { | 151 | { |
170 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; | 152 | struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; |
153 | u32 val; | ||
171 | 154 | ||
172 | /* | 155 | /* |
173 | * Program coex mode and weight registers to | 156 | * Program coex mode and weight registers to |
174 | * enable coex 3-wire | 157 | * enable coex 3-wire |
175 | */ | 158 | */ |
176 | REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); | 159 | 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); | 160 | REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); |
179 | 161 | ||
162 | |||
163 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
164 | REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]); | ||
165 | REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]); | ||
166 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]); | ||
167 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]); | ||
168 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]); | ||
169 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]); | ||
170 | |||
171 | } else | ||
172 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); | ||
173 | |||
174 | |||
175 | |||
176 | if (AR_SREV_9271(ah)) { | ||
177 | val = REG_READ(ah, 0x50040); | ||
178 | val &= 0xFFFFFEFF; | ||
179 | REG_WRITE(ah, 0x50040, val); | ||
180 | } | ||
181 | |||
180 | REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); | 182 | REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); |
181 | REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); | 183 | REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0); |
182 | 184 | ||
@@ -218,10 +220,86 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) | |||
218 | 220 | ||
219 | if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { | 221 | if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { |
220 | REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); | 222 | REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); |
221 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); | ||
222 | REG_WRITE(ah, AR_BT_COEX_MODE2, 0); | 223 | REG_WRITE(ah, AR_BT_COEX_MODE2, 0); |
224 | |||
225 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
226 | REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); | ||
227 | REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); | ||
228 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0); | ||
229 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0); | ||
230 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0); | ||
231 | REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0); | ||
232 | } else | ||
233 | REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); | ||
234 | |||
223 | } | 235 | } |
224 | 236 | ||
225 | ah->btcoex_hw.enabled = false; | 237 | ah->btcoex_hw.enabled = false; |
226 | } | 238 | } |
227 | EXPORT_SYMBOL(ath9k_hw_btcoex_disable); | 239 | EXPORT_SYMBOL(ath9k_hw_btcoex_disable); |
240 | |||
241 | static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, | ||
242 | enum ath_stomp_type stomp_type) | ||
243 | { | ||
244 | ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT; | ||
245 | ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT; | ||
246 | ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT; | ||
247 | ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT; | ||
248 | |||
249 | |||
250 | switch (stomp_type) { | ||
251 | case ATH_BTCOEX_STOMP_ALL: | ||
252 | ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0; | ||
253 | ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1; | ||
254 | break; | ||
255 | case ATH_BTCOEX_STOMP_LOW: | ||
256 | ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0; | ||
257 | ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1; | ||
258 | break; | ||
259 | case ATH_BTCOEX_STOMP_NONE: | ||
260 | ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0; | ||
261 | ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1; | ||
262 | break; | ||
263 | |||
264 | default: | ||
265 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
266 | "Invalid Stomptype\n"); | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | ath9k_hw_btcoex_enable(ah); | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Configures appropriate weight based on stomp type. | ||
275 | */ | ||
276 | void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, | ||
277 | enum ath_stomp_type stomp_type) | ||
278 | { | ||
279 | if (AR_SREV_9300_20_OR_LATER(ah)) { | ||
280 | ar9003_btcoex_bt_stomp(ah, stomp_type); | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | switch (stomp_type) { | ||
285 | case ATH_BTCOEX_STOMP_ALL: | ||
286 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
287 | AR_STOMP_ALL_WLAN_WGHT); | ||
288 | break; | ||
289 | case ATH_BTCOEX_STOMP_LOW: | ||
290 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
291 | AR_STOMP_LOW_WLAN_WGHT); | ||
292 | break; | ||
293 | case ATH_BTCOEX_STOMP_NONE: | ||
294 | ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, | ||
295 | AR_STOMP_NONE_WLAN_WGHT); | ||
296 | break; | ||
297 | default: | ||
298 | ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, | ||
299 | "Invalid Stomptype\n"); | ||
300 | break; | ||
301 | } | ||
302 | |||
303 | ath9k_hw_btcoex_enable(ah); | ||
304 | } | ||
305 | EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); | ||