/** * 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, ¢ers); 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; } }
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); }