18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2010-2011 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
58c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
68c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
98c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
108c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
118c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
128c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
138c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
148c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "hw.h"
188c2ecf20Sopenharmony_ci#include "hw-ops.h"
198c2ecf20Sopenharmony_ci#include "ar9003_phy.h"
208c2ecf20Sopenharmony_ci#include "ar9003_rtt.h"
218c2ecf20Sopenharmony_ci#include "ar9003_mci.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define MAX_MEASUREMENT	MAX_IQCAL_MEASUREMENT
248c2ecf20Sopenharmony_ci#define MAX_MAG_DELTA	11
258c2ecf20Sopenharmony_ci#define MAX_PHS_DELTA	10
268c2ecf20Sopenharmony_ci#define MAXIQCAL        3
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct coeff {
298c2ecf20Sopenharmony_ci	int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
308c2ecf20Sopenharmony_ci	int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL];
318c2ecf20Sopenharmony_ci	int iqc_coeff[2];
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cienum ar9003_cal_types {
358c2ecf20Sopenharmony_ci	IQ_MISMATCH_CAL = BIT(0),
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void ar9003_hw_setup_calibration(struct ath_hw *ah,
398c2ecf20Sopenharmony_ci					struct ath9k_cal_list *currCal)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* Select calibration to run */
448c2ecf20Sopenharmony_ci	switch (currCal->calData->calType) {
458c2ecf20Sopenharmony_ci	case IQ_MISMATCH_CAL:
468c2ecf20Sopenharmony_ci		/*
478c2ecf20Sopenharmony_ci		 * Start calibration with
488c2ecf20Sopenharmony_ci		 * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
498c2ecf20Sopenharmony_ci		 */
508c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_TIMING4,
518c2ecf20Sopenharmony_ci			      AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
528c2ecf20Sopenharmony_ci			      currCal->calData->calCountMax);
538c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
568c2ecf20Sopenharmony_ci			"starting IQ Mismatch Calibration\n");
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		/* Kick-off cal */
598c2ecf20Sopenharmony_ci		REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
608c2ecf20Sopenharmony_ci		break;
618c2ecf20Sopenharmony_ci	default:
628c2ecf20Sopenharmony_ci		ath_err(common, "Invalid calibration type\n");
638c2ecf20Sopenharmony_ci		break;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/*
688c2ecf20Sopenharmony_ci * Generic calibration routine.
698c2ecf20Sopenharmony_ci * Recalibrate the lower PHY chips to account for temperature/environment
708c2ecf20Sopenharmony_ci * changes.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic bool ar9003_hw_per_calibration(struct ath_hw *ah,
738c2ecf20Sopenharmony_ci				      struct ath9k_channel *ichan,
748c2ecf20Sopenharmony_ci				      u8 rxchainmask,
758c2ecf20Sopenharmony_ci				      struct ath9k_cal_list *currCal)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
788c2ecf20Sopenharmony_ci	const struct ath9k_percal_data *cur_caldata = currCal->calData;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* Calibration in progress. */
818c2ecf20Sopenharmony_ci	if (currCal->calState == CAL_RUNNING) {
828c2ecf20Sopenharmony_ci		/* Check to see if it has finished. */
838c2ecf20Sopenharmony_ci		if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)
848c2ecf20Sopenharmony_ci			return false;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		/*
878c2ecf20Sopenharmony_ci		* Accumulate cal measures for active chains
888c2ecf20Sopenharmony_ci		*/
898c2ecf20Sopenharmony_ci		cur_caldata->calCollect(ah);
908c2ecf20Sopenharmony_ci		ah->cal_samples++;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		if (ah->cal_samples >= cur_caldata->calNumSamples) {
938c2ecf20Sopenharmony_ci			unsigned int i, numChains = 0;
948c2ecf20Sopenharmony_ci			for (i = 0; i < AR9300_MAX_CHAINS; i++) {
958c2ecf20Sopenharmony_ci				if (rxchainmask & (1 << i))
968c2ecf20Sopenharmony_ci					numChains++;
978c2ecf20Sopenharmony_ci			}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci			/*
1008c2ecf20Sopenharmony_ci			* Process accumulated data
1018c2ecf20Sopenharmony_ci			*/
1028c2ecf20Sopenharmony_ci			cur_caldata->calPostProc(ah, numChains);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci			/* Calibration has finished. */
1058c2ecf20Sopenharmony_ci			caldata->CalValid |= cur_caldata->calType;
1068c2ecf20Sopenharmony_ci			currCal->calState = CAL_DONE;
1078c2ecf20Sopenharmony_ci			return true;
1088c2ecf20Sopenharmony_ci		} else {
1098c2ecf20Sopenharmony_ci			/*
1108c2ecf20Sopenharmony_ci			 * Set-up collection of another sub-sample until we
1118c2ecf20Sopenharmony_ci			 * get desired number
1128c2ecf20Sopenharmony_ci			 */
1138c2ecf20Sopenharmony_ci			ar9003_hw_setup_calibration(ah, currCal);
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci	} else if (!(caldata->CalValid & cur_caldata->calType)) {
1168c2ecf20Sopenharmony_ci		/* If current cal is marked invalid in channel, kick it off */
1178c2ecf20Sopenharmony_ci		ath9k_hw_reset_calibration(ah, currCal);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return false;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
1248c2ecf20Sopenharmony_ci			       u8 rxchainmask, bool longcal)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	bool iscaldone = true;
1278c2ecf20Sopenharmony_ci	struct ath9k_cal_list *currCal = ah->cal_list_curr;
1288c2ecf20Sopenharmony_ci	int ret;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/*
1318c2ecf20Sopenharmony_ci	 * For given calibration:
1328c2ecf20Sopenharmony_ci	 * 1. Call generic cal routine
1338c2ecf20Sopenharmony_ci	 * 2. When this cal is done (isCalDone) if we have more cals waiting
1348c2ecf20Sopenharmony_ci	 *    (eg after reset), mask this to upper layers by not propagating
1358c2ecf20Sopenharmony_ci	 *    isCalDone if it is set to TRUE.
1368c2ecf20Sopenharmony_ci	 *    Instead, change isCalDone to FALSE and setup the waiting cal(s)
1378c2ecf20Sopenharmony_ci	 *    to be run.
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	if (currCal &&
1408c2ecf20Sopenharmony_ci	    (currCal->calState == CAL_RUNNING ||
1418c2ecf20Sopenharmony_ci	     currCal->calState == CAL_WAITING)) {
1428c2ecf20Sopenharmony_ci		iscaldone = ar9003_hw_per_calibration(ah, chan,
1438c2ecf20Sopenharmony_ci						      rxchainmask, currCal);
1448c2ecf20Sopenharmony_ci		if (iscaldone) {
1458c2ecf20Sopenharmony_ci			ah->cal_list_curr = currCal = currCal->calNext;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci			if (currCal->calState == CAL_WAITING) {
1488c2ecf20Sopenharmony_ci				iscaldone = false;
1498c2ecf20Sopenharmony_ci				ath9k_hw_reset_calibration(ah, currCal);
1508c2ecf20Sopenharmony_ci			}
1518c2ecf20Sopenharmony_ci		}
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * Do NF cal only at longer intervals. Get the value from
1568c2ecf20Sopenharmony_ci	 * the previous NF cal and update history buffer.
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci	if (longcal && ath9k_hw_getnf(ah, chan)) {
1598c2ecf20Sopenharmony_ci		/*
1608c2ecf20Sopenharmony_ci		 * Load the NF from history buffer of the current channel.
1618c2ecf20Sopenharmony_ci		 * NF is slow time-variant, so it is OK to use a historical
1628c2ecf20Sopenharmony_ci		 * value.
1638c2ecf20Sopenharmony_ci		 */
1648c2ecf20Sopenharmony_ci		ret = ath9k_hw_loadnf(ah, ah->curchan);
1658c2ecf20Sopenharmony_ci		if (ret < 0)
1668c2ecf20Sopenharmony_ci			return ret;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci		/* start NF calibration, without updating BB NF register */
1698c2ecf20Sopenharmony_ci		ath9k_hw_start_nfcal(ah, false);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return iscaldone;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic void ar9003_hw_iqcal_collect(struct ath_hw *ah)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	int i;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Accumulate IQ cal measures for active chains */
1808c2ecf20Sopenharmony_ci	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
1818c2ecf20Sopenharmony_ci		if (ah->txchainmask & BIT(i)) {
1828c2ecf20Sopenharmony_ci			ah->totalPowerMeasI[i] +=
1838c2ecf20Sopenharmony_ci				REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
1848c2ecf20Sopenharmony_ci			ah->totalPowerMeasQ[i] +=
1858c2ecf20Sopenharmony_ci				REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
1868c2ecf20Sopenharmony_ci			ah->totalIqCorrMeas[i] +=
1878c2ecf20Sopenharmony_ci				(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
1888c2ecf20Sopenharmony_ci			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
1898c2ecf20Sopenharmony_ci				"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
1908c2ecf20Sopenharmony_ci				ah->cal_samples, i, ah->totalPowerMeasI[i],
1918c2ecf20Sopenharmony_ci				ah->totalPowerMeasQ[i],
1928c2ecf20Sopenharmony_ci				ah->totalIqCorrMeas[i]);
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
2008c2ecf20Sopenharmony_ci	u32 powerMeasQ, powerMeasI, iqCorrMeas;
2018c2ecf20Sopenharmony_ci	u32 qCoffDenom, iCoffDenom;
2028c2ecf20Sopenharmony_ci	int32_t qCoff, iCoff;
2038c2ecf20Sopenharmony_ci	int iqCorrNeg, i;
2048c2ecf20Sopenharmony_ci	static const u_int32_t offset_array[3] = {
2058c2ecf20Sopenharmony_ci		AR_PHY_RX_IQCAL_CORR_B0,
2068c2ecf20Sopenharmony_ci		AR_PHY_RX_IQCAL_CORR_B1,
2078c2ecf20Sopenharmony_ci		AR_PHY_RX_IQCAL_CORR_B2,
2088c2ecf20Sopenharmony_ci	};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	for (i = 0; i < numChains; i++) {
2118c2ecf20Sopenharmony_ci		powerMeasI = ah->totalPowerMeasI[i];
2128c2ecf20Sopenharmony_ci		powerMeasQ = ah->totalPowerMeasQ[i];
2138c2ecf20Sopenharmony_ci		iqCorrMeas = ah->totalIqCorrMeas[i];
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
2168c2ecf20Sopenharmony_ci			"Starting IQ Cal and Correction for Chain %d\n", i);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
2198c2ecf20Sopenharmony_ci			"Original: Chn %d iq_corr_meas = 0x%08x\n",
2208c2ecf20Sopenharmony_ci			i, ah->totalIqCorrMeas[i]);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		iqCorrNeg = 0;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		if (iqCorrMeas > 0x80000000) {
2258c2ecf20Sopenharmony_ci			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
2268c2ecf20Sopenharmony_ci			iqCorrNeg = 1;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",
2308c2ecf20Sopenharmony_ci			i, powerMeasI);
2318c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",
2328c2ecf20Sopenharmony_ci			i, powerMeasQ);
2338c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
2368c2ecf20Sopenharmony_ci		qCoffDenom = powerMeasQ / 64;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci		if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
2398c2ecf20Sopenharmony_ci			iCoff = iqCorrMeas / iCoffDenom;
2408c2ecf20Sopenharmony_ci			qCoff = powerMeasI / qCoffDenom - 64;
2418c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",
2428c2ecf20Sopenharmony_ci				i, iCoff);
2438c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",
2448c2ecf20Sopenharmony_ci				i, qCoff);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci			/* Force bounds on iCoff */
2478c2ecf20Sopenharmony_ci			if (iCoff >= 63)
2488c2ecf20Sopenharmony_ci				iCoff = 63;
2498c2ecf20Sopenharmony_ci			else if (iCoff <= -63)
2508c2ecf20Sopenharmony_ci				iCoff = -63;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci			/* Negate iCoff if iqCorrNeg == 0 */
2538c2ecf20Sopenharmony_ci			if (iqCorrNeg == 0x0)
2548c2ecf20Sopenharmony_ci				iCoff = -iCoff;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci			/* Force bounds on qCoff */
2578c2ecf20Sopenharmony_ci			if (qCoff >= 63)
2588c2ecf20Sopenharmony_ci				qCoff = 63;
2598c2ecf20Sopenharmony_ci			else if (qCoff <= -63)
2608c2ecf20Sopenharmony_ci				qCoff = -63;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci			iCoff = iCoff & 0x7f;
2638c2ecf20Sopenharmony_ci			qCoff = qCoff & 0x7f;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
2668c2ecf20Sopenharmony_ci				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
2678c2ecf20Sopenharmony_ci				i, iCoff, qCoff);
2688c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
2698c2ecf20Sopenharmony_ci				"Register offset (0x%04x) before update = 0x%x\n",
2708c2ecf20Sopenharmony_ci				offset_array[i],
2718c2ecf20Sopenharmony_ci				REG_READ(ah, offset_array[i]));
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci			if (AR_SREV_9565(ah) &&
2748c2ecf20Sopenharmony_ci			    (iCoff == 63 || qCoff == 63 ||
2758c2ecf20Sopenharmony_ci			     iCoff == -63 || qCoff == -63))
2768c2ecf20Sopenharmony_ci				return;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, offset_array[i],
2798c2ecf20Sopenharmony_ci				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
2808c2ecf20Sopenharmony_ci				      iCoff);
2818c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, offset_array[i],
2828c2ecf20Sopenharmony_ci				      AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
2838c2ecf20Sopenharmony_ci				      qCoff);
2848c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
2858c2ecf20Sopenharmony_ci				"Register offset (0x%04x) QI COFF (bitfields 0x%08x) after update = 0x%x\n",
2868c2ecf20Sopenharmony_ci				offset_array[i],
2878c2ecf20Sopenharmony_ci				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
2888c2ecf20Sopenharmony_ci				REG_READ(ah, offset_array[i]));
2898c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
2908c2ecf20Sopenharmony_ci				"Register offset (0x%04x) QQ COFF (bitfields 0x%08x) after update = 0x%x\n",
2918c2ecf20Sopenharmony_ci				offset_array[i],
2928c2ecf20Sopenharmony_ci				AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
2938c2ecf20Sopenharmony_ci				REG_READ(ah, offset_array[i]));
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
2968c2ecf20Sopenharmony_ci				"IQ Cal and Correction done for Chain %d\n", i);
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
3018c2ecf20Sopenharmony_ci		    AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
3028c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE,
3038c2ecf20Sopenharmony_ci		"IQ Cal and Correction (offset 0x%04x) enabled (bit position 0x%08x). New Value 0x%08x\n",
3048c2ecf20Sopenharmony_ci		(unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
3058c2ecf20Sopenharmony_ci		AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
3068c2ecf20Sopenharmony_ci		REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic const struct ath9k_percal_data iq_cal_single_sample = {
3108c2ecf20Sopenharmony_ci	IQ_MISMATCH_CAL,
3118c2ecf20Sopenharmony_ci	MIN_CAL_SAMPLES,
3128c2ecf20Sopenharmony_ci	PER_MAX_LOG_COUNT,
3138c2ecf20Sopenharmony_ci	ar9003_hw_iqcal_collect,
3148c2ecf20Sopenharmony_ci	ar9003_hw_iqcalibrate
3158c2ecf20Sopenharmony_ci};
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic void ar9003_hw_init_cal_settings(struct ath_hw *ah)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	ah->iq_caldata.calData = &iq_cal_single_sample;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah)) {
3228c2ecf20Sopenharmony_ci		ah->enabled_cals |= TX_IQ_CAL;
3238c2ecf20Sopenharmony_ci		if (AR_SREV_9485_OR_LATER(ah) && !AR_SREV_9340(ah))
3248c2ecf20Sopenharmony_ci			ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	ah->supp_cals = IQ_MISMATCH_CAL;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci#define OFF_UPPER_LT 24
3318c2ecf20Sopenharmony_ci#define OFF_LOWER_LT 7
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah,
3348c2ecf20Sopenharmony_ci					      bool txiqcal_done)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
3378c2ecf20Sopenharmony_ci	int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2,
3388c2ecf20Sopenharmony_ci		dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3;
3398c2ecf20Sopenharmony_ci	int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2,
3408c2ecf20Sopenharmony_ci		dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3;
3418c2ecf20Sopenharmony_ci	int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2,
3428c2ecf20Sopenharmony_ci		dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3;
3438c2ecf20Sopenharmony_ci	bool status;
3448c2ecf20Sopenharmony_ci	u32 temp, val;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/*
3478c2ecf20Sopenharmony_ci	 * Clear offset and IQ calibration, run AGC cal.
3488c2ecf20Sopenharmony_ci	 */
3498c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
3508c2ecf20Sopenharmony_ci		    AR_PHY_AGC_CONTROL_OFFSET_CAL);
3518c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
3528c2ecf20Sopenharmony_ci		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
3538c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3548c2ecf20Sopenharmony_ci		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
3578c2ecf20Sopenharmony_ci			       AR_PHY_AGC_CONTROL_CAL,
3588c2ecf20Sopenharmony_ci			       0, AH_WAIT_TIMEOUT);
3598c2ecf20Sopenharmony_ci	if (!status) {
3608c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
3618c2ecf20Sopenharmony_ci			"AGC cal without offset cal failed to complete in 1ms");
3628c2ecf20Sopenharmony_ci		return false;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/*
3668c2ecf20Sopenharmony_ci	 * Allow only offset calibration and disable the others
3678c2ecf20Sopenharmony_ci	 * (Carrier Leak calibration, TX Filter calibration and
3688c2ecf20Sopenharmony_ci	 *  Peak Detector offset calibration).
3698c2ecf20Sopenharmony_ci	 */
3708c2ecf20Sopenharmony_ci	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
3718c2ecf20Sopenharmony_ci		    AR_PHY_AGC_CONTROL_OFFSET_CAL);
3728c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
3738c2ecf20Sopenharmony_ci		    AR_PHY_CL_CAL_ENABLE);
3748c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
3758c2ecf20Sopenharmony_ci		    AR_PHY_AGC_CONTROL_FLTR_CAL);
3768c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
3778c2ecf20Sopenharmony_ci		    AR_PHY_AGC_CONTROL_PKDET_CAL);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ch0_done = 0;
3808c2ecf20Sopenharmony_ci	ch1_done = 0;
3818c2ecf20Sopenharmony_ci	ch2_done = 0;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) {
3848c2ecf20Sopenharmony_ci		osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3;
3858c2ecf20Sopenharmony_ci		osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3;
3868c2ecf20Sopenharmony_ci		osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
3918c2ecf20Sopenharmony_ci			  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
3948c2ecf20Sopenharmony_ci				       AR_PHY_AGC_CONTROL_CAL,
3958c2ecf20Sopenharmony_ci				       0, AH_WAIT_TIMEOUT);
3968c2ecf20Sopenharmony_ci		if (!status) {
3978c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
3988c2ecf20Sopenharmony_ci				"DC offset cal failed to complete in 1ms");
3998c2ecf20Sopenharmony_ci			return false;
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci		REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		/*
4058c2ecf20Sopenharmony_ci		 * High gain.
4068c2ecf20Sopenharmony_ci		 */
4078c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
4088c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8)));
4098c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
4108c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8)));
4118c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
4128c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8)));
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
4158c2ecf20Sopenharmony_ci		dc_off_ch0_i1 = (temp >> 26) & 0x1f;
4168c2ecf20Sopenharmony_ci		dc_off_ch0_q1 = (temp >> 21) & 0x1f;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
4198c2ecf20Sopenharmony_ci		dc_off_ch1_i1 = (temp >> 26) & 0x1f;
4208c2ecf20Sopenharmony_ci		dc_off_ch1_q1 = (temp >> 21) & 0x1f;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
4238c2ecf20Sopenharmony_ci		dc_off_ch2_i1 = (temp >> 26) & 0x1f;
4248c2ecf20Sopenharmony_ci		dc_off_ch2_q1 = (temp >> 21) & 0x1f;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		/*
4278c2ecf20Sopenharmony_ci		 * Low gain.
4288c2ecf20Sopenharmony_ci		 */
4298c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
4308c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8)));
4318c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
4328c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8)));
4338c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
4348c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8)));
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
4378c2ecf20Sopenharmony_ci		dc_off_ch0_i2 = (temp >> 26) & 0x1f;
4388c2ecf20Sopenharmony_ci		dc_off_ch0_q2 = (temp >> 21) & 0x1f;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
4418c2ecf20Sopenharmony_ci		dc_off_ch1_i2 = (temp >> 26) & 0x1f;
4428c2ecf20Sopenharmony_ci		dc_off_ch1_q2 = (temp >> 21) & 0x1f;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
4458c2ecf20Sopenharmony_ci		dc_off_ch2_i2 = (temp >> 26) & 0x1f;
4468c2ecf20Sopenharmony_ci		dc_off_ch2_q2 = (temp >> 21) & 0x1f;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		/*
4498c2ecf20Sopenharmony_ci		 * Loopback.
4508c2ecf20Sopenharmony_ci		 */
4518c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
4528c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8)));
4538c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
4548c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8)));
4558c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
4568c2ecf20Sopenharmony_ci			  ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8)));
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
4598c2ecf20Sopenharmony_ci		dc_off_ch0_i3 = (temp >> 26) & 0x1f;
4608c2ecf20Sopenharmony_ci		dc_off_ch0_q3 = (temp >> 21) & 0x1f;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
4638c2ecf20Sopenharmony_ci		dc_off_ch1_i3 = (temp >> 26) & 0x1f;
4648c2ecf20Sopenharmony_ci		dc_off_ch1_q3 = (temp >> 21) & 0x1f;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
4678c2ecf20Sopenharmony_ci		dc_off_ch2_i3 = (temp >> 26) & 0x1f;
4688c2ecf20Sopenharmony_ci		dc_off_ch2_q3 = (temp >> 21) & 0x1f;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) ||
4718c2ecf20Sopenharmony_ci		    (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) ||
4728c2ecf20Sopenharmony_ci		    (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) ||
4738c2ecf20Sopenharmony_ci		    (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) ||
4748c2ecf20Sopenharmony_ci		    (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) ||
4758c2ecf20Sopenharmony_ci		    (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) {
4768c2ecf20Sopenharmony_ci			if (osdac_ch0 == 3) {
4778c2ecf20Sopenharmony_ci				ch0_done = 1;
4788c2ecf20Sopenharmony_ci			} else {
4798c2ecf20Sopenharmony_ci				osdac_ch0++;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci				val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff;
4828c2ecf20Sopenharmony_ci				val |= (osdac_ch0 << 30);
4838c2ecf20Sopenharmony_ci				REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci				ch0_done = 0;
4868c2ecf20Sopenharmony_ci			}
4878c2ecf20Sopenharmony_ci		} else {
4888c2ecf20Sopenharmony_ci			ch0_done = 1;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) ||
4928c2ecf20Sopenharmony_ci		    (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) ||
4938c2ecf20Sopenharmony_ci		    (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) ||
4948c2ecf20Sopenharmony_ci		    (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) ||
4958c2ecf20Sopenharmony_ci		    (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) ||
4968c2ecf20Sopenharmony_ci		    (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) {
4978c2ecf20Sopenharmony_ci			if (osdac_ch1 == 3) {
4988c2ecf20Sopenharmony_ci				ch1_done = 1;
4998c2ecf20Sopenharmony_ci			} else {
5008c2ecf20Sopenharmony_ci				osdac_ch1++;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci				val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff;
5038c2ecf20Sopenharmony_ci				val |= (osdac_ch1 << 30);
5048c2ecf20Sopenharmony_ci				REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci				ch1_done = 0;
5078c2ecf20Sopenharmony_ci			}
5088c2ecf20Sopenharmony_ci		} else {
5098c2ecf20Sopenharmony_ci			ch1_done = 1;
5108c2ecf20Sopenharmony_ci		}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci		if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) ||
5138c2ecf20Sopenharmony_ci		    (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) ||
5148c2ecf20Sopenharmony_ci		    (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) ||
5158c2ecf20Sopenharmony_ci		    (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) ||
5168c2ecf20Sopenharmony_ci		    (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) ||
5178c2ecf20Sopenharmony_ci		    (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) {
5188c2ecf20Sopenharmony_ci			if (osdac_ch2 == 3) {
5198c2ecf20Sopenharmony_ci				ch2_done = 1;
5208c2ecf20Sopenharmony_ci			} else {
5218c2ecf20Sopenharmony_ci				osdac_ch2++;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci				val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff;
5248c2ecf20Sopenharmony_ci				val |= (osdac_ch2 << 30);
5258c2ecf20Sopenharmony_ci				REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci				ch2_done = 0;
5288c2ecf20Sopenharmony_ci			}
5298c2ecf20Sopenharmony_ci		} else {
5308c2ecf20Sopenharmony_ci			ch2_done = 1;
5318c2ecf20Sopenharmony_ci		}
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
5358c2ecf20Sopenharmony_ci		    AR_PHY_AGC_CONTROL_OFFSET_CAL);
5368c2ecf20Sopenharmony_ci	REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	/*
5398c2ecf20Sopenharmony_ci	 * We don't need to check txiqcal_done here since it is always
5408c2ecf20Sopenharmony_ci	 * set for AR9550.
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci	REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
5438c2ecf20Sopenharmony_ci		    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return true;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/*
5498c2ecf20Sopenharmony_ci * solve 4x4 linear equation used in loopback iq cal.
5508c2ecf20Sopenharmony_ci */
5518c2ecf20Sopenharmony_cistatic bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
5528c2ecf20Sopenharmony_ci				   s32 sin_2phi_1,
5538c2ecf20Sopenharmony_ci				   s32 cos_2phi_1,
5548c2ecf20Sopenharmony_ci				   s32 sin_2phi_2,
5558c2ecf20Sopenharmony_ci				   s32 cos_2phi_2,
5568c2ecf20Sopenharmony_ci				   s32 mag_a0_d0,
5578c2ecf20Sopenharmony_ci				   s32 phs_a0_d0,
5588c2ecf20Sopenharmony_ci				   s32 mag_a1_d0,
5598c2ecf20Sopenharmony_ci				   s32 phs_a1_d0,
5608c2ecf20Sopenharmony_ci				   s32 solved_eq[])
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	s32 f1 = cos_2phi_1 - cos_2phi_2,
5638c2ecf20Sopenharmony_ci	    f3 = sin_2phi_1 - sin_2phi_2,
5648c2ecf20Sopenharmony_ci	    f2;
5658c2ecf20Sopenharmony_ci	s32 mag_tx, phs_tx, mag_rx, phs_rx;
5668c2ecf20Sopenharmony_ci	const s32 result_shift = 1 << 15;
5678c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	f2 = ((f1 >> 3) * (f1 >> 3) + (f3 >> 3) * (f3 >> 3)) >> 9;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (!f2) {
5728c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "Divide by 0\n");
5738c2ecf20Sopenharmony_ci		return false;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* mag mismatch, tx */
5778c2ecf20Sopenharmony_ci	mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
5788c2ecf20Sopenharmony_ci	/* phs mismatch, tx */
5798c2ecf20Sopenharmony_ci	phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	mag_tx = (mag_tx / f2);
5828c2ecf20Sopenharmony_ci	phs_tx = (phs_tx / f2);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/* mag mismatch, rx */
5858c2ecf20Sopenharmony_ci	mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
5868c2ecf20Sopenharmony_ci		 result_shift;
5878c2ecf20Sopenharmony_ci	/* phs mismatch, rx */
5888c2ecf20Sopenharmony_ci	phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
5898c2ecf20Sopenharmony_ci		 result_shift;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	solved_eq[0] = mag_tx;
5928c2ecf20Sopenharmony_ci	solved_eq[1] = phs_tx;
5938c2ecf20Sopenharmony_ci	solved_eq[2] = mag_rx;
5948c2ecf20Sopenharmony_ci	solved_eq[3] = phs_rx;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	return true;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	s32 abs_i = abs(in_re),
6028c2ecf20Sopenharmony_ci	    abs_q = abs(in_im),
6038c2ecf20Sopenharmony_ci	    max_abs, min_abs;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	if (abs_i > abs_q) {
6068c2ecf20Sopenharmony_ci		max_abs = abs_i;
6078c2ecf20Sopenharmony_ci		min_abs = abs_q;
6088c2ecf20Sopenharmony_ci	} else {
6098c2ecf20Sopenharmony_ci		max_abs = abs_q;
6108c2ecf20Sopenharmony_ci		min_abs = abs_i;
6118c2ecf20Sopenharmony_ci	}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci#define DELPT 32
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
6198c2ecf20Sopenharmony_ci				   s32 chain_idx,
6208c2ecf20Sopenharmony_ci				   const s32 iq_res[],
6218c2ecf20Sopenharmony_ci				   s32 iqc_coeff[])
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
6248c2ecf20Sopenharmony_ci	    i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
6258c2ecf20Sopenharmony_ci	    i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
6268c2ecf20Sopenharmony_ci	    i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
6278c2ecf20Sopenharmony_ci	s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
6288c2ecf20Sopenharmony_ci	    phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
6298c2ecf20Sopenharmony_ci	    sin_2phi_1, cos_2phi_1,
6308c2ecf20Sopenharmony_ci	    sin_2phi_2, cos_2phi_2;
6318c2ecf20Sopenharmony_ci	s32 mag_tx, phs_tx, mag_rx, phs_rx;
6328c2ecf20Sopenharmony_ci	s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
6338c2ecf20Sopenharmony_ci	    q_q_coff, q_i_coff;
6348c2ecf20Sopenharmony_ci	const s32 res_scale = 1 << 15;
6358c2ecf20Sopenharmony_ci	const s32 delpt_shift = 1 << 8;
6368c2ecf20Sopenharmony_ci	s32 mag1, mag2;
6378c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
6408c2ecf20Sopenharmony_ci	i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
6418c2ecf20Sopenharmony_ci	iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (i2_m_q2_a0_d0 > 0x800)
6448c2ecf20Sopenharmony_ci		i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (i2_p_q2_a0_d0 > 0x800)
6478c2ecf20Sopenharmony_ci		i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	if (iq_corr_a0_d0 > 0x800)
6508c2ecf20Sopenharmony_ci		iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
6538c2ecf20Sopenharmony_ci	i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
6548c2ecf20Sopenharmony_ci	iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (i2_m_q2_a0_d1 > 0x800)
6578c2ecf20Sopenharmony_ci		i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	if (iq_corr_a0_d1 > 0x800)
6608c2ecf20Sopenharmony_ci		iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
6638c2ecf20Sopenharmony_ci	i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
6648c2ecf20Sopenharmony_ci	iq_corr_a1_d0 = iq_res[4] & 0xfff;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (i2_m_q2_a1_d0 > 0x800)
6678c2ecf20Sopenharmony_ci		i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (i2_p_q2_a1_d0 > 0x800)
6708c2ecf20Sopenharmony_ci		i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (iq_corr_a1_d0 > 0x800)
6738c2ecf20Sopenharmony_ci		iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
6768c2ecf20Sopenharmony_ci	i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
6778c2ecf20Sopenharmony_ci	iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (i2_m_q2_a1_d1 > 0x800)
6808c2ecf20Sopenharmony_ci		i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (i2_p_q2_a1_d1 > 0x800)
6838c2ecf20Sopenharmony_ci		i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (iq_corr_a1_d1 > 0x800)
6868c2ecf20Sopenharmony_ci		iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
6898c2ecf20Sopenharmony_ci	    (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
6908c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
6918c2ecf20Sopenharmony_ci			"Divide by 0:\n"
6928c2ecf20Sopenharmony_ci			"a0_d0=%d\n"
6938c2ecf20Sopenharmony_ci			"a0_d1=%d\n"
6948c2ecf20Sopenharmony_ci			"a2_d0=%d\n"
6958c2ecf20Sopenharmony_ci			"a1_d1=%d\n",
6968c2ecf20Sopenharmony_ci			i2_p_q2_a0_d0, i2_p_q2_a0_d1,
6978c2ecf20Sopenharmony_ci			i2_p_q2_a1_d0, i2_p_q2_a1_d1);
6988c2ecf20Sopenharmony_ci		return false;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	if ((i2_p_q2_a0_d0 < 1024) || (i2_p_q2_a0_d0 > 2047) ||
7028c2ecf20Sopenharmony_ci            (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) ||
7038c2ecf20Sopenharmony_ci            (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) ||
7048c2ecf20Sopenharmony_ci            (i2_p_q2_a0_d0 <= iq_corr_a0_d0) ||
7058c2ecf20Sopenharmony_ci            (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) ||
7068c2ecf20Sopenharmony_ci            (i2_p_q2_a0_d1 <= iq_corr_a0_d1) ||
7078c2ecf20Sopenharmony_ci            (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) ||
7088c2ecf20Sopenharmony_ci            (i2_p_q2_a1_d0 <= iq_corr_a1_d0) ||
7098c2ecf20Sopenharmony_ci            (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) ||
7108c2ecf20Sopenharmony_ci            (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) {
7118c2ecf20Sopenharmony_ci		return false;
7128c2ecf20Sopenharmony_ci	}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
7158c2ecf20Sopenharmony_ci	phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
7188c2ecf20Sopenharmony_ci	phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
7218c2ecf20Sopenharmony_ci	phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
7248c2ecf20Sopenharmony_ci	phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* w/o analog phase shift */
7278c2ecf20Sopenharmony_ci	sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
7288c2ecf20Sopenharmony_ci	/* w/o analog phase shift */
7298c2ecf20Sopenharmony_ci	cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
7308c2ecf20Sopenharmony_ci	/* w/  analog phase shift */
7318c2ecf20Sopenharmony_ci	sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
7328c2ecf20Sopenharmony_ci	/* w/  analog phase shift */
7338c2ecf20Sopenharmony_ci	cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/*
7368c2ecf20Sopenharmony_ci	 * force sin^2 + cos^2 = 1;
7378c2ecf20Sopenharmony_ci	 * find magnitude by approximation
7388c2ecf20Sopenharmony_ci	 */
7398c2ecf20Sopenharmony_ci	mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
7408c2ecf20Sopenharmony_ci	mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if ((mag1 == 0) || (mag2 == 0)) {
7438c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "Divide by 0: mag1=%d, mag2=%d\n",
7448c2ecf20Sopenharmony_ci			mag1, mag2);
7458c2ecf20Sopenharmony_ci		return false;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* normalization sin and cos by mag */
7498c2ecf20Sopenharmony_ci	sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
7508c2ecf20Sopenharmony_ci	cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
7518c2ecf20Sopenharmony_ci	sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
7528c2ecf20Sopenharmony_ci	cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	/* calculate IQ mismatch */
7558c2ecf20Sopenharmony_ci	if (!ar9003_hw_solve_iq_cal(ah,
7568c2ecf20Sopenharmony_ci			     sin_2phi_1, cos_2phi_1,
7578c2ecf20Sopenharmony_ci			     sin_2phi_2, cos_2phi_2,
7588c2ecf20Sopenharmony_ci			     mag_a0_d0, phs_a0_d0,
7598c2ecf20Sopenharmony_ci			     mag_a1_d0,
7608c2ecf20Sopenharmony_ci			     phs_a1_d0, solved_eq)) {
7618c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
7628c2ecf20Sopenharmony_ci			"Call to ar9003_hw_solve_iq_cal() failed\n");
7638c2ecf20Sopenharmony_ci		return false;
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	mag_tx = solved_eq[0];
7678c2ecf20Sopenharmony_ci	phs_tx = solved_eq[1];
7688c2ecf20Sopenharmony_ci	mag_rx = solved_eq[2];
7698c2ecf20Sopenharmony_ci	phs_rx = solved_eq[3];
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE,
7728c2ecf20Sopenharmony_ci		"chain %d: mag mismatch=%d phase mismatch=%d\n",
7738c2ecf20Sopenharmony_ci		chain_idx, mag_tx/res_scale, phs_tx/res_scale);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (res_scale == mag_tx) {
7768c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
7778c2ecf20Sopenharmony_ci			"Divide by 0: mag_tx=%d, res_scale=%d\n",
7788c2ecf20Sopenharmony_ci			mag_tx, res_scale);
7798c2ecf20Sopenharmony_ci		return false;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	/* calculate and quantize Tx IQ correction factor */
7838c2ecf20Sopenharmony_ci	mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
7848c2ecf20Sopenharmony_ci	phs_corr_tx = -phs_tx;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	q_q_coff = (mag_corr_tx * 128 / res_scale);
7878c2ecf20Sopenharmony_ci	q_i_coff = (phs_corr_tx * 256 / res_scale);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE, "tx chain %d: mag corr=%d  phase corr=%d\n",
7908c2ecf20Sopenharmony_ci		chain_idx, q_q_coff, q_i_coff);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (q_i_coff < -63)
7938c2ecf20Sopenharmony_ci		q_i_coff = -63;
7948c2ecf20Sopenharmony_ci	if (q_i_coff > 63)
7958c2ecf20Sopenharmony_ci		q_i_coff = 63;
7968c2ecf20Sopenharmony_ci	if (q_q_coff < -63)
7978c2ecf20Sopenharmony_ci		q_q_coff = -63;
7988c2ecf20Sopenharmony_ci	if (q_q_coff > 63)
7998c2ecf20Sopenharmony_ci		q_q_coff = 63;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE, "tx chain %d: iq corr coeff=%x\n",
8048c2ecf20Sopenharmony_ci		chain_idx, iqc_coeff[0]);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	if (-mag_rx == res_scale) {
8078c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
8088c2ecf20Sopenharmony_ci			"Divide by 0: mag_rx=%d, res_scale=%d\n",
8098c2ecf20Sopenharmony_ci			mag_rx, res_scale);
8108c2ecf20Sopenharmony_ci		return false;
8118c2ecf20Sopenharmony_ci	}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	/* calculate and quantize Rx IQ correction factors */
8148c2ecf20Sopenharmony_ci	mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
8158c2ecf20Sopenharmony_ci	phs_corr_rx = -phs_rx;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	q_q_coff = (mag_corr_rx * 128 / res_scale);
8188c2ecf20Sopenharmony_ci	q_i_coff = (phs_corr_rx * 256 / res_scale);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE, "rx chain %d: mag corr=%d  phase corr=%d\n",
8218c2ecf20Sopenharmony_ci		chain_idx, q_q_coff, q_i_coff);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (q_i_coff < -63)
8248c2ecf20Sopenharmony_ci		q_i_coff = -63;
8258c2ecf20Sopenharmony_ci	if (q_i_coff > 63)
8268c2ecf20Sopenharmony_ci		q_i_coff = 63;
8278c2ecf20Sopenharmony_ci	if (q_q_coff < -63)
8288c2ecf20Sopenharmony_ci		q_q_coff = -63;
8298c2ecf20Sopenharmony_ci	if (q_q_coff > 63)
8308c2ecf20Sopenharmony_ci		q_q_coff = 63;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE, "rx chain %d: iq corr coeff=%x\n",
8358c2ecf20Sopenharmony_ci		chain_idx, iqc_coeff[1]);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return true;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic void ar9003_hw_detect_outlier(int mp_coeff[][MAXIQCAL],
8418c2ecf20Sopenharmony_ci				     int nmeasurement,
8428c2ecf20Sopenharmony_ci				     int max_delta)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	int mp_max = -64, max_idx = 0;
8458c2ecf20Sopenharmony_ci	int mp_min = 63, min_idx = 0;
8468c2ecf20Sopenharmony_ci	int mp_avg = 0, i, outlier_idx = 0, mp_count = 0;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* find min/max mismatch across all calibrated gains */
8498c2ecf20Sopenharmony_ci	for (i = 0; i < nmeasurement; i++) {
8508c2ecf20Sopenharmony_ci		if (mp_coeff[i][0] > mp_max) {
8518c2ecf20Sopenharmony_ci			mp_max = mp_coeff[i][0];
8528c2ecf20Sopenharmony_ci			max_idx = i;
8538c2ecf20Sopenharmony_ci		} else if (mp_coeff[i][0] < mp_min) {
8548c2ecf20Sopenharmony_ci			mp_min = mp_coeff[i][0];
8558c2ecf20Sopenharmony_ci			min_idx = i;
8568c2ecf20Sopenharmony_ci		}
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	/* find average (exclude max abs value) */
8608c2ecf20Sopenharmony_ci	for (i = 0; i < nmeasurement; i++) {
8618c2ecf20Sopenharmony_ci		if ((abs(mp_coeff[i][0]) < abs(mp_max)) ||
8628c2ecf20Sopenharmony_ci		    (abs(mp_coeff[i][0]) < abs(mp_min))) {
8638c2ecf20Sopenharmony_ci			mp_avg += mp_coeff[i][0];
8648c2ecf20Sopenharmony_ci			mp_count++;
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci	}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	/*
8698c2ecf20Sopenharmony_ci	 * finding mean magnitude/phase if possible, otherwise
8708c2ecf20Sopenharmony_ci	 * just use the last value as the mean
8718c2ecf20Sopenharmony_ci	 */
8728c2ecf20Sopenharmony_ci	if (mp_count)
8738c2ecf20Sopenharmony_ci		mp_avg /= mp_count;
8748c2ecf20Sopenharmony_ci	else
8758c2ecf20Sopenharmony_ci		mp_avg = mp_coeff[nmeasurement - 1][0];
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/* detect outlier */
8788c2ecf20Sopenharmony_ci	if (abs(mp_max - mp_min) > max_delta) {
8798c2ecf20Sopenharmony_ci		if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
8808c2ecf20Sopenharmony_ci			outlier_idx = max_idx;
8818c2ecf20Sopenharmony_ci		else
8828c2ecf20Sopenharmony_ci			outlier_idx = min_idx;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		mp_coeff[outlier_idx][0] = mp_avg;
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic void ar9003_hw_tx_iq_cal_outlier_detection(struct ath_hw *ah,
8898c2ecf20Sopenharmony_ci						  struct coeff *coeff,
8908c2ecf20Sopenharmony_ci						  bool is_reusable)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	int i, im, nmeasurement;
8938c2ecf20Sopenharmony_ci	int magnitude, phase;
8948c2ecf20Sopenharmony_ci	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
8958c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
8988c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
8998c2ecf20Sopenharmony_ci		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
9008c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
9018c2ecf20Sopenharmony_ci		if (!AR_SREV_9485(ah)) {
9028c2ecf20Sopenharmony_ci			tx_corr_coeff[i * 2][1] =
9038c2ecf20Sopenharmony_ci			tx_corr_coeff[(i * 2) + 1][1] =
9048c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci			tx_corr_coeff[i * 2][2] =
9078c2ecf20Sopenharmony_ci			tx_corr_coeff[(i * 2) + 1][2] =
9088c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
9098c2ecf20Sopenharmony_ci		}
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* Load the average of 2 passes */
9138c2ecf20Sopenharmony_ci	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
9148c2ecf20Sopenharmony_ci		if (!(ah->txchainmask & (1 << i)))
9158c2ecf20Sopenharmony_ci			continue;
9168c2ecf20Sopenharmony_ci		nmeasurement = REG_READ_FIELD(ah,
9178c2ecf20Sopenharmony_ci				AR_PHY_TX_IQCAL_STATUS_B0,
9188c2ecf20Sopenharmony_ci				AR_PHY_CALIBRATED_GAINS_0);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci		if (nmeasurement > MAX_MEASUREMENT)
9218c2ecf20Sopenharmony_ci			nmeasurement = MAX_MEASUREMENT;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		/*
9248c2ecf20Sopenharmony_ci		 * Skip normal outlier detection for AR9550.
9258c2ecf20Sopenharmony_ci		 */
9268c2ecf20Sopenharmony_ci		if (!AR_SREV_9550(ah)) {
9278c2ecf20Sopenharmony_ci			/* detect outlier only if nmeasurement > 1 */
9288c2ecf20Sopenharmony_ci			if (nmeasurement > 1) {
9298c2ecf20Sopenharmony_ci				/* Detect magnitude outlier */
9308c2ecf20Sopenharmony_ci				ar9003_hw_detect_outlier(coeff->mag_coeff[i],
9318c2ecf20Sopenharmony_ci							 nmeasurement,
9328c2ecf20Sopenharmony_ci							 MAX_MAG_DELTA);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci				/* Detect phase outlier */
9358c2ecf20Sopenharmony_ci				ar9003_hw_detect_outlier(coeff->phs_coeff[i],
9368c2ecf20Sopenharmony_ci							 nmeasurement,
9378c2ecf20Sopenharmony_ci							 MAX_PHS_DELTA);
9388c2ecf20Sopenharmony_ci			}
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		for (im = 0; im < nmeasurement; im++) {
9428c2ecf20Sopenharmony_ci			magnitude = coeff->mag_coeff[i][im][0];
9438c2ecf20Sopenharmony_ci			phase = coeff->phs_coeff[i][im][0];
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci			coeff->iqc_coeff[0] =
9468c2ecf20Sopenharmony_ci				(phase & 0x7f) | ((magnitude & 0x7f) << 7);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci			if ((im % 2) == 0)
9498c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
9508c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
9518c2ecf20Sopenharmony_ci					coeff->iqc_coeff[0]);
9528c2ecf20Sopenharmony_ci			else
9538c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
9548c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
9558c2ecf20Sopenharmony_ci					coeff->iqc_coeff[0]);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci			if (caldata)
9588c2ecf20Sopenharmony_ci				caldata->tx_corr_coeff[im][i] =
9598c2ecf20Sopenharmony_ci					coeff->iqc_coeff[0];
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci		if (caldata)
9628c2ecf20Sopenharmony_ci			caldata->num_measures[i] = nmeasurement;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
9668c2ecf20Sopenharmony_ci		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
9678c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
9688c2ecf20Sopenharmony_ci		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	if (caldata) {
9718c2ecf20Sopenharmony_ci		if (is_reusable)
9728c2ecf20Sopenharmony_ci			set_bit(TXIQCAL_DONE, &caldata->cal_flags);
9738c2ecf20Sopenharmony_ci		else
9748c2ecf20Sopenharmony_ci			clear_bit(TXIQCAL_DONE, &caldata->cal_flags);
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	return;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cistatic bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
9838c2ecf20Sopenharmony_ci	u8 tx_gain_forced;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
9868c2ecf20Sopenharmony_ci					AR_PHY_TXGAIN_FORCE);
9878c2ecf20Sopenharmony_ci	if (tx_gain_forced)
9888c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
9898c2ecf20Sopenharmony_ci			      AR_PHY_TXGAIN_FORCE, 0);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
9928c2ecf20Sopenharmony_ci		      AR_PHY_TX_IQCAL_START_DO_CAL, 1);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
9958c2ecf20Sopenharmony_ci			AR_PHY_TX_IQCAL_START_DO_CAL, 0,
9968c2ecf20Sopenharmony_ci			AH_WAIT_TIMEOUT)) {
9978c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE, "Tx IQ Cal is not completed\n");
9988c2ecf20Sopenharmony_ci		return false;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci	return true;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic void __ar955x_tx_iq_cal_sort(struct ath_hw *ah,
10048c2ecf20Sopenharmony_ci				    struct coeff *coeff,
10058c2ecf20Sopenharmony_ci				    int i, int nmeasurement)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
10088c2ecf20Sopenharmony_ci	int im, ix, iy, temp;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	for (im = 0; im < nmeasurement; im++) {
10118c2ecf20Sopenharmony_ci		for (ix = 0; ix < MAXIQCAL - 1; ix++) {
10128c2ecf20Sopenharmony_ci			for (iy = ix + 1; iy <= MAXIQCAL - 1; iy++) {
10138c2ecf20Sopenharmony_ci				if (coeff->mag_coeff[i][im][iy] <
10148c2ecf20Sopenharmony_ci				    coeff->mag_coeff[i][im][ix]) {
10158c2ecf20Sopenharmony_ci					temp = coeff->mag_coeff[i][im][ix];
10168c2ecf20Sopenharmony_ci					coeff->mag_coeff[i][im][ix] =
10178c2ecf20Sopenharmony_ci						coeff->mag_coeff[i][im][iy];
10188c2ecf20Sopenharmony_ci					coeff->mag_coeff[i][im][iy] = temp;
10198c2ecf20Sopenharmony_ci				}
10208c2ecf20Sopenharmony_ci				if (coeff->phs_coeff[i][im][iy] <
10218c2ecf20Sopenharmony_ci				    coeff->phs_coeff[i][im][ix]) {
10228c2ecf20Sopenharmony_ci					temp = coeff->phs_coeff[i][im][ix];
10238c2ecf20Sopenharmony_ci					coeff->phs_coeff[i][im][ix] =
10248c2ecf20Sopenharmony_ci						coeff->phs_coeff[i][im][iy];
10258c2ecf20Sopenharmony_ci					coeff->phs_coeff[i][im][iy] = temp;
10268c2ecf20Sopenharmony_ci				}
10278c2ecf20Sopenharmony_ci			}
10288c2ecf20Sopenharmony_ci		}
10298c2ecf20Sopenharmony_ci		coeff->mag_coeff[i][im][0] = coeff->mag_coeff[i][im][MAXIQCAL / 2];
10308c2ecf20Sopenharmony_ci		coeff->phs_coeff[i][im][0] = coeff->phs_coeff[i][im][MAXIQCAL / 2];
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
10338c2ecf20Sopenharmony_ci			"IQCAL: Median [ch%d][gain%d]: mag = %d phase = %d\n",
10348c2ecf20Sopenharmony_ci			i, im,
10358c2ecf20Sopenharmony_ci			coeff->mag_coeff[i][im][0],
10368c2ecf20Sopenharmony_ci			coeff->phs_coeff[i][im][0]);
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic bool ar955x_tx_iq_cal_median(struct ath_hw *ah,
10418c2ecf20Sopenharmony_ci				    struct coeff *coeff,
10428c2ecf20Sopenharmony_ci				    int iqcal_idx,
10438c2ecf20Sopenharmony_ci				    int nmeasurement)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	int i;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	if ((iqcal_idx + 1) != MAXIQCAL)
10488c2ecf20Sopenharmony_ci		return false;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
10518c2ecf20Sopenharmony_ci		__ar955x_tx_iq_cal_sort(ah, coeff, i, nmeasurement);
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	return true;
10558c2ecf20Sopenharmony_ci}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_cistatic void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah,
10588c2ecf20Sopenharmony_ci					  int iqcal_idx,
10598c2ecf20Sopenharmony_ci					  bool is_reusable)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
10628c2ecf20Sopenharmony_ci	const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
10638c2ecf20Sopenharmony_ci		AR_PHY_TX_IQCAL_STATUS_B0,
10648c2ecf20Sopenharmony_ci		AR_PHY_TX_IQCAL_STATUS_B1,
10658c2ecf20Sopenharmony_ci		AR_PHY_TX_IQCAL_STATUS_B2,
10668c2ecf20Sopenharmony_ci	};
10678c2ecf20Sopenharmony_ci	const u_int32_t chan_info_tab[] = {
10688c2ecf20Sopenharmony_ci		AR_PHY_CHAN_INFO_TAB_0,
10698c2ecf20Sopenharmony_ci		AR_PHY_CHAN_INFO_TAB_1,
10708c2ecf20Sopenharmony_ci		AR_PHY_CHAN_INFO_TAB_2,
10718c2ecf20Sopenharmony_ci	};
10728c2ecf20Sopenharmony_ci	static struct coeff coeff;
10738c2ecf20Sopenharmony_ci	s32 iq_res[6];
10748c2ecf20Sopenharmony_ci	int i, im, j;
10758c2ecf20Sopenharmony_ci	int nmeasurement = 0;
10768c2ecf20Sopenharmony_ci	bool outlier_detect = true;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
10798c2ecf20Sopenharmony_ci		if (!(ah->txchainmask & (1 << i)))
10808c2ecf20Sopenharmony_ci			continue;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		nmeasurement = REG_READ_FIELD(ah,
10838c2ecf20Sopenharmony_ci				AR_PHY_TX_IQCAL_STATUS_B0,
10848c2ecf20Sopenharmony_ci				AR_PHY_CALIBRATED_GAINS_0);
10858c2ecf20Sopenharmony_ci		if (nmeasurement > MAX_MEASUREMENT)
10868c2ecf20Sopenharmony_ci			nmeasurement = MAX_MEASUREMENT;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci		for (im = 0; im < nmeasurement; im++) {
10898c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE,
10908c2ecf20Sopenharmony_ci				"Doing Tx IQ Cal for chain %d\n", i);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci			if (REG_READ(ah, txiqcal_status[i]) &
10938c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_STATUS_FAILED) {
10948c2ecf20Sopenharmony_ci				ath_dbg(common, CALIBRATE,
10958c2ecf20Sopenharmony_ci					"Tx IQ Cal failed for chain %d\n", i);
10968c2ecf20Sopenharmony_ci				goto tx_iqcal_fail;
10978c2ecf20Sopenharmony_ci			}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci			for (j = 0; j < 3; j++) {
11008c2ecf20Sopenharmony_ci				u32 idx = 2 * j, offset = 4 * (3 * im + j);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah,
11038c2ecf20Sopenharmony_ci						AR_PHY_CHAN_INFO_MEMORY,
11048c2ecf20Sopenharmony_ci						AR_PHY_CHAN_INFO_TAB_S2_READ,
11058c2ecf20Sopenharmony_ci						0);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci				/* 32 bits */
11088c2ecf20Sopenharmony_ci				iq_res[idx] = REG_READ(ah,
11098c2ecf20Sopenharmony_ci						chan_info_tab[i] +
11108c2ecf20Sopenharmony_ci						offset);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah,
11138c2ecf20Sopenharmony_ci						AR_PHY_CHAN_INFO_MEMORY,
11148c2ecf20Sopenharmony_ci						AR_PHY_CHAN_INFO_TAB_S2_READ,
11158c2ecf20Sopenharmony_ci						1);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci				/* 16 bits */
11188c2ecf20Sopenharmony_ci				iq_res[idx + 1] = 0xffff & REG_READ(ah,
11198c2ecf20Sopenharmony_ci						chan_info_tab[i] + offset);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci				ath_dbg(common, CALIBRATE,
11228c2ecf20Sopenharmony_ci					"IQ_RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
11238c2ecf20Sopenharmony_ci					idx, iq_res[idx], idx + 1,
11248c2ecf20Sopenharmony_ci					iq_res[idx + 1]);
11258c2ecf20Sopenharmony_ci			}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci			if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
11288c2ecf20Sopenharmony_ci						coeff.iqc_coeff)) {
11298c2ecf20Sopenharmony_ci				ath_dbg(common, CALIBRATE,
11308c2ecf20Sopenharmony_ci					"Failed in calculation of IQ correction\n");
11318c2ecf20Sopenharmony_ci				goto tx_iqcal_fail;
11328c2ecf20Sopenharmony_ci			}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci			coeff.phs_coeff[i][im][iqcal_idx] =
11358c2ecf20Sopenharmony_ci				coeff.iqc_coeff[0] & 0x7f;
11368c2ecf20Sopenharmony_ci			coeff.mag_coeff[i][im][iqcal_idx] =
11378c2ecf20Sopenharmony_ci				(coeff.iqc_coeff[0] >> 7) & 0x7f;
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci			if (coeff.mag_coeff[i][im][iqcal_idx] > 63)
11408c2ecf20Sopenharmony_ci				coeff.mag_coeff[i][im][iqcal_idx] -= 128;
11418c2ecf20Sopenharmony_ci			if (coeff.phs_coeff[i][im][iqcal_idx] > 63)
11428c2ecf20Sopenharmony_ci				coeff.phs_coeff[i][im][iqcal_idx] -= 128;
11438c2ecf20Sopenharmony_ci		}
11448c2ecf20Sopenharmony_ci	}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (AR_SREV_9550(ah))
11478c2ecf20Sopenharmony_ci		outlier_detect = ar955x_tx_iq_cal_median(ah, &coeff,
11488c2ecf20Sopenharmony_ci							 iqcal_idx, nmeasurement);
11498c2ecf20Sopenharmony_ci	if (outlier_detect)
11508c2ecf20Sopenharmony_ci		ar9003_hw_tx_iq_cal_outlier_detection(ah, &coeff, is_reusable);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	return;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_citx_iqcal_fail:
11558c2ecf20Sopenharmony_ci	ath_dbg(common, CALIBRATE, "Tx IQ Cal failed\n");
11568c2ecf20Sopenharmony_ci	return;
11578c2ecf20Sopenharmony_ci}
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_cistatic void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
11628c2ecf20Sopenharmony_ci	u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
11638c2ecf20Sopenharmony_ci	int i, im;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
11668c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_MEASUREMENT / 2; i++) {
11678c2ecf20Sopenharmony_ci		tx_corr_coeff[i * 2][0] = tx_corr_coeff[(i * 2) + 1][0] =
11688c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B0(i);
11698c2ecf20Sopenharmony_ci		if (!AR_SREV_9485(ah)) {
11708c2ecf20Sopenharmony_ci			tx_corr_coeff[i * 2][1] =
11718c2ecf20Sopenharmony_ci			tx_corr_coeff[(i * 2) + 1][1] =
11728c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B1(i);
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci			tx_corr_coeff[i * 2][2] =
11758c2ecf20Sopenharmony_ci			tx_corr_coeff[(i * 2) + 1][2] =
11768c2ecf20Sopenharmony_ci					AR_PHY_TX_IQCAL_CORR_COEFF_B2(i);
11778c2ecf20Sopenharmony_ci		}
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
11818c2ecf20Sopenharmony_ci		if (!(ah->txchainmask & (1 << i)))
11828c2ecf20Sopenharmony_ci			continue;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci		for (im = 0; im < caldata->num_measures[i]; im++) {
11858c2ecf20Sopenharmony_ci			if ((im % 2) == 0)
11868c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
11878c2ecf20Sopenharmony_ci				     AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE,
11888c2ecf20Sopenharmony_ci				     caldata->tx_corr_coeff[im][i]);
11898c2ecf20Sopenharmony_ci			else
11908c2ecf20Sopenharmony_ci				REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
11918c2ecf20Sopenharmony_ci				     AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
11928c2ecf20Sopenharmony_ci				     caldata->tx_corr_coeff[im][i]);
11938c2ecf20Sopenharmony_ci		}
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
11978c2ecf20Sopenharmony_ci		      AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
11988c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
11998c2ecf20Sopenharmony_ci		      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	int offset[8] = {0}, total = 0, test;
12058c2ecf20Sopenharmony_ci	int agc_out, i, peak_detect_threshold = 0;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	if (AR_SREV_9550(ah) || AR_SREV_9531(ah))
12088c2ecf20Sopenharmony_ci		peak_detect_threshold = 8;
12098c2ecf20Sopenharmony_ci	else if (AR_SREV_9561(ah))
12108c2ecf20Sopenharmony_ci		peak_detect_threshold = 11;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	/*
12138c2ecf20Sopenharmony_ci	 * Turn off LNA/SW.
12148c2ecf20Sopenharmony_ci	 */
12158c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
12168c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
12178c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
12188c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) {
12218c2ecf20Sopenharmony_ci		if (is_2g)
12228c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
12238c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
12248c2ecf20Sopenharmony_ci		else
12258c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
12268c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
12278c2ecf20Sopenharmony_ci	}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/*
12308c2ecf20Sopenharmony_ci	 * Turn off RXON.
12318c2ecf20Sopenharmony_ci	 */
12328c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
12338c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
12348c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
12358c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXTX2_RXON, 0x0);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	/*
12388c2ecf20Sopenharmony_ci	 * Turn on AGC for cal.
12398c2ecf20Sopenharmony_ci	 */
12408c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12418c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
12428c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12438c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);
12448c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12458c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (AR_SREV_9330_11(ah))
12488c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12498c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if (is_2g)
12528c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12538c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
12548c2ecf20Sopenharmony_ci			      peak_detect_threshold);
12558c2ecf20Sopenharmony_ci	else
12568c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12578c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
12588c2ecf20Sopenharmony_ci			      peak_detect_threshold);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	for (i = 6; i > 0; i--) {
12618c2ecf20Sopenharmony_ci		offset[i] = BIT(i - 1);
12628c2ecf20Sopenharmony_ci		test = total + offset[i];
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci		if (is_2g)
12658c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12668c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
12678c2ecf20Sopenharmony_ci				      test);
12688c2ecf20Sopenharmony_ci		else
12698c2ecf20Sopenharmony_ci			REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12708c2ecf20Sopenharmony_ci				      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
12718c2ecf20Sopenharmony_ci				      test);
12728c2ecf20Sopenharmony_ci		udelay(100);
12738c2ecf20Sopenharmony_ci		agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12748c2ecf20Sopenharmony_ci					 AR_PHY_65NM_RXRF_AGC_AGC_OUT);
12758c2ecf20Sopenharmony_ci		offset[i] = (agc_out) ? 0 : 1;
12768c2ecf20Sopenharmony_ci		total += (offset[i] << (i - 1));
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (is_2g)
12808c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12818c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total);
12828c2ecf20Sopenharmony_ci	else
12838c2ecf20Sopenharmony_ci		REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
12848c2ecf20Sopenharmony_ci			      AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	/*
12878c2ecf20Sopenharmony_ci	 * Turn on LNA.
12888c2ecf20Sopenharmony_ci	 */
12898c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
12908c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
12918c2ecf20Sopenharmony_ci	/*
12928c2ecf20Sopenharmony_ci	 * Turn off RXON.
12938c2ecf20Sopenharmony_ci	 */
12948c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
12958c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXTX2_RXON_OVR, 0);
12968c2ecf20Sopenharmony_ci	/*
12978c2ecf20Sopenharmony_ci	 * Turn off peak detect calibration.
12988c2ecf20Sopenharmony_ci	 */
12998c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
13008c2ecf20Sopenharmony_ci		      AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
13018c2ecf20Sopenharmony_ci}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_cistatic void ar9003_hw_do_pcoem_manual_peak_cal(struct ath_hw *ah,
13048c2ecf20Sopenharmony_ci					       struct ath9k_channel *chan,
13058c2ecf20Sopenharmony_ci					       bool run_rtt_cal)
13068c2ecf20Sopenharmony_ci{
13078c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
13088c2ecf20Sopenharmony_ci	int i;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)
13118c2ecf20Sopenharmony_ci		return;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	for (i = 0; i < AR9300_MAX_CHAINS; i++) {
13148c2ecf20Sopenharmony_ci		if (!(ah->rxchainmask & (1 << i)))
13158c2ecf20Sopenharmony_ci			continue;
13168c2ecf20Sopenharmony_ci		ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
13178c2ecf20Sopenharmony_ci	}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (caldata)
13208c2ecf20Sopenharmony_ci		set_bit(SW_PKDET_DONE, &caldata->cal_flags);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {
13238c2ecf20Sopenharmony_ci		if (IS_CHAN_2GHZ(chan)){
13248c2ecf20Sopenharmony_ci			caldata->caldac[0] = REG_READ_FIELD(ah,
13258c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC(0),
13268c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
13278c2ecf20Sopenharmony_ci			caldata->caldac[1] = REG_READ_FIELD(ah,
13288c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC(1),
13298c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
13308c2ecf20Sopenharmony_ci		} else {
13318c2ecf20Sopenharmony_ci			caldata->caldac[0] = REG_READ_FIELD(ah,
13328c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC(0),
13338c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
13348c2ecf20Sopenharmony_ci			caldata->caldac[1] = REG_READ_FIELD(ah,
13358c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC(1),
13368c2ecf20Sopenharmony_ci						    AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
13378c2ecf20Sopenharmony_ci		}
13388c2ecf20Sopenharmony_ci	}
13398c2ecf20Sopenharmony_ci}
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_cistatic void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
13428c2ecf20Sopenharmony_ci{
13438c2ecf20Sopenharmony_ci	u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0,
13448c2ecf20Sopenharmony_ci					  AR_PHY_CL_TAB_1,
13458c2ecf20Sopenharmony_ci					  AR_PHY_CL_TAB_2 };
13468c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
13478c2ecf20Sopenharmony_ci	bool txclcal_done = false;
13488c2ecf20Sopenharmony_ci	int i, j;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (!caldata || !(ah->enabled_cals & TX_CL_CAL))
13518c2ecf20Sopenharmony_ci		return;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
13548c2ecf20Sopenharmony_ci			  AR_PHY_AGC_CONTROL_CLC_SUCCESS);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) {
13578c2ecf20Sopenharmony_ci		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
13588c2ecf20Sopenharmony_ci			if (!(ah->txchainmask & (1 << i)))
13598c2ecf20Sopenharmony_ci				continue;
13608c2ecf20Sopenharmony_ci			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
13618c2ecf20Sopenharmony_ci				REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]),
13628c2ecf20Sopenharmony_ci					  caldata->tx_clcal[i][j]);
13638c2ecf20Sopenharmony_ci		}
13648c2ecf20Sopenharmony_ci	} else if (is_reusable && txclcal_done) {
13658c2ecf20Sopenharmony_ci		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
13668c2ecf20Sopenharmony_ci			if (!(ah->txchainmask & (1 << i)))
13678c2ecf20Sopenharmony_ci				continue;
13688c2ecf20Sopenharmony_ci			for (j = 0; j < MAX_CL_TAB_ENTRY; j++)
13698c2ecf20Sopenharmony_ci				caldata->tx_clcal[i][j] =
13708c2ecf20Sopenharmony_ci					REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
13718c2ecf20Sopenharmony_ci		}
13728c2ecf20Sopenharmony_ci		set_bit(TXCLCAL_DONE, &caldata->cal_flags);
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_cistatic void ar9003_hw_init_cal_common(struct ath_hw *ah)
13778c2ecf20Sopenharmony_ci{
13788c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	/* Initialize list pointers */
13818c2ecf20Sopenharmony_ci	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	INIT_CAL(&ah->iq_caldata);
13848c2ecf20Sopenharmony_ci	INSERT_CAL(ah, &ah->iq_caldata);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	/* Initialize current pointer to first element in list */
13878c2ecf20Sopenharmony_ci	ah->cal_list_curr = ah->cal_list;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	if (ah->cal_list_curr)
13908c2ecf20Sopenharmony_ci		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	if (caldata)
13938c2ecf20Sopenharmony_ci		caldata->CalValid = 0;
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_cistatic bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah,
13978c2ecf20Sopenharmony_ci				     struct ath9k_channel *chan)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
14008c2ecf20Sopenharmony_ci	struct ath9k_hw_cal_data *caldata = ah->caldata;
14018c2ecf20Sopenharmony_ci	bool txiqcal_done = false;
14028c2ecf20Sopenharmony_ci	bool is_reusable = true, status = true;
14038c2ecf20Sopenharmony_ci	bool run_rtt_cal = false, run_agc_cal;
14048c2ecf20Sopenharmony_ci	bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
14058c2ecf20Sopenharmony_ci	u32 rx_delay = 0;
14068c2ecf20Sopenharmony_ci	u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
14078c2ecf20Sopenharmony_ci					  AR_PHY_AGC_CONTROL_FLTR_CAL   |
14088c2ecf20Sopenharmony_ci					  AR_PHY_AGC_CONTROL_PKDET_CAL;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* Use chip chainmask only for calibration */
14118c2ecf20Sopenharmony_ci	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	if (rtt) {
14148c2ecf20Sopenharmony_ci		if (!ar9003_hw_rtt_restore(ah, chan))
14158c2ecf20Sopenharmony_ci			run_rtt_cal = true;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci		if (run_rtt_cal)
14188c2ecf20Sopenharmony_ci			ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");
14198c2ecf20Sopenharmony_ci	}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	run_agc_cal = run_rtt_cal;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (run_rtt_cal) {
14248c2ecf20Sopenharmony_ci		ar9003_hw_rtt_enable(ah);
14258c2ecf20Sopenharmony_ci		ar9003_hw_rtt_set_mask(ah, 0x00);
14268c2ecf20Sopenharmony_ci		ar9003_hw_rtt_clear_hist(ah);
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	if (rtt) {
14308c2ecf20Sopenharmony_ci		if (!run_rtt_cal) {
14318c2ecf20Sopenharmony_ci			agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
14328c2ecf20Sopenharmony_ci			agc_supp_cals &= agc_ctrl;
14338c2ecf20Sopenharmony_ci			agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
14348c2ecf20Sopenharmony_ci				      AR_PHY_AGC_CONTROL_FLTR_CAL |
14358c2ecf20Sopenharmony_ci				      AR_PHY_AGC_CONTROL_PKDET_CAL);
14368c2ecf20Sopenharmony_ci			REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
14378c2ecf20Sopenharmony_ci		} else {
14388c2ecf20Sopenharmony_ci			if (ah->ah_flags & AH_FASTCC)
14398c2ecf20Sopenharmony_ci				run_agc_cal = true;
14408c2ecf20Sopenharmony_ci		}
14418c2ecf20Sopenharmony_ci	}
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if (ah->enabled_cals & TX_CL_CAL) {
14448c2ecf20Sopenharmony_ci		if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags))
14458c2ecf20Sopenharmony_ci			REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
14468c2ecf20Sopenharmony_ci				    AR_PHY_CL_CAL_ENABLE);
14478c2ecf20Sopenharmony_ci		else {
14488c2ecf20Sopenharmony_ci			REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL,
14498c2ecf20Sopenharmony_ci				    AR_PHY_CL_CAL_ENABLE);
14508c2ecf20Sopenharmony_ci			run_agc_cal = true;
14518c2ecf20Sopenharmony_ci		}
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	if ((IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ||
14558c2ecf20Sopenharmony_ci	    !(ah->enabled_cals & TX_IQ_CAL))
14568c2ecf20Sopenharmony_ci		goto skip_tx_iqcal;
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	/* Do Tx IQ Calibration */
14598c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
14608c2ecf20Sopenharmony_ci		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
14618c2ecf20Sopenharmony_ci		      DELPT);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/*
14648c2ecf20Sopenharmony_ci	 * For AR9485 or later chips, TxIQ cal runs as part of
14658c2ecf20Sopenharmony_ci	 * AGC calibration
14668c2ecf20Sopenharmony_ci	 */
14678c2ecf20Sopenharmony_ci	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
14688c2ecf20Sopenharmony_ci		if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags))
14698c2ecf20Sopenharmony_ci			REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
14708c2ecf20Sopenharmony_ci				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
14718c2ecf20Sopenharmony_ci		else
14728c2ecf20Sopenharmony_ci			REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
14738c2ecf20Sopenharmony_ci				    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
14748c2ecf20Sopenharmony_ci		txiqcal_done = run_agc_cal = true;
14758c2ecf20Sopenharmony_ci	}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ciskip_tx_iqcal:
14788c2ecf20Sopenharmony_ci	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
14798c2ecf20Sopenharmony_ci		ar9003_mci_init_cal_req(ah, &is_reusable);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
14828c2ecf20Sopenharmony_ci		rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);
14838c2ecf20Sopenharmony_ci		/* Disable BB_active */
14848c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
14858c2ecf20Sopenharmony_ci		udelay(5);
14868c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY);
14878c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
14888c2ecf20Sopenharmony_ci	}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
14918c2ecf20Sopenharmony_ci		/* Calibrate the AGC */
14928c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
14938c2ecf20Sopenharmony_ci			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
14948c2ecf20Sopenharmony_ci			  AR_PHY_AGC_CONTROL_CAL);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci		/* Poll for offset calibration complete */
14978c2ecf20Sopenharmony_ci		status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
14988c2ecf20Sopenharmony_ci				       AR_PHY_AGC_CONTROL_CAL,
14998c2ecf20Sopenharmony_ci				       0, AH_WAIT_TIMEOUT);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci		ar9003_hw_do_pcoem_manual_peak_cal(ah, chan, run_rtt_cal);
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
15058c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay);
15068c2ecf20Sopenharmony_ci		udelay(5);
15078c2ecf20Sopenharmony_ci	}
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
15108c2ecf20Sopenharmony_ci		ar9003_mci_init_cal_done(ah);
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	if (rtt && !run_rtt_cal) {
15138c2ecf20Sopenharmony_ci		agc_ctrl |= agc_supp_cals;
15148c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
15158c2ecf20Sopenharmony_ci	}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	if (!status) {
15188c2ecf20Sopenharmony_ci		if (run_rtt_cal)
15198c2ecf20Sopenharmony_ci			ar9003_hw_rtt_disable(ah);
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
15228c2ecf20Sopenharmony_ci			"offset calibration failed to complete in %d ms; noisy environment?\n",
15238c2ecf20Sopenharmony_ci			AH_WAIT_TIMEOUT / 1000);
15248c2ecf20Sopenharmony_ci		return false;
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if (txiqcal_done)
15288c2ecf20Sopenharmony_ci		ar9003_hw_tx_iq_cal_post_proc(ah, 0, is_reusable);
15298c2ecf20Sopenharmony_ci	else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
15308c2ecf20Sopenharmony_ci		ar9003_hw_tx_iq_cal_reload(ah);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	ar9003_hw_cl_cal_post_proc(ah, is_reusable);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	if (run_rtt_cal && caldata) {
15358c2ecf20Sopenharmony_ci		if (is_reusable) {
15368c2ecf20Sopenharmony_ci			if (!ath9k_hw_rfbus_req(ah)) {
15378c2ecf20Sopenharmony_ci				ath_err(ath9k_hw_common(ah),
15388c2ecf20Sopenharmony_ci					"Could not stop baseband\n");
15398c2ecf20Sopenharmony_ci			} else {
15408c2ecf20Sopenharmony_ci				ar9003_hw_rtt_fill_hist(ah);
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci				if (test_bit(SW_PKDET_DONE, &caldata->cal_flags))
15438c2ecf20Sopenharmony_ci					ar9003_hw_rtt_load_hist(ah);
15448c2ecf20Sopenharmony_ci			}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci			ath9k_hw_rfbus_done(ah);
15478c2ecf20Sopenharmony_ci		}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci		ar9003_hw_rtt_disable(ah);
15508c2ecf20Sopenharmony_ci	}
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	/* Revert chainmask to runtime parameters */
15538c2ecf20Sopenharmony_ci	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	ar9003_hw_init_cal_common(ah);
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	return true;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic bool do_ar9003_agc_cal(struct ath_hw *ah)
15618c2ecf20Sopenharmony_ci{
15628c2ecf20Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
15638c2ecf20Sopenharmony_ci	bool status;
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
15668c2ecf20Sopenharmony_ci		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
15678c2ecf20Sopenharmony_ci		  AR_PHY_AGC_CONTROL_CAL);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
15708c2ecf20Sopenharmony_ci			       AR_PHY_AGC_CONTROL_CAL,
15718c2ecf20Sopenharmony_ci			       0, AH_WAIT_TIMEOUT);
15728c2ecf20Sopenharmony_ci	if (!status) {
15738c2ecf20Sopenharmony_ci		ath_dbg(common, CALIBRATE,
15748c2ecf20Sopenharmony_ci			"offset calibration failed to complete in %d ms,"
15758c2ecf20Sopenharmony_ci			"noisy environment?\n",
15768c2ecf20Sopenharmony_ci			AH_WAIT_TIMEOUT / 1000);
15778c2ecf20Sopenharmony_ci		return false;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	return true;
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistatic bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
15848c2ecf20Sopenharmony_ci				   struct ath9k_channel *chan)
15858c2ecf20Sopenharmony_ci{
15868c2ecf20Sopenharmony_ci	bool txiqcal_done = false;
15878c2ecf20Sopenharmony_ci	bool status = true;
15888c2ecf20Sopenharmony_ci	bool run_agc_cal = false, sep_iq_cal = false;
15898c2ecf20Sopenharmony_ci	int i = 0;
15908c2ecf20Sopenharmony_ci
15918c2ecf20Sopenharmony_ci	/* Use chip chainmask only for calibration */
15928c2ecf20Sopenharmony_ci	ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	if (ah->enabled_cals & TX_CL_CAL) {
15958c2ecf20Sopenharmony_ci		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
15968c2ecf20Sopenharmony_ci		run_agc_cal = true;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
16008c2ecf20Sopenharmony_ci		goto skip_tx_iqcal;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	/* Do Tx IQ Calibration */
16038c2ecf20Sopenharmony_ci	REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
16048c2ecf20Sopenharmony_ci		      AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
16058c2ecf20Sopenharmony_ci		      DELPT);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	/*
16088c2ecf20Sopenharmony_ci	 * For AR9485 or later chips, TxIQ cal runs as part of
16098c2ecf20Sopenharmony_ci	 * AGC calibration. Specifically, AR9550 in SoC chips.
16108c2ecf20Sopenharmony_ci	 */
16118c2ecf20Sopenharmony_ci	if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
16128c2ecf20Sopenharmony_ci		if (REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0,
16138c2ecf20Sopenharmony_ci				   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)) {
16148c2ecf20Sopenharmony_ci				txiqcal_done = true;
16158c2ecf20Sopenharmony_ci		} else {
16168c2ecf20Sopenharmony_ci			txiqcal_done = false;
16178c2ecf20Sopenharmony_ci		}
16188c2ecf20Sopenharmony_ci		run_agc_cal = true;
16198c2ecf20Sopenharmony_ci	} else {
16208c2ecf20Sopenharmony_ci		sep_iq_cal = true;
16218c2ecf20Sopenharmony_ci		run_agc_cal = true;
16228c2ecf20Sopenharmony_ci	}
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	/*
16258c2ecf20Sopenharmony_ci	 * In the SoC family, this will run for AR9300, AR9331 and AR9340.
16268c2ecf20Sopenharmony_ci	 */
16278c2ecf20Sopenharmony_ci	if (sep_iq_cal) {
16288c2ecf20Sopenharmony_ci		txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
16298c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
16308c2ecf20Sopenharmony_ci		udelay(5);
16318c2ecf20Sopenharmony_ci		REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
16328c2ecf20Sopenharmony_ci	}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) {
16358c2ecf20Sopenharmony_ci		if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done))
16368c2ecf20Sopenharmony_ci			return false;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ciskip_tx_iqcal:
16408c2ecf20Sopenharmony_ci	if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
16418c2ecf20Sopenharmony_ci		for (i = 0; i < AR9300_MAX_CHAINS; i++) {
16428c2ecf20Sopenharmony_ci			if (!(ah->rxchainmask & (1 << i)))
16438c2ecf20Sopenharmony_ci				continue;
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci			ar9003_hw_manual_peak_cal(ah, i,
16468c2ecf20Sopenharmony_ci						  IS_CHAN_2GHZ(chan));
16478c2ecf20Sopenharmony_ci		}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		/*
16508c2ecf20Sopenharmony_ci		 * For non-AR9550 chips, we just trigger AGC calibration
16518c2ecf20Sopenharmony_ci		 * in the HW, poll for completion and then process
16528c2ecf20Sopenharmony_ci		 * the results.
16538c2ecf20Sopenharmony_ci		 *
16548c2ecf20Sopenharmony_ci		 * For AR955x, we run it multiple times and use
16558c2ecf20Sopenharmony_ci		 * median IQ correction.
16568c2ecf20Sopenharmony_ci		 */
16578c2ecf20Sopenharmony_ci		if (!AR_SREV_9550(ah)) {
16588c2ecf20Sopenharmony_ci			status = do_ar9003_agc_cal(ah);
16598c2ecf20Sopenharmony_ci			if (!status)
16608c2ecf20Sopenharmony_ci				return false;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci			if (txiqcal_done)
16638c2ecf20Sopenharmony_ci				ar9003_hw_tx_iq_cal_post_proc(ah, 0, false);
16648c2ecf20Sopenharmony_ci		} else {
16658c2ecf20Sopenharmony_ci			if (!txiqcal_done) {
16668c2ecf20Sopenharmony_ci				status = do_ar9003_agc_cal(ah);
16678c2ecf20Sopenharmony_ci				if (!status)
16688c2ecf20Sopenharmony_ci					return false;
16698c2ecf20Sopenharmony_ci			} else {
16708c2ecf20Sopenharmony_ci				for (i = 0; i < MAXIQCAL; i++) {
16718c2ecf20Sopenharmony_ci					status = do_ar9003_agc_cal(ah);
16728c2ecf20Sopenharmony_ci					if (!status)
16738c2ecf20Sopenharmony_ci						return false;
16748c2ecf20Sopenharmony_ci					ar9003_hw_tx_iq_cal_post_proc(ah, i, false);
16758c2ecf20Sopenharmony_ci				}
16768c2ecf20Sopenharmony_ci			}
16778c2ecf20Sopenharmony_ci		}
16788c2ecf20Sopenharmony_ci	}
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	/* Revert chainmask to runtime parameters */
16818c2ecf20Sopenharmony_ci	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	ar9003_hw_init_cal_common(ah);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	return true;
16868c2ecf20Sopenharmony_ci}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_civoid ar9003_hw_attach_calib_ops(struct ath_hw *ah)
16898c2ecf20Sopenharmony_ci{
16908c2ecf20Sopenharmony_ci	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
16918c2ecf20Sopenharmony_ci	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (AR_SREV_9003_PCOEM(ah))
16948c2ecf20Sopenharmony_ci		priv_ops->init_cal = ar9003_hw_init_cal_pcoem;
16958c2ecf20Sopenharmony_ci	else
16968c2ecf20Sopenharmony_ci		priv_ops->init_cal = ar9003_hw_init_cal_soc;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
16998c2ecf20Sopenharmony_ci	priv_ops->setup_calibration = ar9003_hw_setup_calibration;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	ops->calibrate = ar9003_hw_calibrate;
17028c2ecf20Sopenharmony_ci}
1703