ath9k_hw: Tx IQ cal changes for AR9003
authorVasanthakumar Thiagarajan <vasanth@atheros.com>
Wed, 15 Dec 2010 15:30:50 +0000 (07:30 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 16 Dec 2010 20:22:30 +0000 (15:22 -0500)
Add multiple Tx IQ cal support to improve EVM accross
different power levels.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ar9003_calib.c

index 75a1c6e5195cf02fc5cbbda2d59fead3c31c91af..4a4cd88429c069076945e3d0c13807c8d83b2729 100644 (file)
@@ -608,107 +608,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
        return true;
 }
 
-static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
-               AR_PHY_TX_IQCAL_STATUS_B0,
-               AR_PHY_TX_IQCAL_STATUS_B1,
-               AR_PHY_TX_IQCAL_STATUS_B2,
-       };
-       static const u_int32_t chan_info_tab[] = {
-               AR_PHY_CHAN_INFO_TAB_0,
-               AR_PHY_CHAN_INFO_TAB_1,
-               AR_PHY_CHAN_INFO_TAB_2,
-       };
-       u32 tx_corr_coeff[AR9300_MAX_CHAINS];
-       s32 iq_res[6];
-       s32 iqc_coeff[2];
-       s32 i, j;
-       u32 num_chains = 0;
-
-       tx_corr_coeff[0] = AR_PHY_TX_IQCAL_CORR_COEFF_B0(0);
-       tx_corr_coeff[1] = AR_PHY_TX_IQCAL_CORR_COEFF_B1(0);
-       tx_corr_coeff[2] = AR_PHY_TX_IQCAL_CORR_COEFF_B2(0);
-
-       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
-               if (ah->txchainmask & (1 << i))
-                       num_chains++;
-       }
-
-       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
-                     AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
-                     DELPT);
-       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
-                     AR_PHY_TX_IQCAL_START_DO_CAL,
-                     AR_PHY_TX_IQCAL_START_DO_CAL);
-
-       if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
-                          AR_PHY_TX_IQCAL_START_DO_CAL,
-                          0, AH_WAIT_TIMEOUT)) {
-               ath_dbg(common, ATH_DBG_CALIBRATE,
-                       "Tx IQ Cal not complete.\n");
-               goto TX_IQ_CAL_FAILED;
-       }
-
-       for (i = 0; i < num_chains; i++) {
-               ath_dbg(common, ATH_DBG_CALIBRATE,
-                       "Doing Tx IQ Cal for chain %d.\n", i);
-
-               if (REG_READ(ah, txiqcal_status[i]) &
-                            AR_PHY_TX_IQCAL_STATUS_FAILED) {
-                       ath_dbg(common, ATH_DBG_CALIBRATE,
-                               "Tx IQ Cal failed for chain %d.\n", i);
-                       goto TX_IQ_CAL_FAILED;
-               }
-
-               for (j = 0; j < 3; j++) {
-                       u_int8_t idx = 2 * j,
-                       offset = 4 * j;
-
-                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
-                                     AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
-
-                       /* 32 bits */
-                       iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset);
-
-                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
-                                     AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
-
-                       /* 16 bits */
-                       iq_res[idx+1] = 0xffff & REG_READ(ah,
-                                                         chan_info_tab[i] +
-                                                         offset);
-
-                       ath_dbg(common, ATH_DBG_CALIBRATE,
-                               "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
-                               idx, iq_res[idx], idx+1, iq_res[idx+1]);
-               }
-
-               if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) {
-                       ath_dbg(common, ATH_DBG_CALIBRATE,
-                               "Failed in calculation of IQ correction.\n");
-                       goto TX_IQ_CAL_FAILED;
-               }
-
-               ath_dbg(common, ATH_DBG_CALIBRATE,
-                       "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n",
-                       iqc_coeff[0], iqc_coeff[1]);
-
-               REG_RMW_FIELD(ah, tx_corr_coeff[i],
-                             AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
-                             iqc_coeff[0]);
-       }
-
-       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
-                     AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
-
-       return;
-
-TX_IQ_CAL_FAILED:
-       ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
-}
-
 static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
 {
        int diff[MPASS];
@@ -717,9 +616,9 @@ static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
        diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
        diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
 
-       if (diff[0] > MAX_MEASUREMENT &&
-           diff[1] > MAX_MEASUREMENT &&
-           diff[2] > MAX_MEASUREMENT)
+       if (diff[0] > MAX_DIFFERENCE &&
+           diff[1] > MAX_DIFFERENCE &&
+           diff[2] > MAX_DIFFERENCE)
                return false;
 
        if (diff[0] <= diff[1] && diff[0] <= diff[2])
@@ -817,6 +716,111 @@ disable_txiqcal:
        ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
 }
 
