ath9k: Modify IQ calibration for AR955x

IQ calibration post-processing for AR955x is different
from other chips - instead of just doing it as part
of AGC calibration once, it is triggered 3 times and
a median is determined. This patch adds initial support
for changing the calibration behavior for AR955x.

Also, to simplify things, a helper routine to issue/poll
AGC calibration is used.

For non-AR955x chips, the iqcal_idx (which will be used
in subsequent patches) is set to zero.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Sujith Manoharan 2014-02-07 10:29:53 +05:30 committed by John W. Linville
parent adddc0d20b
commit 97fe6420c9

View file

@ -23,6 +23,7 @@
#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT
#define MAX_MAG_DELTA 11
#define MAX_PHS_DELTA 10
#define MAXIQCAL 3
struct coeff {
int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
@ -797,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[0]);
@ -828,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
if (q_q_coff > 63)
q_q_coff = 63;
iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
chain_idx, iqc_coeff[1]);
@ -991,7 +992,9 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
return true;
}
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
int iqcal_idx,
bool is_reusable)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
@ -1410,7 +1413,7 @@ skip_tx_iqcal:
}
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
ar9003_hw_tx_iq_cal_reload(ah);
@ -1456,6 +1459,29 @@ skip_tx_iqcal:
return true;
}
static bool do_ar9003_agc_cal(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
bool status;
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL);
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (!status) {
ath_dbg(common, CALIBRATE,
"offset calibration failed to complete in %d ms,"
"noisy environment?\n",
AH_WAIT_TIMEOUT / 1000);
return false;
}
return true;
}
static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -1464,6 +1490,7 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
bool txiqcal_done = false;
bool status = true;
bool run_agc_cal = false, sep_iq_cal = false;
int i = 0;
/* Use chip chainmask only for calibration */
ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
@ -1518,27 +1545,37 @@ skip_tx_iqcal:
if (AR_SREV_9330_11(ah))
ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
AR_PHY_AGC_CONTROL_CAL);
/*
* For non-AR9550 chips, we just trigger AGC calibration
* in the HW, poll for completion and then process
* the results.
*
* For AR955x, we run it multiple times and use
* median IQ correction.
*/
if (!AR_SREV_9550(ah)) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
/* Poll for offset calibration complete */
status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
AR_PHY_AGC_CONTROL_CAL,
0, AH_WAIT_TIMEOUT);
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
} else {
if (!txiqcal_done) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
} else {
for (i = 0; i < MAXIQCAL; i++) {
status = do_ar9003_agc_cal(ah);
if (!status)
return false;
ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
}
}
}
}
if (!status) {
ath_dbg(common, CALIBRATE,
"offset calibration failed to complete in %d ms; noisy environment?\n",
AH_WAIT_TIMEOUT / 1000);
return false;
}
if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah, false);
/* Revert chainmask to runtime parameters */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);