aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/phy.c')
-rw-r--r--drivers/net/wireless/ath5k/phy.c54
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 */
2056int 2058int
2057ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) 2059ath5k_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 */
2211static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah, 2213static 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
2240done: 2265done:
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 */