Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[pandora-kernel.git] / drivers / net / wireless / rtlwifi / rtl8192c / dm_common.c
index bb02327..a00774e 100644 (file)
  *****************************************************************************/
 
 #include "dm_common.h"
+#include "phy_common.h"
+#include "../pci.h"
+#include "../base.h"
 
 struct dig_t dm_digtable;
 static struct ps_t dm_pstable;
 
+#define BT_RSSI_STATE_NORMAL_POWER     BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF                BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW      BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW      BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW      BIT_OFFSET_LEN_MASK_32(4, 1)
+
+#define RTLPRIV                        (struct rtl_priv *)
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv)    \
+       ((RTLPRIV(_priv))->mac80211.opmode == \
+                            NL80211_IFTYPE_ADHOC) ?    \
+       ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \
+       ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb)
+
 static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
        0x7f8001fe,
        0x788001e2,
@@ -304,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
 
 static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
 {
-       static u8 binitialized; /* initialized to false */
+       static u8 initialized; /* initialized to false */
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
@@ -315,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
 
        if ((multi_sta == false) || (dm_digtable.cursta_connectctate !=
                                     DIG_STA_DISCONNECT)) {
-               binitialized = false;
+               initialized = false;
                dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
                return;
-       } else if (binitialized == false) {
-               binitialized = true;
+       } else if (initialized == false) {
+               initialized = true;
                dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
                dm_digtable.cur_igvalue = 0x20;
                rtl92c_dm_write_dig(hw);
@@ -458,13 +474,10 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
 {
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
 
-       if (mac->act_scanning == true)
+       if (mac->act_scanning)
                return;
 
-       if ((mac->link_state > MAC80211_NOLINK) &&
-           (mac->link_state < MAC80211_LINKED))
-               dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT;
-       else if (mac->link_state >= MAC80211_LINKED)
+       if (mac->link_state >= MAC80211_LINKED)
                dm_digtable.cursta_connectctate = DIG_STA_CONNECT;
        else
                dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT;
@@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo);
 static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
        static u64 last_txok_cnt;
        static u64 last_rxok_cnt;
-       u64 cur_txok_cnt;
-       u64 cur_rxok_cnt;
+       static u32 last_bt_edca_ul;
+       static u32 last_bt_edca_dl;
+       u64 cur_txok_cnt = 0;
+       u64 cur_rxok_cnt = 0;
        u32 edca_be_ul = 0x5ea42b;
        u32 edca_be_dl = 0x5ea42b;
+       bool bt_change_edca = false;
 
-       if (mac->opmode == NL80211_IFTYPE_ADHOC)
-               goto dm_checkedcaturbo_exit;
+       if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+           (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+               rtlpriv->dm.current_turbo_edca = false;
+               last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+               last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+               edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+               bt_change_edca = true;
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+               edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+               bt_change_edca = true;
+       }
 
        if (mac->link_state != MAC80211_LINKED) {
                rtlpriv->dm.current_turbo_edca = false;
                return;
        }
 
-       if (!mac->ht_enable) {  /*FIX MERGE */
+       if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
                if (!(edca_be_ul & 0xffff0000))
                        edca_be_ul |= 0x005e0000;
 
@@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
                        edca_be_dl |= 0x005e0000;
        }
 
-       if ((!rtlpriv->dm.is_any_nonbepkts) &&
-           (!rtlpriv->dm.disable_framebursting)) {
+       if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+            (!rtlpriv->dm.disable_framebursting))) {
+
                cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
                cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
                if (cur_rxok_cnt > 4 * cur_txok_cnt) {
                        if (!rtlpriv->dm.is_cur_rdlstate ||
                            !rtlpriv->dm.current_turbo_edca) {
@@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
                }
        }
 
-dm_checkedcaturbo_exit:
        rtlpriv->dm.is_any_nonbepkts = false;
        last_txok_cnt = rtlpriv->stats.txbytesunicast;
        last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
@@ -633,14 +666,14 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
        struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
        u8 thermalvalue, delta, delta_lck, delta_iqk;
        long ele_a, ele_d, temp_cck, val_x, value32;
-       long val_y, ele_c;
-       u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old;
+       long val_y, ele_c = 0;
+       u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
        int i;
        bool is2t = IS_92C_SERIAL(rtlhal->version);
-       u8 txpwr_level[2] = {0, 0};
+       s8 txpwr_level[2] = {0, 0};
        u8 ofdm_min_index = 6, rf;
 
-       rtlpriv->dm.txpower_trackingInit = true;
+       rtlpriv->dm.txpower_trackinginit = true;
        RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
                 ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n"));
 
@@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
                        for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
                                if (ele_d == (ofdmswing_table[i] &
                                    MASKOFDM_D)) {
-                                       ofdm_index_old[1] = (u8) i;
 
                                        RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
                                           DBG_LOUD,
@@ -1062,7 +1094,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter(
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
        rtlpriv->dm.txpower_tracking = true;
-       rtlpriv->dm.txpower_trackingInit = false;
+       rtlpriv->dm.txpower_trackinginit = false;
 
        RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
                 ("pMgntInfo->txpower_tracking = %d\n",
@@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rate_adaptive *p_ra = &(rtlpriv->ra);
        u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+       struct ieee80211_sta *sta = NULL;
 
        if (is_hal_stop(rtlhal)) {
                RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
                return;
        }
 
-       if (mac->link_state == MAC80211_LINKED) {
-
+       if (mac->link_state == MAC80211_LINKED &&
+           mac->opmode == NL80211_IFTYPE_STATION) {
                switch (p_ra->pre_ratr_state) {
                case DM_RATR_STA_HIGH:
                        high_rssithresh_for_ra = 50;
@@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
                                 ("PreState = %d, CurState = %d\n",
                                  p_ra->pre_ratr_state, p_ra->ratr_state));
 
-                       rtlpriv->cfg->ops->update_rate_mask(hw,
+                       rcu_read_lock();
+                       sta = ieee80211_find_sta(mac->vif, mac->bssid);
+                       rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
                                        p_ra->ratr_state);
 
                        p_ra->pre_ratr_state = p_ra->ratr_state;
+                       rcu_read_unlock();
                }
        }
 }
@@ -1202,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
        dm_pstable.rssi_val_min = 0;
 }
 
-static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
-       if (dm_pstable.rssi_val_min != 0) {
-               if (dm_pstable.pre_ccastate == CCA_2R) {
-                       if (dm_pstable.rssi_val_min >= 35)
-                               dm_pstable.cur_ccasate = CCA_1R;
-                       else
-                               dm_pstable.cur_ccasate = CCA_2R;
-               } else {
-                       if (dm_pstable.rssi_val_min <= 30)
-                               dm_pstable.cur_ccasate = CCA_2R;
-                       else
-                               dm_pstable.cur_ccasate = CCA_1R;
-               }
-       } else {
-               dm_pstable.cur_ccasate = CCA_MAX;
-       }
-
-       if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) {
-               if (dm_pstable.cur_ccasate == CCA_1R) {
-                       if (get_rf_type(rtlphy) == RF_2T2R) {
-                               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
-                                             MASKBYTE0, 0x13);
-                               rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20);
-                       } else {
-                               rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
-                                             MASKBYTE0, 0x23);
-                               rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c);
-                       }
-               } else {
-                       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0,
-                                     0x33);
-                       rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63);
-               }
-               dm_pstable.pre_ccastate = dm_pstable.cur_ccasate;
-       }
-
-       RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n",
-                                              (dm_pstable.cur_ccasate ==
-                                               0) ? "1RCCA" : "2RCCA"));
-}
-
 void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
 {
        static u8 initialize;
@@ -1352,7 +1343,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
        }
 
        if (IS_92C_SERIAL(rtlhal->version))
