aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/ar9003_calib.c
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vasanth@atheros.com>2010-12-15 10:30:50 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-16 15:22:30 -0500
commit0b2084bc578128be866d6fc9926ed887c3432bb1 (patch)
tree8c1c7d20e720078dd160e6f70492606423203cfb /drivers/net/wireless/ath/ath9k/ar9003_calib.c
parent895ad7eb21ed228444169dbbff44f3dccfc7e006 (diff)
ath9k_hw: Tx IQ cal changes for AR9003
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>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/ar9003_calib.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c212
1 files changed, 108 insertions, 104 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 75a1c6e5195..4a4cd88429c 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -608,107 +608,6 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
608 return true; 608 return true;
609} 609}
610 610
611static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
612{
613 struct ath_common *common = ath9k_hw_common(ah);
614 static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
615 AR_PHY_TX_IQCAL_STATUS_B0,
616 AR_PHY_TX_IQCAL_STATUS_B1,
617 AR_PHY_TX_IQCAL_STATUS_B2,
618 };
619 static const u_int32_t chan_info_tab[] = {
620 AR_PHY_CHAN_INFO_TAB_0,
621 AR_PHY_CHAN_INFO_TAB_1,
622 AR_PHY_CHAN_INFO_TAB_2,
623 };
624 u32 tx_corr_coeff[AR9300_MAX_CHAINS];
625 s32 iq_res[6];
626 s32 iqc_coeff[2];
627 s32 i, j;
628 u32 num_chains = 0;
629
630 tx_corr_coeff[0] = AR_PHY_TX_IQCAL_CORR_COEFF_B0(0);
631 tx_corr_coeff[1] = AR_PHY_TX_IQCAL_CORR_COEFF_B1(0);
632 tx_corr_coeff[2] = AR_PHY_TX_IQCAL_CORR_COEFF_B2(0);
633
634 for (i = 0; i < AR9300_MAX_CHAINS; i++) {
635 if (ah->txchainmask & (1 << i))
636 num_chains++;
637 }
638
639 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
640 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
641 DELPT);
642 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
643 AR_PHY_TX_IQCAL_START_DO_CAL,
644 AR_PHY_TX_IQCAL_START_DO_CAL);
645
646 if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
647 AR_PHY_TX_IQCAL_START_DO_CAL,
648 0, AH_WAIT_TIMEOUT)) {
649 ath_dbg(common, ATH_DBG_CALIBRATE,
650 "Tx IQ Cal not complete.\n");
651 goto TX_IQ_CAL_FAILED;
652 }
653
654 for (i = 0; i < num_chains; i++) {
655 ath_dbg(common, ATH_DBG_CALIBRATE,
656 "Doing Tx IQ Cal for chain %d.\n", i);
657
658 if (REG_READ(ah, txiqcal_status[i]) &
659 AR_PHY_TX_IQCAL_STATUS_FAILED) {
660 ath_dbg(common, ATH_DBG_CALIBRATE,
661 "Tx IQ Cal failed for chain %d.\n", i);
662 goto TX_IQ_CAL_FAILED;
663 }
664
665 for (j = 0; j < 3; j++) {
666 u_int8_t idx = 2 * j,
667 offset = 4 * j;
668
669 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
670 AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
671
672 /* 32 bits */
673 iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset);
674
675 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
676 AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
677
678 /* 16 bits */
679 iq_res[idx+1] = 0xffff & REG_READ(ah,
680 chan_info_tab[i] +
681 offset);
682
683 ath_dbg(common, ATH_DBG_CALIBRATE,
684 "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
685 idx, iq_res[idx], idx+1, iq_res[idx+1]);
686 }
687
688 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) {
689 ath_dbg(common, ATH_DBG_CALIBRATE,
690 "Failed in calculation of IQ correction.\n");
691 goto TX_IQ_CAL_FAILED;
692 }
693
694 ath_dbg(common, ATH_DBG_CALIBRATE,
695 "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n",
696 iqc_coeff[0], iqc_coeff[1]);
697
698 REG_RMW_FIELD(ah, tx_corr_coeff[i],
699 AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
700 iqc_coeff[0]);
701 }
702
703 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
704 AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
705
706 return;
707
708TX_IQ_CAL_FAILED:
709 ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
710}
711
712static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) 611static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
713{ 612{
714 int diff[MPASS]; 613 int diff[MPASS];
@@ -717,9 +616,9 @@ static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
717 diff[1] = abs(mp_coeff[1] - mp_coeff[2]); 616 diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
718 diff[2] = abs(mp_coeff[2] - mp_coeff[0]); 617 diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
719 618
720 if (diff[0] > MAX_MEASUREMENT && 619 if (diff[0] > MAX_DIFFERENCE &&
721 diff[1] > MAX_MEASUREMENT && 620 diff[1] > MAX_DIFFERENCE &&
722 diff[2] > MAX_MEASUREMENT) 621 diff[2] > MAX_DIFFERENCE)
723 return false; 622 return false;
724 623
725 if (diff[0] <= diff[1] && diff[0] <= diff[2]) 624 if (diff[0] <= diff[1] && diff[0] <= diff[2])
@@ -817,6 +716,111 @@ disable_txiqcal:
817 ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); 716 ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
818} 717}
819 718
719static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
720{
721 struct ath_common *common = ath9k_hw_common(ah);
722 static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
723 AR_PHY_TX_IQCAL_STATUS_B0,
724 AR_PHY_TX_IQCAL_STATUS_B1,
725 AR_PHY_TX_IQCAL_STATUS_B2,
726 };
727 static const u32 chan_info_tab[] = {
728 AR_PHY_CHAN_INFO_TAB_0,
729 AR_PHY_CHAN_INFO_TAB_1,
730 AR_PHY_CHAN_INFO_TAB_2,
731 };
732 struct coeff coeff;
733 s32 iq_res[6];
734 s32 i, j, ip, im, nmeasurement;
735 u8 nchains = get_streams(common->tx_chainmask);
736
737 for (ip = 0; ip < MPASS; ip++) {
738 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
739 AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
740 DELPT);
741 REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
742 AR_PHY_TX_IQCAL_START_DO_CAL,
743 AR_PHY_TX_IQCAL_START_DO_CAL);
744
745 if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
746 AR_PHY_TX_IQCAL_START_DO_CAL,
747 0, AH_WAIT_TIMEOUT)) {
748 ath_dbg(common, ATH_DBG_CALIBRATE,
749 "Tx IQ Cal not complete.\n");
750 goto TX_IQ_CAL_FAILED;
751 }
752
753 nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
754 AR_PHY_CALIBRATED_GAINS_0);
755 if (nmeasurement > MAX_MEASUREMENT)
756 nmeasurement = MAX_MEASUREMENT;
757
758 for (i = 0; i < nchains; i++) {
759 ath_dbg(common, ATH_DBG_CALIBRATE,
760 "Doing Tx IQ Cal for chain %d.\n", i);
761 for (im = 0; im < nmeasurement; im++) {
762 if (REG_READ(ah, txiqcal_status[i]) &
763 AR_PHY_TX_IQCAL_STATUS_FAILED) {
764 ath_dbg(common, ATH_DBG_CALIBRATE,
765 "Tx IQ Cal failed for chain %d.\n", i);
766 goto TX_IQ_CAL_FAILED;
767 }
768
769 for (j = 0; j < 3; j++) {
770 u8 idx = 2 * j,
771 offset = 4 * (3 * im + j);
772
773 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
774 AR_PHY_CHAN_INFO_TAB_S2_READ,
775 0);
776
777 /* 32 bits */
778 iq_res[idx] = REG_READ(ah,
779 chan_info_tab[i] +
780 offset);
781
782 REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
783 AR_PHY_CHAN_INFO_TAB_S2_READ,
784 1);
785
786 /* 16 bits */
787 iq_res[idx+1] = 0xffff & REG_READ(ah,
788 chan_info_tab[i] +
789 offset);
790
791 ath_dbg(common, ATH_DBG_CALIBRATE,
792 "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
793 idx, iq_res[idx], idx+1, iq_res[idx+1]);
794 }
795
796 if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
797 coeff.iqc_coeff)) {
798 ath_dbg(common, ATH_DBG_CALIBRATE,
799 "Failed in calculation of IQ correction.\n");
800 goto TX_IQ_CAL_FAILED;
801 }
802 coeff.mag_coeff[i][im][ip] =
803 coeff.iqc_coeff[0] & 0x7f;
804 coeff.phs_coeff[i][im][ip] =
805 (coeff.iqc_coeff[0] >> 7) & 0x7f;
806
807 if (coeff.mag_coeff[i][im][ip] > 63)
808 coeff.mag_coeff[i][im][ip] -= 128;
809 if (coeff.phs_coeff[i][im][ip] > 63)
810 coeff.phs_coeff[i][im][ip] -= 128;
811
812 }
813 }
814 }
815
816 ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
817
818 return;
819
820TX_IQ_CAL_FAILED:
821 ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
822}
823
820static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) 824static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
821{ 825{
822 u8 tx_gain_forced; 826 u8 tx_gain_forced;