}
 EXPORT_SYMBOL(ar9003_paprd_enable);
 
-static void ar9003_paprd_setup_single_table(struct ath_hw *ah)
+static int ar9003_get_training_power_2g(struct ath_hw *ah)
 {
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
+       unsigned int power, scale, delta;
+
+       scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1);
+       power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
+                              AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
+
+       delta = abs((int) ah->paprd_target_power - (int) power);
+       if (delta > scale)
+               return -1;
+
+       if (delta < 4)
+               power -= 4 - delta;
+
+       return power;
+}
+
+static int get_streams(int mask)
+{
+       return !!(mask & BIT(0)) + !!(mask & BIT(1)) + !!(mask & BIT(2));
+}
+
+static int ar9003_get_training_power_5g(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
+       struct ath9k_channel *chan = ah->curchan;
+       unsigned int power, scale, delta;
+
+       if (chan->channel >= 5700)
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt20),
+                          AR9300_PAPRD_SCALE_1);
+       else if (chan->channel >= 5400)
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+                          AR9300_PAPRD_SCALE_2);
+       else
+               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
+                          AR9300_PAPRD_SCALE_1);
+
+       if (IS_CHAN_HT40(chan))
+               power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
+                       AR_PHY_POWERTX_RATE8_POWERTXHT40_5);
+       else
+               power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE6,
+                       AR_PHY_POWERTX_RATE6_POWERTXHT20_5);
+
+       power += scale;
+       delta = abs((int) ah->paprd_target_power - (int) power);
+       if (delta > scale)
+               return -1;
+
+       power += 2 * get_streams(common->tx_chainmask);
+       return power;
+}
+
+static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
        struct ar9300_modal_eep_header *hdr;
        static const u32 ctrl0[3] = {
                AR_PHY_PAPRD_CTRL1_B2
        };
        u32 am_mask, ht40_mask;
+       int training_power;
        int i;
 
        if (ah->curchan && IS_CHAN_5GHZ(ah->curchan))
        am_mask = le32_to_cpu(hdr->papdRateMaskHt20) & AR9300_PAPRD_RATE_MASK;
        ht40_mask = le32_to_cpu(hdr->papdRateMaskHt40) & AR9300_PAPRD_RATE_MASK;
 
+       if (IS_CHAN_2GHZ(ah->curchan))
+               training_power = ar9003_get_training_power_2g(ah);
+       else
+               training_power = ar9003_get_training_power_5g(ah);
+
+       if (training_power < 0) {
+               ath_dbg(common, ATH_DBG_CALIBRATE,
+                       "PAPRD target power delta out of range");
+               return -ERANGE;
+       }
+       ah->paprd_training_power = training_power;
+       ath_dbg(common, ATH_DBG_CALIBRATE,
+               "Training power: %d, Target power: %d\n",
+               ah->paprd_training_power, ah->paprd_target_power);
+
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK, am_mask);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2PM, AR_PHY_PAPRD_AM2PM_MASK, am_mask);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_HT40, AR_PHY_PAPRD_HT40_MASK, ht40_mask);
 
-
        for (i = 0; i < ah->caps.max_txchains; i++) {
                REG_RMW_FIELD(ah, ctrl0[i],
                              AR_PHY_PAPRD_CTRL0_USE_SINGLE_TABLE_MASK, 1);
                      AR_PHY_PAPRD_PRE_POST_SCALING, 185706);
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_PRE_POST_SCALE_7_B0,
                      AR_PHY_PAPRD_PRE_POST_SCALING, 175487);
+       return 0;
 }
 
 static void ar9003_paprd_get_gain_table(struct ath_hw *ah)
 {
        u32 *paprd_table_val = caldata->pa_table[chain];
        u32 small_signal_gain = caldata->small_signal_gain[chain];
-       u32 training_power;
+       u32 training_power = ah->paprd_training_power;
        u32 reg = 0;
        int i;
 
-       training_power =
-           REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
-                          AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-       training_power -= 4;
-
        if (chain == 0)
                reg = AR_PHY_PAPRD_MEM_TAB_B0;
        else if (chain == 1)
 
 int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
 {
-
        unsigned int i, desired_gain, gain_index;
-       unsigned int train_power;
-
-       train_power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
-                                    AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
-
-       train_power = train_power - 4;
+       unsigned int train_power = ah->paprd_training_power;
 
        desired_gain = ar9003_get_desired_gain(ah, chain, train_power);
 
 
 int ar9003_paprd_init_table(struct ath_hw *ah)
 {
-       ar9003_paprd_setup_single_table(ah);
+       int ret;
+
+       ret = ar9003_paprd_setup_single_table(ah);
+       if (ret < 0)
+           return ret;
+
        ar9003_paprd_get_gain_table(ah);
        return 0;
 }