cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ar9002_calib.c (30170B)


      1/*
      2 * Copyright (c) 2008-2011 Atheros Communications Inc.
      3 *
      4 * Permission to use, copy, modify, and/or distribute this software for any
      5 * purpose with or without fee is hereby granted, provided that the above
      6 * copyright notice and this permission notice appear in all copies.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16
     17#include "hw.h"
     18#include "hw-ops.h"
     19#include "ar9002_phy.h"
     20
     21#define AR9285_CLCAL_REDO_THRESH    1
     22/* AGC & I/Q calibrations time limit, ms */
     23#define AR9002_CAL_MAX_TIME		30000
     24
     25enum ar9002_cal_types {
     26	ADC_GAIN_CAL = BIT(0),
     27	ADC_DC_CAL = BIT(1),
     28	IQ_MISMATCH_CAL = BIT(2),
     29};
     30
     31static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
     32				struct ath9k_channel *chan,
     33				enum ar9002_cal_types cal_type)
     34{
     35	bool supported = false;
     36	switch (ah->supp_cals & cal_type) {
     37	case IQ_MISMATCH_CAL:
     38		supported = true;
     39		break;
     40	case ADC_GAIN_CAL:
     41	case ADC_DC_CAL:
     42		/* Run even/odd ADCs calibrations for HT40 channels only */
     43		if (IS_CHAN_HT40(chan))
     44			supported = true;
     45		break;
     46	}
     47	return supported;
     48}
     49
     50static void ar9002_hw_setup_calibration(struct ath_hw *ah,
     51					struct ath9k_cal_list *currCal)
     52{
     53	struct ath_common *common = ath9k_hw_common(ah);
     54
     55	REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
     56		      AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
     57		      currCal->calData->calCountMax);
     58
     59	switch (currCal->calData->calType) {
     60	case IQ_MISMATCH_CAL:
     61		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
     62		ath_dbg(common, CALIBRATE,
     63			"starting IQ Mismatch Calibration\n");
     64		break;
     65	case ADC_GAIN_CAL:
     66		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
     67		ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n");
     68		break;
     69	case ADC_DC_CAL:
     70		REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
     71		ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n");
     72		break;
     73	}
     74
     75	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
     76		    AR_PHY_TIMING_CTRL4_DO_CAL);
     77}
     78
     79static bool ar9002_hw_per_calibration(struct ath_hw *ah,
     80				      struct ath9k_channel *ichan,
     81				      u8 rxchainmask,
     82				      struct ath9k_cal_list *currCal)
     83{
     84	struct ath9k_hw_cal_data *caldata = ah->caldata;
     85	bool iscaldone = false;
     86
     87	if (currCal->calState == CAL_RUNNING) {
     88		if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
     89		      AR_PHY_TIMING_CTRL4_DO_CAL)) {
     90
     91			currCal->calData->calCollect(ah);
     92			ah->cal_samples++;
     93
     94			if (ah->cal_samples >=
     95			    currCal->calData->calNumSamples) {
     96				int i, numChains = 0;
     97				for (i = 0; i < AR5416_MAX_CHAINS; i++) {
     98					if (rxchainmask & (1 << i))
     99						numChains++;
    100				}
    101
    102				currCal->calData->calPostProc(ah, numChains);
    103				caldata->CalValid |= currCal->calData->calType;
    104				currCal->calState = CAL_DONE;
    105				iscaldone = true;
    106			} else {
    107				ar9002_hw_setup_calibration(ah, currCal);
    108			}
    109		} else if (time_after(jiffies, ah->cal_start_time +
    110				      msecs_to_jiffies(AR9002_CAL_MAX_TIME))) {
    111			REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0),
    112				    AR_PHY_TIMING_CTRL4_DO_CAL);
    113			ath_dbg(ath9k_hw_common(ah), CALIBRATE,
    114				"calibration timeout\n");
    115			currCal->calState = CAL_WAITING;	/* Try later */
    116			iscaldone = true;
    117		}
    118	} else if (!(caldata->CalValid & currCal->calData->calType)) {
    119		ath9k_hw_reset_calibration(ah, currCal);
    120	}
    121
    122	return iscaldone;
    123}
    124
    125static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
    126{
    127	int i;
    128
    129	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
    130		ah->totalPowerMeasI[i] +=
    131			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
    132		ah->totalPowerMeasQ[i] +=
    133			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
    134		ah->totalIqCorrMeas[i] +=
    135			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
    136		ath_dbg(ath9k_hw_common(ah), CALIBRATE,
    137			"%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
    138			ah->cal_samples, i, ah->totalPowerMeasI[i],
    139			ah->totalPowerMeasQ[i],
    140			ah->totalIqCorrMeas[i]);
    141	}
    142}
    143
    144static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
    145{
    146	int i;
    147
    148	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
    149		ah->totalAdcIOddPhase[i] +=
    150			REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
    151		ah->totalAdcIEvenPhase[i] +=
    152			REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
    153		ah->totalAdcQOddPhase[i] +=
    154			REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
    155		ah->totalAdcQEvenPhase[i] +=
    156			REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
    157
    158		ath_dbg(ath9k_hw_common(ah), CALIBRATE,
    159			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
    160			ah->cal_samples, i,
    161			ah->totalAdcIOddPhase[i],
    162			ah->totalAdcIEvenPhase[i],
    163			ah->totalAdcQOddPhase[i],
    164			ah->totalAdcQEvenPhase[i]);
    165	}
    166}
    167
    168static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
    169{
    170	int i;
    171
    172	for (i = 0; i < AR5416_MAX_CHAINS; i++) {
    173		ah->totalAdcDcOffsetIOddPhase[i] +=
    174			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
    175		ah->totalAdcDcOffsetIEvenPhase[i] +=
    176			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
    177		ah->totalAdcDcOffsetQOddPhase[i] +=
    178			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
    179		ah->totalAdcDcOffsetQEvenPhase[i] +=
    180			(int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
    181
    182		ath_dbg(ath9k_hw_common(ah), CALIBRATE,
    183			"%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n",
    184			ah->cal_samples, i,
    185			ah->totalAdcDcOffsetIOddPhase[i],
    186			ah->totalAdcDcOffsetIEvenPhase[i],
    187			ah->totalAdcDcOffsetQOddPhase[i],
    188			ah->totalAdcDcOffsetQEvenPhase[i]);
    189	}
    190}
    191
    192static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
    193{
    194	struct ath_common *common = ath9k_hw_common(ah);
    195	u32 powerMeasQ, powerMeasI, iqCorrMeas;
    196	u32 qCoffDenom, iCoffDenom;
    197	int32_t qCoff, iCoff;
    198	int iqCorrNeg, i;
    199
    200	for (i = 0; i < numChains; i++) {
    201		powerMeasI = ah->totalPowerMeasI[i];
    202		powerMeasQ = ah->totalPowerMeasQ[i];
    203		iqCorrMeas = ah->totalIqCorrMeas[i];
    204
    205		ath_dbg(common, CALIBRATE,
    206			"Starting IQ Cal and Correction for Chain %d\n",
    207			i);
    208
    209		ath_dbg(common, CALIBRATE,
    210			"Original: Chn %d iq_corr_meas = 0x%08x\n",
    211			i, ah->totalIqCorrMeas[i]);
    212
    213		iqCorrNeg = 0;
    214
    215		if (iqCorrMeas > 0x80000000) {
    216			iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
    217			iqCorrNeg = 1;
    218		}
    219
    220		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n",
    221			i, powerMeasI);
    222		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n",
    223			i, powerMeasQ);
    224		ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg);
    225
    226		iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
    227		qCoffDenom = powerMeasQ / 64;
    228
    229		if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
    230		    (qCoffDenom != 0)) {
    231			iCoff = iqCorrMeas / iCoffDenom;
    232			qCoff = powerMeasI / qCoffDenom - 64;
    233			ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n",
    234				i, iCoff);
    235			ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n",
    236				i, qCoff);
    237
    238			iCoff = iCoff & 0x3f;
    239			ath_dbg(common, CALIBRATE,
    240				"New: Chn %d iCoff = 0x%08x\n", i, iCoff);
    241			if (iqCorrNeg == 0x0)
    242				iCoff = 0x40 - iCoff;
    243
    244			if (qCoff > 15)
    245				qCoff = 15;
    246			else if (qCoff <= -16)
    247				qCoff = -16;
    248
    249			ath_dbg(common, CALIBRATE,
    250				"Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
    251				i, iCoff, qCoff);
    252
    253			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
    254				      AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
    255				      iCoff);
    256			REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
    257				      AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
    258				      qCoff);
    259			ath_dbg(common, CALIBRATE,
    260				"IQ Cal and Correction done for Chain %d\n",
    261				i);
    262		}
    263	}
    264
    265	REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
    266		    AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
    267}
    268
    269static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
    270{
    271	struct ath_common *common = ath9k_hw_common(ah);
    272	u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
    273	u32 qGainMismatch, iGainMismatch, val, i;
    274
    275	for (i = 0; i < numChains; i++) {
    276		iOddMeasOffset = ah->totalAdcIOddPhase[i];
    277		iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
    278		qOddMeasOffset = ah->totalAdcQOddPhase[i];
    279		qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
    280
    281		ath_dbg(common, CALIBRATE,
    282			"Starting ADC Gain Cal for Chain %d\n", i);
    283
    284		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n",
    285			i, iOddMeasOffset);
    286		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n",
    287			i, iEvenMeasOffset);
    288		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n",
    289			i, qOddMeasOffset);
    290		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n",
    291			i, qEvenMeasOffset);
    292
    293		if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
    294			iGainMismatch =
    295				((iEvenMeasOffset * 32) /
    296				 iOddMeasOffset) & 0x3f;
    297			qGainMismatch =
    298				((qOddMeasOffset * 32) /
    299				 qEvenMeasOffset) & 0x3f;
    300
    301			ath_dbg(common, CALIBRATE,
    302				"Chn %d gain_mismatch_i = 0x%08x\n",
    303				i, iGainMismatch);
    304			ath_dbg(common, CALIBRATE,
    305				"Chn %d gain_mismatch_q = 0x%08x\n",
    306				i, qGainMismatch);
    307
    308			val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
    309			val &= 0xfffff000;
    310			val |= (qGainMismatch) | (iGainMismatch << 6);
    311			REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
    312
    313			ath_dbg(common, CALIBRATE,
    314				"ADC Gain Cal done for Chain %d\n", i);
    315		}
    316	}
    317
    318	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
    319		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
    320		  AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
    321}
    322
    323static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
    324{
    325	struct ath_common *common = ath9k_hw_common(ah);
    326	u32 iOddMeasOffset, iEvenMeasOffset, val, i;
    327	int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
    328	const struct ath9k_percal_data *calData =
    329		ah->cal_list_curr->calData;
    330	u32 numSamples =
    331		(1 << (calData->calCountMax + 5)) * calData->calNumSamples;
    332
    333	for (i = 0; i < numChains; i++) {
    334		iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
    335		iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
    336		qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
    337		qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
    338
    339		ath_dbg(common, CALIBRATE,
    340			"Starting ADC DC Offset Cal for Chain %d\n", i);
    341
    342		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n",
    343			i, iOddMeasOffset);
    344		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n",
    345			i, iEvenMeasOffset);
    346		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n",
    347			i, qOddMeasOffset);
    348		ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n",
    349			i, qEvenMeasOffset);
    350
    351		iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
    352			       numSamples) & 0x1ff;
    353		qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
    354			       numSamples) & 0x1ff;
    355
    356		ath_dbg(common, CALIBRATE,
    357			"Chn %d dc_offset_mismatch_i = 0x%08x\n",
    358			i, iDcMismatch);
    359		ath_dbg(common, CALIBRATE,
    360			"Chn %d dc_offset_mismatch_q = 0x%08x\n",
    361			i, qDcMismatch);
    362
    363		val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
    364		val &= 0xc0000fff;
    365		val |= (qDcMismatch << 12) | (iDcMismatch << 21);
    366		REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
    367
    368		ath_dbg(common, CALIBRATE,
    369			"ADC DC Offset Cal done for Chain %d\n", i);
    370	}
    371
    372	REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
    373		  REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
    374		  AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
    375}
    376
    377static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
    378{
    379	u32 rddata;
    380	int32_t delta, currPDADC, slope;
    381
    382	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
    383	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
    384
    385	if (ah->initPDADC == 0 || currPDADC == 0) {
    386		/*
    387		 * Zero value indicates that no frames have been transmitted
    388		 * yet, can't do temperature compensation until frames are
    389		 * transmitted.
    390		 */
    391		return;
    392	} else {
    393		slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
    394
    395		if (slope == 0) { /* to avoid divide by zero case */
    396			delta = 0;
    397		} else {
    398			delta = ((currPDADC - ah->initPDADC)*4) / slope;
    399		}
    400		REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
    401			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
    402		REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
    403			      AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
    404	}
    405}
    406
    407static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
    408{
    409	u32 rddata, i;
    410	int delta, currPDADC, regval;
    411
    412	rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
    413	currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
    414
    415	if (ah->initPDADC == 0 || currPDADC == 0)
    416		return;
    417
    418	if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
    419		delta = (currPDADC - ah->initPDADC + 4) / 8;
    420	else
    421		delta = (currPDADC - ah->initPDADC + 5) / 10;
    422
    423	if (delta != ah->PDADCdelta) {
    424		ah->PDADCdelta = delta;
    425		for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
    426			regval = ah->originalGain[i] - delta;
    427			if (regval < 0)
    428				regval = 0;
    429
    430			REG_RMW_FIELD(ah,
    431				      AR_PHY_TX_GAIN_TBL1 + i * 4,
    432				      AR_PHY_TX_GAIN, regval);
    433		}
    434	}
    435}
    436
    437static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
    438{
    439	u32 regVal;
    440	unsigned int i;
    441	u32 regList[][2] = {
    442		{ AR9285_AN_TOP3, 0 },
    443		{ AR9285_AN_RXTXBB1, 0 },
    444		{ AR9285_AN_RF2G1, 0 },
    445		{ AR9285_AN_RF2G2, 0 },
    446		{ AR9285_AN_TOP2, 0 },
    447		{ AR9285_AN_RF2G8, 0 },
    448		{ AR9285_AN_RF2G7, 0 },
    449		{ AR9285_AN_RF2G3, 0 },
    450	};
    451
    452	REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList));
    453
    454	ENABLE_REG_RMW_BUFFER(ah);
    455	/* 7834, b1=0 */
    456	REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
    457	/* 9808, b27=1 */
    458	REG_SET_BIT(ah, 0x9808, 1 << 27);
    459	/* 786c,b23,1, pwddac=1 */
    460	REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC);
    461	/* 7854, b5,1, pdrxtxbb=1 */
    462	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1);
    463	/* 7854, b7,1, pdv2i=1 */
    464	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I);
    465	/* 7854, b8,1, pddacinterface=1 */
    466	REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF);
    467	/* 7824,b12,0, offcal=0 */
    468	REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL);
    469	/* 7838, b1,0, pwddb=0 */
    470	REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB);
    471	/* 7820,b11,0, enpacal=0 */
    472	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL);
    473	/* 7820,b25,1, pdpadrv1=0 */
    474	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1);
    475	/* 7820,b24,0, pdpadrv2=0 */
    476	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2);
    477	/* 7820,b23,0, pdpaout=0 */
    478	REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT);
    479	/* 783c,b14-16,7, padrvgn2tab_0=7 */
    480	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
    481	/*
    482	 * 7838,b29-31,0, padrvgn1tab_0=0
    483	 * does not matter since we turn it off
    484	 */
    485	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
    486	/* 7828, b0-11, ccom=fff */
    487	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
    488	REG_RMW_BUFFER_FLUSH(ah);
    489
    490	/* Set:
    491	 * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
    492	 * txon=1,paon=1,oscon=1,synthon_force=1
    493	 */
    494	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
    495	udelay(30);
    496	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
    497
    498	/* find off_6_1; */
    499	for (i = 6; i > 0; i--) {
    500		regVal = REG_READ(ah, AR9285_AN_RF2G6);
    501		regVal |= (1 << (20 + i));
    502		REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
    503		udelay(1);
    504		/* regVal = REG_READ(ah, 0x7834); */
    505		regVal &= (~(0x1 << (20 + i)));
    506		regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9),
    507			      AR9285_AN_RXTXBB1_SPARE9)
    508			    << (20 + i));
    509		REG_WRITE(ah, AR9285_AN_RF2G6, regVal);
    510	}
    511
    512	regVal = (regVal >> 20) & 0x7f;
    513
    514	/* Update PA cal info */
    515	if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
    516		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
    517			ah->pacal_info.max_skipcount =
    518				2 * ah->pacal_info.max_skipcount;
    519		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
    520	} else {
    521		ah->pacal_info.max_skipcount = 1;
    522		ah->pacal_info.skipcount = 0;
    523		ah->pacal_info.prev_offset = regVal;
    524	}
    525
    526
    527	ENABLE_REG_RMW_BUFFER(ah);
    528	/* 7834, b1=1 */
    529	REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0);
    530	/* 9808, b27=0 */
    531	REG_CLR_BIT(ah, 0x9808, 1 << 27);
    532	REG_RMW_BUFFER_FLUSH(ah);
    533
    534	ENABLE_REGWRITE_BUFFER(ah);
    535	for (i = 0; i < ARRAY_SIZE(regList); i++)
    536		REG_WRITE(ah, regList[i][0], regList[i][1]);
    537
    538	REGWRITE_BUFFER_FLUSH(ah);
    539}
    540
    541static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
    542{
    543	struct ath_common *common = ath9k_hw_common(ah);
    544	u32 regVal;
    545	int i, offset, offs_6_1, offs_0;
    546	u32 ccomp_org, reg_field;
    547	u32 regList[][2] = {
    548		{ 0x786c, 0 },
    549		{ 0x7854, 0 },
    550		{ 0x7820, 0 },
    551		{ 0x7824, 0 },
    552		{ 0x7868, 0 },
    553		{ 0x783c, 0 },
    554		{ 0x7838, 0 },
    555	};
    556
    557	ath_dbg(common, CALIBRATE, "Running PA Calibration\n");
    558
    559	/* PA CAL is not needed for high power solution */
    560	if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
    561	    AR5416_EEP_TXGAIN_HIGH_POWER)
    562		return;
    563
    564	for (i = 0; i < ARRAY_SIZE(regList); i++)
    565		regList[i][1] = REG_READ(ah, regList[i][0]);
    566
    567	regVal = REG_READ(ah, 0x7834);
    568	regVal &= (~(0x1));
    569	REG_WRITE(ah, 0x7834, regVal);
    570	regVal = REG_READ(ah, 0x9808);
    571	regVal |= (0x1 << 27);
    572	REG_WRITE(ah, 0x9808, regVal);
    573
    574	REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
    575	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
    576	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
    577	REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
    578	REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
    579	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
    580	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
    581	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
    582	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
    583	REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
    584	REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
    585	REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
    586	ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
    587	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
    588
    589	REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
    590	udelay(30);
    591	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
    592	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
    593
    594	for (i = 6; i > 0; i--) {
    595		regVal = REG_READ(ah, 0x7834);
    596		regVal |= (1 << (19 + i));
    597		REG_WRITE(ah, 0x7834, regVal);
    598		udelay(1);
    599		regVal = REG_READ(ah, 0x7834);
    600		regVal &= (~(0x1 << (19 + i)));
    601		reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
    602		regVal |= (reg_field << (19 + i));
    603		REG_WRITE(ah, 0x7834, regVal);
    604	}
    605
    606	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
    607	udelay(1);
    608	reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
    609	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
    610	offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
    611	offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
    612
    613	offset = (offs_6_1<<1) | offs_0;
    614	offset = offset - 0;
    615	offs_6_1 = offset>>1;
    616	offs_0 = offset & 1;
    617
    618	if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
    619		if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
    620			ah->pacal_info.max_skipcount =
    621				2 * ah->pacal_info.max_skipcount;
    622		ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
    623	} else {
    624		ah->pacal_info.max_skipcount = 1;
    625		ah->pacal_info.skipcount = 0;
    626		ah->pacal_info.prev_offset = offset;
    627	}
    628
    629	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
    630	REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
    631
    632	regVal = REG_READ(ah, 0x7834);
    633	regVal |= 0x1;
    634	REG_WRITE(ah, 0x7834, regVal);
    635	regVal = REG_READ(ah, 0x9808);
    636	regVal &= (~(0x1 << 27));
    637	REG_WRITE(ah, 0x9808, regVal);
    638
    639	for (i = 0; i < ARRAY_SIZE(regList); i++)
    640		REG_WRITE(ah, regList[i][0], regList[i][1]);
    641
    642	REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
    643}
    644
    645static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)
    646{
    647	if (AR_SREV_9271(ah)) {
    648		if (is_reset || !ah->pacal_info.skipcount)
    649			ar9271_hw_pa_cal(ah, is_reset);
    650		else
    651			ah->pacal_info.skipcount--;
    652	} else if (AR_SREV_9285_12_OR_LATER(ah)) {
    653		if (is_reset || !ah->pacal_info.skipcount)
    654			ar9285_hw_pa_cal(ah, is_reset);
    655		else
    656			ah->pacal_info.skipcount--;
    657	}
    658}
    659
    660static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
    661{
    662	if (OLC_FOR_AR9287_10_LATER)
    663		ar9287_hw_olc_temp_compensation(ah);
    664	else if (OLC_FOR_AR9280_20_LATER)
    665		ar9280_hw_olc_temp_compensation(ah);
    666}
    667
    668static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
    669			       u8 rxchainmask, bool longcal)
    670{
    671	struct ath9k_cal_list *currCal = ah->cal_list_curr;
    672	bool nfcal, nfcal_pending = false, percal_pending;
    673	int ret;
    674
    675	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
    676	if (ah->caldata) {
    677		nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
    678		if (longcal)		/* Remember to not miss */
    679			set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags);
    680		else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags))
    681			longcal = true;	/* Respin a previous one */
    682	}
    683
    684	percal_pending = (currCal &&
    685			  (currCal->calState == CAL_RUNNING ||
    686			   currCal->calState == CAL_WAITING));
    687
    688	if (percal_pending && !nfcal) {
    689		if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
    690			return 0;
    691
    692		/* Looking for next waiting calibration if any */
    693		for (currCal = currCal->calNext; currCal != ah->cal_list_curr;
    694		     currCal = currCal->calNext) {
    695			if (currCal->calState == CAL_WAITING)
    696				break;
    697		}
    698		if (currCal->calState == CAL_WAITING) {
    699			percal_pending = true;
    700			ah->cal_list_curr = currCal;
    701		} else {
    702			percal_pending = false;
    703			ah->cal_list_curr = ah->cal_list;
    704		}
    705	}
    706
    707	/* Do not start a next calibration if the longcal is in action */
    708	if (percal_pending && !nfcal && !longcal) {
    709		ath9k_hw_reset_calibration(ah, currCal);
    710
    711		return 0;
    712	}
    713
    714	/* Do NF cal only at longer intervals */
    715	if (longcal || nfcal_pending) {
    716		/*
    717		 * Get the value from the previous NF cal and update
    718		 * history buffer.
    719		 */
    720		if (ath9k_hw_getnf(ah, chan)) {
    721			/*
    722			 * Load the NF from history buffer of the current
    723			 * channel.
    724			 * NF is slow time-variant, so it is OK to use a
    725			 * historical value.
    726			 */
    727			ret = ath9k_hw_loadnf(ah, ah->curchan);
    728			if (ret < 0)
    729				return ret;
    730		}
    731
    732		if (longcal) {
    733			if (ah->caldata)
    734				clear_bit(LONGCAL_PENDING,
    735					  &ah->caldata->cal_flags);
    736			ath9k_hw_start_nfcal(ah, false);
    737			/* Do periodic PAOffset Cal */
    738			ar9002_hw_pa_cal(ah, false);
    739			ar9002_hw_olc_temp_compensation(ah);
    740		}
    741	}
    742
    743	return !percal_pending;
    744}
    745
    746/* Carrier leakage Calibration fix */
    747static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
    748{
    749	struct ath_common *common = ath9k_hw_common(ah);
    750
    751	REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
    752	if (IS_CHAN_HT20(chan)) {
    753		REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
    754		REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
    755		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
    756			    AR_PHY_AGC_CONTROL_FLTR_CAL);
    757		REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
    758		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
    759		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
    760				  AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
    761			ath_dbg(common, CALIBRATE,
    762				"offset calibration failed to complete in %d ms; noisy environment?\n",
    763				AH_WAIT_TIMEOUT / 1000);
    764			return false;
    765		}
    766		REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
    767		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
    768		REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
    769	}
    770	REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
    771	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
    772	REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
    773	REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
    774	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
    775			  0, AH_WAIT_TIMEOUT)) {
    776		ath_dbg(common, CALIBRATE,
    777			"offset calibration failed to complete in %d ms; noisy environment?\n",
    778			AH_WAIT_TIMEOUT / 1000);
    779		return false;
    780	}
    781
    782	REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
    783	REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
    784	REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
    785
    786	return true;
    787}
    788
    789static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
    790{
    791	int i;
    792	u_int32_t txgain_max;
    793	u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
    794	u_int32_t reg_clc_I0, reg_clc_Q0;
    795	u_int32_t i0_num = 0;
    796	u_int32_t q0_num = 0;
    797	u_int32_t total_num = 0;
    798	u_int32_t reg_rf2g5_org;
    799	bool retv = true;
    800
    801	if (!(ar9285_hw_cl_cal(ah, chan)))
    802		return false;
    803
    804	txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
    805			AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
    806
    807	for (i = 0; i < (txgain_max+1); i++) {
    808		clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
    809			   AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
    810		if (!(gain_mask & (1 << clc_gain))) {
    811			gain_mask |= (1 << clc_gain);
    812			clc_num++;
    813		}
    814	}
    815
    816	for (i = 0; i < clc_num; i++) {
    817		reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
    818			      & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
    819		reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
    820			      & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
    821		if (reg_clc_I0 == 0)
    822			i0_num++;
    823
    824		if (reg_clc_Q0 == 0)
    825			q0_num++;
    826	}
    827	total_num = i0_num + q0_num;
    828	if (total_num > AR9285_CLCAL_REDO_THRESH) {
    829		reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
    830		if (AR_SREV_9285E_20(ah)) {
    831			REG_WRITE(ah, AR9285_RF2G5,
    832				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
    833				  AR9285_RF2G5_IC50TX_XE_SET);
    834		} else {
    835			REG_WRITE(ah, AR9285_RF2G5,
    836				  (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
    837				  AR9285_RF2G5_IC50TX_SET);
    838		}
    839		retv = ar9285_hw_cl_cal(ah, chan);
    840		REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
    841	}
    842	return retv;
    843}
    844
    845static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
    846{
    847	struct ath_common *common = ath9k_hw_common(ah);
    848
    849	if (AR_SREV_9271(ah)) {
    850		if (!ar9285_hw_cl_cal(ah, chan))
    851			return false;
    852	} else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
    853		if (!ar9285_hw_clc(ah, chan))
    854			return false;
    855	} else {
    856		if (AR_SREV_9280_20_OR_LATER(ah)) {
    857			if (!AR_SREV_9287_11_OR_LATER(ah))
    858				REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
    859					    AR_PHY_ADC_CTL_OFF_PWDADC);
    860			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
    861				    AR_PHY_AGC_CONTROL_FLTR_CAL);
    862		}
    863
    864		/* Calibrate the AGC */
    865		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
    866			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
    867			  AR_PHY_AGC_CONTROL_CAL);
    868
    869		/* Poll for offset calibration complete */
    870		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
    871				   AR_PHY_AGC_CONTROL_CAL,
    872				   0, AH_WAIT_TIMEOUT)) {
    873			ath_dbg(common, CALIBRATE,
    874				"offset calibration failed to complete in %d ms; noisy environment?\n",
    875				AH_WAIT_TIMEOUT / 1000);
    876			return false;
    877		}
    878
    879		if (AR_SREV_9280_20_OR_LATER(ah)) {
    880			if (!AR_SREV_9287_11_OR_LATER(ah))
    881				REG_SET_BIT(ah, AR_PHY_ADC_CTL,
    882					    AR_PHY_ADC_CTL_OFF_PWDADC);
    883			REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
    884				    AR_PHY_AGC_CONTROL_FLTR_CAL);
    885		}
    886	}
    887
    888	/* Do PA Calibration */
    889	ar9002_hw_pa_cal(ah, true);
    890	ath9k_hw_loadnf(ah, chan);
    891	ath9k_hw_start_nfcal(ah, true);
    892
    893	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
    894
    895	/* Enable IQ, ADC Gain and ADC DC offset CALs */
    896	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
    897		ah->supp_cals = IQ_MISMATCH_CAL;
    898
    899		if (AR_SREV_9160_10_OR_LATER(ah))
    900			ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
    901
    902		if (AR_SREV_9287(ah))
    903			ah->supp_cals &= ~ADC_GAIN_CAL;
    904
    905		if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
    906			INIT_CAL(&ah->adcgain_caldata);
    907			INSERT_CAL(ah, &ah->adcgain_caldata);
    908			ath_dbg(common, CALIBRATE,
    909					"enabling ADC Gain Calibration\n");
    910		}
    911
    912		if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
    913			INIT_CAL(&ah->adcdc_caldata);
    914			INSERT_CAL(ah, &ah->adcdc_caldata);
    915			ath_dbg(common, CALIBRATE,
    916					"enabling ADC DC Calibration\n");
    917		}
    918
    919		if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
    920			INIT_CAL(&ah->iq_caldata);
    921			INSERT_CAL(ah, &ah->iq_caldata);
    922			ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n");
    923		}
    924
    925		ah->cal_list_curr = ah->cal_list;
    926
    927		if (ah->cal_list_curr)
    928			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
    929	}
    930
    931	if (ah->caldata)
    932		ah->caldata->CalValid = 0;
    933
    934	return true;
    935}
    936
    937static const struct ath9k_percal_data iq_cal_multi_sample = {
    938	IQ_MISMATCH_CAL,
    939	MAX_CAL_SAMPLES,
    940	PER_MIN_LOG_COUNT,
    941	ar9002_hw_iqcal_collect,
    942	ar9002_hw_iqcalibrate
    943};
    944static const struct ath9k_percal_data iq_cal_single_sample = {
    945	IQ_MISMATCH_CAL,
    946	MIN_CAL_SAMPLES,
    947	PER_MAX_LOG_COUNT,
    948	ar9002_hw_iqcal_collect,
    949	ar9002_hw_iqcalibrate
    950};
    951static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
    952	ADC_GAIN_CAL,
    953	MAX_CAL_SAMPLES,
    954	PER_MIN_LOG_COUNT,
    955	ar9002_hw_adc_gaincal_collect,
    956	ar9002_hw_adc_gaincal_calibrate
    957};
    958static const struct ath9k_percal_data adc_gain_cal_single_sample = {
    959	ADC_GAIN_CAL,
    960	MIN_CAL_SAMPLES,
    961	PER_MAX_LOG_COUNT,
    962	ar9002_hw_adc_gaincal_collect,
    963	ar9002_hw_adc_gaincal_calibrate
    964};
    965static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
    966	ADC_DC_CAL,
    967	MAX_CAL_SAMPLES,
    968	PER_MIN_LOG_COUNT,
    969	ar9002_hw_adc_dccal_collect,
    970	ar9002_hw_adc_dccal_calibrate
    971};
    972static const struct ath9k_percal_data adc_dc_cal_single_sample = {
    973	ADC_DC_CAL,
    974	MIN_CAL_SAMPLES,
    975	PER_MAX_LOG_COUNT,
    976	ar9002_hw_adc_dccal_collect,
    977	ar9002_hw_adc_dccal_calibrate
    978};
    979
    980static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
    981{
    982	if (AR_SREV_9100(ah)) {
    983		ah->iq_caldata.calData = &iq_cal_multi_sample;
    984		ah->supp_cals = IQ_MISMATCH_CAL;
    985		return;
    986	}
    987
    988	if (AR_SREV_9160_10_OR_LATER(ah)) {
    989		if (AR_SREV_9280_20_OR_LATER(ah)) {
    990			ah->iq_caldata.calData = &iq_cal_single_sample;
    991			ah->adcgain_caldata.calData =
    992				&adc_gain_cal_single_sample;
    993			ah->adcdc_caldata.calData =
    994				&adc_dc_cal_single_sample;
    995		} else {
    996			ah->iq_caldata.calData = &iq_cal_multi_sample;
    997			ah->adcgain_caldata.calData =
    998				&adc_gain_cal_multi_sample;
    999			ah->adcdc_caldata.calData =
   1000				&adc_dc_cal_multi_sample;
   1001		}
   1002		ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
   1003
   1004		if (AR_SREV_9287(ah))
   1005			ah->supp_cals &= ~ADC_GAIN_CAL;
   1006	}
   1007}
   1008
   1009void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
   1010{
   1011	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
   1012	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
   1013
   1014	priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
   1015	priv_ops->init_cal = ar9002_hw_init_cal;
   1016	priv_ops->setup_calibration = ar9002_hw_setup_calibration;
   1017
   1018	ops->calibrate = ar9002_hw_calibrate;
   1019}