예제 #1
0
bool ath9k_hw_init_cal(struct ath_hal *ah,
		       struct ath9k_channel *chan)
{
	struct ath_hal_5416 *ahp = AH5416(ah);
	struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan);

	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
		  AR_PHY_AGC_CONTROL_CAL);

	if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
		DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
			"offset calibration failed to complete in 1ms; "
			"noisy environment?\n");
		return false;
	}

	if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
		ath9k_hw_9285_pa_cal(ah);

	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
		  REG_READ(ah, AR_PHY_AGC_CONTROL) |
		  AR_PHY_AGC_CONTROL_NF);

	ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL;

	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
		if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) {
			INIT_CAL(&ahp->ah_adcGainCalData);
			INSERT_CAL(ahp, &ahp->ah_adcGainCalData);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling ADC Gain Calibration.\n");
		}
		if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) {
			INIT_CAL(&ahp->ah_adcDcCalData);
			INSERT_CAL(ahp, &ahp->ah_adcDcCalData);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling ADC DC Calibration.\n");
		}
		if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) {
			INIT_CAL(&ahp->ah_iqCalData);
			INSERT_CAL(ahp, &ahp->ah_iqCalData);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling IQ Calibration.\n");
		}

		ahp->ah_cal_list_curr = ahp->ah_cal_list;

		if (ahp->ah_cal_list_curr)
			ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr);
	}

	ichan->CalValid = 0;

	return true;
}
예제 #2
0
bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
			u8 rxchainmask, bool longcal)
{
	bool iscaldone = true;
	struct ath9k_cal_list *currCal = ah->cal_list_curr;

	if (currCal &&
	    (currCal->calState == CAL_RUNNING ||
	     currCal->calState == CAL_WAITING)) {
		iscaldone = ath9k_hw_per_calibration(ah, chan,
						     rxchainmask, currCal);
		if (iscaldone) {
			ah->cal_list_curr = currCal = currCal->calNext;

			if (currCal->calState == CAL_WAITING) {
				iscaldone = false;
				ath9k_hw_reset_calibration(ah, currCal);
			}
		}
	}

	/* Do NF cal only at longer intervals */
	if (longcal) {
		/* Do periodic PAOffset Cal */
		if (AR_SREV_9271(ah))
			ath9k_hw_9271_pa_cal(ah);
		else if (AR_SREV_9285_11_OR_LATER(ah)) {
			if (!ah->pacal_info.skipcount)
				ath9k_hw_9285_pa_cal(ah, false);
			else
				ah->pacal_info.skipcount--;
		}

		if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
			ath9k_olc_temp_compensation(ah);

		/* Get the value from the previous NF cal and update history buffer */
		ath9k_hw_getnf(ah, chan);

		/*
		 * Load the NF from history buffer of the current channel.
		 * NF is slow time-variant, so it is OK to use a historical value.
		 */
		ath9k_hw_loadnf(ah, ah->curchan);

		ath9k_hw_start_nfcal(ah);
	}

	return iscaldone;
}
예제 #3
0
bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
{
	if (AR_SREV_9285_12_OR_LATER(ah)) {
		if (!ar9285_clc(ah, chan))
			return false;
	} else {
		if (AR_SREV_9280_10_OR_LATER(ah)) {
			if (!AR_SREV_9287_10_OR_LATER(ah))
				REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
					    AR_PHY_ADC_CTL_OFF_PWDADC);
			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
				    AR_PHY_AGC_CONTROL_FLTR_CAL);
		}

		/* Calibrate the AGC */
		REG_WRITE(ah, AR_PHY_AGC_CONTROL,
			  REG_READ(ah, AR_PHY_AGC_CONTROL) |
			  AR_PHY_AGC_CONTROL_CAL);

		/* Poll for offset calibration complete */
		if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
				   0, AH_WAIT_TIMEOUT)) {
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"offset calibration failed to complete in 1ms; "
				"noisy environment?\n");
			return false;
		}

		if (AR_SREV_9280_10_OR_LATER(ah)) {
			if (!AR_SREV_9287_10_OR_LATER(ah))
				REG_SET_BIT(ah, AR_PHY_ADC_CTL,
					    AR_PHY_ADC_CTL_OFF_PWDADC);
			REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
				    AR_PHY_AGC_CONTROL_FLTR_CAL);
		}
	}

	/* Do PA Calibration */
	if (AR_SREV_9285_11_OR_LATER(ah))
		ath9k_hw_9285_pa_cal(ah, true);

	/* Do NF Calibration after DC offset and other calibrations */
	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);

	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;

	/* Enable IQ, ADC Gain and ADC DC offset CALs */
	if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
		if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
			INIT_CAL(&ah->adcgain_caldata);
			INSERT_CAL(ah, &ah->adcgain_caldata);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling ADC Gain Calibration.\n");
		}
		if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
			INIT_CAL(&ah->adcdc_caldata);
			INSERT_CAL(ah, &ah->adcdc_caldata);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling ADC DC Calibration.\n");
		}
		if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
			INIT_CAL(&ah->iq_caldata);
			INSERT_CAL(ah, &ah->iq_caldata);
			DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
				"enabling IQ Calibration.\n");
		}

		ah->cal_list_curr = ah->cal_list;

		if (ah->cal_list_curr)
			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
	}

	chan->CalValid = 0;

	return true;
}