/**
 * ar9002_hw_set_channel - set channel on single-chip device
 * @ah: atheros hardware structure
 * @chan:
 *
 * This is the function to change channel on single-chip devices, that is
 * all devices after ar9280.
 *
 * This function takes the channel value in MHz and sets
 * hardware channel value. Assumes writes have been enabled to analog bus.
 *
 * Actual Expression,
 *
 * For 2GHz channel,
 * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
 * (freq_ref = 40MHz)
 *
 * For 5GHz channel,
 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
 * (freq_ref = 40MHz/(24>>amodeRefSel))
 */
static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
{
	u16 bMode, fracMode, aModeRefSel = 0;
	u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
	struct chan_centers centers;
	u32 refDivA = 24;

	ath9k_hw_get_channel_centers(ah, chan, &centers);
	freq = centers.synth_center;

	reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
	reg32 &= 0xc0000000;

	if (freq < 4800) { /* 2 GHz, fractional mode */
		u32 txctl;
		int regWrites = 0;

		bMode = 1;
		fracMode = 1;
		aModeRefSel = 0;
		channelSel = CHANSEL_2G(freq);

		if (AR_SREV_9287_11_OR_LATER(ah)) {
			if (freq == 2484) {
				/* Enable channel spreading for channel 14 */
				REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
						1, regWrites);
			} else {
				REG_WRITE_ARRAY(&ah->iniCckfirNormal,
						1, regWrites);
			}
		} else {
			txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
			if (freq == 2484) {
				/* Enable channel spreading for channel 14 */
				REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
					  txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
			} else {
				REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
					  txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
			}
		}
	} else {
		bMode = 0;
		fracMode = 0;

		switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
		case 0:
			if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
				aModeRefSel = 0;
			else if ((freq % 20) == 0)
				aModeRefSel = 3;
			else if ((freq % 10) == 0)
				aModeRefSel = 2;
			if (aModeRefSel)
				break;
		case 1:
		default:
			aModeRefSel = 0;
			/*
			 * Enable 2G (fractional) mode for channels
			 * which are 5MHz spaced.
			 */
			fracMode = 1;
			refDivA = 1;
			channelSel = CHANSEL_5G(freq);

			/* RefDivA setting */
			ath9k_hw_analog_shift_rmw(ah, AR_AN_SYNTH9,
				      AR_AN_SYNTH9_REFDIVA,
				      AR_AN_SYNTH9_REFDIVA_S, refDivA);

		}

		if (!fracMode) {
			ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
			channelSel = ndiv & 0x1ff;
			channelFrac = (ndiv & 0xfffffe00) * 2;
			channelSel = (channelSel << 17) | channelFrac;
		}
	}
Пример #2
0
int
ar9280_set_synth(struct athn_softc *sc, struct ieee80211_channel *c,
    struct ieee80211_channel *extc)
{
	uint32_t phy, reg, ndiv = 0;
	uint32_t freq = c->ic_freq;

	phy = AR_READ(sc, AR9280_PHY_SYNTH_CONTROL) & ~0x3fffffff;

	if (IEEE80211_IS_CHAN_2GHZ(c)) {
		phy |= (freq << 16) / 15;
		phy |= AR9280_BMODE | AR9280_FRACMODE;

		if (AR_SREV_9287_11_OR_LATER(sc)) {
			/* NB: Magic values from the Linux driver. */
			if (freq == 2484) {	/* Channel 14. */
				/* Japanese regulatory requirements. */
				AR_WRITE(sc, AR_PHY(637), 0x00000000);
				AR_WRITE(sc, AR_PHY(638), 0xefff0301);
				AR_WRITE(sc, AR_PHY(639), 0xca9228ee);
			} else {
				AR_WRITE(sc, AR_PHY(637), 0x00fffeff);
				AR_WRITE(sc, AR_PHY(638), 0x00f5f9ff);
				AR_WRITE(sc, AR_PHY(639), 0xb79f6427);
			}
		} else {
			reg = AR_READ(sc, AR_PHY_CCK_TX_CTRL);
			if (freq == 2484)	/* Channel 14. */
				reg |= AR_PHY_CCK_TX_CTRL_JAPAN;
			else
				reg &= ~AR_PHY_CCK_TX_CTRL_JAPAN;
			AR_WRITE(sc, AR_PHY_CCK_TX_CTRL, reg);
		}
	} else {
		if (AR_SREV_9285_10_OR_LATER(sc) ||
		    sc->eep_rev < AR_EEP_MINOR_VER_22 ||
		    !((struct ar5416_base_eep_header *)sc->eep)->frac_n_5g) {
			if ((freq % 20) == 0) {
				ndiv = (freq * 3) / 60;
				phy |= SM(AR9280_AMODE_REFSEL, 3);
			} else if ((freq % 10) == 0) {
				ndiv = (freq * 6) / 60;
				phy |= SM(AR9280_AMODE_REFSEL, 2);
			}
		}
		if (ndiv != 0) {
			phy |= (ndiv & 0x1ff) << 17;
			phy |= (ndiv & ~0x1ff) * 2;
		} else {
			phy |= (freq << 15) / 15;
			phy |= AR9280_FRACMODE;

			reg = AR_READ(sc, AR_AN_SYNTH9);
			reg = RW(reg, AR_AN_SYNTH9_REFDIVA, 1);
			AR_WRITE(sc, AR_AN_SYNTH9, reg);
		}
	}
	AR_WRITE_BARRIER(sc);
	DPRINTFN(4, ("AR9280_PHY_SYNTH_CONTROL=0x%08x\n", phy));
	AR_WRITE(sc, AR9280_PHY_SYNTH_CONTROL, phy);
	AR_WRITE_BARRIER(sc);
	return (0);
}