+static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+               AR_PHY_TX_IQCAL_STATUS_B0,
+               AR_PHY_TX_IQCAL_STATUS_B1,
+               AR_PHY_TX_IQCAL_STATUS_B2,
+       };
+       static const u32 chan_info_tab[] = {
+               AR_PHY_CHAN_INFO_TAB_0,
+               AR_PHY_CHAN_INFO_TAB_1,
+               AR_PHY_CHAN_INFO_TAB_2,
+       };
+       struct coeff coeff;
+       s32 iq_res[6];
+       s32 i, j, ip, im, nmeasurement;
+       u8 nchains = get_streams(common->tx_chainmask);
+
+       for (ip = 0; ip < MPASS; ip++) {
+               REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+                             AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+                             DELPT);
+               REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+                             AR_PHY_TX_IQCAL_START_DO_CAL,
+                             AR_PHY_TX_IQCAL_START_DO_CAL);
+
+               if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+                                  AR_PHY_TX_IQCAL_START_DO_CAL,
+                                  0, AH_WAIT_TIMEOUT)) {
+                       ath_dbg(common, ATH_DBG_CALIBRATE,
+                               "Tx IQ Cal not complete.\n");
+                       goto TX_IQ_CAL_FAILED;
+               }
+
+               nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
+                                             AR_PHY_CALIBRATED_GAINS_0);
+                       if (nmeasurement > MAX_MEASUREMENT)
+                               nmeasurement = MAX_MEASUREMENT;
+
+               for (i = 0; i < nchains; i++) {
+                       ath_dbg(common, ATH_DBG_CALIBRATE,
+                               "Doing Tx IQ Cal for chain %d.\n", i);
+                       for (im = 0; im < nmeasurement; im++) {
+                               if (REG_READ(ah, txiqcal_status[i]) &
+                                            AR_PHY_TX_IQCAL_STATUS_FAILED) {
+                                       ath_dbg(common, ATH_DBG_CALIBRATE,
+                                               "Tx IQ Cal failed for chain %d.\n", i);
+                                       goto TX_IQ_CAL_FAILED;
+                               }
+
+                               for (j = 0; j < 3; j++) {
+                                       u8 idx = 2 * j,
+                                          offset = 4 * (3 * im + j);
+
+                                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+                                                     AR_PHY_CHAN_INFO_TAB_S2_READ,
+                                                     0);
+
+                                       /* 32 bits */
+                                       iq_res[idx] = REG_READ(ah,
+                                                       chan_info_tab[i] +
+                                                       offset);
+
+                                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+                                                     AR_PHY_CHAN_INFO_TAB_S2_READ,
+                                                     1);
+
+                                       /* 16 bits */
+                                       iq_res[idx+1] = 0xffff & REG_READ(ah,
+                                                               chan_info_tab[i] +
+                                                               offset);
+
+                                       ath_dbg(common, ATH_DBG_CALIBRATE,
+                                               "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
+                                               idx, iq_res[idx], idx+1, iq_res[idx+1]);
+                               }
+
+                               if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+                                                           coeff.iqc_coeff)) {
+                                       ath_dbg(common, ATH_DBG_CALIBRATE,
+                                               "Failed in calculation of IQ correction.\n");
+                                       goto TX_IQ_CAL_FAILED;
+                               }
+                               coeff.mag_coeff[i][im][ip] =
+                                               coeff.iqc_coeff[0] & 0x7f;
+                               coeff.phs_coeff[i][im][ip] =
+                                               (coeff.iqc_coeff[0] >> 7) & 0x7f;
+
+                               if (coeff.mag_coeff[i][im][ip] > 63)
+                                       coeff.mag_coeff[i][im][ip] -= 128;
+                               if (coeff.phs_coeff[i][im][ip] > 63)
+                                       coeff.phs_coeff[i][im][ip] -= 128;
+
+                       }
+               }
+       }
+
+       ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
+
+       return;
+
+TX_IQ_CAL_FAILED:
+       ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+}
+
 static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
 {
        u8 tx_gain_forced;