-               rtl92c_dm_1r_cca(hw);
+               ;/* rtl92c_dm_1r_cca(hw); */
+       else
+               rtl92c_dm_rf_saving(hw, false);
 }
 
 void rtl92c_dm_init(struct ieee80211_hw *hw)
@@ -1369,6 +1362,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(rtl92c_dm_init);
 
+void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       long undecorated_smoothed_pwdb;
+
+       if (!rtlpriv->dm.dynamic_txpower_enable)
+               return;
+
+       if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+               return;
+       }
+
+       if ((mac->link_state < MAC80211_LINKED) &&
+           (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+                        ("Not connected to any\n"));
+
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+               rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+               return;
+       }
+
+       if (mac->link_state >= MAC80211_LINKED) {
+               if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       undecorated_smoothed_pwdb =
+                           rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+                       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                ("AP Client PWDB = 0x%lx\n",
+                                 undecorated_smoothed_pwdb));
+               } else {
+                       undecorated_smoothed_pwdb =
+                           rtlpriv->dm.undecorated_smoothed_pwdb;
+                       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                ("STA Default Port PWDB = 0x%lx\n",
+                                 undecorated_smoothed_pwdb));
+               }
+       } else {
+               undecorated_smoothed_pwdb =
+                   rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        ("AP Ext Port PWDB = 0x%lx\n",
+                         undecorated_smoothed_pwdb));
+       }
+
+       if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"));
+       } else if ((undecorated_smoothed_pwdb <
+                   (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+                  (undecorated_smoothed_pwdb >=
+                   TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"));
+       } else if (undecorated_smoothed_pwdb <
+                  (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        ("TXHIGHPWRLEVEL_NORMAL\n"));
+       }
+
+       if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        ("PHY_SetTxPowerLevel8192S() Channel = %d\n",
+                         rtlphy->current_channel));
+               rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+       }
+
+       rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
 void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1388,11 +1459,321 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
                rtl92c_dm_dig(hw);
                rtl92c_dm_false_alarm_counter_statistics(hw);
                rtl92c_dm_dynamic_bb_powersaving(hw);
-               rtlpriv->cfg->ops->dm_dynamic_txpower(hw);
+               rtl92c_dm_dynamic_txpower(hw);
                rtl92c_dm_check_txpower_tracking(hw);
                rtl92c_dm_refresh_rate_adaptive_mask(hw);
+               rtl92c_dm_bt_coexist(hw);
                rtl92c_dm_check_edca_turbo(hw);
-
        }
 }
 EXPORT_SYMBOL(rtl92c_dm_watchdog);
