ath9k_hw: Improve fast channel change for AR9003 chips
[profile/ivi/kernel-x86-ivi.git] / drivers / net / wireless / ath / ath9k / ar9003_phy.c
index 779f407..4e31d65 100644 (file)
@@ -688,6 +688,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        if (AR_SREV_9480(ah))
                ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1);
 
+       ah->modes_index = modesIndex;
        ar9003_hw_override_ini(ah);
        ar9003_hw_set_channel_regs(ah, chan);
        ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
@@ -1247,6 +1248,73 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
        REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
 }
 
+static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
+                                     struct ath9k_channel *chan,
+                                     u8 *ini_reloaded)
+{
+       unsigned int regWrites = 0;
+       u32 modesIndex;
+
+       switch (chan->chanmode) {
+       case CHANNEL_A:
+       case CHANNEL_A_HT20:
+               modesIndex = 1;
+               break;
+       case CHANNEL_A_HT40PLUS:
+       case CHANNEL_A_HT40MINUS:
+               modesIndex = 2;
+               break;
+       case CHANNEL_G:
+       case CHANNEL_G_HT20:
+       case CHANNEL_B:
+               modesIndex = 4;
+               break;
+       case CHANNEL_G_HT40PLUS:
+       case CHANNEL_G_HT40MINUS:
+               modesIndex = 3;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (modesIndex == ah->modes_index) {
+               *ini_reloaded = false;
+               goto set_rfmode;
+       }
+
+       ar9003_hw_prog_ini(ah, &ah->iniSOC[ATH_INI_POST], modesIndex);
+       ar9003_hw_prog_ini(ah, &ah->iniMac[ATH_INI_POST], modesIndex);
+       ar9003_hw_prog_ini(ah, &ah->iniBB[ATH_INI_POST], modesIndex);
+       ar9003_hw_prog_ini(ah, &ah->iniRadio[ATH_INI_POST], modesIndex);
+       if (AR_SREV_9480_20(ah))
+               ar9003_hw_prog_ini(ah,
+                               &ah->ini_radio_post_sys2ant,
+                               modesIndex);
+
+       REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+       /*
+        * For 5GHz channels requiring Fast Clock, apply
+        * different modal values.
+        */
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+               REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites);
+
+       if (AR_SREV_9330(ah))
+               REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites);
+
+       if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
+               REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+
+       ah->modes_index = modesIndex;
+       *ini_reloaded = true;
+
+set_rfmode:
+       ar9003_hw_set_rfmode(ah, chan);
+       return 0;
+}
+
 void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
 {
        struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
@@ -1275,6 +1343,7 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
        priv_ops->do_getnf = ar9003_hw_do_getnf;
        priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
        priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+       priv_ops->fast_chan_change = ar9003_hw_fast_chan_change;
 
        ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
        ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;