diff options
author | Nick Kossifidis <mick@madwifi.org> | 2008-07-19 23:47:12 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-01 15:31:32 -0400 |
commit | f860ee26db51c478fd70039bd4902912a8d93993 (patch) | |
tree | 847120766bab69cc2a572e4d6fe863b046d1eafc | |
parent | cc6323c7d8c231d83e592ff9f7acf2cac5e016f7 (diff) |
ath5k: Update phy calibration functions
* Enable I/Q calibration each time we have correction results (we
were only enabling calibration during reset). If we don't we commit
the same results each time calibration routine is called.
* Add some documentation and a TODO on nf calibration
* Return -EAGAIN on noise floor timeout/failure
Changes-licensed-under: ISC
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath5k/phy.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index cbc362d20719..fa0d47faf574 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c | |||
@@ -2052,6 +2052,8 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) | |||
2052 | * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ | 2052 | * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ |
2053 | * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 | 2053 | * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 |
2054 | * | 2054 | * |
2055 | * XXX: Since during noise floor calibration antennas are detached according to | ||
2056 | * the patent, we should stop tx queues here. | ||
2055 | */ | 2057 | */ |
2056 | int | 2058 | int |
2057 | ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) | 2059 | ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) |
@@ -2061,7 +2063,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) | |||
2061 | s32 noise_floor; | 2063 | s32 noise_floor; |
2062 | 2064 | ||
2063 | /* | 2065 | /* |
2064 | * Enable noise floor calibration and wait until completion | 2066 | * Enable noise floor calibration |
2065 | */ | 2067 | */ |
2066 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, | 2068 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, |
2067 | AR5K_PHY_AGCCTL_NF); | 2069 | AR5K_PHY_AGCCTL_NF); |
@@ -2071,7 +2073,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) | |||
2071 | if (ret) { | 2073 | if (ret) { |
2072 | ATH5K_ERR(ah->ah_sc, | 2074 | ATH5K_ERR(ah->ah_sc, |
2073 | "noise floor calibration timeout (%uMHz)\n", freq); | 2075 | "noise floor calibration timeout (%uMHz)\n", freq); |
2074 | return ret; | 2076 | return -EAGAIN; |
2075 | } | 2077 | } |
2076 | 2078 | ||
2077 | /* Wait until the noise floor is calibrated and read the value */ | 2079 | /* Wait until the noise floor is calibrated and read the value */ |
@@ -2093,7 +2095,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) | |||
2093 | if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { | 2095 | if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { |
2094 | ATH5K_ERR(ah->ah_sc, | 2096 | ATH5K_ERR(ah->ah_sc, |
2095 | "noise floor calibration failed (%uMHz)\n", freq); | 2097 | "noise floor calibration failed (%uMHz)\n", freq); |
2096 | return -EIO; | 2098 | return -EAGAIN; |
2097 | } | 2099 | } |
2098 | 2100 | ||
2099 | ah->ah_noise_floor = noise_floor; | 2101 | ah->ah_noise_floor = noise_floor; |
@@ -2206,38 +2208,66 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, | |||
2206 | } | 2208 | } |
2207 | 2209 | ||
2208 | /* | 2210 | /* |
2209 | * Perform a PHY calibration on RF5111/5112 | 2211 | * Perform a PHY calibration on RF5111/5112 and newer chips |
2210 | */ | 2212 | */ |
2211 | static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, | 2213 | static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, |
2212 | struct ieee80211_channel *channel) | 2214 | struct ieee80211_channel *channel) |
2213 | { | 2215 | { |
2214 | u32 i_pwr, q_pwr; | 2216 | u32 i_pwr, q_pwr; |
2215 | s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; | 2217 | s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd; |
2218 | int i; | ||
2216 | ATH5K_TRACE(ah->ah_sc); | 2219 | ATH5K_TRACE(ah->ah_sc); |
2217 | 2220 | ||
2218 | if (!ah->ah_calibration || | 2221 | if (!ah->ah_calibration || |
2219 | ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) | 2222 | ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) |
2220 | goto done; | 2223 | goto done; |
2221 | 2224 | ||
2222 | ah->ah_calibration = false; | 2225 | /* Calibration has finished, get the results and re-run */ |
2226 | for (i = 0; i <= 10; i++) { | ||
2227 | iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); | ||
2228 | i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); | ||
2229 | q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); | ||
2230 | } | ||
2223 | 2231 | ||
2224 | iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); | ||
2225 | i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); | ||
2226 | q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); | ||
2227 | i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; | 2232 | i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; |
2228 | q_coffd = q_pwr >> 6; | 2233 | q_coffd = q_pwr >> 7; |
2229 | 2234 | ||
2235 | /* No correction */ | ||
2230 | if (i_coffd == 0 || q_coffd == 0) | 2236 | if (i_coffd == 0 || q_coffd == 0) |
2231 | goto done; | 2237 | goto done; |
2232 | 2238 | ||
2233 | i_coff = ((-iq_corr) / i_coffd) & 0x3f; | 2239 | i_coff = ((-iq_corr) / i_coffd) & 0x3f; |
2234 | q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f; | ||
2235 | 2240 | ||
2236 | /* Commit new IQ value */ | 2241 | /* Boundary check */ |
2242 | if (i_coff > 31) | ||
2243 | i_coff = 31; | ||
2244 | if (i_coff < -32) | ||
2245 | i_coff = -32; | ||
2246 | |||
2247 | q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; | ||
2248 | |||
2249 | /* Boundary check */ | ||
2250 | if (q_coff > 15) | ||
2251 | q_coff = 15; | ||
2252 | if (q_coff < -16) | ||
2253 | q_coff = -16; | ||
2254 | |||
2255 | /* Commit new I/Q value */ | ||
2237 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | | 2256 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | |
2238 | ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); | 2257 | ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); |
2239 | 2258 | ||
2259 | /* Re-enable calibration -if we don't we'll commit | ||
2260 | * the same values again and again */ | ||
2261 | AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, | ||
2262 | AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15); | ||
2263 | AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN); | ||
2264 | |||
2240 | done: | 2265 | done: |
2266 | |||
2267 | /* TODO: Separate noise floor calibration from I/Q calibration | ||
2268 | * since noise floor calibration interrupts rx path while I/Q | ||
2269 | * calibration doesn't. We don't need to run noise floor calibration | ||
2270 | * as often as I/Q calibration.*/ | ||
2241 | ath5k_hw_noise_floor_calibration(ah, channel->center_freq); | 2271 | ath5k_hw_noise_floor_calibration(ah, channel->center_freq); |
2242 | 2272 | ||
2243 | /* Request RF gain */ | 2273 | /* Request RF gain */ |