+
+u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       long undecorated_smoothed_pwdb;
+       u8 curr_bt_rssi_state = 0x00;
+
+       if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+               undecorated_smoothed_pwdb =
+                                GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+       } else {
+               if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)
+                       undecorated_smoothed_pwdb = 100;
+               else
+                       undecorated_smoothed_pwdb =
+                               rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+       }
+
+       /* Check RSSI to determine HighPower/NormalPower state for
+        * BT coexistence. */
+       if (undecorated_smoothed_pwdb >= 67)
+               curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER);
+       else if (undecorated_smoothed_pwdb < 62)
+               curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER;
+
+       /* Check RSSI to determine AMPDU setting for BT coexistence. */
+       if (undecorated_smoothed_pwdb >= 40)
+               curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF);
+       else if (undecorated_smoothed_pwdb <= 32)
+               curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF;
+
+       /* Marked RSSI state. It will be used to determine BT coexistence
+        * setting later. */
+       if (undecorated_smoothed_pwdb < 35)
+               curr_bt_rssi_state |=  BT_RSSI_STATE_SPECIAL_LOW;
+       else
+               curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
+
+       /* Set Tx Power according to BT status. */
+       if (undecorated_smoothed_pwdb >= 30)
+               curr_bt_rssi_state |=  BT_RSSI_STATE_TXPOWER_LOW;
+       else if (undecorated_smoothed_pwdb < 25)
+               curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
+
+       /* Check BT state related to BT_Idle in B/G mode. */
+       if (undecorated_smoothed_pwdb < 15)
+               curr_bt_rssi_state |=  BT_RSSI_STATE_BG_EDCA_LOW;
+       else
+               curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW);
+
+       if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) {
+               rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state;
+               return true;
+       } else {
+               return false;
+       }
+}
+EXPORT_SYMBOL(rtl92c_bt_rssi_state_change);
+
+static bool rtl92c_bt_state_change(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       u32 polling, ratio_tx, ratio_pri;
+       u32 bt_tx, bt_pri;
+       u8 bt_state;
+       u8 cur_service_type;
+
+       if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+               return false;
+
+       bt_state = rtl_read_byte(rtlpriv, 0x4fd);
+       bt_tx = rtl_read_dword(rtlpriv, 0x488);
+       bt_tx = bt_tx & 0x00ffffff;
+       bt_pri = rtl_read_dword(rtlpriv, 0x48c);
+       bt_pri = bt_pri & 0x00ffffff;
+       polling = rtl_read_dword(rtlpriv, 0x490);
+
+       if (bt_tx == 0xffffffff && bt_pri == 0xffffffff &&
+           polling == 0xffffffff && bt_state == 0xff)
+               return false;
+
+       bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1);
+       if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) {
+               rtlpcipriv->bt_coexist.bt_cur_state = bt_state;
+
+               if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+                       rtlpcipriv->bt_coexist.bt_service = BT_IDLE;
+
+                       bt_state = bt_state |
+                         ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+                         0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+                         BIT_OFFSET_LEN_MASK_32(2, 1);
+                       rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+               }
+               return true;
+       }
+
+       ratio_tx = bt_tx * 1000 / polling;
+       ratio_pri = bt_pri * 1000 / polling;
+       rtlpcipriv->bt_coexist.ratio_tx = ratio_tx;
+       rtlpcipriv->bt_coexist.ratio_pri = ratio_pri;
+
+       if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+
+               if ((ratio_tx < 30)  && (ratio_pri < 30))
+                       cur_service_type = BT_IDLE;
+               else if ((ratio_pri > 110) && (ratio_pri < 250))
+                       cur_service_type = BT_SCO;
+               else if ((ratio_tx >= 200) && (ratio_pri >= 200))
+                       cur_service_type = BT_BUSY;
+               else if ((ratio_tx >= 350) && (ratio_tx < 500))
+                       cur_service_type = BT_OTHERBUSY;
+               else if (ratio_tx >= 500)
+                       cur_service_type = BT_PAN;
+               else
+                       cur_service_type = BT_OTHER_ACTION;
+
+               if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) {
+                       rtlpcipriv->bt_coexist.bt_service = cur_service_type;
+                       bt_state = bt_state |
+                          ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+                          0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+                          ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ?
+                          0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+
+                       /* Add interrupt migration when bt is not ini
+                        * idle state (no traffic). */
+                       if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+                               rtl_write_word(rtlpriv, 0x504, 0x0ccc);
+                               rtl_write_byte(rtlpriv, 0x506, 0x54);
+                               rtl_write_byte(rtlpriv, 0x507, 0x54);
+                       } else {
+                               rtl_write_byte(rtlpriv, 0x506, 0x00);
+                               rtl_write_byte(rtlpriv, 0x507, 0x00);
+                       }
+
+                       rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+                       return true;
+               }
+       }
+
+       return false;
+
+}
+
+static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       static bool media_connect;
+
+       if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+               media_connect = false;
+       } else {
+               if (!media_connect) {
+                       media_connect = true;
+                       return true;
+               }
+               media_connect = true;
+       }
+
+       return false;
+}
+
+static void rtl92c_bt_set_normal(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+       if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) {
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b;
+       } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) {
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f;
+       } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) {
+               if (rtlpcipriv->bt_coexist.ratio_tx > 160) {
+                       rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f;
+                       rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f;
+               } else {
+                       rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b;
+                       rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b;
+               }
+       } else {
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+       }
+
+       if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) &&
+            (rtlpriv->mac80211.mode == WIRELESS_MODE_G ||
+            (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) &&
+            (rtlpcipriv->bt_coexist.bt_rssi_state &
+            BT_RSSI_STATE_BG_EDCA_LOW)) {
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b;
+       }
+}
+
+static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+       /* Only enable HW BT coexist when BT in "Busy" state. */
+       if (rtlpriv->mac80211.vendor == PEER_CISCO &&
+           rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) {
+               rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+       } else {
+               if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) &&
+                   (rtlpcipriv->bt_coexist.bt_rssi_state &
+                    BT_RSSI_STATE_NORMAL_POWER)) {
+                       rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+               } else if ((rtlpcipriv->bt_coexist.bt_service ==
+                           BT_OTHER_ACTION) && (rtlpriv->mac80211.mode <
+                           WIRELESS_MODE_N_24G) &&
+                           (rtlpcipriv->bt_coexist.bt_rssi_state &
+                           BT_RSSI_STATE_SPECIAL_LOW)) {
+                       rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+               } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) {
+                       rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+               } else {
+                       rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+               }
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_service == BT_PAN)
+               rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100);
+       else
+               rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0);
+
+       if (rtlpcipriv->bt_coexist.bt_rssi_state &
+           BT_RSSI_STATE_NORMAL_POWER) {
+               rtl92c_bt_set_normal(hw);
+       } else {
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+               rtlpriv->cfg->ops->set_rfreg(hw,
+                                RF90_PATH_A,
+                                0x1e,
+                                0xf0, 0xf);
+       } else {
+               rtlpriv->cfg->ops->set_rfreg(hw,
+                    RF90_PATH_A, 0x1e, 0xf0,
+                    rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+       }
+
+       if (!rtlpriv->dm.dynamic_txpower_enable) {
+               if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+                       if (rtlpcipriv->bt_coexist.bt_rssi_state &
+                               BT_RSSI_STATE_TXPOWER_LOW) {
+                               rtlpriv->dm.dynamic_txhighpower_lvl =
+                                                       TXHIGHPWRLEVEL_BT2;
+                       } else {
+                               rtlpriv->dm.dynamic_txhighpower_lvl =
+                                       TXHIGHPWRLEVEL_BT1;
+                       }
+               } else {
+                       rtlpriv->dm.dynamic_txhighpower_lvl =
+                               TXHIGHPWRLEVEL_NORMAL;
+               }
+               rtl92c_phy_set_txpower_level(hw,
+                       rtlpriv->phy.current_channel);
+       }
+}
+
+static void rtl92c_check_bt_change(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       if (rtlpcipriv->bt_coexist.bt_cur_state) {
+               if (rtlpcipriv->bt_coexist.bt_ant_isolation)
+                       rtl92c_bt_ant_isolation(hw);
+       } else {
+               rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+               rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0,
+                               rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+
+               rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+               rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+       }
+}
+
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       bool wifi_connect_change;
+       bool bt_state_change;
+       bool rssi_state_change;
+
+       if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+            (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+
+               wifi_connect_change = rtl92c_bt_wifi_connect_change(hw);
+               bt_state_change = rtl92c_bt_state_change(hw);
+               rssi_state_change = rtl92c_bt_rssi_state_change(hw);
+
+               if (wifi_connect_change || bt_state_change || rssi_state_change)
+                       rtl92c_check_bt_change(hw);
+       }
+}
+EXPORT_SYMBOL(rtl92c_dm_bt_coexist);