]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - drivers/net/wireless/ath/ath9k/btcoex.c
ath9k: clarify what hw code is and remove ath9k.h from a few files
[linux-2.6.git] / drivers / net / wireless / ath / ath9k / btcoex.c
index 55f607b7699e47e08917faf981acc4eaf39047e2..0c54489ca443024e8def364afd763501156f3b6e 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "ath9k.h"
+#include "hw.h"
 
-static const struct ath_btcoex_config ath_bt_config = { 0, true, true,
-                       ATH_BT_COEX_MODE_SLOTTED, true, true, 2, 5, true };
+enum ath_bt_mode {
+       ATH_BT_COEX_MODE_LEGACY,        /* legacy rx_clear mode */
+       ATH_BT_COEX_MODE_UNSLOTTED,     /* untimed/unslotted mode */
+       ATH_BT_COEX_MODE_SLOTTED,       /* slotted mode */
+       ATH_BT_COEX_MODE_DISALBED,      /* coexistence disabled */
+};
+
+struct ath_btcoex_config {
+       u8 bt_time_extend;
+       bool bt_txstate_extend;
+       bool bt_txframe_extend;
+       enum ath_bt_mode bt_mode; /* coexistence mode */
+       bool bt_quiet_collision;
+       bool bt_rxclear_polarity; /* invert rx_clear as WLAN_ACTIVE*/
+       u8 bt_priority_time;
+       u8 bt_first_slot_time;
+       bool bt_hold_rx_clear;
+};
 
 static const u16 ath_subsysid_tbl[] = {
        AR9280_COEX2WIRE_SUBSYSID,
@@ -29,141 +45,38 @@ static const u16 ath_subsysid_tbl[] = {
  * Checks the subsystem id of the device to see if it
  * supports btcoex
  */
-bool ath_btcoex_supported(u16 subsysid)
+bool ath9k_hw_btcoex_supported(struct ath_hw *ah)
 {
        int i;
 
-       if (!subsysid)
+       if (!ah->hw_version.subsysid)
                return false;
 
        for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
-               if (subsysid == ath_subsysid_tbl[i])
+               if (ah->hw_version.subsysid == ath_subsysid_tbl[i])
                        return true;
 
        return false;
 }
 
-/*
- * Detects if there is any priority bt traffic
- */
-static void ath_detect_bt_priority(struct ath_softc *sc)
-{
-       struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
-       if (ath9k_hw_gpio_get(sc->sc_ah, btinfo->btpriority_gpio))
-               btinfo->bt_priority_cnt++;
-
-       if (time_after(jiffies, btinfo->bt_priority_time +
-                       msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
-               if (btinfo->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
-                       DPRINTF(sc, ATH_DBG_BTCOEX,
-                               "BT priority traffic detected");
-                       sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED;
-               } else {
-                       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
-               }
-
-               btinfo->bt_priority_cnt = 0;
-               btinfo->bt_priority_time = jiffies;
-       }
-}
-
-/*
- * Configures appropriate weight based on stomp type.
- */
-static void ath_btcoex_bt_stomp(struct ath_softc *sc,
-                               struct ath_btcoex_info *btinfo,
-                               int stomp_type)
-{
-
-       switch (stomp_type) {
-       case ATH_BTCOEX_STOMP_ALL:
-               ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
-                                     AR_STOMP_ALL_WLAN_WGHT);
-               break;
-       case ATH_BTCOEX_STOMP_LOW:
-               ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
-                                     AR_STOMP_LOW_WLAN_WGHT);
-               break;
-       case ATH_BTCOEX_STOMP_NONE:
-               ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT,
-                                     AR_STOMP_NONE_WLAN_WGHT);
-               break;
-       default:
-               DPRINTF(sc, ATH_DBG_BTCOEX, "Invalid Stomptype\n");
-               break;
-       }
-
-       ath9k_hw_btcoex_enable(sc->sc_ah);
-}
-
-/*
- * This is the master bt coex timer which runs for every
- * 45ms, bt traffic will be given priority during 55% of this
- * period while wlan gets remaining 45%
- */
-
-static void ath_btcoex_period_timer(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *) data;
-       struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
-       ath_detect_bt_priority(sc);
-
-       spin_lock_bh(&btinfo->btcoex_lock);
-
-       ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type);
-
-       spin_unlock_bh(&btinfo->btcoex_lock);
-
-       if (btinfo->btcoex_period != btinfo->btcoex_no_stomp) {
-               if (btinfo->hw_timer_enabled)
-                       ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
-
-               ath_gen_timer_start(sc->sc_ah,
-                       btinfo->no_stomp_timer,
-                       (ath9k_hw_gettsf32(sc->sc_ah) +
-                               btinfo->btcoex_no_stomp),
-                               btinfo->btcoex_no_stomp * 10);
-               btinfo->hw_timer_enabled = true;
-       }
-
-       mod_timer(&btinfo->period_timer, jiffies +
-                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
-}
-
-/*
- * Generic tsf based hw timer which configures weight
- * registers to time slice between wlan and bt traffic
- */
-
-static void ath_btcoex_no_stomp_timer(void *arg)
-{
-       struct ath_softc *sc = (struct ath_softc *)arg;
-       struct ath_btcoex_info *btinfo = &sc->btcoex_info;
-
-       DPRINTF(sc, ATH_DBG_BTCOEX, "no stomp timer running \n");
-
-       spin_lock_bh(&btinfo->btcoex_lock);
-
-       if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW)
-               ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE);
-        else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
-               ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW);
-
-       spin_unlock_bh(&btinfo->btcoex_lock);
-}
-
-static int ath_init_btcoex_info(struct ath_hw *hw,
-                               struct ath_btcoex_info *btcoex_info)
+void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 {
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+       const struct ath_btcoex_config ath_bt_config = {
+               .bt_time_extend = 0,
+               .bt_txstate_extend = true,
+               .bt_txframe_extend = true,
+               .bt_mode = ATH_BT_COEX_MODE_SLOTTED,
+               .bt_quiet_collision = true,
+               .bt_rxclear_polarity = true,
+               .bt_priority_time = 2,
+               .bt_first_slot_time = 5,
+               .bt_hold_rx_clear = true,
+       };
        u32 i;
-       int qnum;
 
-       qnum = ath_tx_get_qnum(hw->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE);
-
-       btcoex_info->bt_coex_mode =
-               (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) |
+       btcoex_hw->bt_coex_mode =
+               (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
                SM(ath_bt_config.bt_time_extend, AR_BT_TIME_EXTEND) |
                SM(ath_bt_config.bt_txstate_extend, AR_BT_TXSTATE_EXTEND) |
                SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
@@ -174,167 +87,135 @@ static int ath_init_btcoex_info(struct ath_hw *hw,
                SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
                SM(qnum, AR_BT_QCU_THRESH);
 
-       btcoex_info->bt_coex_mode2 =
+       btcoex_hw->bt_coex_mode2 =
                SM(ath_bt_config.bt_hold_rx_clear, AR_BT_HOLD_RX_CLEAR) |
                SM(ATH_BTCOEX_BMISS_THRESH, AR_BT_BCN_MISS_THRESH) |
                AR_BT_DISABLE_BT_ANT;
 
-       btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+       for (i = 0; i < 32; i++)
+               ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+}
 
-       btcoex_info->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
+void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah)
+{
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       btcoex_info->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
-               btcoex_info->btcoex_period / 100;
+       /* connect bt_active to baseband */
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
+                    AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
 
-       for (i = 0; i < 32; i++)
-               hw->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i;
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
 
-       setup_timer(&btcoex_info->period_timer, ath_btcoex_period_timer,
-                       (unsigned long) hw->ah_sc);
+       /* Set input mux for bt_active to gpio pin */
+       REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+                     AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+                     btcoex_hw->btactive_gpio);
 
-       btcoex_info->no_stomp_timer = ath_gen_timer_alloc(hw,
-                       ath_btcoex_no_stomp_timer,
-                       ath_btcoex_no_stomp_timer,
-                       (void *)hw->ah_sc, AR_FIRST_NDP_TIMER);
+       /* Configure the desired gpio port for input */
+       ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+}
+
+void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah)
+{
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       if (btcoex_info->no_stomp_timer == NULL)
-               return -ENOMEM;
+       /* btcoex 3-wire */
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                       (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
+                        AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
 
-       spin_lock_init(&btcoex_info->btcoex_lock);
+       /* Set input mux for bt_prority_async and
+        *                  bt_active_async to GPIO pins */
+       REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+                       AR_GPIO_INPUT_MUX1_BT_ACTIVE,
+                       btcoex_hw->btactive_gpio);
 
-       return 0;
+       REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
+                       AR_GPIO_INPUT_MUX1_BT_PRIORITY,
+                       btcoex_hw->btpriority_gpio);
+
+       /* Configure the desired GPIO ports for input */
+
+       ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btactive_gpio);
+       ath9k_hw_cfg_gpio_input(ah, btcoex_hw->btpriority_gpio);
 }
 
