2 * Copyright (c) 2009 Atheros Communications Inc.
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
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 static const struct ath_btcoex_config ath_bt_config
= { 0, true, true,
20 ATH_BT_COEX_MODE_SLOTTED
, true, true, 2, 5, true };
22 static const u16 ath_subsysid_tbl
[] = {
23 AR9280_COEX2WIRE_SUBSYSID
,
24 AT9285_COEX3WIRE_SA_SUBSYSID
,
25 AT9285_COEX3WIRE_DA_SUBSYSID
29 * Checks the subsystem id of the device to see if it
32 bool ath_btcoex_supported(u16 subsysid
)
39 for (i
= 0; i
< ARRAY_SIZE(ath_subsysid_tbl
); i
++)
40 if (subsysid
== ath_subsysid_tbl
[i
])
47 * Detects if there is any priority bt traffic
49 static void ath_detect_bt_priority(struct ath_softc
*sc
)
51 struct ath_btcoex_info
*btinfo
= &sc
->btcoex_info
;
53 if (ath9k_hw_gpio_get(sc
->sc_ah
, btinfo
->btpriority_gpio
))
54 btinfo
->bt_priority_cnt
++;
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
;
63 sc
->sc_flags
&= ~SC_OP_BT_PRIORITY_DETECTED
;
66 btinfo
->bt_priority_cnt
= 0;
67 btinfo
->bt_priority_time
= jiffies
;
72 * Configures appropriate weight based on stomp type.
74 static void ath_btcoex_bt_stomp(struct ath_softc
*sc
,
75 struct ath_btcoex_info
*btinfo
,
80 case ATH_BTCOEX_STOMP_ALL
:
81 ath_btcoex_set_weight(btinfo
, AR_BT_COEX_WGHT
,
82 AR_STOMP_ALL_WLAN_WGHT
);
84 case ATH_BTCOEX_STOMP_LOW
:
85 ath_btcoex_set_weight(btinfo
, AR_BT_COEX_WGHT
,
86 AR_STOMP_LOW_WLAN_WGHT
);
88 case ATH_BTCOEX_STOMP_NONE
:
89 ath_btcoex_set_weight(btinfo
, AR_BT_COEX_WGHT
,
90 AR_STOMP_NONE_WLAN_WGHT
);
93 DPRINTF(sc
, ATH_DBG_BTCOEX
, "Invalid Stomptype\n");
97 ath9k_hw_btcoex_enable(sc
->sc_ah
);
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%
106 static void ath_btcoex_period_timer(unsigned long data
)
108 struct ath_softc
*sc
= (struct ath_softc
*) data
;
109 struct ath_btcoex_info
*btinfo
= &sc
->btcoex_info
;
111 ath_detect_bt_priority(sc
);
113 spin_lock_bh(&btinfo
->btcoex_lock
);
115 ath_btcoex_bt_stomp(sc
, btinfo
, btinfo
->bt_stomp_type
);
117 spin_unlock_bh(&btinfo
->btcoex_lock
);
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
);
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;
131 mod_timer(&btinfo
->period_timer
, jiffies
+
132 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD
));
136 * Generic tsf based hw timer which configures weight
137 * registers to time slice between wlan and bt traffic
140 static void ath_btcoex_no_stomp_timer(void *arg
)
142 struct ath_softc
*sc
= (struct ath_softc
*)arg
;
143 struct ath_btcoex_info
*btinfo
= &sc
->btcoex_info
;
145 DPRINTF(sc
, ATH_DBG_BTCOEX
, "no stomp timer running \n");
147 spin_lock_bh(&btinfo
->btcoex_lock
);
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
);
154 spin_unlock_bh(&btinfo
->btcoex_lock
);
157 static int ath_init_btcoex_info(struct ath_hw
*hw
,
158 struct ath_btcoex_info
*btcoex_info
)
163 qnum
= ath_tx_get_qnum(hw
->ah_sc
, ATH9K_TX_QUEUE_DATA
, ATH9K_WME_AC_BE
);
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
) |
168 SM(ath_bt_config
.bt_txstate_extend
, AR_BT_TXSTATE_EXTEND
) |
169 SM(ath_bt_config
.bt_txframe_extend
, AR_BT_TX_FRAME_EXTEND
) |
170 SM(ath_bt_config
.bt_mode
, AR_BT_MODE
) |
171 SM(ath_bt_config
.bt_quiet_collision
, AR_BT_QUIET
) |
172 SM(ath_bt_config
.bt_rxclear_polarity
, AR_BT_RX_CLEAR_POLARITY
) |
173 SM(ath_bt_config
.bt_priority_time
, AR_BT_PRIORITY_TIME
) |
174 SM(ath_bt_config
.bt_first_slot_time
, AR_BT_FIRST_SLOT_TIME
) |
175 SM(qnum
, AR_BT_QCU_THRESH
);
177 btcoex_info
->bt_coex_mode2
=
178 SM(ath_bt_config
.bt_hold_rx_clear
, AR_BT_HOLD_RX_CLEAR
) |
179 SM(ATH_BTCOEX_BMISS_THRESH
, AR_BT_BCN_MISS_THRESH
) |
180 AR_BT_DISABLE_BT_ANT
;
182 btcoex_info
->bt_stomp_type
= ATH_BTCOEX_STOMP_LOW
;
184 btcoex_info
->btcoex_period
= ATH_BTCOEX_DEF_BT_PERIOD
* 1000;
186 btcoex_info
->btcoex_no_stomp
= (100 - ATH_BTCOEX_DEF_DUTY_CYCLE
) *
187 btcoex_info
->btcoex_period
/ 100;
189 for (i
= 0; i
< 32; i
++)
190 hw
->hw_gen_timers
.gen_timer_index
[(debruijn32
<< i
) >> 27] = i
;
192 setup_timer(&btcoex_info
->period_timer
, ath_btcoex_period_timer
,
193 (unsigned long) hw
->ah_sc
);
195 btcoex_info
->no_stomp_timer
= ath_gen_timer_alloc(hw
,
196 ath_btcoex_no_stomp_timer
,
197 ath_btcoex_no_stomp_timer
,
198 (void *)hw
->ah_sc
, AR_FIRST_NDP_TIMER
);
200 if (btcoex_info
->no_stomp_timer
== NULL
)
203 spin_lock_init(&btcoex_info
->btcoex_lock
);
208 int ath9k_hw_btcoex_init(struct ath_hw
*ah
)
210 struct ath_btcoex_info
*btcoex_info
= &ah
->ah_sc
->btcoex_info
;
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
));
219 REG_SET_BIT(ah
, AR_GPIO_INPUT_EN_VAL
,
220 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB
);
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
);
227 /* Configure the desired gpio port for input */
228 ath9k_hw_cfg_gpio_input(ah
, btcoex_info
->btactive_gpio
);
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
));
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
);
241 REG_RMW_FIELD(ah
, AR_GPIO_INPUT_MUX1
,
242 AR_GPIO_INPUT_MUX1_BT_PRIORITY
,
243 btcoex_info
->btpriority_gpio
);
245 /* Configure the desired GPIO ports for input */
247 ath9k_hw_cfg_gpio_input(ah
, btcoex_info
->btactive_gpio
);
248 ath9k_hw_cfg_gpio_input(ah
, btcoex_info
->btpriority_gpio
);
250 ret
= ath_init_btcoex_info(ah
, btcoex_info
);
256 void ath9k_hw_btcoex_enable(struct ath_hw
*ah
)
258 struct ath_btcoex_info
*btcoex_info
= &ah
->ah_sc
->btcoex_info
;
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
);
266 * Program coex mode and weight registers to
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
);
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);
278 ath9k_hw_cfg_output(ah
, btcoex_info
->wlanactive_gpio
,
279 AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL
);
282 REG_RMW(ah
, AR_GPIO_PDPU
,
283 (0x2 << (btcoex_info
->btactive_gpio
* 2)),
284 (0x3 << (btcoex_info
->btactive_gpio
* 2)));
286 ah
->ah_sc
->sc_flags
|= SC_OP_BTCOEX_ENABLED
;
289 void ath9k_hw_btcoex_disable(struct ath_hw
*ah
)
291 struct ath_btcoex_info
*btcoex_info
= &ah
->ah_sc
->btcoex_info
;
293 ath9k_hw_set_gpio(ah
, btcoex_info
->wlanactive_gpio
, 0);
295 ath9k_hw_cfg_output(ah
, btcoex_info
->wlanactive_gpio
,
296 AR_GPIO_OUTPUT_MUX_AS_OUTPUT
);
298 if (btcoex_info
->btcoex_scheme
== ATH_BTCOEX_CFG_3WIRE
) {
299 REG_WRITE(ah
, AR_BT_COEX_MODE
, AR_BT_QUIET
| AR_BT_MODE
);
300 REG_WRITE(ah
, AR_BT_COEX_WEIGHT
, 0);
301 REG_WRITE(ah
, AR_BT_COEX_MODE2
, 0);
304 ah
->ah_sc
->sc_flags
&= ~SC_OP_BTCOEX_ENABLED
;
308 * Pause btcoex timer and bt duty cycle timer
310 void ath_btcoex_timer_pause(struct ath_softc
*sc
,
311 struct ath_btcoex_info
*btinfo
)
314 del_timer_sync(&btinfo
->period_timer
);
316 if (btinfo
->hw_timer_enabled
)
317 ath_gen_timer_stop(sc
->sc_ah
, btinfo
->no_stomp_timer
);
319 btinfo
->hw_timer_enabled
= false;
323 * (Re)start btcoex timers
325 void ath_btcoex_timer_resume(struct ath_softc
*sc
,
326 struct ath_btcoex_info
*btinfo
)
329 DPRINTF(sc
, ATH_DBG_BTCOEX
, "Starting btcoex timers");
331 /* make sure duty cycle timer is also stopped when resuming */
332 if (btinfo
->hw_timer_enabled
)
333 ath_gen_timer_stop(sc
->sc_ah
, btinfo
->no_stomp_timer
);
335 btinfo
->bt_priority_cnt
= 0;
336 btinfo
->bt_priority_time
= jiffies
;
337 sc
->sc_flags
&= ~SC_OP_BT_PRIORITY_DETECTED
;
339 mod_timer(&btinfo
->period_timer
, jiffies
);