1795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez/*
25b68138e5659cbfd5df2879d17f9ba0b66477fecSujith Manoharan * Copyright (c) 2010-2011 Atheros Communications Inc.
3795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez *
4795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any
5795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above
6795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * copyright notice and this permission notice appear in all copies.
7795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez *
8795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez */
16795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
17795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez#include "hw.h"
18795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez#include "hw-ops.h"
19795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez#include "ar9003_phy.h"
20324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan#include "ar9003_rtt.h"
213ebfcdc43ae261e58e5b9b381ae1f278cda068e3Mohammed Shafi Shajakhan#include "ar9003_mci.h"
22795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
235f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan#define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT
243782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan#define MAX_MAG_DELTA	11
253782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan#define MAX_PHS_DELTA	10
26858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
27858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajanstruct coeff {
283782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
293782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
30858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	int iqc_coeff[2];
31858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan};
32858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
336497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkauenum ar9003_cal_types {
346497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau	IQ_MISMATCH_CAL = BIT(0),
356497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau	TEMP_COMP_CAL = BIT(1),
366497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau};
376497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau
38795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguezstatic void ar9003_hw_setup_calibration(struct ath_hw *ah,
39795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez					struct ath9k_cal_list *currCal)
40795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez{
414b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
424b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez
434b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	/* Select calibration to run */
444b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	switch (currCal->calData->calType) {
454b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	case IQ_MISMATCH_CAL:
464b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		/*
474b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		 * Start calibration with
484b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
494b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		 */
504b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		REG_RMW_FIELD(ah, AR_PHY_TIMING4,
514b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez			      AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
524b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		currCal->calData->calCountMax);
534b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
544b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez
55d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
56226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"starting IQ Mismatch Calibration\n");
574b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez
584b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		/* Kick-off cal */
594b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
604b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		break;
614b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	case TEMP_COMP_CAL:
624b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
634b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez			      AR_PHY_65NM_CH0_THERM_LOCAL, 1);
644b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
654b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez			      AR_PHY_65NM_CH0_THERM_START, 1);
664b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez
67d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
68226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"starting Temperature Compensation Calibration\n");
694b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez		break;
704b01931e3a3ca5ec49604e2b279b8b9dd42fbe4cLuis R. Rodriguez	}
71795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez}
72795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
73df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez/*
74df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez * Generic calibration routine.
75df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez * Recalibrate the lower PHY chips to account for temperature/environment
76df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez * changes.
77df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez */
78df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguezstatic bool ar9003_hw_per_calibration(struct ath_hw *ah,
79df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				      struct ath9k_channel *ichan,
80df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				      u8 rxchainmask,
81df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				      struct ath9k_cal_list *currCal)
82df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez{
8320bd2a0952d01ba82a99b3f22d46e3832c255529Felix Fietkau	struct ath9k_hw_cal_data *caldata = ah->caldata;
84df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* Cal is assumed not done until explicitly set below */
85df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	bool iscaldone = false;
86df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
87df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* Calibration in progress. */
88df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (currCal->calState == CAL_RUNNING) {
89df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		/* Check to see if it has finished. */
90df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
91df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			/*
92df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			* Accumulate cal measures for active chains
93df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			*/
94df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			currCal->calData->calCollect(ah);
95df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			ah->cal_samples++;
96df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
97df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			if (ah->cal_samples >=
98df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			    currCal->calData->calNumSamples) {
99df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				unsigned int i, numChains = 0;
100df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				for (i = 0; i < AR9300_MAX_CHAINS; i++) {
101df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez					if (rxchainmask & (1 << i))
102df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez						numChains++;
103df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				}
104df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
105df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				/*
106df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				* Process accumulated data
107df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				*/
108df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				currCal->calData->calPostProc(ah, numChains);
109df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
110df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				/* Calibration has finished. */
11120bd2a0952d01ba82a99b3f22d46e3832c255529Felix Fietkau				caldata->CalValid |= currCal->calData->calType;
112df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				currCal->calState = CAL_DONE;
113df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				iscaldone = true;
114df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			} else {
115df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			/*
116df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			 * Set-up collection of another sub-sample until we
117df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			 * get desired number
118df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			 */
119df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			ar9003_hw_setup_calibration(ah, currCal);
120df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			}
121df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		}
12220bd2a0952d01ba82a99b3f22d46e3832c255529Felix Fietkau	} else if (!(caldata->CalValid & currCal->calData->calType)) {
123df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		/* If current cal is marked invalid in channel, kick it off */
124df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		ath9k_hw_reset_calibration(ah, currCal);
125df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
126df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
127df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return iscaldone;
128df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez}
129df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
130795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguezstatic bool ar9003_hw_calibrate(struct ath_hw *ah,
131795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez				struct ath9k_channel *chan,
132795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez				u8 rxchainmask,
133795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez				bool longcal)
134795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez{
135df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	bool iscaldone = true;
136df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	struct ath9k_cal_list *currCal = ah->cal_list_curr;
137df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
138df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/*
139df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 * For given calibration:
140df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 * 1. Call generic cal routine
141df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 * 2. When this cal is done (isCalDone) if we have more cals waiting
142df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 *    (eg after reset), mask this to upper layers by not propagating
143df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 *    isCalDone if it is set to TRUE.
144df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 *    Instead, change isCalDone to FALSE and setup the waiting cal(s)
145df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 *    to be run.
146df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 */
147df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (currCal &&
148df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    (currCal->calState == CAL_RUNNING ||
149df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	     currCal->calState == CAL_WAITING)) {
150df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		iscaldone = ar9003_hw_per_calibration(ah, chan,
151df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez						      rxchainmask, currCal);
152df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		if (iscaldone) {
153df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			ah->cal_list_curr = currCal = currCal->calNext;
154df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
155df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			if (currCal->calState == CAL_WAITING) {
156df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				iscaldone = false;
157df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				ath9k_hw_reset_calibration(ah, currCal);
158df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			}
159df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		}
160df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
161795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
162df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* Do NF cal only at longer intervals */
163df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (longcal) {
164df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		/*
1659369746050e838c57e357f0caa552386ad65a82dFelix Fietkau		 * Get the value from the previous NF cal and update
1669369746050e838c57e357f0caa552386ad65a82dFelix Fietkau		 * history buffer.
1679369746050e838c57e357f0caa552386ad65a82dFelix Fietkau		 */
1689369746050e838c57e357f0caa552386ad65a82dFelix Fietkau		ath9k_hw_getnf(ah, chan);
1699369746050e838c57e357f0caa552386ad65a82dFelix Fietkau
1709369746050e838c57e357f0caa552386ad65a82dFelix Fietkau		/*
171df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 * Load the NF from history buffer of the current channel.
172df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 * NF is slow time-variant, so it is OK to use a historical
173df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 * value.
174df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 */
175df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		ath9k_hw_loadnf(ah, ah->curchan);
176df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
177df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		/* start NF calibration, without updating BB NF register */
17800c86590e36bd42574821b43b5124d75f30df9ddFelix Fietkau		ath9k_hw_start_nfcal(ah, false);
179df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
180df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
181df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return iscaldone;
182795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez}
183795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
184590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguezstatic void ar9003_hw_iqcal_collect(struct ath_hw *ah)
185590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez{
186590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	int i;
187590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
188590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	/* Accumulate IQ cal measures for active chains */
189590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
1905d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan		if (ah->txchainmask & BIT(i)) {
1915d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan			ah->totalPowerMeasI[i] +=
1925d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
1935d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan			ah->totalPowerMeasQ[i] +=
1945d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
1955d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan			ah->totalIqCorrMeas[i] +=
1965d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
197d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
1985d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
1995d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				ah->cal_samples, i, ah->totalPowerMeasI[i],
2005d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				ah->totalPowerMeasQ[i],
2015d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan				ah->totalIqCorrMeas[i]);
2025d48ae78cf81b4006ee1b7690b850db84820dc14Vasanthakumar Thiagarajan		}
203590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	}
204590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez}
205590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
206590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguezstatic void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
207590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez{
208590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
209590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	u32 powerMeasQ, powerMeasI, iqCorrMeas;
210590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	u32 qCoffDenom, iCoffDenom;
211590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	int32_t qCoff, iCoff;
212590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	int iqCorrNeg, i;
21307b2fa5a2368accf0fe6cb16e7eca6d1150554edJoe Perches	static const u_int32_t offset_array[3] = {
214590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		AR_PHY_RX_IQCAL_CORR_B0,
215590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		AR_PHY_RX_IQCAL_CORR_B1,
216590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		AR_PHY_RX_IQCAL_CORR_B2,
217590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	};
218590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
219590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	for (i = 0; i < numChains; i++) {
220590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		powerMeasI = ah->totalPowerMeasI[i];
221590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		powerMeasQ = ah->totalPowerMeasQ[i];
222590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		iqCorrMeas = ah->totalIqCorrMeas[i];
223590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
224d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
225d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			"Starting IQ Cal and Correction for Chain %d\n", i);
226590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
227d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
228a9b2ce03b2a071420c10f3873869480fbb7f4493Nikolay Martynov			"Original: Chn %d iq_corr_meas = 0x%08x\n",
229226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			i, ah->totalIqCorrMeas[i]);
230590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
231590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		iqCorrNeg = 0;
232590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
233590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		if (iqCorrMeas > 0x80000000) {
234590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
235590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			iqCorrNeg = 1;
236590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		}
237590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
238d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",
239d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			i, powerMeasI);
240d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",
241d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			i, powerMeasQ);
242d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);
243590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
244590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
245590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		qCoffDenom = powerMeasQ / 64;
246590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
247590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
248590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			iCoff = iqCorrMeas / iCoffDenom;
249590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			qCoff = powerMeasI / qCoffDenom - 64;
250d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",
251d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				i, iCoff);
252d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",
253d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				i, qCoff);
254590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
255590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			/* Force bounds on iCoff */
256590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			if (iCoff >= 63)
257590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				iCoff = 63;
258590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			else if (iCoff <= -63)
259590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				iCoff = -63;
260590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
261590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			/* Negate iCoff if iqCorrNeg == 0 */
262590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			if (iqCorrNeg == 0x0)
263590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				iCoff = -iCoff;
264590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
265590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			/* Force bounds on qCoff */
266590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			if (qCoff >= 63)
267590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				qCoff = 63;
268590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			else if (qCoff <= -63)
269590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				qCoff = -63;
270590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
271590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			iCoff = iCoff & 0x7f;
272590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			qCoff = qCoff & 0x7f;
273590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
274d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
275226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
276226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				i, iCoff, qCoff);
277d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
278226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"Register offset (0x%04x) before update = 0x%x\n",
279226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				offset_array[i],
280226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				REG_READ(ah, offset_array[i]));
281590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
282590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			REG_RMW_FIELD(ah, offset_array[i],
283590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
284590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				      iCoff);
285590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez			REG_RMW_FIELD(ah, offset_array[i],
286590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
287590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez				      qCoff);
288d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
289226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
290226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				offset_array[i],
291226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
292226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				REG_READ(ah, offset_array[i]));
293d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
294226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
295226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				offset_array[i],
296226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
297226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				REG_READ(ah, offset_array[i]));
298226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches
299d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
300226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches				"IQ Cal and Correction done for Chain %d\n", i);
301590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		}
302590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	}
303590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
304590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
305590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez		    AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
306d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE,
307226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		"IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
308226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
309226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
310226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
311590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez}
312590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
313590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguezstatic const struct ath9k_percal_data iq_cal_single_sample = {
314590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	IQ_MISMATCH_CAL,
315590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	MIN_CAL_SAMPLES,
316590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	PER_MAX_LOG_COUNT,
317590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	ar9003_hw_iqcal_collect,
318590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	ar9003_hw_iqcalibrate
319590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez};
320590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez
321795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguezstatic void ar9003_hw_init_cal_settings(struct ath_hw *ah)
322795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez{
323590b7d2f10f4552e5b7570c84dc565d3cb7825c9Luis R. Rodriguez	ah->iq_caldata.calData = &iq_cal_single_sample;
324795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez}
325795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
326df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez/*
327df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez * solve 4x4 linear equation used in loopback iq cal.
328df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez */
329df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguezstatic bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
330df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 sin_2phi_1,
331df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 cos_2phi_1,
332df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 sin_2phi_2,
333df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 cos_2phi_2,
334df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 mag_a0_d0,
335df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 phs_a0_d0,
336df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 mag_a1_d0,
337df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 phs_a1_d0,
338df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 solved_eq[])
339df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez{
340df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 f1 = cos_2phi_1 - cos_2phi_2,
341df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    f3 = sin_2phi_1 - sin_2phi_2,
342df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    f2;
343df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 mag_tx, phs_tx, mag_rx, phs_rx;
344df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	const s32 result_shift = 1 << 15;
345df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
346df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
347df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	f2 = (f1 * f1 + f3 * f3) / result_shift;
348df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
349df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (!f2) {
350d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "Divide by 0\n");
351df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
352df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
353df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
354df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* mag mismatch, tx */
355df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
356df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* phs mismatch, tx */
357df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
358df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
359df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_tx = (mag_tx / f2);
360df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_tx = (phs_tx / f2);
361df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
362df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* mag mismatch, rx */
363df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
364df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 result_shift;
365df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* phs mismatch, rx */
366df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
367df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		 result_shift;
368df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
369df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	solved_eq[0] = mag_tx;
370df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	solved_eq[1] = phs_tx;
371df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	solved_eq[2] = mag_rx;
372df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	solved_eq[3] = phs_rx;
373df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
374df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return true;
375df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez}
376df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
377df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguezstatic s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im)
37877d6d39a77939e5ed7e2ec72a1c1dce828ee582eLuis R. Rodriguez{
379df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 abs_i = abs(in_re),
380df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    abs_q = abs(in_im),
381df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    max_abs, min_abs;
382df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
383df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (abs_i > abs_q) {
384df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		max_abs = abs_i;
385df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		min_abs = abs_q;
386df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	} else {
387df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		max_abs = abs_q;
388df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		min_abs = abs_i;
389df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
390df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
391df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
392df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez}
393df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
394df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez#define DELPT 32
395df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
396df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguezstatic bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
397df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 chain_idx,
398df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   const s32 iq_res[],
399df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez				   s32 iqc_coeff[])
400df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez{
401df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
402df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
403df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
404df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
405df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
406df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
407df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    sin_2phi_1, cos_2phi_1,
408df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    sin_2phi_2, cos_2phi_2;
409df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 mag_tx, phs_tx, mag_rx, phs_rx;
410df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
411df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    q_q_coff, q_i_coff;
412df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	const s32 res_scale = 1 << 15;
413df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	const s32 delpt_shift = 1 << 8;
414df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	s32 mag1, mag2;
415df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
416df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
417df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
418df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
419df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
420df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
421df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_m_q2_a0_d0 > 0x800)
422df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
423df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
424df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_p_q2_a0_d0 > 0x800)
425df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
426df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
427df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (iq_corr_a0_d0 > 0x800)
428df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
429df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
430df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
431df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
432df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
433df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
434df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_m_q2_a0_d1 > 0x800)
435df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
436df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
437df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_p_q2_a0_d1 > 0x800)
438df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
439df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
440df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (iq_corr_a0_d1 > 0x800)
441df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
442df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
443df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
444df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
445df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iq_corr_a1_d0 = iq_res[4] & 0xfff;
446df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
447df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_m_q2_a1_d0 > 0x800)
448df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
449df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
450df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_p_q2_a1_d0 > 0x800)
451df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
452df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
453df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (iq_corr_a1_d0 > 0x800)
454df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
455df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
456df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
457df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
458df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
459df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
460df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_m_q2_a1_d1 > 0x800)
461df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
462df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
463df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (i2_p_q2_a1_d1 > 0x800)
464df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
465df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
466df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (iq_corr_a1_d1 > 0x800)
467df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
468df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
469df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
470df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	    (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
471d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
472226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"Divide by 0:\n"
473226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"a0_d0=%d\n"
474226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"a0_d1=%d\n"
475226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"a2_d0=%d\n"
476226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"a1_d1=%d\n",
477226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			i2_p_q2_a0_d0, i2_p_q2_a0_d1,
478226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			i2_p_q2_a1_d0, i2_p_q2_a1_d1);
479df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
480df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
481df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
482df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
483df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
484df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
485df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
486df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
487df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
488df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
489df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
490df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
491df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
492df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
493df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
494df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* w/o analog phase shift */
495df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
496df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* w/o analog phase shift */
497df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
498df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* w/  analog phase shift */
499df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
500df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* w/  analog phase shift */
501df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
502df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
503df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/*
504df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 * force sin^2 + cos^2 = 1;
505df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 * find magnitude by approximation
506df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	 */
507df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
508df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
509df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
510df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if ((mag1 == 0) || (mag2 == 0)) {
511d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n",
512226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			mag1, mag2);
513df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
514df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
515df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
516df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* normalization sin and cos by mag */
517df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
518df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
519df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
520df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
521df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
522df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* calculate IQ mismatch */
523df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (!ar9003_hw_solve_iq_cal(ah,
524df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			     sin_2phi_1, cos_2phi_1,
525df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			     sin_2phi_2, cos_2phi_2,
526df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			     mag_a0_d0, phs_a0_d0,
527df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			     mag_a1_d0,
528df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			     phs_a1_d0, solved_eq)) {
529d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
530d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			"Call to ar9003_hw_solve_iq_cal() failed\n");
531df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
532df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
533df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
534df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_tx = solved_eq[0];
535df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_tx = solved_eq[1];
536df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_rx = solved_eq[2];
537df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_rx = solved_eq[3];
538df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
539d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE,
540226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		"chain %d: mag mismatch=%d phase mismatch=%d\n",
541226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		chain_idx, mag_tx/res_scale, phs_tx/res_scale);
542df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
543df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (res_scale == mag_tx) {
544d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
545226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"Divide by 0: mag_tx=%d, res_scale=%d\n",
546226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			mag_tx, res_scale);
547df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
548df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
549df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
550df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* calculate and quantize Tx IQ correction factor */
551df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
552df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_corr_tx = -phs_tx;
553df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
554df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	q_q_coff = (mag_corr_tx * 128 / res_scale);
555df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	q_i_coff = (phs_corr_tx * 256 / res_scale);
556df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
557d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d  phase corr=%d\n",
558226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		chain_idx, q_q_coff, q_i_coff);
559df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
560df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_i_coff < -63)
561df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_i_coff = -63;
562df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_i_coff > 63)
563df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_i_coff = 63;
564df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_q_coff < -63)
565df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_q_coff = -63;
566df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_q_coff > 63)
567df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_q_coff = 63;
568df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
569df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
570df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
571d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
572226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		chain_idx, iqc_coeff[0]);
573df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
574df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (-mag_rx == res_scale) {
575d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
576226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			"Divide by 0: mag_rx=%d, res_scale=%d\n",
577226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches			mag_rx, res_scale);
578df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
579df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
580df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
581df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* calculate and quantize Rx IQ correction factors */
582df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
583df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	phs_corr_rx = -phs_rx;
584df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
585df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	q_q_coff = (mag_corr_rx * 128 / res_scale);
586df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	q_i_coff = (phs_corr_rx * 256 / res_scale);
587df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
588d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE, "rx chain %d: mag corr=%d  phase corr=%d\n",
589226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		chain_idx, q_q_coff, q_i_coff);
590df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
591df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_i_coff < -63)
592df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_i_coff = -63;
593df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_i_coff > 63)
594df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_i_coff = 63;
595df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_q_coff < -63)
596df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_q_coff = -63;
597df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (q_q_coff > 63)
598df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		q_q_coff = 63;
599df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
600df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
601df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
602d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
603226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches		chain_idx, iqc_coeff[1]);
604df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
605df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return true;
606df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez}
607df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
6083782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharanstatic void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
6093782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				     int max_delta)
610858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan{
6113782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	int mp_max = -64, max_idx = 0;
6123782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	int mp_min = 63, min_idx = 0;
613e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	int mp_avg = 0, i, outlier_idx = 0, mp_count = 0;
6143782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan
6153782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	/* find min/max mismatch across all calibrated gains */
6163782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	for (i = 0; i < nmeasurement; i++) {
6173782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		if (mp_coeff[i] > mp_max) {
6183782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			mp_max = mp_coeff[i];
6193782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			max_idx = i;
6203782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		} else if (mp_coeff[i] < mp_min) {
6213782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			mp_min = mp_coeff[i];
6223782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			min_idx = i;
6233782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		}
6243782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	}
625858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
6263782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	/* find average (exclude max abs value) */
6273782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	for (i = 0; i < nmeasurement; i++) {
6283782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		if ((abs(mp_coeff[i]) < abs(mp_max)) ||
629e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan		    (abs(mp_coeff[i]) < abs(mp_min))) {
6303782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			mp_avg += mp_coeff[i];
631e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan			mp_count++;
632e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan		}
6333782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	}
634e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan
635e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	/*
636e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	 * finding mean magnitude/phase if possible, otherwise
637e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	 * just use the last value as the mean
638e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	 */
639e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	if (mp_count)
640e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan		mp_avg /= mp_count;
641e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan	else
642e948b99d6f38b726ad1c8f99a2672b792756b549Rajkumar Manoharan		mp_avg = mp_coeff[nmeasurement - 1];
643858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
6443782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	/* detect outlier */
6453782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	if (abs(mp_max - mp_min) > max_delta) {
6463782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
6473782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			outlier_idx = max_idx;
6483782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		else
6493782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			outlier_idx = min_idx;
650e9c10469cf3c71bc1c6b0f01319161e277d6ac9bRajkumar Manoharan
651e9c10469cf3c71bc1c6b0f01319161e277d6ac9bRajkumar Manoharan		mp_coeff[outlier_idx] = mp_avg;
6523782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	}
653858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan}
654858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
655858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajanstatic void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
656858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						 u8 num_chains,
65734013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan						 struct coeff *coeff,
65834013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan						 bool is_reusable)
659858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan{
660858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	int i, im, nmeasurement;
661858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
6625f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	struct ath9k_hw_cal_data *caldata = ah->caldata;
663858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
664858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
665858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
666858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
667858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
668858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		if (!AR_SREV_9485(ah)) {
669858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			tx_corr_coeff[i * 2][1] =
670858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			tx_corr_coeff[(i * 2) + 1][1] =
671858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
672858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
673858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			tx_corr_coeff[i * 2][2] =
674858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			tx_corr_coeff[(i * 2) + 1][2] =
675858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
676858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		}
677858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	}
678858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
679858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	/* Load the average of 2 passes */
680858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	for (i = 0; i < num_chains; i++) {
6813782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		nmeasurement = REG_READ_FIELD(ah,
6823782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				AR_PHY_TX_IQCAL_STATUS_B0,
6833782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				AR_PHY_CALIBRATED_GAINS_0);
684858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
685858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		if (nmeasurement > MAX_MEASUREMENT)
686858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			nmeasurement = MAX_MEASUREMENT;
687858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
6883782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		/* detect outlier only if nmeasurement > 1 */
6893782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		if (nmeasurement > 1) {
6903782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			/* Detect magnitude outlier */
6913782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			ar9003_hw_detect_outlier(coeff->mag_coeff[i],
6923782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan					nmeasurement, MAX_MAG_DELTA);
693858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
6943782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			/* Detect phase outlier */
6953782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			ar9003_hw_detect_outlier(coeff->phs_coeff[i],
6963782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan					nmeasurement, MAX_PHS_DELTA);
6973782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		}
698858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
6993782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		for (im = 0; im < nmeasurement; im++) {
7003782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan
7013782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
7023782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				((coeff->phs_coeff[i][im] & 0x7f) << 7);
703858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
704858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			if ((im % 2) == 0)
705858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
706858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
707858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					coeff->iqc_coeff[0]);
708858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			else
709858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
710858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
711858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					coeff->iqc_coeff[0]);
7125f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
7135f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			if (caldata)
7145f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				caldata->tx_corr_coeff[im][i] =
7155f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan					coeff->iqc_coeff[0];
716858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		}
7175f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		if (caldata)
7185f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			caldata->num_measures[i] = nmeasurement;
719858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	}
720858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
721858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
722858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
723858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
724858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
72534013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan
7265f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	if (caldata)
72734013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan		caldata->done_txiqcal_once = is_reusable;
728858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
729858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	return;
730858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan}
731858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7323782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharanstatic bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
7330b2084bc578128be866d6fc9926ed887c3432bb1Vasanthakumar Thiagarajan{
7340b2084bc578128be866d6fc9926ed887c3432bb1Vasanthakumar Thiagarajan	struct ath_common *common = ath9k_hw_common(ah);
735858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	u8 tx_gain_forced;
736858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
737858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
738858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan					AR_PHY_TXGAIN_FORCE);
739858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	if (tx_gain_forced)
740858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
741858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			      AR_PHY_TXGAIN_FORCE, 0);
742858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7433782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
7443782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		      AR_PHY_TX_IQCAL_START_DO_CAL, 1);
7453782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan
7463782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
7473782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			AR_PHY_TX_IQCAL_START_DO_CAL, 0,
7483782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			AH_WAIT_TIMEOUT)) {
749d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n");
7503782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		return false;
7513782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	}
7523782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	return true;
753858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan}
754858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
75534013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharanstatic void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable)
756858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan{
757858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	struct ath_common *common = ath9k_hw_common(ah);
758858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
7593782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		AR_PHY_TX_IQCAL_STATUS_B0,
760858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		AR_PHY_TX_IQCAL_STATUS_B1,
761858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		AR_PHY_TX_IQCAL_STATUS_B2,
762858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	};
763858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	const u_int32_t chan_info_tab[] = {
764858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		AR_PHY_CHAN_INFO_TAB_0,
765858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		AR_PHY_CHAN_INFO_TAB_1,
766858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		AR_PHY_CHAN_INFO_TAB_2,
767858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	};
768858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	struct coeff coeff;
769858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	s32 iq_res[6];
770858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	u8 num_chains = 0;
7713782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	int i, im, j;
772858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	int nmeasurement;
773858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
774858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
775858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		if (ah->txchainmask & (1 << i))
776858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan			num_chains++;
777858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	}
778858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7793782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	for (i = 0; i < num_chains; i++) {
7803782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		nmeasurement = REG_READ_FIELD(ah,
7813782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				AR_PHY_TX_IQCAL_STATUS_B0,
7823782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				AR_PHY_CALIBRATED_GAINS_0);
7833782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		if (nmeasurement > MAX_MEASUREMENT)
7843782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			nmeasurement = MAX_MEASUREMENT;
785858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7863782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		for (im = 0; im < nmeasurement; im++) {
787d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			ath_dbg(common, CALIBRATE,
788d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				"Doing Tx IQ Cal for chain %d\n", i);
789858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7903782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			if (REG_READ(ah, txiqcal_status[i]) &
7913782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan					AR_PHY_TX_IQCAL_STATUS_FAILED) {
792d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				ath_dbg(common, CALIBRATE,
793d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches					"Tx IQ Cal failed for chain %d\n", i);
7943782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				goto tx_iqcal_fail;
7953782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			}
796858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
7973782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			for (j = 0; j < 3; j++) {
7983782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				u32 idx = 2 * j, offset = 4 * (3 * im + j);
799858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8003782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				REG_RMW_FIELD(ah,
801858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						AR_PHY_CHAN_INFO_MEMORY,
802858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						AR_PHY_CHAN_INFO_TAB_S2_READ,
803858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						0);
804858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8053782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				/* 32 bits */
8063782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				iq_res[idx] = REG_READ(ah,
8073782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan						chan_info_tab[i] +
8083782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan						offset);
809858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8103782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				REG_RMW_FIELD(ah,
811858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						AR_PHY_CHAN_INFO_MEMORY,
812858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						AR_PHY_CHAN_INFO_TAB_S2_READ,
813858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan						1);
814858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8153782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				/* 16 bits */
8163782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				iq_res[idx + 1] = 0xffff & REG_READ(ah,
8173782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan						chan_info_tab[i] + offset);
818858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
819d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				ath_dbg(common, CALIBRATE,
820d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches					"IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
8213782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan					idx, iq_res[idx], idx + 1,
8223782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan					iq_res[idx + 1]);
8233782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			}
824858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8253782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
8263782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan						coeff.iqc_coeff)) {
827d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches				ath_dbg(common, CALIBRATE,
828d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches					"Failed in calculation of IQ correction\n");
8293782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				goto tx_iqcal_fail;
8303782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			}
831858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8323782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
8333782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			coeff.phs_coeff[i][im] =
8343782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				(coeff.iqc_coeff[0] >> 7) & 0x7f;
835858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
8363782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			if (coeff.mag_coeff[i][im] > 63)
8373782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				coeff.mag_coeff[i][im] -= 128;
8383782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan			if (coeff.phs_coeff[i][im] > 63)
8393782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan				coeff.phs_coeff[i][im] -= 128;
840858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan		}
841858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	}
84234013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan	ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains,
84334013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan					     &coeff, is_reusable);
844858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
845858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	return;
846858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
847858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajantx_iqcal_fail:
848d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches	ath_dbg(common, CALIBRATE, "Tx IQ Cal failed\n");
849858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan	return;
850858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan}
8515f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8525f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharanstatic void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
8535f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan{
8545f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	struct ath9k_hw_cal_data *caldata = ah->caldata;
8555f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
8565f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	int i, im;
8575f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8585f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
8595f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
8605f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
8615f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan					AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
8625f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		if (!AR_SREV_9485(ah)) {
8635f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			tx_corr_coeff[i * 2][1] =
8645f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			tx_corr_coeff[(i * 2) + 1][1] =
8655f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
8665f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8675f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			tx_corr_coeff[i * 2][2] =
8685f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			tx_corr_coeff[(i * 2) + 1][2] =
8695f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
8705f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		}
8715f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	}
8725f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8735f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
8745f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		if (!(ah->txchainmask & (1 << i)))
8755f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			continue;
8765f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8775f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		for (im = 0; im < caldata->num_measures[i]; im++) {
8785f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			if ((im % 2) == 0)
8795f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
8805f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				     AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
8815f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				     caldata->tx_corr_coeff[im][i]);
8825f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			else
8835f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
8845f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				     AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
8855f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				     caldata->tx_corr_coeff[im][i]);
8865f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		}
8875f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	}
8885f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
8895f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
8905f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
8915f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
8925f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
8935f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan}
8945f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan
895324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharanstatic bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
896324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan{
897324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	struct ath9k_rtt_hist *hist;
898324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	u32 *table;
899324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	int i;
900324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	bool restore;
901324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
90291ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan	if (!ah->caldata)
903324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		return false;
904324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
905324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	hist = &ah->caldata->rtt_hist;
90691ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan	if (!hist->num_readings)
90791ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan		return false;
90891ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan
909324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	ar9003_hw_rtt_enable(ah);
91091ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan	ar9003_hw_rtt_set_mask(ah, 0x00);
911324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
912324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		if (!(ah->rxchainmask & (1 << i)))
913324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			continue;
914324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		table = &hist->table[i][hist->num_readings][0];
915324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		ar9003_hw_rtt_load_hist(ah, i, table);
916324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
917324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	restore = ar9003_hw_rtt_force_restore(ah);
918324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	ar9003_hw_rtt_disable(ah);
919324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
920324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	return restore;
921324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan}
922324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
923df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguezstatic bool ar9003_hw_init_cal(struct ath_hw *ah,
924df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez			       struct ath9k_channel *chan)
925df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez{
926df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	struct ath_common *common = ath9k_hw_common(ah);
9275f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	struct ath9k_hw_cal_data *caldata = ah->caldata;
92877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan	bool txiqcal_done = false, txclcal_done = false;
929324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	bool is_reusable = true, status = true;
930324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	bool run_rtt_cal = false, run_agc_cal;
931324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
9323ebfcdc43ae261e58e5b9b381ae1f278cda068e3Mohammed Shafi Shajakhan	bool mci = !!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI);
933324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
934324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan					  AR_PHY_AGC_CONTROL_FLTR_CAL   |
935324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan					  AR_PHY_AGC_CONTROL_PKDET_CAL;
9368ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	int i, j;
93777a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan	u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
93877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					  AR_PHY_CL_TAB_1,
93977a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					  AR_PHY_CL_TAB_2 };
94077a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan
941324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (rtt) {
942324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		if (!ar9003_hw_rtt_restore(ah, chan))
943324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			run_rtt_cal = true;
944324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
945d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "RTT restore %s\n",
946324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			run_rtt_cal ? "failed" : "succeed");
947324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
948324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	run_agc_cal = run_rtt_cal;
949324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
950324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (run_rtt_cal) {
951324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		ar9003_hw_rtt_enable(ah);
952324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		ar9003_hw_rtt_set_mask(ah, 0x00);
953324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		ar9003_hw_rtt_clear_hist(ah);
954324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
955324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
956324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (rtt && !run_rtt_cal) {
957324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
958324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		agc_supp_cals &= agc_ctrl;
959324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
960324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			     AR_PHY_AGC_CONTROL_FLTR_CAL |
961324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			     AR_PHY_AGC_CONTROL_PKDET_CAL);
962324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
963324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
964324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
9658ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	if (ah->enabled_cals & TX_CL_CAL) {
96677a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan		if (caldata && caldata->done_txclcal_once)
96777a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
96877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				    AR_PHY_CL_CAL_ENABLE);
969324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		else {
97077a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL,
97177a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				    AR_PHY_CL_CAL_ENABLE);
972324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			run_agc_cal = true;
973324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		}
97477a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan	}
975df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
9768ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	if (!(ah->enabled_cals & TX_IQ_CAL))
9778ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan		goto skip_tx_iqcal;
9788ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan
979c5395b67437b47c4a4c0686d3db99be9327ef67eLuis R. Rodriguez	/* Do Tx IQ Calibration */
9803782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
9813782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
9823782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan		      DELPT);
983858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
9843782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	/*
9853782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	 * For AR9485 or later chips, TxIQ cal runs as part of
9863782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	 * AGC calibration
9873782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	 */
9888ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
9895f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		if (caldata && !caldata->done_txiqcal_once)
9905f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
9915f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
9925f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		else
9935f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan			REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
9945f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
995324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		txiqcal_done = run_agc_cal = true;
9968ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan		goto skip_tx_iqcal;
997324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	} else if (caldata && !caldata->done_txiqcal_once)
998324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		run_agc_cal = true;
999324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1000f2f408eff7eb10a834859457b2ced5d3255d0cd3Sujith Manoharan	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
1001f2f408eff7eb10a834859457b2ced5d3255d0cd3Sujith Manoharan		ar9003_mci_init_cal_req(ah, &is_reusable);
10023ebfcdc43ae261e58e5b9b381ae1f278cda068e3Mohammed Shafi Shajakhan
10038ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
10048ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
10058ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	udelay(5);
10068ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
1007c5395b67437b47c4a4c0686d3db99be9327ef67eLuis R. Rodriguez
10088ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharanskip_tx_iqcal:
1009a126ff511b12bd0e7b6ca9c16ab3f6f325ba6356Rajkumar Manoharan	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
1010324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		/* Calibrate the AGC */
1011324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
1012324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
1013324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			  AR_PHY_AGC_CONTROL_CAL);
1014324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1015324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		/* Poll for offset calibration complete */
1016324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
1017324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan				       AR_PHY_AGC_CONTROL_CAL,
1018324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan				       0, AH_WAIT_TIMEOUT);
1019324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
10203ebfcdc43ae261e58e5b9b381ae1f278cda068e3Mohammed Shafi Shajakhan
1021f2f408eff7eb10a834859457b2ced5d3255d0cd3Sujith Manoharan	if (mci && IS_CHAN_2GHZ(chan) && run_agc_cal)
1022f2f408eff7eb10a834859457b2ced5d3255d0cd3Sujith Manoharan		ar9003_mci_init_cal_done(ah);
10233ebfcdc43ae261e58e5b9b381ae1f278cda068e3Mohammed Shafi Shajakhan
1024324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (rtt && !run_rtt_cal) {
1025324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		agc_ctrl |= agc_supp_cals;
1026324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
1027324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
1028324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1029324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (!status) {
1030324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		if (run_rtt_cal)
1031324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			ar9003_hw_rtt_disable(ah);
1032324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1033d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
1034d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			"offset calibration failed to complete in 1ms; noisy environment?\n");
1035df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		return false;
1036df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
1037df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
10383782c69d6e35e698bcc2aefe803e62d06c5c4997Rajkumar Manoharan	if (txiqcal_done)
103934013524a1644bbd00c592541f67c536a384e707Rajkumar Manoharan		ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
10405f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	else if (caldata && caldata->done_txiqcal_once)
10415f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		ar9003_hw_tx_iq_cal_reload(ah);
1042858b7e36e82cc03cb77b64f096b64446a24a346aVasanthakumar Thiagarajan
104377a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan#define CL_TAB_ENTRY(reg_base)	(reg_base + (4 * j))
10448ad74c4d8c5e26121f698f56595768b76d1bed81Rajkumar Manoharan	if (caldata && (ah->enabled_cals & TX_CL_CAL)) {
104577a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan		txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
104677a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					   AR_PHY_AGC_CONTROL_CLC_SUCCESS);
104777a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan		if (caldata->done_txclcal_once) {
104877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
104977a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				if (!(ah->txchainmask & (1 << i)))
105077a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					continue;
105177a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
105277a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
105377a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan						  caldata->tx_clcal[i][j]);
105477a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			}
105577a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan		} else if (is_reusable && txclcal_done) {
105677a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
105777a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				if (!(ah->txchainmask & (1 << i)))
105877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					continue;
105977a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan				for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
106077a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan					caldata->tx_clcal[i][j] =
106177a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan						REG_READ(ah,
106277a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan						  CL_TAB_ENTRY(cl_idx[i]));
106377a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			}
106477a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan			caldata->done_txclcal_once = true;
106577a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan		}
106677a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan	}
106777a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan#undef CL_TAB_ENTRY
106877a5a6648da6b90d6ba990bf03c59993cdd5a516Rajkumar Manoharan
1069324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	if (run_rtt_cal && caldata) {
1070324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		struct ath9k_rtt_hist *hist = &caldata->rtt_hist;
1071324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) {
1072324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			u32 *table;
1073324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
107491ae4d02913808fc4056168766185d1a3bd63f65Rajkumar Manoharan			hist->num_readings++;
1075324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
1076324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan				if (!(ah->rxchainmask & (1 << i)))
1077324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan					continue;
1078324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan				table = &hist->table[i][hist->num_readings][0];
1079324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan				ar9003_hw_rtt_fill_hist(ah, i, table);
1080324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan			}
1081324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		}
1082324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1083324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan		ar9003_hw_rtt_disable(ah);
1084324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan	}
1085324c74ad64c7528a9cf243455723d5ed57238e15Rajkumar Manoharan
1086df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* Initialize list pointers */
1087df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
10886497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau	ah->supp_cals = IQ_MISMATCH_CAL;
1089df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
10906497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau	if (ah->supp_cals & IQ_MISMATCH_CAL) {
1091df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		INIT_CAL(&ah->iq_caldata);
1092df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		INSERT_CAL(ah, &ah->iq_caldata);
1093d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
1094df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
1095df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
10966497827f53eb90dcf30c5d6414c83238f722e8aeFelix Fietkau	if (ah->supp_cals & TEMP_COMP_CAL) {
1097df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		INIT_CAL(&ah->tempCompCalData);
1098df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		INSERT_CAL(ah, &ah->tempCompCalData);
1099d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches		ath_dbg(common, CALIBRATE,
1100d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches			"enabling Temperature Compensation Calibration\n");
1101df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	}
1102df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
1103df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	/* Initialize current pointer to first element in list */
1104df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	ah->cal_list_curr = ah->cal_list;
1105df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
1106df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	if (ah->cal_list_curr)
1107df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
1108df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
11095f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan	if (caldata)
11105f0c04ea1e7394c2b28fa247c1722487f9a77523Rajkumar Manoharan		caldata->CalValid = 0;
1111df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez
1112df23acaa5d3239745805650e2f27a4252182c063Luis R. Rodriguez	return true;
111377d6d39a77939e5ed7e2ec72a1c1dce828ee582eLuis R. Rodriguez}
111477d6d39a77939e5ed7e2ec72a1c1dce828ee582eLuis R. Rodriguez
1115795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguezvoid ar9003_hw_attach_calib_ops(struct ath_hw *ah)
1116795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez{
1117795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
1118795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
1119795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
1120795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
1121795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	priv_ops->init_cal = ar9003_hw_init_cal;
1122795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	priv_ops->setup_calibration = ar9003_hw_setup_calibration;
1123795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez
1124795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez	ops->calibrate = ar9003_hw_calibrate;
1125795f5e2ca672727a96bacf97075976cfe1249fcfLuis R. Rodriguez}
1126