xref: /linux/drivers/net/wireless/ath/ath9k/btcoex.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
117d50d1dSVasanthakumar Thiagarajan /*
25b68138eSSujith Manoharan  * Copyright (c) 2009-2011 Atheros Communications Inc.
317d50d1dSVasanthakumar Thiagarajan  *
417d50d1dSVasanthakumar Thiagarajan  * Permission to use, copy, modify, and/or distribute this software for any
517d50d1dSVasanthakumar Thiagarajan  * purpose with or without fee is hereby granted, provided that the above
617d50d1dSVasanthakumar Thiagarajan  * copyright notice and this permission notice appear in all copies.
717d50d1dSVasanthakumar Thiagarajan  *
817d50d1dSVasanthakumar Thiagarajan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
917d50d1dSVasanthakumar Thiagarajan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1017d50d1dSVasanthakumar Thiagarajan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1117d50d1dSVasanthakumar Thiagarajan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1217d50d1dSVasanthakumar Thiagarajan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1317d50d1dSVasanthakumar Thiagarajan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1417d50d1dSVasanthakumar Thiagarajan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1517d50d1dSVasanthakumar Thiagarajan  */
1617d50d1dSVasanthakumar Thiagarajan 
17ee40fa06SPaul Gortmaker #include <linux/export.h>
18c8770bcfSMiaoqing Pan #include <linux/types.h>
19c8770bcfSMiaoqing Pan #include <linux/ath9k_platform.h>
20cfe8cba9SLuis R. Rodriguez #include "hw.h"
2117d50d1dSVasanthakumar Thiagarajan 
228b4fc5baSLuis R. Rodriguez enum ath_bt_mode {
238b4fc5baSLuis R. Rodriguez 	ATH_BT_COEX_MODE_LEGACY,        /* legacy rx_clear mode */
248b4fc5baSLuis R. Rodriguez 	ATH_BT_COEX_MODE_UNSLOTTED,     /* untimed/unslotted mode */
258b4fc5baSLuis R. Rodriguez 	ATH_BT_COEX_MODE_SLOTTED,       /* slotted mode */
2632b1076dSMohammed Shafi Shajakhan 	ATH_BT_COEX_MODE_DISABLED,      /* coexistence disabled */
278b4fc5baSLuis R. Rodriguez };
288b4fc5baSLuis R. Rodriguez 
298b4fc5baSLuis R. Rodriguez struct ath_btcoex_config {
308b4fc5baSLuis R. Rodriguez 	u8 bt_time_extend;
318b4fc5baSLuis R. Rodriguez 	bool bt_txstate_extend;
328b4fc5baSLuis R. Rodriguez 	bool bt_txframe_extend;
338b4fc5baSLuis R. Rodriguez 	enum ath_bt_mode bt_mode; /* coexistence mode */
348b4fc5baSLuis R. Rodriguez 	bool bt_quiet_collision;
358b4fc5baSLuis R. Rodriguez 	bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
368b4fc5baSLuis R. Rodriguez 	u8 bt_priority_time;
378b4fc5baSLuis R. Rodriguez 	u8 bt_first_slot_time;
388b4fc5baSLuis R. Rodriguez 	bool bt_hold_rx_clear;
39c7212b71SMiaoqing Pan 	u8 wl_active_time;
40c7212b71SMiaoqing Pan 	u8 wl_qc_time;
418b4fc5baSLuis R. Rodriguez };
421773912bSVasanthakumar Thiagarajan 
4354f10b05SRajkumar Manoharan static const u32 ar9003_wlan_weights[ATH_BTCOEX_STOMP_MAX]
4454f10b05SRajkumar Manoharan 				    [AR9300_NUM_WLAN_WEIGHTS] = {
4554f10b05SRajkumar Manoharan 	{ 0xfffffff0, 0xfffffff0, 0xfffffff0, 0xfffffff0 }, /* STOMP_ALL */
4654f10b05SRajkumar Manoharan 	{ 0x88888880, 0x88888880, 0x88888880, 0x88888880 }, /* STOMP_LOW */
4754f10b05SRajkumar Manoharan 	{ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* STOMP_NONE */
4854f10b05SRajkumar Manoharan };
491773912bSVasanthakumar Thiagarajan 
505160b46fSSujith Manoharan static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
518227bf45SRajkumar Manoharan 				 [AR9300_NUM_WLAN_WEIGHTS] = {
528227bf45SRajkumar Manoharan 	{ 0x01017d01, 0x41414101, 0x41414101, 0x41414141 }, /* STOMP_ALL */
538227bf45SRajkumar Manoharan 	{ 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */
548227bf45SRajkumar Manoharan 	{ 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */
558227bf45SRajkumar Manoharan 	{ 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */
562884561aSRajkumar Manoharan 	{ 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */
578227bf45SRajkumar Manoharan };
588227bf45SRajkumar Manoharan 
ath9k_hw_init_btcoex_hw(struct ath_hw * ah,int qnum)59766ec4a9SLuis R. Rodriguez void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
60af03abecSLuis R. Rodriguez {
61766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
628b4fc5baSLuis R. Rodriguez 	const struct ath_btcoex_config ath_bt_config = {
638b4fc5baSLuis R. Rodriguez 		.bt_time_extend = 0,
648b4fc5baSLuis R. Rodriguez 		.bt_txstate_extend = true,
658b4fc5baSLuis R. Rodriguez 		.bt_txframe_extend = true,
668b4fc5baSLuis R. Rodriguez 		.bt_mode = ATH_BT_COEX_MODE_SLOTTED,
678b4fc5baSLuis R. Rodriguez 		.bt_quiet_collision = true,
688b4fc5baSLuis R. Rodriguez 		.bt_rxclear_polarity = true,
698b4fc5baSLuis R. Rodriguez 		.bt_priority_time = 2,
708b4fc5baSLuis R. Rodriguez 		.bt_first_slot_time = 5,
718b4fc5baSLuis R. Rodriguez 		.bt_hold_rx_clear = true,
72c7212b71SMiaoqing Pan 		.wl_active_time = 0x20,
73c7212b71SMiaoqing Pan 		.wl_qc_time = 0x20,
748b4fc5baSLuis R. Rodriguez 	};
75a6ef530fSVivek Natarajan 	bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
76c7212b71SMiaoqing Pan 	u8 time_extend = ath_bt_config.bt_time_extend;
77c7212b71SMiaoqing Pan 	u8 first_slot_time = ath_bt_config.bt_first_slot_time;
78a6ef530fSVivek Natarajan 
79a6ef530fSVivek Natarajan 	if (AR_SREV_9300_20_OR_LATER(ah))
80a6ef530fSVivek Natarajan 		rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
811773912bSVasanthakumar Thiagarajan 
82c7212b71SMiaoqing Pan 	if (AR_SREV_SOC(ah)) {
83c7212b71SMiaoqing Pan 		first_slot_time = 0x1d;
84c7212b71SMiaoqing Pan 		time_extend = 0xa;
85c7212b71SMiaoqing Pan 
86c7212b71SMiaoqing Pan 		btcoex_hw->bt_coex_mode3 =
87c7212b71SMiaoqing Pan 			SM(ath_bt_config.wl_active_time, AR_BT_WL_ACTIVE_TIME) |
88c7212b71SMiaoqing Pan 			SM(ath_bt_config.wl_qc_time, AR_BT_WL_QC_TIME);
89c7212b71SMiaoqing Pan 
90c7212b71SMiaoqing Pan 		btcoex_hw->bt_coex_mode2 =
91c7212b71SMiaoqing Pan 			AR_BT_PROTECT_BT_AFTER_WAKEUP |
92c7212b71SMiaoqing Pan 			AR_BT_PHY_ERR_BT_COLL_ENABLE;
93c7212b71SMiaoqing Pan 	}
94c7212b71SMiaoqing Pan 
95766ec4a9SLuis R. Rodriguez 	btcoex_hw->bt_coex_mode =
96766ec4a9SLuis R. Rodriguez 		(btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
97c7212b71SMiaoqing Pan 		SM(time_extend, AR_BT_TIME_EXTEND) |
981773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
991773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
1001773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_mode, AR_BT_MODE) |
1011773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
102a6ef530fSVivek Natarajan 		SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
1031773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
104c7212b71SMiaoqing Pan 		SM(first_slot_time, AR_BT_FIRST_SLOT_TIME) |
1051773912bSVasanthakumar Thiagarajan 		SM(qnum, AR_BT_QCU_THRESH);
1061773912bSVasanthakumar Thiagarajan 
107c7212b71SMiaoqing Pan 	btcoex_hw->bt_coex_mode2 |=
1081773912bSVasanthakumar Thiagarajan 		SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
1091773912bSVasanthakumar Thiagarajan 		SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
1101773912bSVasanthakumar Thiagarajan 		AR_BT_DISABLE_BT_ANT;
1111773912bSVasanthakumar Thiagarajan }
1127322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_init_btcoex_hw);
1131773912bSVasanthakumar Thiagarajan 
ath9k_hw_btcoex_pin_init(struct ath_hw * ah,u8 wlanactive_gpio,u8 btactive_gpio,u8 btpriority_gpio)114c8770bcfSMiaoqing Pan static void ath9k_hw_btcoex_pin_init(struct ath_hw *ah, u8 wlanactive_gpio,
115c8770bcfSMiaoqing Pan 				     u8 btactive_gpio, u8 btpriority_gpio)
116c8770bcfSMiaoqing Pan {
117c8770bcfSMiaoqing Pan 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
118c8770bcfSMiaoqing Pan 	struct ath9k_platform_data *pdata = ah->dev->platform_data;
119c8770bcfSMiaoqing Pan 
120c8770bcfSMiaoqing Pan 	if (btcoex_hw->scheme != ATH_BTCOEX_CFG_2WIRE &&
121c8770bcfSMiaoqing Pan 	    btcoex_hw->scheme != ATH_BTCOEX_CFG_3WIRE)
122c8770bcfSMiaoqing Pan 		return;
123c8770bcfSMiaoqing Pan 
124c8770bcfSMiaoqing Pan 	/* bt priority GPIO will be ignored by 2 wire scheme */
125c8770bcfSMiaoqing Pan 	if (pdata && (pdata->bt_active_pin || pdata->bt_priority_pin ||
126c8770bcfSMiaoqing Pan 		      pdata->wlan_active_pin)) {
127c8770bcfSMiaoqing Pan 		btcoex_hw->btactive_gpio = pdata->bt_active_pin;
128c8770bcfSMiaoqing Pan 		btcoex_hw->wlanactive_gpio = pdata->wlan_active_pin;
129c8770bcfSMiaoqing Pan 		btcoex_hw->btpriority_gpio = pdata->bt_priority_pin;
130c8770bcfSMiaoqing Pan 	} else {
131c8770bcfSMiaoqing Pan 		btcoex_hw->btactive_gpio = btactive_gpio;
132c8770bcfSMiaoqing Pan 		btcoex_hw->wlanactive_gpio = wlanactive_gpio;
133c8770bcfSMiaoqing Pan 		btcoex_hw->btpriority_gpio = btpriority_gpio;
134c8770bcfSMiaoqing Pan 	}
135c8770bcfSMiaoqing Pan }
136c8770bcfSMiaoqing Pan 
ath9k_hw_btcoex_init_scheme(struct ath_hw * ah)137d68475deSSujith Manoharan void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah)
138d68475deSSujith Manoharan {
139d68475deSSujith Manoharan 	struct ath_common *common = ath9k_hw_common(ah);
140d68475deSSujith Manoharan 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
141d68475deSSujith Manoharan 
142d68475deSSujith Manoharan 	/*
143d68475deSSujith Manoharan 	 * Check if BTCOEX is globally disabled.
144d68475deSSujith Manoharan 	 */
145d68475deSSujith Manoharan 	if (!common->btcoex_enabled) {
146d68475deSSujith Manoharan 		btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
147d68475deSSujith Manoharan 		return;
148d68475deSSujith Manoharan 	}
149d68475deSSujith Manoharan 
150e1ff147dSSujith Manoharan 	if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
151e1ff147dSSujith Manoharan 		btcoex_hw->scheme = ATH_BTCOEX_CFG_MCI;
152e1ff147dSSujith Manoharan 	} else if (AR_SREV_9300_20_OR_LATER(ah)) {
153d68475deSSujith Manoharan 		btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
154d68475deSSujith Manoharan 
155c8770bcfSMiaoqing Pan 		ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9300,
156c8770bcfSMiaoqing Pan 					 ATH_BTACTIVE_GPIO_9300,
157c8770bcfSMiaoqing Pan 					 ATH_BTPRIORITY_GPIO_9300);
158c8770bcfSMiaoqing Pan 	} else if (AR_SREV_9280_20_OR_LATER(ah)) {
159c8770bcfSMiaoqing Pan 		if (AR_SREV_9285(ah))
160d68475deSSujith Manoharan 			btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
161c8770bcfSMiaoqing Pan 		else
162d68475deSSujith Manoharan 			btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
163c8770bcfSMiaoqing Pan 
164c8770bcfSMiaoqing Pan 		ath9k_hw_btcoex_pin_init(ah, ATH_WLANACTIVE_GPIO_9280,
165c8770bcfSMiaoqing Pan 					 ATH_BTACTIVE_GPIO_9280,
166c8770bcfSMiaoqing Pan 					 ATH_BTPRIORITY_GPIO_9285);
167d68475deSSujith Manoharan 	}
168d68475deSSujith Manoharan }
169d68475deSSujith Manoharan EXPORT_SYMBOL(ath9k_hw_btcoex_init_scheme);
170d68475deSSujith Manoharan 
ath9k_hw_btcoex_init_2wire(struct ath_hw * ah)17175d7839fSLuis R. Rodriguez void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
17217d50d1dSVasanthakumar Thiagarajan {
173766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
174f14462c6SVasanthakumar Thiagarajan 
17517d50d1dSVasanthakumar Thiagarajan 	/* connect bt_active to baseband */
176*b3a663f0SWenli Looi 	REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah),
17717d50d1dSVasanthakumar Thiagarajan 		    (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
17817d50d1dSVasanthakumar Thiagarajan 		     AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
17917d50d1dSVasanthakumar Thiagarajan 
180*b3a663f0SWenli Looi 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah),
18117d50d1dSVasanthakumar Thiagarajan 		    AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
18217d50d1dSVasanthakumar Thiagarajan 
18317d50d1dSVasanthakumar Thiagarajan 	/* Set input mux for bt_active to gpio pin */
184dfcf02cdSMiaoqing Pan 	if (!AR_SREV_SOC(ah))
185*b3a663f0SWenli Looi 		REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah),
18617d50d1dSVasanthakumar Thiagarajan 			      AR_GPIO_INPUT_MUX1_BT_ACTIVE,
187766ec4a9SLuis R. Rodriguez 			      btcoex_hw->btactive_gpio);
18817d50d1dSVasanthakumar Thiagarajan 
18917d50d1dSVasanthakumar Thiagarajan 	/* Configure the desired gpio port for input */
190b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
191b2d70d49SMiaoqing Pan 				 "ath9k-btactive");
1927a2f0f58SLuis R. Rodriguez }
1937322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_btcoex_init_2wire);
1947a2f0f58SLuis R. Rodriguez 
ath9k_hw_btcoex_init_3wire(struct ath_hw * ah)19575d7839fSLuis R. Rodriguez void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
1967a2f0f58SLuis R. Rodriguez {
197766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
1987a2f0f58SLuis R. Rodriguez 
1991773912bSVasanthakumar Thiagarajan 	/* btcoex 3-wire */
200*b3a663f0SWenli Looi 	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL(ah),
2011773912bSVasanthakumar Thiagarajan 			(AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
2021773912bSVasanthakumar Thiagarajan 			 AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
2031773912bSVasanthakumar Thiagarajan 
2041773912bSVasanthakumar Thiagarajan 	/* Set input mux for bt_prority_async and
2051773912bSVasanthakumar Thiagarajan 	 *                  bt_active_async to GPIO pins */
206dfcf02cdSMiaoqing Pan 	if (!AR_SREV_SOC(ah)) {
207*b3a663f0SWenli Looi 		REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah),
2081773912bSVasanthakumar Thiagarajan 			      AR_GPIO_INPUT_MUX1_BT_ACTIVE,
209766ec4a9SLuis R. Rodriguez 			      btcoex_hw->btactive_gpio);
210*b3a663f0SWenli Looi 		REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1(ah),
2111773912bSVasanthakumar Thiagarajan 			      AR_GPIO_INPUT_MUX1_BT_PRIORITY,
212766ec4a9SLuis R. Rodriguez 			      btcoex_hw->btpriority_gpio);
213dfcf02cdSMiaoqing Pan 	}
2141773912bSVasanthakumar Thiagarajan 
2151773912bSVasanthakumar Thiagarajan 	/* Configure the desired GPIO ports for input */
216b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_in(ah, btcoex_hw->btactive_gpio,
217b2d70d49SMiaoqing Pan 				 "ath9k-btactive");
218b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_in(ah, btcoex_hw->btpriority_gpio,
219b2d70d49SMiaoqing Pan 				 "ath9k-btpriority");
2207a2f0f58SLuis R. Rodriguez }
2217322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_btcoex_init_3wire);
2221773912bSVasanthakumar Thiagarajan 
ath9k_hw_btcoex_deinit(struct ath_hw * ah)223db222190SMiaoqing Pan void ath9k_hw_btcoex_deinit(struct ath_hw *ah)
224db222190SMiaoqing Pan {
225db222190SMiaoqing Pan 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
226db222190SMiaoqing Pan 
227db222190SMiaoqing Pan 	ath9k_hw_gpio_free(ah, btcoex_hw->btactive_gpio);
228db222190SMiaoqing Pan 	ath9k_hw_gpio_free(ah, btcoex_hw->btpriority_gpio);
229db222190SMiaoqing Pan 	ath9k_hw_gpio_free(ah, btcoex_hw->wlanactive_gpio);
230db222190SMiaoqing Pan }
231db222190SMiaoqing Pan EXPORT_SYMBOL(ath9k_hw_btcoex_deinit);
232db222190SMiaoqing Pan 
ath9k_hw_btcoex_init_mci(struct ath_hw * ah)233d3c83ac1SSujith Manoharan void ath9k_hw_btcoex_init_mci(struct ath_hw *ah)
234d3c83ac1SSujith Manoharan {
235d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.ready = false;
236d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.bt_state = 0;
237d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.bt_ver_major = 3;
238d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.bt_ver_minor = 0;
239d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.bt_version_known = false;
240d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.update_2g5g = true;
241d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.is_2g = true;
242d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_channels_update = false;
243d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_channels[0] = 0x00000000;
244d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_channels[1] = 0xffffffff;
245d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_channels[2] = 0xffffffff;
246d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_channels[3] = 0x7fffffff;
247d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.query_bt = true;
248d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.unhalt_bt_gpm = true;
249d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.halted_bt_gpm = false;
250d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.need_flush_btinfo = false;
251d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_cal_seq = 0;
252d3c83ac1SSujith Manoharan 	ah->btcoex_hw.mci.wlan_cal_done = 0;
2533c5c9d04SRajkumar Manoharan 	ah->btcoex_hw.mci.config = (AR_SREV_9462(ah)) ? 0x2201 : 0xa4c1;
254d3c83ac1SSujith Manoharan }
255d3c83ac1SSujith Manoharan EXPORT_SYMBOL(ath9k_hw_btcoex_init_mci);
256d3c83ac1SSujith Manoharan 
ath9k_hw_btcoex_enable_2wire(struct ath_hw * ah)257bc74bf8fSLuis R. Rodriguez static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
25817d50d1dSVasanthakumar Thiagarajan {
259766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
260f14462c6SVasanthakumar Thiagarajan 
26117d50d1dSVasanthakumar Thiagarajan 	/* Configure the desired GPIO port for TX_FRAME output */
262b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
263b2d70d49SMiaoqing Pan 				  "ath9k-wlanactive",
26417d50d1dSVasanthakumar Thiagarajan 				  AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
265bc74bf8fSLuis R. Rodriguez }
266bc74bf8fSLuis R. Rodriguez 
2675160b46fSSujith Manoharan /*
2685160b46fSSujith Manoharan  * For AR9002, bt_weight/wlan_weight are used.
2695160b46fSSujith Manoharan  * For AR9003 and above, stomp_type is used.
2705160b46fSSujith Manoharan  */
ath9k_hw_btcoex_set_weight(struct ath_hw * ah,u32 bt_weight,u32 wlan_weight,enum ath_stomp_type stomp_type)2715e197292SLuis R. Rodriguez void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
2725e197292SLuis R. Rodriguez 				u32 bt_weight,
2735160b46fSSujith Manoharan 				u32 wlan_weight,
2745160b46fSSujith Manoharan 				enum ath_stomp_type stomp_type)
2755e197292SLuis R. Rodriguez {
2765e197292SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
277db60428bSRajkumar Manoharan 	struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
278db60428bSRajkumar Manoharan 	u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */
279db60428bSRajkumar Manoharan 	bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]);
2805160b46fSSujith Manoharan 	const u32 *weight = ar9003_wlan_weights[stomp_type];
2815160b46fSSujith Manoharan 	int i;
2825160b46fSSujith Manoharan 
283db60428bSRajkumar Manoharan 	if (!AR_SREV_9300_20_OR_LATER(ah)) {
284db60428bSRajkumar Manoharan 		btcoex_hw->bt_coex_weights =
285db60428bSRajkumar Manoharan 			SM(bt_weight, AR_BTCOEX_BT_WGHT) |
286db60428bSRajkumar Manoharan 			SM(wlan_weight, AR_BTCOEX_WL_WGHT);
287db60428bSRajkumar Manoharan 		return;
288db60428bSRajkumar Manoharan 	}
289db60428bSRajkumar Manoharan 
2905160b46fSSujith Manoharan 	if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
291db60428bSRajkumar Manoharan 		enum ath_stomp_type stype =
292db60428bSRajkumar Manoharan 			((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
293db60428bSRajkumar Manoharan 			 btcoex_hw->mci.stomp_ftp) ?
294db60428bSRajkumar Manoharan 			ATH_BTCOEX_STOMP_LOW_FTP : stomp_type;
295db60428bSRajkumar Manoharan 		weight = mci_wlan_weights[stype];
2965160b46fSSujith Manoharan 	}
2975160b46fSSujith Manoharan 
2985160b46fSSujith Manoharan 	for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
2995160b46fSSujith Manoharan 		btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
3005160b46fSSujith Manoharan 		btcoex_hw->wlan_weight[i] = weight[i];
301db60428bSRajkumar Manoharan 		if (concur_tx && i) {
302db60428bSRajkumar Manoharan 			btcoex_hw->wlan_weight[i] &=
303db60428bSRajkumar Manoharan 				~(0xff << txprio_shift[i-1]);
304db60428bSRajkumar Manoharan 			btcoex_hw->wlan_weight[i] |=
305db60428bSRajkumar Manoharan 				(btcoex_hw->tx_prio[stomp_type] <<
306db60428bSRajkumar Manoharan 				 txprio_shift[i-1]);
3075160b46fSSujith Manoharan 		}
3085e197292SLuis R. Rodriguez 	}
309dfcf02cdSMiaoqing Pan 
310db60428bSRajkumar Manoharan 	/* Last WLAN weight has to be adjusted wrt tx priority */
311db60428bSRajkumar Manoharan 	if (concur_tx) {
312db60428bSRajkumar Manoharan 		btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
313db60428bSRajkumar Manoharan 		btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
314db60428bSRajkumar Manoharan 						      << txprio_shift[i-1]);
315db60428bSRajkumar Manoharan 	}
3165160b46fSSujith Manoharan }
3177322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
3185e197292SLuis R. Rodriguez 
319a6ef530fSVivek Natarajan 
ath9k_hw_btcoex_enable_3wire(struct ath_hw * ah)320bc74bf8fSLuis R. Rodriguez static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
321bc74bf8fSLuis R. Rodriguez {
32254f10b05SRajkumar Manoharan 	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
32321cb9879SVivek Natarajan 	u32  val;
32454f10b05SRajkumar Manoharan 	int i;
325bc74bf8fSLuis R. Rodriguez 
3261773912bSVasanthakumar Thiagarajan 	/*
3271773912bSVasanthakumar Thiagarajan 	 * Program coex mode and weight registers to
3281773912bSVasanthakumar Thiagarajan 	 * enable coex 3-wire
3291773912bSVasanthakumar Thiagarajan 	 */
330c7212b71SMiaoqing Pan 	if (AR_SREV_SOC(ah))
331c7212b71SMiaoqing Pan 		REG_CLR_BIT(ah, AR_BT_COEX_MODE2, AR_BT_PHY_ERR_BT_COLL_ENABLE);
332c7212b71SMiaoqing Pan 
33354f10b05SRajkumar Manoharan 	REG_WRITE(ah, AR_BT_COEX_MODE, btcoex->bt_coex_mode);
33454f10b05SRajkumar Manoharan 	REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex->bt_coex_mode2);
3351773912bSVasanthakumar Thiagarajan 
336c7212b71SMiaoqing Pan 	if (AR_SREV_SOC(ah))
337c7212b71SMiaoqing Pan 		REG_WRITE(ah, AR_BT_COEX_MODE3, btcoex->bt_coex_mode3);
338c7212b71SMiaoqing Pan 
339a6ef530fSVivek Natarajan 	if (AR_SREV_9300_20_OR_LATER(ah)) {
34054f10b05SRajkumar Manoharan 		REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, btcoex->wlan_weight[0]);
34154f10b05SRajkumar Manoharan 		REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, btcoex->wlan_weight[1]);
34254f10b05SRajkumar Manoharan 		for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
34354f10b05SRajkumar Manoharan 			REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i),
34454f10b05SRajkumar Manoharan 				  btcoex->bt_weight[i]);
345a6ef530fSVivek Natarajan 	} else
34654f10b05SRajkumar Manoharan 		REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex->bt_coex_weights);
347a6ef530fSVivek Natarajan 
34821cb9879SVivek Natarajan 	if (AR_SREV_9271(ah)) {
34921cb9879SVivek Natarajan 		val = REG_READ(ah, 0x50040);
35021cb9879SVivek Natarajan 		val &= 0xFFFFFEFF;
35121cb9879SVivek Natarajan 		REG_WRITE(ah, 0x50040, val);
35221cb9879SVivek Natarajan 	}
35321cb9879SVivek Natarajan 
354bc74bf8fSLuis R. Rodriguez 	REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
355bc74bf8fSLuis R. Rodriguez 	REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
3561773912bSVasanthakumar Thiagarajan 
357b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_out(ah, btcoex->wlanactive_gpio,
358b2d70d49SMiaoqing Pan 				  "ath9k-wlanactive",
3591773912bSVasanthakumar Thiagarajan 				  AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
3601773912bSVasanthakumar Thiagarajan }
3611773912bSVasanthakumar Thiagarajan 
ath9k_hw_btcoex_enable_mci(struct ath_hw * ah)3628227bf45SRajkumar Manoharan static void ath9k_hw_btcoex_enable_mci(struct ath_hw *ah)
3638227bf45SRajkumar Manoharan {
3648227bf45SRajkumar Manoharan 	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
3658227bf45SRajkumar Manoharan 	int i;
3668227bf45SRajkumar Manoharan 
3678227bf45SRajkumar Manoharan 	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
3688227bf45SRajkumar Manoharan 		REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
3698227bf45SRajkumar Manoharan 			  btcoex->wlan_weight[i]);
3708227bf45SRajkumar Manoharan 
3718227bf45SRajkumar Manoharan 	REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
3728227bf45SRajkumar Manoharan 	btcoex->enabled = true;
3738227bf45SRajkumar Manoharan }
3748227bf45SRajkumar Manoharan 
ath9k_hw_btcoex_disable_mci(struct ath_hw * ah)375e1ff147dSSujith Manoharan static void ath9k_hw_btcoex_disable_mci(struct ath_hw *ah)
376e1ff147dSSujith Manoharan {
377e1ff147dSSujith Manoharan 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
378e1ff147dSSujith Manoharan 	int i;
379e1ff147dSSujith Manoharan 
380e1ff147dSSujith Manoharan 	ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
381e1ff147dSSujith Manoharan 
382e1ff147dSSujith Manoharan 	for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
383e1ff147dSSujith Manoharan 		REG_WRITE(ah, AR_MCI_COEX_WL_WEIGHTS(i),
384e1ff147dSSujith Manoharan 			  btcoex_hw->wlan_weight[i]);
385e1ff147dSSujith Manoharan }
386e1ff147dSSujith Manoharan 
ath9k_hw_btcoex_enable(struct ath_hw * ah)387bc74bf8fSLuis R. Rodriguez void ath9k_hw_btcoex_enable(struct ath_hw *ah)
388bc74bf8fSLuis R. Rodriguez {
389766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
390bc74bf8fSLuis R. Rodriguez 
3918a309305SFelix Fietkau 	switch (ath9k_hw_get_btcoex_scheme(ah)) {
392bc74bf8fSLuis R. Rodriguez 	case ATH_BTCOEX_CFG_NONE:
3938a309305SFelix Fietkau 		return;
394bc74bf8fSLuis R. Rodriguez 	case ATH_BTCOEX_CFG_2WIRE:
395bc74bf8fSLuis R. Rodriguez 		ath9k_hw_btcoex_enable_2wire(ah);
396bc74bf8fSLuis R. Rodriguez 		break;
397bc74bf8fSLuis R. Rodriguez 	case ATH_BTCOEX_CFG_3WIRE:
3980466e254SRajkumar Manoharan 		ath9k_hw_btcoex_enable_3wire(ah);
3990466e254SRajkumar Manoharan 		break;
400e1ff147dSSujith Manoharan 	case ATH_BTCOEX_CFG_MCI:
401e1ff147dSSujith Manoharan 		ath9k_hw_btcoex_enable_mci(ah);
402e1ff147dSSujith Manoharan 		break;
4030466e254SRajkumar Manoharan 	}
404bc74bf8fSLuis R. Rodriguez 
405dfcf02cdSMiaoqing Pan 	if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI &&
406dfcf02cdSMiaoqing Pan 	    !AR_SREV_SOC(ah)) {
407*b3a663f0SWenli Looi 		REG_RMW(ah, AR_GPIO_PDPU(ah),
408766ec4a9SLuis R. Rodriguez 			(0x2 << (btcoex_hw->btactive_gpio * 2)),
409766ec4a9SLuis R. Rodriguez 			(0x3 << (btcoex_hw->btactive_gpio * 2)));
410e1ff147dSSujith Manoharan 	}
41117d50d1dSVasanthakumar Thiagarajan 
412766ec4a9SLuis R. Rodriguez 	ah->btcoex_hw.enabled = true;
41317d50d1dSVasanthakumar Thiagarajan }
4147322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_btcoex_enable);
41517d50d1dSVasanthakumar Thiagarajan 
ath9k_hw_btcoex_disable(struct ath_hw * ah)41617d50d1dSVasanthakumar Thiagarajan void ath9k_hw_btcoex_disable(struct ath_hw *ah)
41717d50d1dSVasanthakumar Thiagarajan {
418766ec4a9SLuis R. Rodriguez 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
41954f10b05SRajkumar Manoharan 	int i;
42017d50d1dSVasanthakumar Thiagarajan 
4218227bf45SRajkumar Manoharan 	btcoex_hw->enabled = false;
422e1ff147dSSujith Manoharan 
423e1ff147dSSujith Manoharan 	if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_MCI) {
424e1ff147dSSujith Manoharan 		ath9k_hw_btcoex_disable_mci(ah);
4250466e254SRajkumar Manoharan 		return;
4268227bf45SRajkumar Manoharan 	}
427e1ff147dSSujith Manoharan 
42830b81898SSujith Manoharan 	if (!AR_SREV_9300_20_OR_LATER(ah))
429766ec4a9SLuis R. Rodriguez 		ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
430f14462c6SVasanthakumar Thiagarajan 
431b2d70d49SMiaoqing Pan 	ath9k_hw_gpio_request_out(ah, btcoex_hw->wlanactive_gpio,
432b2d70d49SMiaoqing Pan 				  NULL, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
43317d50d1dSVasanthakumar Thiagarajan 
434766ec4a9SLuis R. Rodriguez 	if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
4351773912bSVasanthakumar Thiagarajan 		REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
4361773912bSVasanthakumar Thiagarajan 		REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
437a6ef530fSVivek Natarajan 
438a6ef530fSVivek Natarajan 		if (AR_SREV_9300_20_OR_LATER(ah)) {
439a6ef530fSVivek Natarajan 			REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0);
440a6ef530fSVivek Natarajan 			REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0);
44154f10b05SRajkumar Manoharan 			for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
44254f10b05SRajkumar Manoharan 				REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS(i), 0);
443a6ef530fSVivek Natarajan 		} else
444a6ef530fSVivek Natarajan 			REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
445a6ef530fSVivek Natarajan 
4461773912bSVasanthakumar Thiagarajan 	}
44717d50d1dSVasanthakumar Thiagarajan }
4487322fd19SLuis R. Rodriguez EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
449978f78bfSVivek Natarajan 
450978f78bfSVivek Natarajan /*
451978f78bfSVivek Natarajan  * Configures appropriate weight based on stomp type.
452978f78bfSVivek Natarajan  */
ath9k_hw_btcoex_bt_stomp(struct ath_hw * ah,enum ath_stomp_type stomp_type)453978f78bfSVivek Natarajan void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
454978f78bfSVivek Natarajan 			      enum ath_stomp_type stomp_type)
455978f78bfSVivek Natarajan {
456978f78bfSVivek Natarajan 	if (AR_SREV_9300_20_OR_LATER(ah)) {
4575160b46fSSujith Manoharan 		ath9k_hw_btcoex_set_weight(ah, 0, 0, stomp_type);
458978f78bfSVivek Natarajan 		return;
459978f78bfSVivek Natarajan 	}
460978f78bfSVivek Natarajan 
461978f78bfSVivek Natarajan 	switch (stomp_type) {
462978f78bfSVivek Natarajan 	case ATH_BTCOEX_STOMP_ALL:
463978f78bfSVivek Natarajan 		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
4645160b46fSSujith Manoharan 					   AR_STOMP_ALL_WLAN_WGHT, 0);
465978f78bfSVivek Natarajan 		break;
466978f78bfSVivek Natarajan 	case ATH_BTCOEX_STOMP_LOW:
467978f78bfSVivek Natarajan 		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
4685160b46fSSujith Manoharan 					   AR_STOMP_LOW_WLAN_WGHT, 0);
469978f78bfSVivek Natarajan 		break;
470978f78bfSVivek Natarajan 	case ATH_BTCOEX_STOMP_NONE:
471978f78bfSVivek Natarajan 		ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
4725160b46fSSujith Manoharan 					   AR_STOMP_NONE_WLAN_WGHT, 0);
473978f78bfSVivek Natarajan 		break;
474978f78bfSVivek Natarajan 	default:
475d2182b69SJoe Perches 		ath_dbg(ath9k_hw_common(ah), BTCOEX, "Invalid Stomptype\n");
476978f78bfSVivek Natarajan 		break;
477978f78bfSVivek Natarajan 	}
478978f78bfSVivek Natarajan }
479978f78bfSVivek Natarajan EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
480db60428bSRajkumar Manoharan 
ath9k_hw_btcoex_set_concur_txprio(struct ath_hw * ah,u8 * stomp_txprio)481db60428bSRajkumar Manoharan void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio)
482db60428bSRajkumar Manoharan {
483db60428bSRajkumar Manoharan 	struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
484db60428bSRajkumar Manoharan 	int i;
485db60428bSRajkumar Manoharan 
486db60428bSRajkumar Manoharan 	for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
487db60428bSRajkumar Manoharan 		btcoex->tx_prio[i] = stomp_txprio[i];
488db60428bSRajkumar Manoharan }
489db60428bSRajkumar Manoharan EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio);
490