162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "hw.h" 1862306a36Sopenharmony_ci#include "hw-ops.h" 1962306a36Sopenharmony_ci#include "ar9002_phy.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define AR9285_CLCAL_REDO_THRESH 1 2262306a36Sopenharmony_ci/* AGC & I/Q calibrations time limit, ms */ 2362306a36Sopenharmony_ci#define AR9002_CAL_MAX_TIME 30000 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cienum ar9002_cal_types { 2662306a36Sopenharmony_ci ADC_GAIN_CAL = BIT(0), 2762306a36Sopenharmony_ci ADC_DC_CAL = BIT(1), 2862306a36Sopenharmony_ci IQ_MISMATCH_CAL = BIT(2), 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic bool ar9002_hw_is_cal_supported(struct ath_hw *ah, 3262306a36Sopenharmony_ci struct ath9k_channel *chan, 3362306a36Sopenharmony_ci enum ar9002_cal_types cal_type) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci bool supported = false; 3662306a36Sopenharmony_ci switch (ah->supp_cals & cal_type) { 3762306a36Sopenharmony_ci case IQ_MISMATCH_CAL: 3862306a36Sopenharmony_ci supported = true; 3962306a36Sopenharmony_ci break; 4062306a36Sopenharmony_ci case ADC_GAIN_CAL: 4162306a36Sopenharmony_ci case ADC_DC_CAL: 4262306a36Sopenharmony_ci /* Run even/odd ADCs calibrations for HT40 channels only */ 4362306a36Sopenharmony_ci if (IS_CHAN_HT40(chan)) 4462306a36Sopenharmony_ci supported = true; 4562306a36Sopenharmony_ci break; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci return supported; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void ar9002_hw_setup_calibration(struct ath_hw *ah, 5162306a36Sopenharmony_ci struct ath9k_cal_list *currCal) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), 5662306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, 5762306a36Sopenharmony_ci currCal->calData->calCountMax); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci switch (currCal->calData->calType) { 6062306a36Sopenharmony_ci case IQ_MISMATCH_CAL: 6162306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); 6262306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 6362306a36Sopenharmony_ci "starting IQ Mismatch Calibration\n"); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci case ADC_GAIN_CAL: 6662306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); 6762306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "starting ADC Gain Calibration\n"); 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci case ADC_DC_CAL: 7062306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); 7162306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "starting ADC DC Calibration\n"); 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 7662306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic bool ar9002_hw_per_calibration(struct ath_hw *ah, 8062306a36Sopenharmony_ci struct ath9k_channel *ichan, 8162306a36Sopenharmony_ci u8 rxchainmask, 8262306a36Sopenharmony_ci struct ath9k_cal_list *currCal) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct ath9k_hw_cal_data *caldata = ah->caldata; 8562306a36Sopenharmony_ci bool iscaldone = false; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (currCal->calState == CAL_RUNNING) { 8862306a36Sopenharmony_ci if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & 8962306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL)) { 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci currCal->calData->calCollect(ah); 9262306a36Sopenharmony_ci ah->cal_samples++; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (ah->cal_samples >= 9562306a36Sopenharmony_ci currCal->calData->calNumSamples) { 9662306a36Sopenharmony_ci int i, numChains = 0; 9762306a36Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 9862306a36Sopenharmony_ci if (rxchainmask & (1 << i)) 9962306a36Sopenharmony_ci numChains++; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci currCal->calData->calPostProc(ah, numChains); 10362306a36Sopenharmony_ci caldata->CalValid |= currCal->calData->calType; 10462306a36Sopenharmony_ci currCal->calState = CAL_DONE; 10562306a36Sopenharmony_ci iscaldone = true; 10662306a36Sopenharmony_ci } else { 10762306a36Sopenharmony_ci ar9002_hw_setup_calibration(ah, currCal); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci } else if (time_after(jiffies, ah->cal_start_time + 11062306a36Sopenharmony_ci msecs_to_jiffies(AR9002_CAL_MAX_TIME))) { 11162306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0), 11262306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_DO_CAL); 11362306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 11462306a36Sopenharmony_ci "calibration timeout\n"); 11562306a36Sopenharmony_ci currCal->calState = CAL_WAITING; /* Try later */ 11662306a36Sopenharmony_ci iscaldone = true; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci } else if (!(caldata->CalValid & currCal->calData->calType)) { 11962306a36Sopenharmony_ci ath9k_hw_reset_calibration(ah, currCal); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return iscaldone; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void ar9002_hw_iqcal_collect(struct ath_hw *ah) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci int i; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 13062306a36Sopenharmony_ci ah->totalPowerMeasI[i] += 13162306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 13262306a36Sopenharmony_ci ah->totalPowerMeasQ[i] += 13362306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 13462306a36Sopenharmony_ci ah->totalIqCorrMeas[i] += 13562306a36Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 13662306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 13762306a36Sopenharmony_ci "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", 13862306a36Sopenharmony_ci ah->cal_samples, i, ah->totalPowerMeasI[i], 13962306a36Sopenharmony_ci ah->totalPowerMeasQ[i], 14062306a36Sopenharmony_ci ah->totalIqCorrMeas[i]); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci int i; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 14962306a36Sopenharmony_ci ah->totalAdcIOddPhase[i] += 15062306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 15162306a36Sopenharmony_ci ah->totalAdcIEvenPhase[i] += 15262306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 15362306a36Sopenharmony_ci ah->totalAdcQOddPhase[i] += 15462306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 15562306a36Sopenharmony_ci ah->totalAdcQEvenPhase[i] += 15662306a36Sopenharmony_ci REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 15962306a36Sopenharmony_ci "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 16062306a36Sopenharmony_ci ah->cal_samples, i, 16162306a36Sopenharmony_ci ah->totalAdcIOddPhase[i], 16262306a36Sopenharmony_ci ah->totalAdcIEvenPhase[i], 16362306a36Sopenharmony_ci ah->totalAdcQOddPhase[i], 16462306a36Sopenharmony_ci ah->totalAdcQEvenPhase[i]); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void ar9002_hw_adc_dccal_collect(struct ath_hw *ah) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int i; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci for (i = 0; i < AR5416_MAX_CHAINS; i++) { 17362306a36Sopenharmony_ci ah->totalAdcDcOffsetIOddPhase[i] += 17462306a36Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); 17562306a36Sopenharmony_ci ah->totalAdcDcOffsetIEvenPhase[i] += 17662306a36Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); 17762306a36Sopenharmony_ci ah->totalAdcDcOffsetQOddPhase[i] += 17862306a36Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); 17962306a36Sopenharmony_ci ah->totalAdcDcOffsetQEvenPhase[i] += 18062306a36Sopenharmony_ci (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci ath_dbg(ath9k_hw_common(ah), CALIBRATE, 18362306a36Sopenharmony_ci "%d: Chn %d oddi=0x%08x; eveni=0x%08x; oddq=0x%08x; evenq=0x%08x;\n", 18462306a36Sopenharmony_ci ah->cal_samples, i, 18562306a36Sopenharmony_ci ah->totalAdcDcOffsetIOddPhase[i], 18662306a36Sopenharmony_ci ah->totalAdcDcOffsetIEvenPhase[i], 18762306a36Sopenharmony_ci ah->totalAdcDcOffsetQOddPhase[i], 18862306a36Sopenharmony_ci ah->totalAdcDcOffsetQEvenPhase[i]); 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 19562306a36Sopenharmony_ci u32 powerMeasQ, powerMeasI, iqCorrMeas; 19662306a36Sopenharmony_ci u32 qCoffDenom, iCoffDenom; 19762306a36Sopenharmony_ci int32_t qCoff, iCoff; 19862306a36Sopenharmony_ci int iqCorrNeg, i; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci for (i = 0; i < numChains; i++) { 20162306a36Sopenharmony_ci powerMeasI = ah->totalPowerMeasI[i]; 20262306a36Sopenharmony_ci powerMeasQ = ah->totalPowerMeasQ[i]; 20362306a36Sopenharmony_ci iqCorrMeas = ah->totalIqCorrMeas[i]; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 20662306a36Sopenharmony_ci "Starting IQ Cal and Correction for Chain %d\n", 20762306a36Sopenharmony_ci i); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 21062306a36Sopenharmony_ci "Original: Chn %d iq_corr_meas = 0x%08x\n", 21162306a36Sopenharmony_ci i, ah->totalIqCorrMeas[i]); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci iqCorrNeg = 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (iqCorrMeas > 0x80000000) { 21662306a36Sopenharmony_ci iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; 21762306a36Sopenharmony_ci iqCorrNeg = 1; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", 22162306a36Sopenharmony_ci i, powerMeasI); 22262306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", 22362306a36Sopenharmony_ci i, powerMeasQ); 22462306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "iqCorrNeg is 0x%08x\n", iqCorrNeg); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; 22762306a36Sopenharmony_ci qCoffDenom = powerMeasQ / 64; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if ((powerMeasQ != 0) && (iCoffDenom != 0) && 23062306a36Sopenharmony_ci (qCoffDenom != 0)) { 23162306a36Sopenharmony_ci iCoff = iqCorrMeas / iCoffDenom; 23262306a36Sopenharmony_ci qCoff = powerMeasI / qCoffDenom - 64; 23362306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d iCoff = 0x%08x\n", 23462306a36Sopenharmony_ci i, iCoff); 23562306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d qCoff = 0x%08x\n", 23662306a36Sopenharmony_ci i, qCoff); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci iCoff = iCoff & 0x3f; 23962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 24062306a36Sopenharmony_ci "New: Chn %d iCoff = 0x%08x\n", i, iCoff); 24162306a36Sopenharmony_ci if (iqCorrNeg == 0x0) 24262306a36Sopenharmony_ci iCoff = 0x40 - iCoff; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (qCoff > 15) 24562306a36Sopenharmony_ci qCoff = 15; 24662306a36Sopenharmony_ci else if (qCoff <= -16) 24762306a36Sopenharmony_ci qCoff = -16; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 25062306a36Sopenharmony_ci "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", 25162306a36Sopenharmony_ci i, iCoff, qCoff); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 25462306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 25562306a36Sopenharmony_ci iCoff); 25662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), 25762306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 25862306a36Sopenharmony_ci qCoff); 25962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 26062306a36Sopenharmony_ci "IQ Cal and Correction done for Chain %d\n", 26162306a36Sopenharmony_ci i); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), 26662306a36Sopenharmony_ci AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 27262306a36Sopenharmony_ci u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; 27362306a36Sopenharmony_ci u32 qGainMismatch, iGainMismatch, val, i; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci for (i = 0; i < numChains; i++) { 27662306a36Sopenharmony_ci iOddMeasOffset = ah->totalAdcIOddPhase[i]; 27762306a36Sopenharmony_ci iEvenMeasOffset = ah->totalAdcIEvenPhase[i]; 27862306a36Sopenharmony_ci qOddMeasOffset = ah->totalAdcQOddPhase[i]; 27962306a36Sopenharmony_ci qEvenMeasOffset = ah->totalAdcQEvenPhase[i]; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 28262306a36Sopenharmony_ci "Starting ADC Gain Cal for Chain %d\n", i); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = 0x%08x\n", 28562306a36Sopenharmony_ci i, iOddMeasOffset); 28662306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = 0x%08x\n", 28762306a36Sopenharmony_ci i, iEvenMeasOffset); 28862306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = 0x%08x\n", 28962306a36Sopenharmony_ci i, qOddMeasOffset); 29062306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = 0x%08x\n", 29162306a36Sopenharmony_ci i, qEvenMeasOffset); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { 29462306a36Sopenharmony_ci iGainMismatch = 29562306a36Sopenharmony_ci ((iEvenMeasOffset * 32) / 29662306a36Sopenharmony_ci iOddMeasOffset) & 0x3f; 29762306a36Sopenharmony_ci qGainMismatch = 29862306a36Sopenharmony_ci ((qOddMeasOffset * 32) / 29962306a36Sopenharmony_ci qEvenMeasOffset) & 0x3f; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 30262306a36Sopenharmony_ci "Chn %d gain_mismatch_i = 0x%08x\n", 30362306a36Sopenharmony_ci i, iGainMismatch); 30462306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 30562306a36Sopenharmony_ci "Chn %d gain_mismatch_q = 0x%08x\n", 30662306a36Sopenharmony_ci i, qGainMismatch); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 30962306a36Sopenharmony_ci val &= 0xfffff000; 31062306a36Sopenharmony_ci val |= (qGainMismatch) | (iGainMismatch << 6); 31162306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 31462306a36Sopenharmony_ci "ADC Gain Cal done for Chain %d\n", i); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 31962306a36Sopenharmony_ci REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 32062306a36Sopenharmony_ci AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 32662306a36Sopenharmony_ci u32 iOddMeasOffset, iEvenMeasOffset, val, i; 32762306a36Sopenharmony_ci int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; 32862306a36Sopenharmony_ci const struct ath9k_percal_data *calData = 32962306a36Sopenharmony_ci ah->cal_list_curr->calData; 33062306a36Sopenharmony_ci u32 numSamples = 33162306a36Sopenharmony_ci (1 << (calData->calCountMax + 5)) * calData->calNumSamples; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci for (i = 0; i < numChains; i++) { 33462306a36Sopenharmony_ci iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i]; 33562306a36Sopenharmony_ci iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i]; 33662306a36Sopenharmony_ci qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i]; 33762306a36Sopenharmony_ci qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i]; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 34062306a36Sopenharmony_ci "Starting ADC DC Offset Cal for Chain %d\n", i); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_i = %d\n", 34362306a36Sopenharmony_ci i, iOddMeasOffset); 34462306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_i = %d\n", 34562306a36Sopenharmony_ci i, iEvenMeasOffset); 34662306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_odd_q = %d\n", 34762306a36Sopenharmony_ci i, qOddMeasOffset); 34862306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Chn %d pwr_meas_even_q = %d\n", 34962306a36Sopenharmony_ci i, qEvenMeasOffset); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / 35262306a36Sopenharmony_ci numSamples) & 0x1ff; 35362306a36Sopenharmony_ci qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / 35462306a36Sopenharmony_ci numSamples) & 0x1ff; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 35762306a36Sopenharmony_ci "Chn %d dc_offset_mismatch_i = 0x%08x\n", 35862306a36Sopenharmony_ci i, iDcMismatch); 35962306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 36062306a36Sopenharmony_ci "Chn %d dc_offset_mismatch_q = 0x%08x\n", 36162306a36Sopenharmony_ci i, qDcMismatch); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); 36462306a36Sopenharmony_ci val &= 0xc0000fff; 36562306a36Sopenharmony_ci val |= (qDcMismatch << 12) | (iDcMismatch << 21); 36662306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 36962306a36Sopenharmony_ci "ADC DC Offset Cal done for Chain %d\n", i); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), 37362306a36Sopenharmony_ci REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | 37462306a36Sopenharmony_ci AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic void ar9287_hw_olc_temp_compensation(struct ath_hw *ah) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci u32 rddata; 38062306a36Sopenharmony_ci int32_t delta, currPDADC, slope; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 38362306a36Sopenharmony_ci currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (ah->initPDADC == 0 || currPDADC == 0) { 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * Zero value indicates that no frames have been transmitted 38862306a36Sopenharmony_ci * yet, can't do temperature compensation until frames are 38962306a36Sopenharmony_ci * transmitted. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci return; 39262306a36Sopenharmony_ci } else { 39362306a36Sopenharmony_ci slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (slope == 0) { /* to avoid divide by zero case */ 39662306a36Sopenharmony_ci delta = 0; 39762306a36Sopenharmony_ci } else { 39862306a36Sopenharmony_ci delta = ((currPDADC - ah->initPDADC)*4) / slope; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11, 40162306a36Sopenharmony_ci AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 40262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11, 40362306a36Sopenharmony_ci AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta); 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void ar9280_hw_olc_temp_compensation(struct ath_hw *ah) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci u32 rddata, i; 41062306a36Sopenharmony_ci int delta, currPDADC, regval; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); 41362306a36Sopenharmony_ci currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (ah->initPDADC == 0 || currPDADC == 0) 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) 41962306a36Sopenharmony_ci delta = (currPDADC - ah->initPDADC + 4) / 8; 42062306a36Sopenharmony_ci else 42162306a36Sopenharmony_ci delta = (currPDADC - ah->initPDADC + 5) / 10; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci if (delta != ah->PDADCdelta) { 42462306a36Sopenharmony_ci ah->PDADCdelta = delta; 42562306a36Sopenharmony_ci for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { 42662306a36Sopenharmony_ci regval = ah->originalGain[i] - delta; 42762306a36Sopenharmony_ci if (regval < 0) 42862306a36Sopenharmony_ci regval = 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci REG_RMW_FIELD(ah, 43162306a36Sopenharmony_ci AR_PHY_TX_GAIN_TBL1 + i * 4, 43262306a36Sopenharmony_ci AR_PHY_TX_GAIN, regval); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci u32 regVal; 44062306a36Sopenharmony_ci unsigned int i; 44162306a36Sopenharmony_ci u32 regList[][2] = { 44262306a36Sopenharmony_ci { AR9285_AN_TOP3, 0 }, 44362306a36Sopenharmony_ci { AR9285_AN_RXTXBB1, 0 }, 44462306a36Sopenharmony_ci { AR9285_AN_RF2G1, 0 }, 44562306a36Sopenharmony_ci { AR9285_AN_RF2G2, 0 }, 44662306a36Sopenharmony_ci { AR9285_AN_TOP2, 0 }, 44762306a36Sopenharmony_ci { AR9285_AN_RF2G8, 0 }, 44862306a36Sopenharmony_ci { AR9285_AN_RF2G7, 0 }, 44962306a36Sopenharmony_ci { AR9285_AN_RF2G3, 0 }, 45062306a36Sopenharmony_ci }; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci REG_READ_ARRAY(ah, regList, ARRAY_SIZE(regList)); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ENABLE_REG_RMW_BUFFER(ah); 45562306a36Sopenharmony_ci /* 7834, b1=0 */ 45662306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G6, 1 << 0); 45762306a36Sopenharmony_ci /* 9808, b27=1 */ 45862306a36Sopenharmony_ci REG_SET_BIT(ah, 0x9808, 1 << 27); 45962306a36Sopenharmony_ci /* 786c,b23,1, pwddac=1 */ 46062306a36Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); 46162306a36Sopenharmony_ci /* 7854, b5,1, pdrxtxbb=1 */ 46262306a36Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); 46362306a36Sopenharmony_ci /* 7854, b7,1, pdv2i=1 */ 46462306a36Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); 46562306a36Sopenharmony_ci /* 7854, b8,1, pddacinterface=1 */ 46662306a36Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); 46762306a36Sopenharmony_ci /* 7824,b12,0, offcal=0 */ 46862306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); 46962306a36Sopenharmony_ci /* 7838, b1,0, pwddb=0 */ 47062306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); 47162306a36Sopenharmony_ci /* 7820,b11,0, enpacal=0 */ 47262306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); 47362306a36Sopenharmony_ci /* 7820,b25,1, pdpadrv1=0 */ 47462306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); 47562306a36Sopenharmony_ci /* 7820,b24,0, pdpadrv2=0 */ 47662306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); 47762306a36Sopenharmony_ci /* 7820,b23,0, pdpaout=0 */ 47862306a36Sopenharmony_ci REG_CLR_BIT(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); 47962306a36Sopenharmony_ci /* 783c,b14-16,7, padrvgn2tab_0=7 */ 48062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * 7838,b29-31,0, padrvgn1tab_0=0 48362306a36Sopenharmony_ci * does not matter since we turn it off 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 48662306a36Sopenharmony_ci /* 7828, b0-11, ccom=fff */ 48762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff); 48862306a36Sopenharmony_ci REG_RMW_BUFFER_FLUSH(ah); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Set: 49162306a36Sopenharmony_ci * localmode=1,bmode=1,bmoderxtx=1,synthon=1, 49262306a36Sopenharmony_ci * txon=1,paon=1,oscon=1,synthon_force=1 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 49562306a36Sopenharmony_ci udelay(30); 49662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* find off_6_1; */ 49962306a36Sopenharmony_ci for (i = 6; i > 0; i--) { 50062306a36Sopenharmony_ci regVal = REG_READ(ah, AR9285_AN_RF2G6); 50162306a36Sopenharmony_ci regVal |= (1 << (20 + i)); 50262306a36Sopenharmony_ci REG_WRITE(ah, AR9285_AN_RF2G6, regVal); 50362306a36Sopenharmony_ci udelay(1); 50462306a36Sopenharmony_ci /* regVal = REG_READ(ah, 0x7834); */ 50562306a36Sopenharmony_ci regVal &= (~(0x1 << (20 + i))); 50662306a36Sopenharmony_ci regVal |= (MS(REG_READ(ah, AR9285_AN_RF2G9), 50762306a36Sopenharmony_ci AR9285_AN_RXTXBB1_SPARE9) 50862306a36Sopenharmony_ci << (20 + i)); 50962306a36Sopenharmony_ci REG_WRITE(ah, AR9285_AN_RF2G6, regVal); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci regVal = (regVal >> 20) & 0x7f; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Update PA cal info */ 51562306a36Sopenharmony_ci if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) { 51662306a36Sopenharmony_ci if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 51762306a36Sopenharmony_ci ah->pacal_info.max_skipcount = 51862306a36Sopenharmony_ci 2 * ah->pacal_info.max_skipcount; 51962306a36Sopenharmony_ci ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci ah->pacal_info.max_skipcount = 1; 52262306a36Sopenharmony_ci ah->pacal_info.skipcount = 0; 52362306a36Sopenharmony_ci ah->pacal_info.prev_offset = regVal; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ENABLE_REG_RMW_BUFFER(ah); 52862306a36Sopenharmony_ci /* 7834, b1=1 */ 52962306a36Sopenharmony_ci REG_SET_BIT(ah, AR9285_AN_RF2G6, 1 << 0); 53062306a36Sopenharmony_ci /* 9808, b27=0 */ 53162306a36Sopenharmony_ci REG_CLR_BIT(ah, 0x9808, 1 << 27); 53262306a36Sopenharmony_ci REG_RMW_BUFFER_FLUSH(ah); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ENABLE_REGWRITE_BUFFER(ah); 53562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 53662306a36Sopenharmony_ci REG_WRITE(ah, regList[i][0], regList[i][1]); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci REGWRITE_BUFFER_FLUSH(ah); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 54462306a36Sopenharmony_ci u32 regVal; 54562306a36Sopenharmony_ci int i, offset, offs_6_1, offs_0; 54662306a36Sopenharmony_ci u32 ccomp_org, reg_field; 54762306a36Sopenharmony_ci u32 regList[][2] = { 54862306a36Sopenharmony_ci { 0x786c, 0 }, 54962306a36Sopenharmony_ci { 0x7854, 0 }, 55062306a36Sopenharmony_ci { 0x7820, 0 }, 55162306a36Sopenharmony_ci { 0x7824, 0 }, 55262306a36Sopenharmony_ci { 0x7868, 0 }, 55362306a36Sopenharmony_ci { 0x783c, 0 }, 55462306a36Sopenharmony_ci { 0x7838, 0 }, 55562306a36Sopenharmony_ci }; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "Running PA Calibration\n"); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* PA CAL is not needed for high power solution */ 56062306a36Sopenharmony_ci if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 56162306a36Sopenharmony_ci AR5416_EEP_TXGAIN_HIGH_POWER) 56262306a36Sopenharmony_ci return; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 56562306a36Sopenharmony_ci regList[i][1] = REG_READ(ah, regList[i][0]); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 56862306a36Sopenharmony_ci regVal &= (~(0x1)); 56962306a36Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 57062306a36Sopenharmony_ci regVal = REG_READ(ah, 0x9808); 57162306a36Sopenharmony_ci regVal |= (0x1 << 27); 57262306a36Sopenharmony_ci REG_WRITE(ah, 0x9808, regVal); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); 57562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); 57662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); 57762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); 57862306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); 57962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); 58062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); 58162306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0); 58262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); 58362306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); 58462306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 58562306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 58662306a36Sopenharmony_ci ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); 58762306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); 59062306a36Sopenharmony_ci udelay(30); 59162306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); 59262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci for (i = 6; i > 0; i--) { 59562306a36Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 59662306a36Sopenharmony_ci regVal |= (1 << (19 + i)); 59762306a36Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 59862306a36Sopenharmony_ci udelay(1); 59962306a36Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 60062306a36Sopenharmony_ci regVal &= (~(0x1 << (19 + i))); 60162306a36Sopenharmony_ci reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); 60262306a36Sopenharmony_ci regVal |= (reg_field << (19 + i)); 60362306a36Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); 60762306a36Sopenharmony_ci udelay(1); 60862306a36Sopenharmony_ci reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); 60962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); 61062306a36Sopenharmony_ci offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); 61162306a36Sopenharmony_ci offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci offset = (offs_6_1<<1) | offs_0; 61462306a36Sopenharmony_ci offset = offset - 0; 61562306a36Sopenharmony_ci offs_6_1 = offset>>1; 61662306a36Sopenharmony_ci offs_0 = offset & 1; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) { 61962306a36Sopenharmony_ci if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT) 62062306a36Sopenharmony_ci ah->pacal_info.max_skipcount = 62162306a36Sopenharmony_ci 2 * ah->pacal_info.max_skipcount; 62262306a36Sopenharmony_ci ah->pacal_info.skipcount = ah->pacal_info.max_skipcount; 62362306a36Sopenharmony_ci } else { 62462306a36Sopenharmony_ci ah->pacal_info.max_skipcount = 1; 62562306a36Sopenharmony_ci ah->pacal_info.skipcount = 0; 62662306a36Sopenharmony_ci ah->pacal_info.prev_offset = offset; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); 63062306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci regVal = REG_READ(ah, 0x7834); 63362306a36Sopenharmony_ci regVal |= 0x1; 63462306a36Sopenharmony_ci REG_WRITE(ah, 0x7834, regVal); 63562306a36Sopenharmony_ci regVal = REG_READ(ah, 0x9808); 63662306a36Sopenharmony_ci regVal &= (~(0x1 << 27)); 63762306a36Sopenharmony_ci REG_WRITE(ah, 0x9808, regVal); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regList); i++) 64062306a36Sopenharmony_ci REG_WRITE(ah, regList[i][0], regList[i][1]); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci if (AR_SREV_9271(ah)) { 64862306a36Sopenharmony_ci if (is_reset || !ah->pacal_info.skipcount) 64962306a36Sopenharmony_ci ar9271_hw_pa_cal(ah, is_reset); 65062306a36Sopenharmony_ci else 65162306a36Sopenharmony_ci ah->pacal_info.skipcount--; 65262306a36Sopenharmony_ci } else if (AR_SREV_9285_12_OR_LATER(ah)) { 65362306a36Sopenharmony_ci if (is_reset || !ah->pacal_info.skipcount) 65462306a36Sopenharmony_ci ar9285_hw_pa_cal(ah, is_reset); 65562306a36Sopenharmony_ci else 65662306a36Sopenharmony_ci ah->pacal_info.skipcount--; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci if (OLC_FOR_AR9287_10_LATER(ah)) 66362306a36Sopenharmony_ci ar9287_hw_olc_temp_compensation(ah); 66462306a36Sopenharmony_ci else if (OLC_FOR_AR9280_20_LATER(ah)) 66562306a36Sopenharmony_ci ar9280_hw_olc_temp_compensation(ah); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, 66962306a36Sopenharmony_ci u8 rxchainmask, bool longcal) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct ath9k_cal_list *currCal = ah->cal_list_curr; 67262306a36Sopenharmony_ci bool nfcal, nfcal_pending = false, percal_pending; 67362306a36Sopenharmony_ci int ret; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) & AR_PHY_AGC_CONTROL_NF); 67662306a36Sopenharmony_ci if (ah->caldata) { 67762306a36Sopenharmony_ci nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags); 67862306a36Sopenharmony_ci if (longcal) /* Remember to not miss */ 67962306a36Sopenharmony_ci set_bit(LONGCAL_PENDING, &ah->caldata->cal_flags); 68062306a36Sopenharmony_ci else if (test_bit(LONGCAL_PENDING, &ah->caldata->cal_flags)) 68162306a36Sopenharmony_ci longcal = true; /* Respin a previous one */ 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci percal_pending = (currCal && 68562306a36Sopenharmony_ci (currCal->calState == CAL_RUNNING || 68662306a36Sopenharmony_ci currCal->calState == CAL_WAITING)); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (percal_pending && !nfcal) { 68962306a36Sopenharmony_ci if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal)) 69062306a36Sopenharmony_ci return 0; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Looking for next waiting calibration if any */ 69362306a36Sopenharmony_ci for (currCal = currCal->calNext; currCal != ah->cal_list_curr; 69462306a36Sopenharmony_ci currCal = currCal->calNext) { 69562306a36Sopenharmony_ci if (currCal->calState == CAL_WAITING) 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci if (currCal->calState == CAL_WAITING) { 69962306a36Sopenharmony_ci percal_pending = true; 70062306a36Sopenharmony_ci ah->cal_list_curr = currCal; 70162306a36Sopenharmony_ci } else { 70262306a36Sopenharmony_ci percal_pending = false; 70362306a36Sopenharmony_ci ah->cal_list_curr = ah->cal_list; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Do not start a next calibration if the longcal is in action */ 70862306a36Sopenharmony_ci if (percal_pending && !nfcal && !longcal) { 70962306a36Sopenharmony_ci ath9k_hw_reset_calibration(ah, currCal); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return 0; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* Do NF cal only at longer intervals */ 71562306a36Sopenharmony_ci if (longcal || nfcal_pending) { 71662306a36Sopenharmony_ci /* 71762306a36Sopenharmony_ci * Get the value from the previous NF cal and update 71862306a36Sopenharmony_ci * history buffer. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci if (ath9k_hw_getnf(ah, chan)) { 72162306a36Sopenharmony_ci /* 72262306a36Sopenharmony_ci * Load the NF from history buffer of the current 72362306a36Sopenharmony_ci * channel. 72462306a36Sopenharmony_ci * NF is slow time-variant, so it is OK to use a 72562306a36Sopenharmony_ci * historical value. 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_ci ret = ath9k_hw_loadnf(ah, ah->curchan); 72862306a36Sopenharmony_ci if (ret < 0) 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (longcal) { 73362306a36Sopenharmony_ci if (ah->caldata) 73462306a36Sopenharmony_ci clear_bit(LONGCAL_PENDING, 73562306a36Sopenharmony_ci &ah->caldata->cal_flags); 73662306a36Sopenharmony_ci ath9k_hw_start_nfcal(ah, false); 73762306a36Sopenharmony_ci /* Do periodic PAOffset Cal */ 73862306a36Sopenharmony_ci ar9002_hw_pa_cal(ah, false); 73962306a36Sopenharmony_ci ar9002_hw_olc_temp_compensation(ah); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci return !percal_pending; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* Carrier leakage Calibration fix */ 74762306a36Sopenharmony_cistatic bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 75262306a36Sopenharmony_ci if (IS_CHAN_HT20(chan)) { 75362306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 75462306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 75562306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 75662306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 75762306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 75862306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL); 75962306a36Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), 76062306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) { 76162306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 76262306a36Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 76362306a36Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 76462306a36Sopenharmony_ci return false; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 76762306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 76862306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 77162306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); 77262306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 77362306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL); 77462306a36Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_CAL, 77562306a36Sopenharmony_ci 0, AH_WAIT_TIMEOUT)) { 77662306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 77762306a36Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 77862306a36Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 77962306a36Sopenharmony_ci return false; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 78362306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 78462306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), AR_PHY_AGC_CONTROL_FLTR_CAL); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return true; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int i; 79262306a36Sopenharmony_ci u_int32_t txgain_max; 79362306a36Sopenharmony_ci u_int32_t clc_gain, gain_mask = 0, clc_num = 0; 79462306a36Sopenharmony_ci u_int32_t reg_clc_I0, reg_clc_Q0; 79562306a36Sopenharmony_ci u_int32_t i0_num = 0; 79662306a36Sopenharmony_ci u_int32_t q0_num = 0; 79762306a36Sopenharmony_ci u_int32_t total_num = 0; 79862306a36Sopenharmony_ci u_int32_t reg_rf2g5_org; 79962306a36Sopenharmony_ci bool retv = true; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (!(ar9285_hw_cl_cal(ah, chan))) 80262306a36Sopenharmony_ci return false; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7), 80562306a36Sopenharmony_ci AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci for (i = 0; i < (txgain_max+1); i++) { 80862306a36Sopenharmony_ci clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) & 80962306a36Sopenharmony_ci AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S; 81062306a36Sopenharmony_ci if (!(gain_mask & (1 << clc_gain))) { 81162306a36Sopenharmony_ci gain_mask |= (1 << clc_gain); 81262306a36Sopenharmony_ci clc_num++; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci for (i = 0; i < clc_num; i++) { 81762306a36Sopenharmony_ci reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 81862306a36Sopenharmony_ci & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S; 81962306a36Sopenharmony_ci reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2))) 82062306a36Sopenharmony_ci & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S; 82162306a36Sopenharmony_ci if (reg_clc_I0 == 0) 82262306a36Sopenharmony_ci i0_num++; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (reg_clc_Q0 == 0) 82562306a36Sopenharmony_ci q0_num++; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci total_num = i0_num + q0_num; 82862306a36Sopenharmony_ci if (total_num > AR9285_CLCAL_REDO_THRESH) { 82962306a36Sopenharmony_ci reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5); 83062306a36Sopenharmony_ci if (AR_SREV_9285E_20(ah)) { 83162306a36Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, 83262306a36Sopenharmony_ci (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 83362306a36Sopenharmony_ci AR9285_RF2G5_IC50TX_XE_SET); 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, 83662306a36Sopenharmony_ci (reg_rf2g5_org & AR9285_RF2G5_IC50TX) | 83762306a36Sopenharmony_ci AR9285_RF2G5_IC50TX_SET); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci retv = ar9285_hw_cl_cal(ah, chan); 84062306a36Sopenharmony_ci REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org); 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci return retv; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (AR_SREV_9271(ah)) { 85062306a36Sopenharmony_ci if (!ar9285_hw_cl_cal(ah, chan)) 85162306a36Sopenharmony_ci return false; 85262306a36Sopenharmony_ci } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) { 85362306a36Sopenharmony_ci if (!ar9285_hw_clc(ah, chan)) 85462306a36Sopenharmony_ci return false; 85562306a36Sopenharmony_ci } else { 85662306a36Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 85762306a36Sopenharmony_ci if (!AR_SREV_9287_11_OR_LATER(ah)) 85862306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_ADC_CTL, 85962306a36Sopenharmony_ci AR_PHY_ADC_CTL_OFF_PWDADC); 86062306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_AGC_CONTROL(ah), 86162306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Calibrate the AGC */ 86562306a36Sopenharmony_ci REG_WRITE(ah, AR_PHY_AGC_CONTROL(ah), 86662306a36Sopenharmony_ci REG_READ(ah, AR_PHY_AGC_CONTROL(ah)) | 86762306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* Poll for offset calibration complete */ 87062306a36Sopenharmony_ci if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL(ah), 87162306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_CAL, 87262306a36Sopenharmony_ci 0, AH_WAIT_TIMEOUT)) { 87362306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 87462306a36Sopenharmony_ci "offset calibration failed to complete in %d ms; noisy environment?\n", 87562306a36Sopenharmony_ci AH_WAIT_TIMEOUT / 1000); 87662306a36Sopenharmony_ci return false; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 88062306a36Sopenharmony_ci if (!AR_SREV_9287_11_OR_LATER(ah)) 88162306a36Sopenharmony_ci REG_SET_BIT(ah, AR_PHY_ADC_CTL, 88262306a36Sopenharmony_ci AR_PHY_ADC_CTL_OFF_PWDADC); 88362306a36Sopenharmony_ci REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL(ah), 88462306a36Sopenharmony_ci AR_PHY_AGC_CONTROL_FLTR_CAL); 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci /* Do PA Calibration */ 88962306a36Sopenharmony_ci ar9002_hw_pa_cal(ah, true); 89062306a36Sopenharmony_ci ath9k_hw_loadnf(ah, chan); 89162306a36Sopenharmony_ci ath9k_hw_start_nfcal(ah, true); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Enable IQ, ADC Gain and ADC DC offset CALs */ 89662306a36Sopenharmony_ci if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { 89762306a36Sopenharmony_ci ah->supp_cals = IQ_MISMATCH_CAL; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(ah)) 90062306a36Sopenharmony_ci ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (AR_SREV_9287(ah)) 90362306a36Sopenharmony_ci ah->supp_cals &= ~ADC_GAIN_CAL; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) { 90662306a36Sopenharmony_ci INIT_CAL(&ah->adcgain_caldata); 90762306a36Sopenharmony_ci INSERT_CAL(ah, &ah->adcgain_caldata); 90862306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 90962306a36Sopenharmony_ci "enabling ADC Gain Calibration\n"); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) { 91362306a36Sopenharmony_ci INIT_CAL(&ah->adcdc_caldata); 91462306a36Sopenharmony_ci INSERT_CAL(ah, &ah->adcdc_caldata); 91562306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, 91662306a36Sopenharmony_ci "enabling ADC DC Calibration\n"); 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) { 92062306a36Sopenharmony_ci INIT_CAL(&ah->iq_caldata); 92162306a36Sopenharmony_ci INSERT_CAL(ah, &ah->iq_caldata); 92262306a36Sopenharmony_ci ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ah->cal_list_curr = ah->cal_list; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (ah->cal_list_curr) 92862306a36Sopenharmony_ci ath9k_hw_reset_calibration(ah, ah->cal_list_curr); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (ah->caldata) 93262306a36Sopenharmony_ci ah->caldata->CalValid = 0; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return true; 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic const struct ath9k_percal_data iq_cal_multi_sample = { 93862306a36Sopenharmony_ci IQ_MISMATCH_CAL, 93962306a36Sopenharmony_ci MAX_CAL_SAMPLES, 94062306a36Sopenharmony_ci PER_MIN_LOG_COUNT, 94162306a36Sopenharmony_ci ar9002_hw_iqcal_collect, 94262306a36Sopenharmony_ci ar9002_hw_iqcalibrate 94362306a36Sopenharmony_ci}; 94462306a36Sopenharmony_cistatic const struct ath9k_percal_data iq_cal_single_sample = { 94562306a36Sopenharmony_ci IQ_MISMATCH_CAL, 94662306a36Sopenharmony_ci MIN_CAL_SAMPLES, 94762306a36Sopenharmony_ci PER_MAX_LOG_COUNT, 94862306a36Sopenharmony_ci ar9002_hw_iqcal_collect, 94962306a36Sopenharmony_ci ar9002_hw_iqcalibrate 95062306a36Sopenharmony_ci}; 95162306a36Sopenharmony_cistatic const struct ath9k_percal_data adc_gain_cal_multi_sample = { 95262306a36Sopenharmony_ci ADC_GAIN_CAL, 95362306a36Sopenharmony_ci MAX_CAL_SAMPLES, 95462306a36Sopenharmony_ci PER_MIN_LOG_COUNT, 95562306a36Sopenharmony_ci ar9002_hw_adc_gaincal_collect, 95662306a36Sopenharmony_ci ar9002_hw_adc_gaincal_calibrate 95762306a36Sopenharmony_ci}; 95862306a36Sopenharmony_cistatic const struct ath9k_percal_data adc_gain_cal_single_sample = { 95962306a36Sopenharmony_ci ADC_GAIN_CAL, 96062306a36Sopenharmony_ci MIN_CAL_SAMPLES, 96162306a36Sopenharmony_ci PER_MAX_LOG_COUNT, 96262306a36Sopenharmony_ci ar9002_hw_adc_gaincal_collect, 96362306a36Sopenharmony_ci ar9002_hw_adc_gaincal_calibrate 96462306a36Sopenharmony_ci}; 96562306a36Sopenharmony_cistatic const struct ath9k_percal_data adc_dc_cal_multi_sample = { 96662306a36Sopenharmony_ci ADC_DC_CAL, 96762306a36Sopenharmony_ci MAX_CAL_SAMPLES, 96862306a36Sopenharmony_ci PER_MIN_LOG_COUNT, 96962306a36Sopenharmony_ci ar9002_hw_adc_dccal_collect, 97062306a36Sopenharmony_ci ar9002_hw_adc_dccal_calibrate 97162306a36Sopenharmony_ci}; 97262306a36Sopenharmony_cistatic const struct ath9k_percal_data adc_dc_cal_single_sample = { 97362306a36Sopenharmony_ci ADC_DC_CAL, 97462306a36Sopenharmony_ci MIN_CAL_SAMPLES, 97562306a36Sopenharmony_ci PER_MAX_LOG_COUNT, 97662306a36Sopenharmony_ci ar9002_hw_adc_dccal_collect, 97762306a36Sopenharmony_ci ar9002_hw_adc_dccal_calibrate 97862306a36Sopenharmony_ci}; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistatic void ar9002_hw_init_cal_settings(struct ath_hw *ah) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci if (AR_SREV_9100(ah)) { 98362306a36Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_multi_sample; 98462306a36Sopenharmony_ci ah->supp_cals = IQ_MISMATCH_CAL; 98562306a36Sopenharmony_ci return; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (AR_SREV_9160_10_OR_LATER(ah)) { 98962306a36Sopenharmony_ci if (AR_SREV_9280_20_OR_LATER(ah)) { 99062306a36Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_single_sample; 99162306a36Sopenharmony_ci ah->adcgain_caldata.calData = 99262306a36Sopenharmony_ci &adc_gain_cal_single_sample; 99362306a36Sopenharmony_ci ah->adcdc_caldata.calData = 99462306a36Sopenharmony_ci &adc_dc_cal_single_sample; 99562306a36Sopenharmony_ci } else { 99662306a36Sopenharmony_ci ah->iq_caldata.calData = &iq_cal_multi_sample; 99762306a36Sopenharmony_ci ah->adcgain_caldata.calData = 99862306a36Sopenharmony_ci &adc_gain_cal_multi_sample; 99962306a36Sopenharmony_ci ah->adcdc_caldata.calData = 100062306a36Sopenharmony_ci &adc_dc_cal_multi_sample; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (AR_SREV_9287(ah)) 100562306a36Sopenharmony_ci ah->supp_cals &= ~ADC_GAIN_CAL; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_civoid ar9002_hw_attach_calib_ops(struct ath_hw *ah) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); 101262306a36Sopenharmony_ci struct ath_hw_ops *ops = ath9k_hw_ops(ah); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci priv_ops->init_cal_settings = ar9002_hw_init_cal_settings; 101562306a36Sopenharmony_ci priv_ops->init_cal = ar9002_hw_init_cal; 101662306a36Sopenharmony_ci priv_ops->setup_calibration = ar9002_hw_setup_calibration; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ops->calibrate = ar9002_hw_calibrate; 101962306a36Sopenharmony_ci} 1020