117d50d1dSVasanthakumar Thiagarajan /* 217d50d1dSVasanthakumar Thiagarajan * Copyright (c) 2009 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 1717d50d1dSVasanthakumar Thiagarajan #include "ath9k.h" 1817d50d1dSVasanthakumar Thiagarajan 191773912bSVasanthakumar Thiagarajan static const struct ath_btcoex_config ath_bt_config = { 0, true, true, 201773912bSVasanthakumar Thiagarajan ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true }; 211773912bSVasanthakumar Thiagarajan 22fe12946eSVasanthakumar Thiagarajan static const u16 ath_subsysid_tbl[] = { 23fe12946eSVasanthakumar Thiagarajan AR9280_COEX2WIRE_SUBSYSID, 24fe12946eSVasanthakumar Thiagarajan AT9285_COEX3WIRE_SA_SUBSYSID, 25fe12946eSVasanthakumar Thiagarajan AT9285_COEX3WIRE_DA_SUBSYSID 26fe12946eSVasanthakumar Thiagarajan }; 27fe12946eSVasanthakumar Thiagarajan 28fe12946eSVasanthakumar Thiagarajan /* 29fe12946eSVasanthakumar Thiagarajan * Checks the subsystem id of the device to see if it 30fe12946eSVasanthakumar Thiagarajan * supports btcoex 31fe12946eSVasanthakumar Thiagarajan */ 32fe12946eSVasanthakumar Thiagarajan bool ath_btcoex_supported(u16 subsysid) 33fe12946eSVasanthakumar Thiagarajan { 34fe12946eSVasanthakumar Thiagarajan int i; 35fe12946eSVasanthakumar Thiagarajan 36fe12946eSVasanthakumar Thiagarajan if (!subsysid) 37fe12946eSVasanthakumar Thiagarajan return false; 38fe12946eSVasanthakumar Thiagarajan 39fe12946eSVasanthakumar Thiagarajan for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++) 40fe12946eSVasanthakumar Thiagarajan if (subsysid == ath_subsysid_tbl[i]) 41fe12946eSVasanthakumar Thiagarajan return true; 42fe12946eSVasanthakumar Thiagarajan 43fe12946eSVasanthakumar Thiagarajan return false; 44fe12946eSVasanthakumar Thiagarajan } 451773912bSVasanthakumar Thiagarajan 46*af03abecSLuis R. Rodriguez static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, 47*af03abecSLuis R. Rodriguez u32 bt_weight, 48*af03abecSLuis R. Rodriguez u32 wlan_weight) 49*af03abecSLuis R. Rodriguez { 50*af03abecSLuis R. Rodriguez btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | 51*af03abecSLuis R. Rodriguez SM(wlan_weight, AR_BTCOEX_WL_WGHT); 52*af03abecSLuis R. Rodriguez } 53*af03abecSLuis R. Rodriguez 54*af03abecSLuis R. Rodriguez void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) 55*af03abecSLuis R. Rodriguez { 56*af03abecSLuis R. Rodriguez ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, 57*af03abecSLuis R. Rodriguez AR_STOMP_LOW_WLAN_WGHT); 58*af03abecSLuis R. Rodriguez } 59*af03abecSLuis R. Rodriguez 601773912bSVasanthakumar Thiagarajan /* 611773912bSVasanthakumar Thiagarajan * Detects if there is any priority bt traffic 621773912bSVasanthakumar Thiagarajan */ 631773912bSVasanthakumar Thiagarajan static void ath_detect_bt_priority(struct ath_softc *sc) 641773912bSVasanthakumar Thiagarajan { 652e20250aSLuis R. Rodriguez struct ath_btcoex *btcoex = &sc->btcoex; 66*af03abecSLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 671773912bSVasanthakumar Thiagarajan 68*af03abecSLuis R. Rodriguez if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) 692e20250aSLuis R. Rodriguez btcoex->bt_priority_cnt++; 701773912bSVasanthakumar Thiagarajan 712e20250aSLuis R. Rodriguez if (time_after(jiffies, btcoex->bt_priority_time + 721773912bSVasanthakumar Thiagarajan msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { 732e20250aSLuis R. Rodriguez if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { 744d6b228dSLuis R. Rodriguez DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, 751773912bSVasanthakumar Thiagarajan "BT priority traffic detected"); 761773912bSVasanthakumar Thiagarajan sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; 771773912bSVasanthakumar Thiagarajan } else { 781773912bSVasanthakumar Thiagarajan sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; 791773912bSVasanthakumar Thiagarajan } 801773912bSVasanthakumar Thiagarajan 812e20250aSLuis R. Rodriguez btcoex->bt_priority_cnt = 0; 822e20250aSLuis R. Rodriguez btcoex->bt_priority_time = jiffies; 831773912bSVasanthakumar Thiagarajan } 841773912bSVasanthakumar Thiagarajan } 851773912bSVasanthakumar Thiagarajan 861773912bSVasanthakumar Thiagarajan /* 871773912bSVasanthakumar Thiagarajan * Configures appropriate weight based on stomp type. 881773912bSVasanthakumar Thiagarajan */ 891773912bSVasanthakumar Thiagarajan static void ath_btcoex_bt_stomp(struct ath_softc *sc, 901773912bSVasanthakumar Thiagarajan struct ath_btcoex_info *btinfo, 911773912bSVasanthakumar Thiagarajan int stomp_type) 921773912bSVasanthakumar Thiagarajan { 931773912bSVasanthakumar Thiagarajan 941773912bSVasanthakumar Thiagarajan switch (stomp_type) { 951773912bSVasanthakumar Thiagarajan case ATH_BTCOEX_STOMP_ALL: 961773912bSVasanthakumar Thiagarajan ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, 971773912bSVasanthakumar Thiagarajan AR_STOMP_ALL_WLAN_WGHT); 981773912bSVasanthakumar Thiagarajan break; 991773912bSVasanthakumar Thiagarajan case ATH_BTCOEX_STOMP_LOW: 1001773912bSVasanthakumar Thiagarajan ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, 1011773912bSVasanthakumar Thiagarajan AR_STOMP_LOW_WLAN_WGHT); 1021773912bSVasanthakumar Thiagarajan break; 1031773912bSVasanthakumar Thiagarajan case ATH_BTCOEX_STOMP_NONE: 1041773912bSVasanthakumar Thiagarajan ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, 1051773912bSVasanthakumar Thiagarajan AR_STOMP_NONE_WLAN_WGHT); 1061773912bSVasanthakumar Thiagarajan break; 1071773912bSVasanthakumar Thiagarajan default: 1084d6b228dSLuis R. Rodriguez DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); 1091773912bSVasanthakumar Thiagarajan break; 1101773912bSVasanthakumar Thiagarajan } 1111773912bSVasanthakumar Thiagarajan 1121773912bSVasanthakumar Thiagarajan ath9k_hw_btcoex_enable(sc->sc_ah); 1131773912bSVasanthakumar Thiagarajan } 1141773912bSVasanthakumar Thiagarajan 1151773912bSVasanthakumar Thiagarajan /* 1161773912bSVasanthakumar Thiagarajan * This is the master bt coex timer which runs for every 1171773912bSVasanthakumar Thiagarajan * 45ms, bt traffic will be given priority during 55% of this 1181773912bSVasanthakumar Thiagarajan * period while wlan gets remaining 45% 1191773912bSVasanthakumar Thiagarajan */ 1201773912bSVasanthakumar Thiagarajan 1211773912bSVasanthakumar Thiagarajan static void ath_btcoex_period_timer(unsigned long data) 1221773912bSVasanthakumar Thiagarajan { 1231773912bSVasanthakumar Thiagarajan struct ath_softc *sc = (struct ath_softc *) data; 124*af03abecSLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 1252e20250aSLuis R. Rodriguez struct ath_btcoex *btcoex = &sc->btcoex; 126*af03abecSLuis R. Rodriguez struct ath_btcoex_info *btinfo = &ah->btcoex_info; 1271773912bSVasanthakumar Thiagarajan 1281773912bSVasanthakumar Thiagarajan ath_detect_bt_priority(sc); 1291773912bSVasanthakumar Thiagarajan 1302e20250aSLuis R. Rodriguez spin_lock_bh(&btcoex->btcoex_lock); 1311773912bSVasanthakumar Thiagarajan 1321773912bSVasanthakumar Thiagarajan ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); 1331773912bSVasanthakumar Thiagarajan 1342e20250aSLuis R. Rodriguez spin_unlock_bh(&btcoex->btcoex_lock); 1351773912bSVasanthakumar Thiagarajan 1362e20250aSLuis R. Rodriguez if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { 1372e20250aSLuis R. Rodriguez if (btcoex->hw_timer_enabled) 138*af03abecSLuis R. Rodriguez ath_gen_timer_stop(ah, btinfo->no_stomp_timer); 1391773912bSVasanthakumar Thiagarajan 140*af03abecSLuis R. Rodriguez ath_gen_timer_start(ah, 1411773912bSVasanthakumar Thiagarajan btinfo->no_stomp_timer, 1421773912bSVasanthakumar Thiagarajan (ath9k_hw_gettsf32(sc->sc_ah) + 1432e20250aSLuis R. Rodriguez btcoex->btcoex_no_stomp), 1442e20250aSLuis R. Rodriguez btcoex->btcoex_no_stomp * 10); 1452e20250aSLuis R. Rodriguez btcoex->hw_timer_enabled = true; 1461773912bSVasanthakumar Thiagarajan } 1471773912bSVasanthakumar Thiagarajan 1482e20250aSLuis R. Rodriguez mod_timer(&btcoex->period_timer, jiffies + 1491773912bSVasanthakumar Thiagarajan msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); 1501773912bSVasanthakumar Thiagarajan } 1511773912bSVasanthakumar Thiagarajan 1521773912bSVasanthakumar Thiagarajan /* 1531773912bSVasanthakumar Thiagarajan * Generic tsf based hw timer which configures weight 1541773912bSVasanthakumar Thiagarajan * registers to time slice between wlan and bt traffic 1551773912bSVasanthakumar Thiagarajan */ 1561773912bSVasanthakumar Thiagarajan 1571773912bSVasanthakumar Thiagarajan static void ath_btcoex_no_stomp_timer(void *arg) 1581773912bSVasanthakumar Thiagarajan { 1591773912bSVasanthakumar Thiagarajan struct ath_softc *sc = (struct ath_softc *)arg; 160*af03abecSLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 1612e20250aSLuis R. Rodriguez struct ath_btcoex *btcoex = &sc->btcoex; 162*af03abecSLuis R. Rodriguez struct ath_btcoex_info *btinfo = &ah->btcoex_info; 1631773912bSVasanthakumar Thiagarajan 164*af03abecSLuis R. Rodriguez DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); 1651773912bSVasanthakumar Thiagarajan 1662e20250aSLuis R. Rodriguez spin_lock_bh(&btcoex->btcoex_lock); 1671773912bSVasanthakumar Thiagarajan 1681773912bSVasanthakumar Thiagarajan if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) 1691773912bSVasanthakumar Thiagarajan ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); 1701773912bSVasanthakumar Thiagarajan else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) 1711773912bSVasanthakumar Thiagarajan ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); 1721773912bSVasanthakumar Thiagarajan 1732e20250aSLuis R. Rodriguez spin_unlock_bh(&btcoex->btcoex_lock); 1741773912bSVasanthakumar Thiagarajan } 1751773912bSVasanthakumar Thiagarajan 176*af03abecSLuis R. Rodriguez static int ath_init_btcoex_info(struct ath_hw *ah, 1771773912bSVasanthakumar Thiagarajan struct ath_btcoex_info *btcoex_info) 1781773912bSVasanthakumar Thiagarajan { 179*af03abecSLuis R. Rodriguez struct ath_btcoex *btcoex = &ah->ah_sc->btcoex; 1801773912bSVasanthakumar Thiagarajan u32 i; 1811773912bSVasanthakumar Thiagarajan int qnum; 1821773912bSVasanthakumar Thiagarajan 183*af03abecSLuis R. Rodriguez qnum = ath_tx_get_qnum(ah->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); 1841773912bSVasanthakumar Thiagarajan 1851773912bSVasanthakumar Thiagarajan btcoex_info->bt_coex_mode = 1861773912bSVasanthakumar Thiagarajan (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | 1871773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) | 1881773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) | 1891773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | 1901773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_mode, AR_BT_MODE) | 1911773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | 1921773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | 1931773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | 1941773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | 1951773912bSVasanthakumar Thiagarajan SM(qnum, AR_BT_QCU_THRESH); 1961773912bSVasanthakumar Thiagarajan 1971773912bSVasanthakumar Thiagarajan btcoex_info->bt_coex_mode2 = 1981773912bSVasanthakumar Thiagarajan SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) | 1991773912bSVasanthakumar Thiagarajan SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) | 2001773912bSVasanthakumar Thiagarajan AR_BT_DISABLE_BT_ANT; 2011773912bSVasanthakumar Thiagarajan 2021773912bSVasanthakumar Thiagarajan btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; 2031773912bSVasanthakumar Thiagarajan 2042e20250aSLuis R. Rodriguez btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; 2051773912bSVasanthakumar Thiagarajan 2062e20250aSLuis R. Rodriguez btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 2072e20250aSLuis R. Rodriguez btcoex->btcoex_period / 100; 2081773912bSVasanthakumar Thiagarajan 2091773912bSVasanthakumar Thiagarajan for (i = 0; i < 32; i++) 210*af03abecSLuis R. Rodriguez ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; 2111773912bSVasanthakumar Thiagarajan 2122e20250aSLuis R. Rodriguez setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, 213*af03abecSLuis R. Rodriguez (unsigned long) ah->ah_sc); 2141773912bSVasanthakumar Thiagarajan 215*af03abecSLuis R. Rodriguez btcoex_info->no_stomp_timer = ath_gen_timer_alloc(ah, 2161773912bSVasanthakumar Thiagarajan ath_btcoex_no_stomp_timer, 2171773912bSVasanthakumar Thiagarajan ath_btcoex_no_stomp_timer, 218*af03abecSLuis R. Rodriguez (void *)ah->ah_sc, AR_FIRST_NDP_TIMER); 2191773912bSVasanthakumar Thiagarajan 2201773912bSVasanthakumar Thiagarajan if (btcoex_info->no_stomp_timer == NULL) 2211773912bSVasanthakumar Thiagarajan return -ENOMEM; 2221773912bSVasanthakumar Thiagarajan 2232e20250aSLuis R. Rodriguez spin_lock_init(&btcoex->btcoex_lock); 2241773912bSVasanthakumar Thiagarajan 2251773912bSVasanthakumar Thiagarajan return 0; 2261773912bSVasanthakumar Thiagarajan } 2271773912bSVasanthakumar Thiagarajan 2281773912bSVasanthakumar Thiagarajan int ath9k_hw_btcoex_init(struct ath_hw *ah) 22917d50d1dSVasanthakumar Thiagarajan { 230*af03abecSLuis R. Rodriguez struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; 2311773912bSVasanthakumar Thiagarajan int ret = 0; 232f14462c6SVasanthakumar Thiagarajan 2331773912bSVasanthakumar Thiagarajan if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { 23417d50d1dSVasanthakumar Thiagarajan /* connect bt_active to baseband */ 23517d50d1dSVasanthakumar Thiagarajan REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL, 23617d50d1dSVasanthakumar Thiagarajan (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF | 23717d50d1dSVasanthakumar Thiagarajan AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF)); 23817d50d1dSVasanthakumar Thiagarajan 23917d50d1dSVasanthakumar Thiagarajan REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 24017d50d1dSVasanthakumar Thiagarajan AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB); 24117d50d1dSVasanthakumar Thiagarajan 24217d50d1dSVasanthakumar Thiagarajan /* Set input mux for bt_active to gpio pin */ 24317d50d1dSVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 24417d50d1dSVasanthakumar Thiagarajan AR_GPIO_INPUT_MUX1_BT_ACTIVE, 245f14462c6SVasanthakumar Thiagarajan btcoex_info->btactive_gpio); 24617d50d1dSVasanthakumar Thiagarajan 24717d50d1dSVasanthakumar Thiagarajan /* Configure the desired gpio port for input */ 248f14462c6SVasanthakumar Thiagarajan ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); 2491773912bSVasanthakumar Thiagarajan } else { 2501773912bSVasanthakumar Thiagarajan /* btcoex 3-wire */ 2511773912bSVasanthakumar Thiagarajan REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, 2521773912bSVasanthakumar Thiagarajan (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB | 2531773912bSVasanthakumar Thiagarajan AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB)); 2541773912bSVasanthakumar Thiagarajan 2551773912bSVasanthakumar Thiagarajan /* Set input mux for bt_prority_async and 2561773912bSVasanthakumar Thiagarajan * bt_active_async to GPIO pins */ 2571773912bSVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 2581773912bSVasanthakumar Thiagarajan AR_GPIO_INPUT_MUX1_BT_ACTIVE, 2591773912bSVasanthakumar Thiagarajan btcoex_info->btactive_gpio); 2601773912bSVasanthakumar Thiagarajan 2611773912bSVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1, 2621773912bSVasanthakumar Thiagarajan AR_GPIO_INPUT_MUX1_BT_PRIORITY, 2631773912bSVasanthakumar Thiagarajan btcoex_info->btpriority_gpio); 2641773912bSVasanthakumar Thiagarajan 2651773912bSVasanthakumar Thiagarajan /* Configure the desired GPIO ports for input */ 2661773912bSVasanthakumar Thiagarajan 2671773912bSVasanthakumar Thiagarajan ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); 2681773912bSVasanthakumar Thiagarajan ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); 2691773912bSVasanthakumar Thiagarajan 2701773912bSVasanthakumar Thiagarajan ret = ath_init_btcoex_info(ah, btcoex_info); 2711773912bSVasanthakumar Thiagarajan } 2721773912bSVasanthakumar Thiagarajan 2731773912bSVasanthakumar Thiagarajan return ret; 27417d50d1dSVasanthakumar Thiagarajan } 27517d50d1dSVasanthakumar Thiagarajan 27617d50d1dSVasanthakumar Thiagarajan void ath9k_hw_btcoex_enable(struct ath_hw *ah) 27717d50d1dSVasanthakumar Thiagarajan { 278*af03abecSLuis R. Rodriguez struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; 279f14462c6SVasanthakumar Thiagarajan 2801773912bSVasanthakumar Thiagarajan if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) { 28117d50d1dSVasanthakumar Thiagarajan /* Configure the desired GPIO port for TX_FRAME output */ 282f14462c6SVasanthakumar Thiagarajan ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, 28317d50d1dSVasanthakumar Thiagarajan AR_GPIO_OUTPUT_MUX_AS_TX_FRAME); 2841773912bSVasanthakumar Thiagarajan } else { 2851773912bSVasanthakumar Thiagarajan /* 2861773912bSVasanthakumar Thiagarajan * Program coex mode and weight registers to 2871773912bSVasanthakumar Thiagarajan * enable coex 3-wire 2881773912bSVasanthakumar Thiagarajan */ 2891773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode); 2901773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights); 2911773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2); 2921773912bSVasanthakumar Thiagarajan 2931773912bSVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_QUIET1, 2941773912bSVasanthakumar Thiagarajan AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); 2951773912bSVasanthakumar Thiagarajan REG_RMW_FIELD(ah, AR_PCU_MISC, 2961773912bSVasanthakumar Thiagarajan AR_PCU_BT_ANT_PREVENT_RX, 0); 2971773912bSVasanthakumar Thiagarajan 2981773912bSVasanthakumar Thiagarajan ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, 2991773912bSVasanthakumar Thiagarajan AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL); 3001773912bSVasanthakumar Thiagarajan } 3011773912bSVasanthakumar Thiagarajan 3021773912bSVasanthakumar Thiagarajan REG_RMW(ah, AR_GPIO_PDPU, 3031773912bSVasanthakumar Thiagarajan (0x2 << (btcoex_info->btactive_gpio * 2)), 3041773912bSVasanthakumar Thiagarajan (0x3 << (btcoex_info->btactive_gpio * 2))); 30517d50d1dSVasanthakumar Thiagarajan 30617d50d1dSVasanthakumar Thiagarajan ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED; 30717d50d1dSVasanthakumar Thiagarajan } 30817d50d1dSVasanthakumar Thiagarajan 30917d50d1dSVasanthakumar Thiagarajan void ath9k_hw_btcoex_disable(struct ath_hw *ah) 31017d50d1dSVasanthakumar Thiagarajan { 311*af03abecSLuis R. Rodriguez struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; 31217d50d1dSVasanthakumar Thiagarajan 313f14462c6SVasanthakumar Thiagarajan ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0); 314f14462c6SVasanthakumar Thiagarajan 315f14462c6SVasanthakumar Thiagarajan ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio, 31617d50d1dSVasanthakumar Thiagarajan AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 31717d50d1dSVasanthakumar Thiagarajan 3181773912bSVasanthakumar Thiagarajan if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) { 3191773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); 3201773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); 3211773912bSVasanthakumar Thiagarajan REG_WRITE(ah, AR_BT_COEX_MODE2, 0); 3221773912bSVasanthakumar Thiagarajan } 3231773912bSVasanthakumar Thiagarajan 32417d50d1dSVasanthakumar Thiagarajan ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; 32517d50d1dSVasanthakumar Thiagarajan } 3261773912bSVasanthakumar Thiagarajan 3271773912bSVasanthakumar Thiagarajan /* 3281773912bSVasanthakumar Thiagarajan * Pause btcoex timer and bt duty cycle timer 3291773912bSVasanthakumar Thiagarajan */ 3302e20250aSLuis R. Rodriguez void ath_btcoex_timer_pause(struct ath_softc *sc) 3311773912bSVasanthakumar Thiagarajan { 3322e20250aSLuis R. Rodriguez struct ath_btcoex *btcoex = &sc->btcoex; 333*af03abecSLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 3341773912bSVasanthakumar Thiagarajan 3352e20250aSLuis R. Rodriguez del_timer_sync(&btcoex->period_timer); 3361773912bSVasanthakumar Thiagarajan 3372e20250aSLuis R. Rodriguez if (btcoex->hw_timer_enabled) 338*af03abecSLuis R. Rodriguez ath_gen_timer_stop(ah, ah->btcoex_info.no_stomp_timer); 3391773912bSVasanthakumar Thiagarajan 3402e20250aSLuis R. Rodriguez btcoex->hw_timer_enabled = false; 3411773912bSVasanthakumar Thiagarajan } 3421773912bSVasanthakumar Thiagarajan 3431773912bSVasanthakumar Thiagarajan /* 3441773912bSVasanthakumar Thiagarajan * (Re)start btcoex timers 3451773912bSVasanthakumar Thiagarajan */ 3462e20250aSLuis R. Rodriguez void ath_btcoex_timer_resume(struct ath_softc *sc) 3471773912bSVasanthakumar Thiagarajan { 3482e20250aSLuis R. Rodriguez struct ath_btcoex *btcoex = &sc->btcoex; 349*af03abecSLuis R. Rodriguez struct ath_hw *ah = sc->sc_ah; 3501773912bSVasanthakumar Thiagarajan 351*af03abecSLuis R. Rodriguez DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); 3521773912bSVasanthakumar Thiagarajan 3531773912bSVasanthakumar Thiagarajan /* make sure duty cycle timer is also stopped when resuming */ 3542e20250aSLuis R. Rodriguez if (btcoex->hw_timer_enabled) 355*af03abecSLuis R. Rodriguez ath_gen_timer_stop(sc->sc_ah, ah->btcoex_info.no_stomp_timer); 3561773912bSVasanthakumar Thiagarajan 3572e20250aSLuis R. Rodriguez btcoex->bt_priority_cnt = 0; 3582e20250aSLuis R. Rodriguez btcoex->bt_priority_time = jiffies; 3591773912bSVasanthakumar Thiagarajan sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; 3601773912bSVasanthakumar Thiagarajan 3612e20250aSLuis R. Rodriguez mod_timer(&btcoex->period_timer, jiffies); 3621773912bSVasanthakumar Thiagarajan } 363