1795f5e2cSLuis R. Rodriguez /* 25b68138eSSujith Manoharan * Copyright (c) 2008-2011 Atheros Communications Inc. 3795f5e2cSLuis R. Rodriguez * 4795f5e2cSLuis R. Rodriguez * Permission to use, copy, modify, and/or distribute this software for any 5795f5e2cSLuis R. Rodriguez * purpose with or without fee is hereby granted, provided that the above 6795f5e2cSLuis R. Rodriguez * copyright notice and this permission notice appear in all copies. 7795f5e2cSLuis R. Rodriguez * 8795f5e2cSLuis R. Rodriguez * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9795f5e2cSLuis R. Rodriguez * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10795f5e2cSLuis R. Rodriguez * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11795f5e2cSLuis R. Rodriguez * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12795f5e2cSLuis R. Rodriguez * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13795f5e2cSLuis R. Rodriguez * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14795f5e2cSLuis R. Rodriguez * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15795f5e2cSLuis R. Rodriguez */ 16795f5e2cSLuis R. Rodriguez 17795f5e2cSLuis R. Rodriguez #include "hw.h" 18795f5e2cSLuis R. Rodriguez #include "hw-ops.h" 19795f5e2cSLuis R. Rodriguez #include "ar9002_phy.h" 20795f5e2cSLuis R. Rodriguez 21795f5e2cSLuis R. Rodriguez #define AR9285_CLCAL_REDO_THRESH 1 22795f5e2cSLuis R. Rodriguez 236497827fSFelix Fietkau enum ar9002_cal_types { 246497827fSFelix Fietkau ADC_GAIN_CAL = BIT(0), 256497827fSFelix Fietkau ADC_DC_CAL = BIT(1), 266497827fSFelix Fietkau IQ_MISMATCH_CAL = BIT(2), 276497827fSFelix Fietkau }; 286497827fSFelix Fietkau 2981544026SRajkumar Manoharan static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, 3081544026SRajkumar Manoharan struct ath9k_channel *chan, 3181544026SRajkumar Manoharan enum ar9002_cal_types cal_type) 3281544026SRajkumar Manoharan { 3381544026SRajkumar Manoharan bool supported = false; 3481544026SRajkumar Manoharan switch (ah->supp_cals & cal_type) { 3581544026SRajkumar Manoharan case IQ_MISMATCH_CAL: 3681544026SRajkumar Manoharan /* Run IQ Mismatch for non-CCK only */ 3781544026SRajkumar Manoharan if (!IS_CHAN_B(chan)) 3881544026SRajkumar Manoharan supported = true; 3981544026SRajkumar Manoharan break; 4081544026SRajkumar Manoharan case ADC_GAIN_CAL: 4181544026SRajkumar Manoharan case ADC_DC_CAL: 4281544026SRajkumar Manoharan /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ 4381544026SRajkumar Manoharan if (!IS_CHAN_B(chan) && 440e4660cbSFelix Fietkau !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) && 450e4660cbSFelix Fietkau IS_CHAN_HT20(chan))) 4681544026SRajkumar Manoharan supported = true; 4781544026SRajkumar Manoharan break; 4881544026SRajkumar Manoharan } 4981544026SRajkumar Manoharan return supported; 5081544026SRajkumar Manoharan } 516497827fSFelix Fietkau 52795f5e2cSLuis R. Rodriguez static void ar9002_hw_setup_calibration(struct ath_hw *ah, 53795f5e2cSLuis R. Rodriguez struct ath9k_cal_list *currCal) 54795f5e2cSLuis R. Rodriguez { 55795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 56795f5e2cSLuis R. Rodriguez 57795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), 58795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 59795f5e2cSLuis R. Rodriguez currCal->calData->calCountMax); 60795f5e2cSLuis R. Rodriguez 61795f5e2cSLuis R. Rodriguez switch (currCal->calData->calType) { 62795f5e2cSLuis R. Rodriguez case IQ_MISMATCH_CAL: 63795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 64226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 65795f5e2cSLuis R. Rodriguez "starting IQ Mismatch Calibration\n"); 66795f5e2cSLuis R. Rodriguez break; 67795f5e2cSLuis R. Rodriguez case ADC_GAIN_CAL: 68795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 69226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 70795f5e2cSLuis R. Rodriguez "starting ADC Gain Calibration\n"); 71795f5e2cSLuis R. Rodriguez break; 72795f5e2cSLuis R. Rodriguez case ADC_DC_CAL: 73795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 74226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 75795f5e2cSLuis R. Rodriguez "starting ADC DC Calibration\n"); 76795f5e2cSLuis R. Rodriguez break; 77795f5e2cSLuis R. Rodriguez } 78795f5e2cSLuis R. Rodriguez 79795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 80795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_DO_CAL); 81795f5e2cSLuis R. Rodriguez } 82795f5e2cSLuis R. Rodriguez 83795f5e2cSLuis R. Rodriguez static bool ar9002_hw_per_calibration(struct ath_hw *ah, 84795f5e2cSLuis R. Rodriguez struct ath9k_channel *ichan, 85795f5e2cSLuis R. Rodriguez u8 rxchainmask, 86795f5e2cSLuis R. Rodriguez struct ath9k_cal_list *currCal) 87795f5e2cSLuis R. Rodriguez { 8820bd2a09SFelix Fietkau struct ath9k_hw_cal_data *caldata = ah->caldata; 89795f5e2cSLuis R. Rodriguez bool iscaldone = false; 90795f5e2cSLuis R. Rodriguez 91795f5e2cSLuis R. Rodriguez if (currCal->calState == CAL_RUNNING) { 92795f5e2cSLuis R. Rodriguez if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & 93795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_DO_CAL)) { 94795f5e2cSLuis R. Rodriguez 95795f5e2cSLuis R. Rodriguez currCal->calData->calCollect(ah); 96795f5e2cSLuis R. Rodriguez ah->cal_samples++; 97795f5e2cSLuis R. Rodriguez 98795f5e2cSLuis R. Rodriguez if (ah->cal_samples >= 99795f5e2cSLuis R. Rodriguez currCal->calData->calNumSamples) { 100795f5e2cSLuis R. Rodriguez int i, numChains = 0; 101795f5e2cSLuis R. Rodriguez for (i = 0; i < AR5416_MAX_CHAINS; i++) { 102795f5e2cSLuis R. Rodriguez if (rxchainmask & (1 << i)) 103795f5e2cSLuis R. Rodriguez numChains++; 104795f5e2cSLuis R. Rodriguez } 105795f5e2cSLuis R. Rodriguez 106795f5e2cSLuis R. Rodriguez currCal->calData->calPostProc(ah, numChains); 10720bd2a09SFelix Fietkau caldata->CalValid |= currCal->calData->calType; 108795f5e2cSLuis R. Rodriguez currCal->calState = CAL_DONE; 109795f5e2cSLuis R. Rodriguez iscaldone = true; 110795f5e2cSLuis R. Rodriguez } else { 111795f5e2cSLuis R. Rodriguez ar9002_hw_setup_calibration(ah, currCal); 112795f5e2cSLuis R. Rodriguez } 113795f5e2cSLuis R. Rodriguez } 11420bd2a09SFelix Fietkau } else if (!(caldata->CalValid & currCal->calData->calType)) { 115795f5e2cSLuis R. Rodriguez ath9k_hw_reset_calibration(ah, currCal); 116795f5e2cSLuis R. Rodriguez } 117795f5e2cSLuis R. Rodriguez 118795f5e2cSLuis R. Rodriguez return iscaldone; 119795f5e2cSLuis R. Rodriguez } 120795f5e2cSLuis R. Rodriguez 121795f5e2cSLuis R. Rodriguez static void ar9002_hw_iqcal_collect(struct ath_hw *ah) 122795f5e2cSLuis R. Rodriguez { 123795f5e2cSLuis R. Rodriguez int i; 124795f5e2cSLuis R. Rodriguez 125795f5e2cSLuis R. Rodriguez for (i = 0; i < AR5416_MAX_CHAINS; i++) { 126795f5e2cSLuis R. Rodriguez ah->totalPowerMeasI[i] += 127795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 128795f5e2cSLuis R. Rodriguez ah->totalPowerMeasQ[i] += 129795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 130795f5e2cSLuis R. Rodriguez ah->totalIqCorrMeas[i] += 131795f5e2cSLuis R. Rodriguez (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 132226afe68SJoe Perches ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, 133795f5e2cSLuis R. Rodriguez "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 134795f5e2cSLuis R. Rodriguez ah->cal_samples, i, ah->totalPowerMeasI[i], 135795f5e2cSLuis R. Rodriguez ah->totalPowerMeasQ[i], 136795f5e2cSLuis R. Rodriguez ah->totalIqCorrMeas[i]); 137795f5e2cSLuis R. Rodriguez } 138795f5e2cSLuis R. Rodriguez } 139795f5e2cSLuis R. Rodriguez 140795f5e2cSLuis R. Rodriguez static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah) 141795f5e2cSLuis R. Rodriguez { 142795f5e2cSLuis R. Rodriguez int i; 143795f5e2cSLuis R. Rodriguez 144795f5e2cSLuis R. Rodriguez for (i = 0; i < AR5416_MAX_CHAINS; i++) { 145795f5e2cSLuis R. Rodriguez ah->totalAdcIOddPhase[i] += 146795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 147795f5e2cSLuis R. Rodriguez ah->totalAdcIEvenPhase[i] += 148795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 149795f5e2cSLuis R. Rodriguez ah->totalAdcQOddPhase[i] += 150795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 151795f5e2cSLuis R. Rodriguez ah->totalAdcQEvenPhase[i] += 152795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 153795f5e2cSLuis R. Rodriguez 154226afe68SJoe Perches ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, 155226afe68SJoe Perches "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 156795f5e2cSLuis R. Rodriguez ah->cal_samples, i, 157795f5e2cSLuis R. Rodriguez ah->totalAdcIOddPhase[i], 158795f5e2cSLuis R. Rodriguez ah->totalAdcIEvenPhase[i], 159795f5e2cSLuis R. Rodriguez ah->totalAdcQOddPhase[i], 160795f5e2cSLuis R. Rodriguez ah->totalAdcQEvenPhase[i]); 161795f5e2cSLuis R. Rodriguez } 162795f5e2cSLuis R. Rodriguez } 163795f5e2cSLuis R. Rodriguez 164795f5e2cSLuis R. Rodriguez static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah) 165795f5e2cSLuis R. Rodriguez { 166795f5e2cSLuis R. Rodriguez int i; 167795f5e2cSLuis R. Rodriguez 168795f5e2cSLuis R. Rodriguez for (i = 0; i < AR5416_MAX_CHAINS; i++) { 169795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetIOddPhase[i] += 170795f5e2cSLuis R. Rodriguez (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 171795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetIEvenPhase[i] += 172795f5e2cSLuis R. Rodriguez (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 173795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetQOddPhase[i] += 174795f5e2cSLuis R. Rodriguez (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 175795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetQEvenPhase[i] += 176795f5e2cSLuis R. Rodriguez (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 177795f5e2cSLuis R. Rodriguez 178226afe68SJoe Perches ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, 179226afe68SJoe Perches "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 180795f5e2cSLuis R. Rodriguez ah->cal_samples, i, 181795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetIOddPhase[i], 182795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetIEvenPhase[i], 183795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetQOddPhase[i], 184795f5e2cSLuis R. Rodriguez ah->totalAdcDcOffsetQEvenPhase[i]); 185795f5e2cSLuis R. Rodriguez } 186795f5e2cSLuis R. Rodriguez } 187795f5e2cSLuis R. Rodriguez 188795f5e2cSLuis R. Rodriguez static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 189795f5e2cSLuis R. Rodriguez { 190795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 191795f5e2cSLuis R. Rodriguez u32 powerMeasQ, powerMeasI, iqCorrMeas; 192795f5e2cSLuis R. Rodriguez u32 qCoffDenom, iCoffDenom; 193795f5e2cSLuis R. Rodriguez int32_t qCoff, iCoff; 194795f5e2cSLuis R. Rodriguez int iqCorrNeg, i; 195795f5e2cSLuis R. Rodriguez 196795f5e2cSLuis R. Rodriguez for (i = 0; i < numChains; i++) { 197795f5e2cSLuis R. Rodriguez powerMeasI = ah->totalPowerMeasI[i]; 198795f5e2cSLuis R. Rodriguez powerMeasQ = ah->totalPowerMeasQ[i]; 199795f5e2cSLuis R. Rodriguez iqCorrMeas = ah->totalIqCorrMeas[i]; 200795f5e2cSLuis R. Rodriguez 201226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 202795f5e2cSLuis R. Rodriguez "Starting IQ Cal and Correction for Chain %d\n", 203795f5e2cSLuis R. Rodriguez i); 204795f5e2cSLuis R. Rodriguez 205226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 206795f5e2cSLuis R. Rodriguez "Orignal: Chn %diq_corr_meas = 0x%08x\n", 207795f5e2cSLuis R. Rodriguez i, ah->totalIqCorrMeas[i]); 208795f5e2cSLuis R. Rodriguez 209795f5e2cSLuis R. Rodriguez iqCorrNeg = 0; 210795f5e2cSLuis R. Rodriguez 211795f5e2cSLuis R. Rodriguez if (iqCorrMeas > 0x80000000) { 212795f5e2cSLuis R. Rodriguez iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 213795f5e2cSLuis R. Rodriguez iqCorrNeg = 1; 214795f5e2cSLuis R. Rodriguez } 215795f5e2cSLuis R. Rodriguez 216226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 217795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); 218226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 219795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); 220226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", 221795f5e2cSLuis R. Rodriguez iqCorrNeg); 222795f5e2cSLuis R. Rodriguez 223795f5e2cSLuis R. Rodriguez iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; 224795f5e2cSLuis R. Rodriguez qCoffDenom = powerMeasQ / 64; 225795f5e2cSLuis R. Rodriguez 226795f5e2cSLuis R. Rodriguez if ((powerMeasQ != 0) && (iCoffDenom != 0) && 227795f5e2cSLuis R. Rodriguez (qCoffDenom != 0)) { 228795f5e2cSLuis R. Rodriguez iCoff = iqCorrMeas / iCoffDenom; 229795f5e2cSLuis R. Rodriguez qCoff = powerMeasI / qCoffDenom - 64; 230226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 231795f5e2cSLuis R. Rodriguez "Chn %d iCoff = 0x%08x\n", i, iCoff); 232226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 233795f5e2cSLuis R. Rodriguez "Chn %d qCoff = 0x%08x\n", i, qCoff); 234795f5e2cSLuis R. Rodriguez 235795f5e2cSLuis R. Rodriguez iCoff = iCoff & 0x3f; 236226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 237795f5e2cSLuis R. Rodriguez "New: Chn %d iCoff = 0x%08x\n", i, iCoff); 238795f5e2cSLuis R. Rodriguez if (iqCorrNeg == 0x0) 239795f5e2cSLuis R. Rodriguez iCoff = 0x40 - iCoff; 240795f5e2cSLuis R. Rodriguez 241795f5e2cSLuis R. Rodriguez if (qCoff > 15) 242795f5e2cSLuis R. Rodriguez qCoff = 15; 243795f5e2cSLuis R. Rodriguez else if (qCoff <= -16) 24423399016SFelix Fietkau qCoff = -16; 245795f5e2cSLuis R. Rodriguez 246226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 247795f5e2cSLuis R. Rodriguez "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 248795f5e2cSLuis R. Rodriguez i, iCoff, qCoff); 249795f5e2cSLuis R. Rodriguez 250795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 251795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 252795f5e2cSLuis R. Rodriguez iCoff); 253795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 254795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 255795f5e2cSLuis R. Rodriguez qCoff); 256226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 257795f5e2cSLuis R. Rodriguez "IQ Cal and Correction done for Chain %d\n", 258795f5e2cSLuis R. Rodriguez i); 259795f5e2cSLuis R. Rodriguez } 260795f5e2cSLuis R. Rodriguez } 261795f5e2cSLuis R. Rodriguez 262795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 263795f5e2cSLuis R. Rodriguez AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); 264795f5e2cSLuis R. Rodriguez } 265795f5e2cSLuis R. Rodriguez 266795f5e2cSLuis R. Rodriguez static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) 267795f5e2cSLuis R. Rodriguez { 268795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 269795f5e2cSLuis R. Rodriguez u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; 270795f5e2cSLuis R. Rodriguez u32 qGainMismatch, iGainMismatch, val, i; 271795f5e2cSLuis R. Rodriguez 272795f5e2cSLuis R. Rodriguez for (i = 0; i < numChains; i++) { 273795f5e2cSLuis R. Rodriguez iOddMeasOffset = ah->totalAdcIOddPhase[i]; 274795f5e2cSLuis R. Rodriguez iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; 275795f5e2cSLuis R. Rodriguez qOddMeasOffset = ah->totalAdcQOddPhase[i]; 276795f5e2cSLuis R. Rodriguez qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; 277795f5e2cSLuis R. Rodriguez 278226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 279795f5e2cSLuis R. Rodriguez "Starting ADC Gain Cal for Chain %d\n", i); 280795f5e2cSLuis R. Rodriguez 281226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 282795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_odd_i = 0x%08x\n", i, 283795f5e2cSLuis R. Rodriguez iOddMeasOffset); 284226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 285795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_even_i = 0x%08x\n", i, 286795f5e2cSLuis R. Rodriguez iEvenMeasOffset); 287226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 288795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_odd_q = 0x%08x\n", i, 289795f5e2cSLuis R. Rodriguez qOddMeasOffset); 290226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 291795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_even_q = 0x%08x\n", i, 292795f5e2cSLuis R. Rodriguez qEvenMeasOffset); 293795f5e2cSLuis R. Rodriguez 294795f5e2cSLuis R. Rodriguez if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { 295795f5e2cSLuis R. Rodriguez iGainMismatch = 296795f5e2cSLuis R. Rodriguez ((iEvenMeasOffset * 32) / 297795f5e2cSLuis R. Rodriguez iOddMeasOffset) & 0x3f; 298795f5e2cSLuis R. Rodriguez qGainMismatch = 299795f5e2cSLuis R. Rodriguez ((qOddMeasOffset * 32) / 300795f5e2cSLuis R. Rodriguez qEvenMeasOffset) & 0x3f; 301795f5e2cSLuis R. Rodriguez 302226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 303795f5e2cSLuis R. Rodriguez "Chn %d gain_mismatch_i = 0x%08x\n", i, 304795f5e2cSLuis R. Rodriguez iGainMismatch); 305226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 306795f5e2cSLuis R. Rodriguez "Chn %d gain_mismatch_q = 0x%08x\n", i, 307795f5e2cSLuis R. Rodriguez qGainMismatch); 308795f5e2cSLuis R. Rodriguez 309795f5e2cSLuis R. Rodriguez val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 310795f5e2cSLuis R. Rodriguez val &= 0xfffff000; 311795f5e2cSLuis R. Rodriguez val |= (qGainMismatch) | (iGainMismatch << 6); 312795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 313795f5e2cSLuis R. Rodriguez 314226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 315795f5e2cSLuis R. Rodriguez "ADC Gain Cal done for Chain %d\n", i); 316795f5e2cSLuis R. Rodriguez } 317795f5e2cSLuis R. Rodriguez } 318795f5e2cSLuis R. Rodriguez 319795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 320795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 321795f5e2cSLuis R. Rodriguez AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); 322795f5e2cSLuis R. Rodriguez } 323795f5e2cSLuis R. Rodriguez 324795f5e2cSLuis R. Rodriguez static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) 325795f5e2cSLuis R. Rodriguez { 326795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 327795f5e2cSLuis R. Rodriguez u32 iOddMeasOffset, iEvenMeasOffset, val, i; 328795f5e2cSLuis R. Rodriguez int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; 329795f5e2cSLuis R. Rodriguez const struct ath9k_percal_data *calData = 330795f5e2cSLuis R. Rodriguez ah->cal_list_curr->calData; 331795f5e2cSLuis R. Rodriguez u32 numSamples = 332795f5e2cSLuis R. Rodriguez (1 << (calData->calCountMax + 5)) * calData->calNumSamples; 333795f5e2cSLuis R. Rodriguez 334795f5e2cSLuis R. Rodriguez for (i = 0; i < numChains; i++) { 335795f5e2cSLuis R. Rodriguez iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; 336795f5e2cSLuis R. Rodriguez iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; 337795f5e2cSLuis R. Rodriguez qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; 338795f5e2cSLuis R. Rodriguez qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; 339795f5e2cSLuis R. Rodriguez 340226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 341795f5e2cSLuis R. Rodriguez "Starting ADC DC Offset Cal for Chain %d\n", i); 342795f5e2cSLuis R. Rodriguez 343226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 344795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_odd_i = %d\n", i, 345795f5e2cSLuis R. Rodriguez iOddMeasOffset); 346226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 347795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_even_i = %d\n", i, 348795f5e2cSLuis R. Rodriguez iEvenMeasOffset); 349226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 350795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_odd_q = %d\n", i, 351795f5e2cSLuis R. Rodriguez qOddMeasOffset); 352226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 353795f5e2cSLuis R. Rodriguez "Chn %d pwr_meas_even_q = %d\n", i, 354795f5e2cSLuis R. Rodriguez qEvenMeasOffset); 355795f5e2cSLuis R. Rodriguez 356795f5e2cSLuis R. Rodriguez iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / 357795f5e2cSLuis R. Rodriguez numSamples) & 0x1ff; 358795f5e2cSLuis R. Rodriguez qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / 359795f5e2cSLuis R. Rodriguez numSamples) & 0x1ff; 360795f5e2cSLuis R. Rodriguez 361226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 362795f5e2cSLuis R. Rodriguez "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, 363795f5e2cSLuis R. Rodriguez iDcMismatch); 364226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 365795f5e2cSLuis R. Rodriguez "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, 366795f5e2cSLuis R. Rodriguez qDcMismatch); 367795f5e2cSLuis R. Rodriguez 368795f5e2cSLuis R. Rodriguez val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 369795f5e2cSLuis R. Rodriguez val &= 0xc0000fff; 370795f5e2cSLuis R. Rodriguez val |= (qDcMismatch << 12) | (iDcMismatch << 21); 371795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 372795f5e2cSLuis R. Rodriguez 373226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 374795f5e2cSLuis R. Rodriguez "ADC DC Offset Cal done for Chain %d\n", i); 375795f5e2cSLuis R. Rodriguez } 376795f5e2cSLuis R. Rodriguez 377795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 378795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 379795f5e2cSLuis R. Rodriguez AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); 380795f5e2cSLuis R. Rodriguez } 381795f5e2cSLuis R. Rodriguez 382795f5e2cSLuis R. Rodriguez static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah) 383795f5e2cSLuis R. Rodriguez { 384795f5e2cSLuis R. Rodriguez u32 rddata; 385795f5e2cSLuis R. Rodriguez int32_t delta, currPDADC, slope; 386795f5e2cSLuis R. Rodriguez 387795f5e2cSLuis R. Rodriguez rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 388795f5e2cSLuis R. Rodriguez currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 389795f5e2cSLuis R. Rodriguez 390795f5e2cSLuis R. Rodriguez if (ah->initPDADC == 0 || currPDADC == 0) { 391795f5e2cSLuis R. Rodriguez /* 392795f5e2cSLuis R. Rodriguez * Zero value indicates that no frames have been transmitted 393795f5e2cSLuis R. Rodriguez * yet, can't do temperature compensation until frames are 394795f5e2cSLuis R. Rodriguez * transmitted. 395795f5e2cSLuis R. Rodriguez */ 396795f5e2cSLuis R. Rodriguez return; 397795f5e2cSLuis R. Rodriguez } else { 398795f5e2cSLuis R. Rodriguez slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); 399795f5e2cSLuis R. Rodriguez 400795f5e2cSLuis R. Rodriguez if (slope == 0) { /* to avoid divide by zero case */ 401795f5e2cSLuis R. Rodriguez delta = 0; 402795f5e2cSLuis R. Rodriguez } else { 403795f5e2cSLuis R. Rodriguez delta = ((currPDADC - ah->initPDADC)*4) / slope; 404795f5e2cSLuis R. Rodriguez } 405795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 406795f5e2cSLuis R. Rodriguez AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 407795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 408795f5e2cSLuis R. Rodriguez AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 409795f5e2cSLuis R. Rodriguez } 410795f5e2cSLuis R. Rodriguez } 411795f5e2cSLuis R. Rodriguez 412795f5e2cSLuis R. Rodriguez static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah) 413795f5e2cSLuis R. Rodriguez { 414795f5e2cSLuis R. Rodriguez u32 rddata, i; 415795f5e2cSLuis R. Rodriguez int delta, currPDADC, regval; 416795f5e2cSLuis R. Rodriguez 417795f5e2cSLuis R. Rodriguez rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 418795f5e2cSLuis R. Rodriguez currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 419795f5e2cSLuis R. Rodriguez 420795f5e2cSLuis R. Rodriguez if (ah->initPDADC == 0 || currPDADC == 0) 421795f5e2cSLuis R. Rodriguez return; 422795f5e2cSLuis R. Rodriguez 423795f5e2cSLuis R. Rodriguez if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) 424795f5e2cSLuis R. Rodriguez delta = (currPDADC - ah->initPDADC + 4) / 8; 425795f5e2cSLuis R. Rodriguez else 426795f5e2cSLuis R. Rodriguez delta = (currPDADC - ah->initPDADC + 5) / 10; 427795f5e2cSLuis R. Rodriguez 428795f5e2cSLuis R. Rodriguez if (delta != ah->PDADCdelta) { 429795f5e2cSLuis R. Rodriguez ah->PDADCdelta = delta; 430795f5e2cSLuis R. Rodriguez for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { 431795f5e2cSLuis R. Rodriguez regval = ah->originalGain[i] - delta; 432795f5e2cSLuis R. Rodriguez if (regval < 0) 433795f5e2cSLuis R. Rodriguez regval = 0; 434795f5e2cSLuis R. Rodriguez 435795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, 436795f5e2cSLuis R. Rodriguez AR_PHY_TX_GAIN_TBL1 + i * 4, 437795f5e2cSLuis R. Rodriguez AR_PHY_TX_GAIN, regval); 438795f5e2cSLuis R. Rodriguez } 439795f5e2cSLuis R. Rodriguez } 440795f5e2cSLuis R. Rodriguez } 441795f5e2cSLuis R. Rodriguez 442795f5e2cSLuis R. Rodriguez static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) 443795f5e2cSLuis R. Rodriguez { 444795f5e2cSLuis R. Rodriguez u32 regVal; 445795f5e2cSLuis R. Rodriguez unsigned int i; 446795f5e2cSLuis R. Rodriguez u32 regList[][2] = { 447795f5e2cSLuis R. Rodriguez { 0x786c, 0 }, 448795f5e2cSLuis R. Rodriguez { 0x7854, 0 }, 449795f5e2cSLuis R. Rodriguez { 0x7820, 0 }, 450795f5e2cSLuis R. Rodriguez { 0x7824, 0 }, 451795f5e2cSLuis R. Rodriguez { 0x7868, 0 }, 452795f5e2cSLuis R. Rodriguez { 0x783c, 0 }, 453795f5e2cSLuis R. Rodriguez { 0x7838, 0 } , 454795f5e2cSLuis R. Rodriguez { 0x7828, 0 } , 455795f5e2cSLuis R. Rodriguez }; 456795f5e2cSLuis R. Rodriguez 457795f5e2cSLuis R. Rodriguez for (i = 0; i < ARRAY_SIZE(regList); i++) 458795f5e2cSLuis R. Rodriguez regList[i][1] = REG_READ(ah, regList[i][0]); 459795f5e2cSLuis R. Rodriguez 460795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 461795f5e2cSLuis R. Rodriguez regVal &= (~(0x1)); 462795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 463795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x9808); 464795f5e2cSLuis R. Rodriguez regVal |= (0x1 << 27); 465795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x9808, regVal); 466795f5e2cSLuis R. Rodriguez 467795f5e2cSLuis R. Rodriguez /* 786c,b23,1, pwddac=1 */ 468795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 469795f5e2cSLuis R. Rodriguez /* 7854, b5,1, pdrxtxbb=1 */ 470795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 471795f5e2cSLuis R. Rodriguez /* 7854, b7,1, pdv2i=1 */ 472795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 473795f5e2cSLuis R. Rodriguez /* 7854, b8,1, pddacinterface=1 */ 474795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 475795f5e2cSLuis R. Rodriguez /* 7824,b12,0, offcal=0 */ 476795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 477795f5e2cSLuis R. Rodriguez /* 7838, b1,0, pwddb=0 */ 478795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 479795f5e2cSLuis R. Rodriguez /* 7820,b11,0, enpacal=0 */ 480795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 481795f5e2cSLuis R. Rodriguez /* 7820,b25,1, pdpadrv1=0 */ 482795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 483795f5e2cSLuis R. Rodriguez /* 7820,b24,0, pdpadrv2=0 */ 484795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 485795f5e2cSLuis R. Rodriguez /* 7820,b23,0, pdpaout=0 */ 486795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 487795f5e2cSLuis R. Rodriguez /* 783c,b14-16,7, padrvgn2tab_0=7 */ 488795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 489795f5e2cSLuis R. Rodriguez /* 490795f5e2cSLuis R. Rodriguez * 7838,b29-31,0, padrvgn1tab_0=0 491795f5e2cSLuis R. Rodriguez * does not matter since we turn it off 492795f5e2cSLuis R. Rodriguez */ 493795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 494795f5e2cSLuis R. Rodriguez 495795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); 496795f5e2cSLuis R. Rodriguez 497795f5e2cSLuis R. Rodriguez /* Set: 498795f5e2cSLuis R. Rodriguez * localmode=1,bmode=1,bmoderxtx=1,synthon=1, 499795f5e2cSLuis R. Rodriguez * txon=1,paon=1,oscon=1,synthon_force=1 500795f5e2cSLuis R. Rodriguez */ 501795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 502795f5e2cSLuis R. Rodriguez udelay(30); 503795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); 504795f5e2cSLuis R. Rodriguez 505795f5e2cSLuis R. Rodriguez /* find off_6_1; */ 506795f5e2cSLuis R. Rodriguez for (i = 6; i > 0; i--) { 507795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 508795f5e2cSLuis R. Rodriguez regVal |= (1 << (20 + i)); 509795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 510795f5e2cSLuis R. Rodriguez udelay(1); 511795f5e2cSLuis R. Rodriguez /* regVal = REG_READ(ah, 0x7834); */ 512795f5e2cSLuis R. Rodriguez regVal &= (~(0x1 << (20 + i))); 513795f5e2cSLuis R. Rodriguez regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9) 514795f5e2cSLuis R. Rodriguez << (20 + i)); 515795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 516795f5e2cSLuis R. Rodriguez } 517795f5e2cSLuis R. Rodriguez 518795f5e2cSLuis R. Rodriguez regVal = (regVal >> 20) & 0x7f; 519795f5e2cSLuis R. Rodriguez 520795f5e2cSLuis R. Rodriguez /* Update PA cal info */ 521795f5e2cSLuis R. Rodriguez if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { 522795f5e2cSLuis R. Rodriguez if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 523795f5e2cSLuis R. Rodriguez ah->pacal_info.max_skipcount = 524795f5e2cSLuis R. Rodriguez 2 * ah->pacal_info.max_skipcount; 525795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 526795f5e2cSLuis R. Rodriguez } else { 527795f5e2cSLuis R. Rodriguez ah->pacal_info.max_skipcount = 1; 528795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount = 0; 529795f5e2cSLuis R. Rodriguez ah->pacal_info.prev_offset = regVal; 530795f5e2cSLuis R. Rodriguez } 531795f5e2cSLuis R. Rodriguez 5327d0d0df0SSujith ENABLE_REGWRITE_BUFFER(ah); 5337d0d0df0SSujith 534795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 535795f5e2cSLuis R. Rodriguez regVal |= 0x1; 536795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 537795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x9808); 538795f5e2cSLuis R. Rodriguez regVal &= (~(0x1 << 27)); 539795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x9808, regVal); 540795f5e2cSLuis R. Rodriguez 541795f5e2cSLuis R. Rodriguez for (i = 0; i < ARRAY_SIZE(regList); i++) 542795f5e2cSLuis R. Rodriguez REG_WRITE(ah, regList[i][0], regList[i][1]); 5437d0d0df0SSujith 5447d0d0df0SSujith REGWRITE_BUFFER_FLUSH(ah); 545795f5e2cSLuis R. Rodriguez } 546795f5e2cSLuis R. Rodriguez 547795f5e2cSLuis R. Rodriguez static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) 548795f5e2cSLuis R. Rodriguez { 549795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 550795f5e2cSLuis R. Rodriguez u32 regVal; 551795f5e2cSLuis R. Rodriguez int i, offset, offs_6_1, offs_0; 552795f5e2cSLuis R. Rodriguez u32 ccomp_org, reg_field; 553795f5e2cSLuis R. Rodriguez u32 regList[][2] = { 554795f5e2cSLuis R. Rodriguez { 0x786c, 0 }, 555795f5e2cSLuis R. Rodriguez { 0x7854, 0 }, 556795f5e2cSLuis R. Rodriguez { 0x7820, 0 }, 557795f5e2cSLuis R. Rodriguez { 0x7824, 0 }, 558795f5e2cSLuis R. Rodriguez { 0x7868, 0 }, 559795f5e2cSLuis R. Rodriguez { 0x783c, 0 }, 560795f5e2cSLuis R. Rodriguez { 0x7838, 0 }, 561795f5e2cSLuis R. Rodriguez }; 562795f5e2cSLuis R. Rodriguez 563226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n"); 564795f5e2cSLuis R. Rodriguez 565795f5e2cSLuis R. Rodriguez /* PA CAL is not needed for high power solution */ 566795f5e2cSLuis R. Rodriguez if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 567795f5e2cSLuis R. Rodriguez AR5416_EEP_TXGAIN_HIGH_POWER) 568795f5e2cSLuis R. Rodriguez return; 569795f5e2cSLuis R. Rodriguez 570795f5e2cSLuis R. Rodriguez for (i = 0; i < ARRAY_SIZE(regList); i++) 571795f5e2cSLuis R. Rodriguez regList[i][1] = REG_READ(ah, regList[i][0]); 572795f5e2cSLuis R. Rodriguez 573795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 574795f5e2cSLuis R. Rodriguez regVal &= (~(0x1)); 575795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 576795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x9808); 577795f5e2cSLuis R. Rodriguez regVal |= (0x1 << 27); 578795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x9808, regVal); 579795f5e2cSLuis R. Rodriguez 580795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 581795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 582795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 583795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 584795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 585795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 586795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 587795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 588795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 589795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 590795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 591795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 592795f5e2cSLuis R. Rodriguez ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 593795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); 594795f5e2cSLuis R. Rodriguez 595795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 596795f5e2cSLuis R. Rodriguez udelay(30); 597795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 598795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 599795f5e2cSLuis R. Rodriguez 600795f5e2cSLuis R. Rodriguez for (i = 6; i > 0; i--) { 601795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 602795f5e2cSLuis R. Rodriguez regVal |= (1 << (19 + i)); 603795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 604795f5e2cSLuis R. Rodriguez udelay(1); 605795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 606795f5e2cSLuis R. Rodriguez regVal &= (~(0x1 << (19 + i))); 607795f5e2cSLuis R. Rodriguez reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 608795f5e2cSLuis R. Rodriguez regVal |= (reg_field << (19 + i)); 609795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 610795f5e2cSLuis R. Rodriguez } 611795f5e2cSLuis R. Rodriguez 612795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 613795f5e2cSLuis R. Rodriguez udelay(1); 614795f5e2cSLuis R. Rodriguez reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 615795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 616795f5e2cSLuis R. Rodriguez offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 617795f5e2cSLuis R. Rodriguez offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 618795f5e2cSLuis R. Rodriguez 619795f5e2cSLuis R. Rodriguez offset = (offs_6_1<<1) | offs_0; 620795f5e2cSLuis R. Rodriguez offset = offset - 0; 621795f5e2cSLuis R. Rodriguez offs_6_1 = offset>>1; 622795f5e2cSLuis R. Rodriguez offs_0 = offset & 1; 623795f5e2cSLuis R. Rodriguez 624795f5e2cSLuis R. Rodriguez if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { 625795f5e2cSLuis R. Rodriguez if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 626795f5e2cSLuis R. Rodriguez ah->pacal_info.max_skipcount = 627795f5e2cSLuis R. Rodriguez 2 * ah->pacal_info.max_skipcount; 628795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 629795f5e2cSLuis R. Rodriguez } else { 630795f5e2cSLuis R. Rodriguez ah->pacal_info.max_skipcount = 1; 631795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount = 0; 632795f5e2cSLuis R. Rodriguez ah->pacal_info.prev_offset = offset; 633795f5e2cSLuis R. Rodriguez } 634795f5e2cSLuis R. Rodriguez 635795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 636795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 637795f5e2cSLuis R. Rodriguez 638795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x7834); 639795f5e2cSLuis R. Rodriguez regVal |= 0x1; 640795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x7834, regVal); 641795f5e2cSLuis R. Rodriguez regVal = REG_READ(ah, 0x9808); 642795f5e2cSLuis R. Rodriguez regVal &= (~(0x1 << 27)); 643795f5e2cSLuis R. Rodriguez REG_WRITE(ah, 0x9808, regVal); 644795f5e2cSLuis R. Rodriguez 645795f5e2cSLuis R. Rodriguez for (i = 0; i < ARRAY_SIZE(regList); i++) 646795f5e2cSLuis R. Rodriguez REG_WRITE(ah, regList[i][0], regList[i][1]); 647795f5e2cSLuis R. Rodriguez 648795f5e2cSLuis R. Rodriguez REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 649795f5e2cSLuis R. Rodriguez } 650795f5e2cSLuis R. Rodriguez 651795f5e2cSLuis R. Rodriguez static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) 652795f5e2cSLuis R. Rodriguez { 653795f5e2cSLuis R. Rodriguez if (AR_SREV_9271(ah)) { 654795f5e2cSLuis R. Rodriguez if (is_reset || !ah->pacal_info.skipcount) 655795f5e2cSLuis R. Rodriguez ar9271_hw_pa_cal(ah, is_reset); 656795f5e2cSLuis R. Rodriguez else 657795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount--; 658e17f83eaSFelix Fietkau } else if (AR_SREV_9285_12_OR_LATER(ah)) { 659795f5e2cSLuis R. Rodriguez if (is_reset || !ah->pacal_info.skipcount) 660795f5e2cSLuis R. Rodriguez ar9285_hw_pa_cal(ah, is_reset); 661795f5e2cSLuis R. Rodriguez else 662795f5e2cSLuis R. Rodriguez ah->pacal_info.skipcount--; 663795f5e2cSLuis R. Rodriguez } 664795f5e2cSLuis R. Rodriguez } 665795f5e2cSLuis R. Rodriguez 666795f5e2cSLuis R. Rodriguez static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) 667795f5e2cSLuis R. Rodriguez { 668795f5e2cSLuis R. Rodriguez if (OLC_FOR_AR9287_10_LATER) 669795f5e2cSLuis R. Rodriguez ar9287_hw_olc_temp_compensation(ah); 670795f5e2cSLuis R. Rodriguez else if (OLC_FOR_AR9280_20_LATER) 671795f5e2cSLuis R. Rodriguez ar9280_hw_olc_temp_compensation(ah); 672795f5e2cSLuis R. Rodriguez } 673795f5e2cSLuis R. Rodriguez 674795f5e2cSLuis R. Rodriguez static bool ar9002_hw_calibrate(struct ath_hw *ah, 675795f5e2cSLuis R. Rodriguez struct ath9k_channel *chan, 676795f5e2cSLuis R. Rodriguez u8 rxchainmask, 677795f5e2cSLuis R. Rodriguez bool longcal) 678795f5e2cSLuis R. Rodriguez { 679795f5e2cSLuis R. Rodriguez bool iscaldone = true; 680795f5e2cSLuis R. Rodriguez struct ath9k_cal_list *currCal = ah->cal_list_curr; 6814254bc1cSFelix Fietkau bool nfcal, nfcal_pending = false; 682795f5e2cSLuis R. Rodriguez 6834254bc1cSFelix Fietkau nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); 6844254bc1cSFelix Fietkau if (ah->caldata) 6854254bc1cSFelix Fietkau nfcal_pending = ah->caldata->nfcal_pending; 6864254bc1cSFelix Fietkau 6874254bc1cSFelix Fietkau if (currCal && !nfcal && 688795f5e2cSLuis R. Rodriguez (currCal->calState == CAL_RUNNING || 689795f5e2cSLuis R. Rodriguez currCal->calState == CAL_WAITING)) { 690795f5e2cSLuis R. Rodriguez iscaldone = ar9002_hw_per_calibration(ah, chan, 691795f5e2cSLuis R. Rodriguez rxchainmask, currCal); 692795f5e2cSLuis R. Rodriguez if (iscaldone) { 693795f5e2cSLuis R. Rodriguez ah->cal_list_curr = currCal = currCal->calNext; 694795f5e2cSLuis R. Rodriguez 695795f5e2cSLuis R. Rodriguez if (currCal->calState == CAL_WAITING) { 696795f5e2cSLuis R. Rodriguez iscaldone = false; 697795f5e2cSLuis R. Rodriguez ath9k_hw_reset_calibration(ah, currCal); 698795f5e2cSLuis R. Rodriguez } 699795f5e2cSLuis R. Rodriguez } 700795f5e2cSLuis R. Rodriguez } 701795f5e2cSLuis R. Rodriguez 702795f5e2cSLuis R. Rodriguez /* Do NF cal only at longer intervals */ 7034254bc1cSFelix Fietkau if (longcal || nfcal_pending) { 704795f5e2cSLuis R. Rodriguez /* 705795f5e2cSLuis R. Rodriguez * Get the value from the previous NF cal and update 706795f5e2cSLuis R. Rodriguez * history buffer. 707795f5e2cSLuis R. Rodriguez */ 7084254bc1cSFelix Fietkau if (ath9k_hw_getnf(ah, chan)) { 709795f5e2cSLuis R. Rodriguez /* 7104254bc1cSFelix Fietkau * Load the NF from history buffer of the current 7114254bc1cSFelix Fietkau * channel. 7124254bc1cSFelix Fietkau * NF is slow time-variant, so it is OK to use a 7134254bc1cSFelix Fietkau * historical value. 714795f5e2cSLuis R. Rodriguez */ 715795f5e2cSLuis R. Rodriguez ath9k_hw_loadnf(ah, ah->curchan); 7164254bc1cSFelix Fietkau } 717795f5e2cSLuis R. Rodriguez 718811ea256SRajkumar Manoharan if (longcal) { 71900c86590SFelix Fietkau ath9k_hw_start_nfcal(ah, false); 720811ea256SRajkumar Manoharan /* Do periodic PAOffset Cal */ 721811ea256SRajkumar Manoharan ar9002_hw_pa_cal(ah, false); 722811ea256SRajkumar Manoharan ar9002_hw_olc_temp_compensation(ah); 723811ea256SRajkumar Manoharan } 724795f5e2cSLuis R. Rodriguez } 725795f5e2cSLuis R. Rodriguez 726795f5e2cSLuis R. Rodriguez return iscaldone; 727795f5e2cSLuis R. Rodriguez } 728795f5e2cSLuis R. Rodriguez 729795f5e2cSLuis R. Rodriguez /* Carrier leakage Calibration fix */ 730795f5e2cSLuis R. Rodriguez static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) 731795f5e2cSLuis R. Rodriguez { 732795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 733795f5e2cSLuis R. Rodriguez 734795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 735795f5e2cSLuis R. Rodriguez if (IS_CHAN_HT20(chan)) { 736795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 737795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 738795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 739795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_FLTR_CAL); 740795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 741795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 742795f5e2cSLuis R. Rodriguez if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 743795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { 744226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 745226afe68SJoe Perches "offset calibration failed to complete in 1ms; noisy environment?\n"); 746795f5e2cSLuis R. Rodriguez return false; 747795f5e2cSLuis R. Rodriguez } 748795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 749795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 750795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 751795f5e2cSLuis R. Rodriguez } 752795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 753795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 754795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 755795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 756795f5e2cSLuis R. Rodriguez if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 757795f5e2cSLuis R. Rodriguez 0, AH_WAIT_TIMEOUT)) { 758226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 759226afe68SJoe Perches "offset calibration failed to complete in 1ms; noisy environment?\n"); 760795f5e2cSLuis R. Rodriguez return false; 761795f5e2cSLuis R. Rodriguez } 762795f5e2cSLuis R. Rodriguez 763795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 764795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 765795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 766795f5e2cSLuis R. Rodriguez 767795f5e2cSLuis R. Rodriguez return true; 768795f5e2cSLuis R. Rodriguez } 769795f5e2cSLuis R. Rodriguez 770795f5e2cSLuis R. Rodriguez static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan) 771795f5e2cSLuis R. Rodriguez { 772795f5e2cSLuis R. Rodriguez int i; 773795f5e2cSLuis R. Rodriguez u_int32_t txgain_max; 774795f5e2cSLuis R. Rodriguez u_int32_t clc_gain, gain_mask = 0, clc_num = 0; 775795f5e2cSLuis R. Rodriguez u_int32_t reg_clc_I0, reg_clc_Q0; 776795f5e2cSLuis R. Rodriguez u_int32_t i0_num = 0; 777795f5e2cSLuis R. Rodriguez u_int32_t q0_num = 0; 778795f5e2cSLuis R. Rodriguez u_int32_t total_num = 0; 779795f5e2cSLuis R. Rodriguez u_int32_t reg_rf2g5_org; 780795f5e2cSLuis R. Rodriguez bool retv = true; 781795f5e2cSLuis R. Rodriguez 782795f5e2cSLuis R. Rodriguez if (!(ar9285_hw_cl_cal(ah, chan))) 783795f5e2cSLuis R. Rodriguez return false; 784795f5e2cSLuis R. Rodriguez 785795f5e2cSLuis R. Rodriguez txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7), 786795f5e2cSLuis R. Rodriguez AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 787795f5e2cSLuis R. Rodriguez 788795f5e2cSLuis R. Rodriguez for (i = 0; i < (txgain_max+1); i++) { 789795f5e2cSLuis R. Rodriguez clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & 790795f5e2cSLuis R. Rodriguez AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; 791795f5e2cSLuis R. Rodriguez if (!(gain_mask & (1 << clc_gain))) { 792795f5e2cSLuis R. Rodriguez gain_mask |= (1 << clc_gain); 793795f5e2cSLuis R. Rodriguez clc_num++; 794795f5e2cSLuis R. Rodriguez } 795795f5e2cSLuis R. Rodriguez } 796795f5e2cSLuis R. Rodriguez 797795f5e2cSLuis R. Rodriguez for (i = 0; i < clc_num; i++) { 798795f5e2cSLuis R. Rodriguez reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 799795f5e2cSLuis R. Rodriguez & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; 800795f5e2cSLuis R. Rodriguez reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 801795f5e2cSLuis R. Rodriguez & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; 802795f5e2cSLuis R. Rodriguez if (reg_clc_I0 == 0) 803795f5e2cSLuis R. Rodriguez i0_num++; 804795f5e2cSLuis R. Rodriguez 805795f5e2cSLuis R. Rodriguez if (reg_clc_Q0 == 0) 806795f5e2cSLuis R. Rodriguez q0_num++; 807795f5e2cSLuis R. Rodriguez } 808795f5e2cSLuis R. Rodriguez total_num = i0_num + q0_num; 809795f5e2cSLuis R. Rodriguez if (total_num > AR9285_CLCAL_REDO_THRESH) { 810795f5e2cSLuis R. Rodriguez reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5); 811795f5e2cSLuis R. Rodriguez if (AR_SREV_9285E_20(ah)) { 812795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR9285_RF2G5, 813795f5e2cSLuis R. Rodriguez (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 814795f5e2cSLuis R. Rodriguez AR9285_RF2G5_IC50TX_XE_SET); 815795f5e2cSLuis R. Rodriguez } else { 816795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR9285_RF2G5, 817795f5e2cSLuis R. Rodriguez (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 818795f5e2cSLuis R. Rodriguez AR9285_RF2G5_IC50TX_SET); 819795f5e2cSLuis R. Rodriguez } 820795f5e2cSLuis R. Rodriguez retv = ar9285_hw_cl_cal(ah, chan); 821795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); 822795f5e2cSLuis R. Rodriguez } 823795f5e2cSLuis R. Rodriguez return retv; 824795f5e2cSLuis R. Rodriguez } 825795f5e2cSLuis R. Rodriguez 826795f5e2cSLuis R. Rodriguez static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) 827795f5e2cSLuis R. Rodriguez { 828795f5e2cSLuis R. Rodriguez struct ath_common *common = ath9k_hw_common(ah); 829795f5e2cSLuis R. Rodriguez 830a4d6e17dSRajkumar Manoharan if (AR_SREV_9271(ah)) { 831a4d6e17dSRajkumar Manoharan if (!ar9285_hw_cl_cal(ah, chan)) 832a4d6e17dSRajkumar Manoharan return false; 8331df85eceSAdrian Chadd } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { 834795f5e2cSLuis R. Rodriguez if (!ar9285_hw_clc(ah, chan)) 835795f5e2cSLuis R. Rodriguez return false; 836795f5e2cSLuis R. Rodriguez } else { 8377a37081eSFelix Fietkau if (AR_SREV_9280_20_OR_LATER(ah)) { 838a42acef0SFelix Fietkau if (!AR_SREV_9287_11_OR_LATER(ah)) 839795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_ADC_CTL, 840795f5e2cSLuis R. Rodriguez AR_PHY_ADC_CTL_OFF_PWDADC); 841795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 842795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_FLTR_CAL); 843795f5e2cSLuis R. Rodriguez } 844795f5e2cSLuis R. Rodriguez 845795f5e2cSLuis R. Rodriguez /* Calibrate the AGC */ 846795f5e2cSLuis R. Rodriguez REG_WRITE(ah, AR_PHY_AGC_CONTROL, 847795f5e2cSLuis R. Rodriguez REG_READ(ah, AR_PHY_AGC_CONTROL) | 848795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_CAL); 849795f5e2cSLuis R. Rodriguez 850795f5e2cSLuis R. Rodriguez /* Poll for offset calibration complete */ 851795f5e2cSLuis R. Rodriguez if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, 852795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_CAL, 853795f5e2cSLuis R. Rodriguez 0, AH_WAIT_TIMEOUT)) { 854226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 855226afe68SJoe Perches "offset calibration failed to complete in 1ms; noisy environment?\n"); 856795f5e2cSLuis R. Rodriguez return false; 857795f5e2cSLuis R. Rodriguez } 858795f5e2cSLuis R. Rodriguez 8597a37081eSFelix Fietkau if (AR_SREV_9280_20_OR_LATER(ah)) { 860a42acef0SFelix Fietkau if (!AR_SREV_9287_11_OR_LATER(ah)) 861795f5e2cSLuis R. Rodriguez REG_SET_BIT(ah, AR_PHY_ADC_CTL, 862795f5e2cSLuis R. Rodriguez AR_PHY_ADC_CTL_OFF_PWDADC); 863795f5e2cSLuis R. Rodriguez REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, 864795f5e2cSLuis R. Rodriguez AR_PHY_AGC_CONTROL_FLTR_CAL); 865795f5e2cSLuis R. Rodriguez } 866795f5e2cSLuis R. Rodriguez } 867795f5e2cSLuis R. Rodriguez 868795f5e2cSLuis R. Rodriguez /* Do PA Calibration */ 869795f5e2cSLuis R. Rodriguez ar9002_hw_pa_cal(ah, true); 870795f5e2cSLuis R. Rodriguez 871795f5e2cSLuis R. Rodriguez /* Do NF Calibration after DC offset and other calibrations */ 87200c86590SFelix Fietkau ath9k_hw_start_nfcal(ah, true); 873795f5e2cSLuis R. Rodriguez 8744254bc1cSFelix Fietkau if (ah->caldata) 8754254bc1cSFelix Fietkau ah->caldata->nfcal_pending = true; 8764254bc1cSFelix Fietkau 877795f5e2cSLuis R. Rodriguez ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 878795f5e2cSLuis R. Rodriguez 879795f5e2cSLuis R. Rodriguez /* Enable IQ, ADC Gain and ADC DC offset CALs */ 880795f5e2cSLuis R. Rodriguez if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { 8816497827fSFelix Fietkau ah->supp_cals = IQ_MISMATCH_CAL; 8826497827fSFelix Fietkau 88381544026SRajkumar Manoharan if (AR_SREV_9160_10_OR_LATER(ah)) 8846497827fSFelix Fietkau ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; 8856497827fSFelix Fietkau 88681544026SRajkumar Manoharan if (AR_SREV_9287(ah)) 88781544026SRajkumar Manoharan ah->supp_cals &= ~ADC_GAIN_CAL; 8886497827fSFelix Fietkau 88981544026SRajkumar Manoharan if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { 890795f5e2cSLuis R. Rodriguez INIT_CAL(&ah->adcgain_caldata); 891795f5e2cSLuis R. Rodriguez INSERT_CAL(ah, &ah->adcgain_caldata); 892226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 893795f5e2cSLuis R. Rodriguez "enabling ADC Gain Calibration.\n"); 89481544026SRajkumar Manoharan } 8956497827fSFelix Fietkau 89681544026SRajkumar Manoharan if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { 897795f5e2cSLuis R. Rodriguez INIT_CAL(&ah->adcdc_caldata); 898795f5e2cSLuis R. Rodriguez INSERT_CAL(ah, &ah->adcdc_caldata); 899226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 900795f5e2cSLuis R. Rodriguez "enabling ADC DC Calibration.\n"); 901795f5e2cSLuis R. Rodriguez } 9026497827fSFelix Fietkau 90381544026SRajkumar Manoharan if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { 904795f5e2cSLuis R. Rodriguez INIT_CAL(&ah->iq_caldata); 905795f5e2cSLuis R. Rodriguez INSERT_CAL(ah, &ah->iq_caldata); 906226afe68SJoe Perches ath_dbg(common, ATH_DBG_CALIBRATE, 907795f5e2cSLuis R. Rodriguez "enabling IQ Calibration.\n"); 90881544026SRajkumar Manoharan } 909795f5e2cSLuis R. Rodriguez 910795f5e2cSLuis R. Rodriguez ah->cal_list_curr = ah->cal_list; 911795f5e2cSLuis R. Rodriguez 912795f5e2cSLuis R. Rodriguez if (ah->cal_list_curr) 913795f5e2cSLuis R. Rodriguez ath9k_hw_reset_calibration(ah, ah->cal_list_curr); 914795f5e2cSLuis R. Rodriguez } 915795f5e2cSLuis R. Rodriguez 91620bd2a09SFelix Fietkau if (ah->caldata) 91720bd2a09SFelix Fietkau ah->caldata->CalValid = 0; 918795f5e2cSLuis R. Rodriguez 919795f5e2cSLuis R. Rodriguez return true; 920795f5e2cSLuis R. Rodriguez } 921795f5e2cSLuis R. Rodriguez 922795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data iq_cal_multi_sample = { 923795f5e2cSLuis R. Rodriguez IQ_MISMATCH_CAL, 924795f5e2cSLuis R. Rodriguez MAX_CAL_SAMPLES, 925795f5e2cSLuis R. Rodriguez PER_MIN_LOG_COUNT, 926795f5e2cSLuis R. Rodriguez ar9002_hw_iqcal_collect, 927795f5e2cSLuis R. Rodriguez ar9002_hw_iqcalibrate 928795f5e2cSLuis R. Rodriguez }; 929795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data iq_cal_single_sample = { 930795f5e2cSLuis R. Rodriguez IQ_MISMATCH_CAL, 931795f5e2cSLuis R. Rodriguez MIN_CAL_SAMPLES, 932795f5e2cSLuis R. Rodriguez PER_MAX_LOG_COUNT, 933795f5e2cSLuis R. Rodriguez ar9002_hw_iqcal_collect, 934795f5e2cSLuis R. Rodriguez ar9002_hw_iqcalibrate 935795f5e2cSLuis R. Rodriguez }; 936795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data adc_gain_cal_multi_sample = { 937795f5e2cSLuis R. Rodriguez ADC_GAIN_CAL, 938795f5e2cSLuis R. Rodriguez MAX_CAL_SAMPLES, 939795f5e2cSLuis R. Rodriguez PER_MIN_LOG_COUNT, 940795f5e2cSLuis R. Rodriguez ar9002_hw_adc_gaincal_collect, 941795f5e2cSLuis R. Rodriguez ar9002_hw_adc_gaincal_calibrate 942795f5e2cSLuis R. Rodriguez }; 943795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data adc_gain_cal_single_sample = { 944795f5e2cSLuis R. Rodriguez ADC_GAIN_CAL, 945795f5e2cSLuis R. Rodriguez MIN_CAL_SAMPLES, 946795f5e2cSLuis R. Rodriguez PER_MAX_LOG_COUNT, 947795f5e2cSLuis R. Rodriguez ar9002_hw_adc_gaincal_collect, 948795f5e2cSLuis R. Rodriguez ar9002_hw_adc_gaincal_calibrate 949795f5e2cSLuis R. Rodriguez }; 950795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data adc_dc_cal_multi_sample = { 951795f5e2cSLuis R. Rodriguez ADC_DC_CAL, 952795f5e2cSLuis R. Rodriguez MAX_CAL_SAMPLES, 953795f5e2cSLuis R. Rodriguez PER_MIN_LOG_COUNT, 954795f5e2cSLuis R. Rodriguez ar9002_hw_adc_dccal_collect, 955795f5e2cSLuis R. Rodriguez ar9002_hw_adc_dccal_calibrate 956795f5e2cSLuis R. Rodriguez }; 957795f5e2cSLuis R. Rodriguez static const struct ath9k_percal_data adc_dc_cal_single_sample = { 958795f5e2cSLuis R. Rodriguez ADC_DC_CAL, 959795f5e2cSLuis R. Rodriguez MIN_CAL_SAMPLES, 960795f5e2cSLuis R. Rodriguez PER_MAX_LOG_COUNT, 961795f5e2cSLuis R. Rodriguez ar9002_hw_adc_dccal_collect, 962795f5e2cSLuis R. Rodriguez ar9002_hw_adc_dccal_calibrate 963795f5e2cSLuis R. Rodriguez }; 964795f5e2cSLuis R. Rodriguez 965795f5e2cSLuis R. Rodriguez static void ar9002_hw_init_cal_settings(struct ath_hw *ah) 966795f5e2cSLuis R. Rodriguez { 967795f5e2cSLuis R. Rodriguez if (AR_SREV_9100(ah)) { 968795f5e2cSLuis R. Rodriguez ah->iq_caldata.calData = &iq_cal_multi_sample; 969795f5e2cSLuis R. Rodriguez ah->supp_cals = IQ_MISMATCH_CAL; 970795f5e2cSLuis R. Rodriguez return; 971795f5e2cSLuis R. Rodriguez } 972795f5e2cSLuis R. Rodriguez 973795f5e2cSLuis R. Rodriguez if (AR_SREV_9160_10_OR_LATER(ah)) { 9747a37081eSFelix Fietkau if (AR_SREV_9280_20_OR_LATER(ah)) { 975795f5e2cSLuis R. Rodriguez ah->iq_caldata.calData = &iq_cal_single_sample; 976795f5e2cSLuis R. Rodriguez ah->adcgain_caldata.calData = 977795f5e2cSLuis R. Rodriguez &adc_gain_cal_single_sample; 978795f5e2cSLuis R. Rodriguez ah->adcdc_caldata.calData = 979795f5e2cSLuis R. Rodriguez &adc_dc_cal_single_sample; 980795f5e2cSLuis R. Rodriguez } else { 981795f5e2cSLuis R. Rodriguez ah->iq_caldata.calData = &iq_cal_multi_sample; 982795f5e2cSLuis R. Rodriguez ah->adcgain_caldata.calData = 983795f5e2cSLuis R. Rodriguez &adc_gain_cal_multi_sample; 984795f5e2cSLuis R. Rodriguez ah->adcdc_caldata.calData = 985795f5e2cSLuis R. Rodriguez &adc_dc_cal_multi_sample; 986795f5e2cSLuis R. Rodriguez } 987795f5e2cSLuis R. Rodriguez ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; 98807422063SSujith Manoharan 98907422063SSujith Manoharan if (AR_SREV_9287(ah)) 99007422063SSujith Manoharan ah->supp_cals &= ~ADC_GAIN_CAL; 991795f5e2cSLuis R. Rodriguez } 992795f5e2cSLuis R. Rodriguez } 993795f5e2cSLuis R. Rodriguez 994795f5e2cSLuis R. Rodriguez void ar9002_hw_attach_calib_ops(struct ath_hw *ah) 995795f5e2cSLuis R. Rodriguez { 996795f5e2cSLuis R. Rodriguez struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 997795f5e2cSLuis R. Rodriguez struct ath_hw_ops *ops = ath9k_hw_ops(ah); 998795f5e2cSLuis R. Rodriguez 999795f5e2cSLuis R. Rodriguez priv_ops->init_cal_settings = ar9002_hw_init_cal_settings; 1000795f5e2cSLuis R. Rodriguez priv_ops->init_cal = ar9002_hw_init_cal; 1001795f5e2cSLuis R. Rodriguez priv_ops->setup_calibration = ar9002_hw_setup_calibration; 1002795f5e2cSLuis R. Rodriguez 1003795f5e2cSLuis R. Rodriguez ops->calibrate = ar9002_hw_calibrate; 1004795f5e2cSLuis R. Rodriguez } 1005