-int ath9k_hw_btcoex_init(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_2wire(struct ath_hw *ah)
 {
-       struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
-       int ret = 0;
-
-       if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
-               /* connect bt_active to baseband */
-               REG_CLR_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                               (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF |
-                                AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF));
-
-               REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                               AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB);
-
-               /* Set input mux for bt_active to gpio pin */
-               REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
-                               AR_GPIO_INPUT_MUX1_BT_ACTIVE,
-                               btcoex_info->btactive_gpio);
-
-               /* Configure the desired gpio port for input */
-               ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
-       } else {
-               /* btcoex 3-wire */
-               REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                               (AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_BB |
-                                AR_GPIO_INPUT_EN_VAL_BT_ACTIVE_BB));
-
-               /* Set input mux for bt_prority_async and
-                *                  bt_active_async to GPIO pins */
-               REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
-                               AR_GPIO_INPUT_MUX1_BT_ACTIVE,
-                               btcoex_info->btactive_gpio);
-
-               REG_RMW_FIELD(ah, AR_GPIO_INPUT_MUX1,
-                               AR_GPIO_INPUT_MUX1_BT_PRIORITY,
-                               btcoex_info->btpriority_gpio);
-
-               /* Configure the desired GPIO ports for input */
-
-               ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio);
-               ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio);
-
-               ret = ath_init_btcoex_info(ah, btcoex_info);
-       }
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       return ret;
+       /* Configure the desired GPIO port for TX_FRAME output */
+       ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+                           AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
 }
 
