diff options
author | Sujith Manoharan <c_manoha@qca.qualcomm.com> | 2014-02-06 23:59:53 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-02-12 15:36:07 -0500 |
commit | 97fe6420c9a362ac9d0749db44b7b6629583813b (patch) | |
tree | b7fd07af7b1436ace4046baece39f277ba7b1987 | |
parent | adddc0d20bf4476380da94bfda8c591c49bb6cde (diff) |
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>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9003_calib.c | 81 |
1 files changed, 59 insertions, 22 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 12310e19275d..327befa06699 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT | 23 | #define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT |
24 | #define MAX_MAG_DELTA 11 | 24 | #define MAX_MAG_DELTA 11 |
25 | #define MAX_PHS_DELTA 10 | 25 | #define MAX_PHS_DELTA 10 |
26 | #define MAXIQCAL 3 | ||
26 | 27 | ||
27 | struct coeff { | 28 | struct coeff { |
28 | int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; | 29 | int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; |
@@ -797,7 +798,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, | |||
797 | if (q_q_coff > 63) | 798 | if (q_q_coff > 63) |
798 | q_q_coff = 63; | 799 | q_q_coff = 63; |
799 | 800 | ||
800 | iqc_coeff[0] = (q_q_coff * 128) + q_i_coff; | 801 | iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); |
801 | 802 | ||
802 | ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", | 803 | ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n", |
803 | chain_idx, iqc_coeff[0]); | 804 | chain_idx, iqc_coeff[0]); |
@@ -828,7 +829,7 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, | |||
828 | if (q_q_coff > 63) | 829 | if (q_q_coff > 63) |
829 | q_q_coff = 63; | 830 | q_q_coff = 63; |
830 | 831 | ||
831 | iqc_coeff[1] = (q_q_coff * 128) + q_i_coff; | 832 | iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); |
832 | 833 | ||
833 | ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", | 834 | ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n", |
834 | chain_idx, iqc_coeff[1]); | 835 | chain_idx, iqc_coeff[1]); |
@@ -991,7 +992,9 @@ static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) | |||
991 | return true; | 992 | return true; |
992 | } | 993 | } |
993 | 994 | ||
994 | static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) | 995 | static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, |
996 | int iqcal_idx, | ||
997 | bool is_reusable) | ||
995 | { | 998 | { |
996 | struct ath_common *common = ath9k_hw_common(ah); | 999 | struct ath_common *common = ath9k_hw_common(ah); |
997 | const u32 txiqcal_status[AR9300_MAX_CHAINS] = { | 1000 | const u32 txiqcal_status[AR9300_MAX_CHAINS] = { |
@@ -1410,7 +1413,7 @@ skip_tx_iqcal: | |||
1410 | } | 1413 | } |
1411 | 1414 | ||
1412 | if (txiqcal_done) | 1415 | if (txiqcal_done) |
1413 | ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); | 1416 | ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable); |
1414 | else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) | 1417 | else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags)) |
1415 | ar9003_hw_tx_iq_cal_reload(ah); | 1418 | ar9003_hw_tx_iq_cal_reload(ah); |
1416 | 1419 | ||
@@ -1456,6 +1459,29 @@ skip_tx_iqcal: | |||
1456 | return true; | 1459 | return true; |
1457 | } | 1460 | } |
1458 | 1461 | ||
1462 | static bool do_ar9003_agc_cal(struct ath_hw *ah) | ||
1463 | { | ||
1464 | struct ath_common *common = ath9k_hw_common(ah); | ||
1465 | bool status; | ||
1466 | |||
1467 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
1468 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | ||
1469 | AR_PHY_AGC_CONTROL_CAL); | ||
1470 | |||
1471 | status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | ||
1472 | AR_PHY_AGC_CONTROL_CAL, | ||
1473 | 0, AH_WAIT_TIMEOUT); | ||
1474 | if (!status) { | ||
1475 | ath_dbg(common, CALIBRATE, | ||
1476 | "offset calibration failed to complete in %d ms," | ||
1477 | "noisy environment?\n", | ||
1478 | AH_WAIT_TIMEOUT / 1000); | ||
1479 | return false; | ||
1480 | } | ||
1481 | |||
1482 | return true; | ||
1483 | } | ||
1484 | |||
1459 | static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, | 1485 | static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, |
1460 | struct ath9k_channel *chan) | 1486 | struct ath9k_channel *chan) |
1461 | { | 1487 | { |
@@ -1464,6 +1490,7 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, | |||
1464 | bool txiqcal_done = false; | 1490 | bool txiqcal_done = false; |
1465 | bool status = true; | 1491 | bool status = true; |
1466 | bool run_agc_cal = false, sep_iq_cal = false; | 1492 | bool run_agc_cal = false, sep_iq_cal = false; |
1493 | int i = 0; | ||
1467 | 1494 | ||
1468 | /* Use chip chainmask only for calibration */ | 1495 | /* Use chip chainmask only for calibration */ |
1469 | ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); | 1496 | ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); |
@@ -1518,27 +1545,37 @@ skip_tx_iqcal: | |||
1518 | if (AR_SREV_9330_11(ah)) | 1545 | if (AR_SREV_9330_11(ah)) |
1519 | ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); | 1546 | ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan)); |
1520 | 1547 | ||
1521 | /* Calibrate the AGC */ | 1548 | /* |
1522 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | 1549 | * For non-AR9550 chips, we just trigger AGC calibration |
1523 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | 1550 | * in the HW, poll for completion and then process |
1524 | AR_PHY_AGC_CONTROL_CAL); | 1551 | * the results. |
1525 | 1552 | * | |
1526 | /* Poll for offset calibration complete */ | 1553 | * For AR955x, we run it multiple times and use |
1527 | status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | 1554 | * median IQ correction. |
1528 | AR_PHY_AGC_CONTROL_CAL, | 1555 | */ |
1529 | 0, AH_WAIT_TIMEOUT); | 1556 | if (!AR_SREV_9550(ah)) { |
1530 | } | 1557 | status = do_ar9003_agc_cal(ah); |
1558 | if (!status) | ||
1559 | return false; | ||
1531 | 1560 | ||
1532 | if (!status) { | 1561 | if (txiqcal_done) |
1533 | ath_dbg(common, CALIBRATE, | 1562 | ar9003_hw_tx_iq_cal_post_proc(ah, 0, false); |
1534 | "offset calibration failed to complete in %d ms; noisy environment?\n", | 1563 | } else { |
1535 | AH_WAIT_TIMEOUT / 1000); | 1564 | if (!txiqcal_done) { |
1536 | return false; | 1565 | status = do_ar9003_agc_cal(ah); |
1566 | if (!status) | ||
1567 | return false; | ||
1568 | } else { | ||
1569 | for (i = 0; i < MAXIQCAL; i++) { | ||
1570 | status = do_ar9003_agc_cal(ah); | ||
1571 | if (!status) | ||
1572 | return false; | ||
1573 | ar9003_hw_tx_iq_cal_post_proc(ah, i, false); | ||
1574 | } | ||
1575 | } | ||
1576 | } | ||
1537 | } | 1577 | } |
1538 | 1578 | ||
1539 | if (txiqcal_done) | ||
1540 | ar9003_hw_tx_iq_cal_post_proc(ah, false); | ||
1541 | |||
1542 | /* Revert chainmask to runtime parameters */ | 1579 | /* Revert chainmask to runtime parameters */ |
1543 | ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); | 1580 | ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); |
1544 | 1581 | ||