-void ath9k_hw_btcoex_enable(struct ath_hw *ah)
+void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
+                               u32 bt_weight,
+                               u32 wlan_weight)
 {
-       struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
-
-       if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) {
-               /* Configure the desired GPIO port for TX_FRAME output */
-               ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
-                               AR_GPIO_OUTPUT_MUX_AS_TX_FRAME);
-       } else {
-               /*
-                * Program coex mode and weight registers to
-                * enable coex 3-wire
-                */
-               REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_info->bt_coex_mode);
-               REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_info->bt_coex_weights);
-               REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_info->bt_coex_mode2);
-
-               REG_RMW_FIELD(ah, AR_QUIET1,
-                               AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
-               REG_RMW_FIELD(ah, AR_PCU_MISC,
-                               AR_PCU_BT_ANT_PREVENT_RX, 0);
-
-               ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
-                               AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
-       }
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       REG_RMW(ah, AR_GPIO_PDPU,
-               (0x2 << (btcoex_info->btactive_gpio * 2)),
-               (0x3 << (btcoex_info->btactive_gpio * 2)));
-
-       ah->ah_sc->sc_flags |= SC_OP_BTCOEX_ENABLED;
+       btcoex_hw->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) |
+                                    SM(wlan_weight, AR_BTCOEX_WL_WGHT);
 }
 
-void ath9k_hw_btcoex_disable(struct ath_hw *ah)
+static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
 {
-       struct ath_btcoex_info *btcoex_info = &ah->ah_sc->btcoex_info;
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       ath9k_hw_set_gpio(ah, btcoex_info->wlanactive_gpio, 0);
+       /*
+        * Program coex mode and weight registers to
+        * enable coex 3-wire
+        */
+       REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode);
+       REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
+       REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
 
-       ath9k_hw_cfg_output(ah, btcoex_info->wlanactive_gpio,
-                       AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+       REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1);
+       REG_RMW_FIELD(ah, AR_PCU_MISC, AR_PCU_BT_ANT_PREVENT_RX, 0);
 
-       if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) {
-               REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
-               REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
-               REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
-       }
-
-       ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED;
+       ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+                           AR_GPIO_OUTPUT_MUX_AS_RX_CLEAR_EXTERNAL);
 }
 
-/*
- * Pause btcoex timer and bt duty cycle timer
- */
-void ath_btcoex_timer_pause(struct ath_softc *sc,
-                           struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_enable(struct ath_hw *ah)
 {
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       del_timer_sync(&btinfo->period_timer);
+       switch (btcoex_hw->scheme) {
+       case ATH_BTCOEX_CFG_NONE:
+               break;
+       case ATH_BTCOEX_CFG_2WIRE:
+               ath9k_hw_btcoex_enable_2wire(ah);
+               break;
+       case ATH_BTCOEX_CFG_3WIRE:
+               ath9k_hw_btcoex_enable_3wire(ah);
+               break;
+       }
 
-       if (btinfo->hw_timer_enabled)
-               ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+       REG_RMW(ah, AR_GPIO_PDPU,
+               (0x2 << (btcoex_hw->btactive_gpio * 2)),
+               (0x3 << (btcoex_hw->btactive_gpio * 2)));
 
-       btinfo->hw_timer_enabled = false;
+       ah->btcoex_hw.enabled = true;
 }
 
-/*
- * (Re)start btcoex timers
- */
-void ath_btcoex_timer_resume(struct ath_softc *sc,
-                            struct ath_btcoex_info *btinfo)
+void ath9k_hw_btcoex_disable(struct ath_hw *ah)
 {
+       struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
-       DPRINTF(sc, ATH_DBG_BTCOEX, "Starting btcoex timers");
+       ath9k_hw_set_gpio(ah, btcoex_hw->wlanactive_gpio, 0);
 
-       /* make sure duty cycle timer is also stopped when resuming */
-       if (btinfo->hw_timer_enabled)
-               ath_gen_timer_stop(sc->sc_ah, btinfo->no_stomp_timer);
+       ath9k_hw_cfg_output(ah, btcoex_hw->wlanactive_gpio,
+                       AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 
-       btinfo->bt_priority_cnt = 0;
-       btinfo->bt_priority_time = jiffies;
-       sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED;
+       if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
+               REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
+               REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+               REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+       }
 
-       mod_timer(&btinfo->period_timer, jiffies);
+       ah->btcoex_hw.enabled = false;
 }