diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/phy.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath5k/phy.c | 42 | 
1 files changed, 22 insertions, 20 deletions
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 72474c0ccaf..68e2bccd90d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -23,6 +23,7 @@  #define _ATH5K_PHY  #include <linux/delay.h> +#include <linux/slab.h>  #include "ath5k.h"  #include "reg.h" @@ -1386,38 +1387,39 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,  		goto done;  	/* Calibration has finished, get the results and re-run */ + +	/* work around empty results which can apparently happen on 5212 */  	for (i = 0; i <= 10; i++) {  		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);  		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);  		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); +		ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, +			"iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr); +		if (i_pwr && q_pwr) +			break;  	}  	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;  	q_coffd = q_pwr >> 7; -	/* No correction */ -	if (i_coffd == 0 || q_coffd == 0) +	/* protect against divide by 0 and loss of sign bits */ +	if (i_coffd == 0 || q_coffd < 2)  		goto done; -	i_coff = ((-iq_corr) / i_coffd); - -	/* Boundary check */ -	if (i_coff > 31) -		i_coff = 31; -	if (i_coff < -32) -		i_coff = -32; +	i_coff = (-iq_corr) / i_coffd; +	i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */ -	q_coff = (((s32)i_pwr / q_coffd) - 128); +	q_coff = (i_pwr / q_coffd) - 128; +	q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */ -	/* Boundary check */ -	if (q_coff > 15) -		q_coff = 15; -	if (q_coff < -16) -		q_coff = -16; +	ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, +			"new I:%d Q:%d (i_coffd:%x q_coffd:%x)", +			i_coff, q_coff, i_coffd, q_coffd); -	/* Commit new I/Q value */ -	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | -		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); +	/* Commit new I/Q values (set enable bit last to match HAL sources) */ +	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff); +	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff); +	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);  	/* Re-enable calibration -if we don't we'll commit  	 * the same values again and again */ @@ -1873,7 +1875,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)  		break;  	case AR5K_ANTMODE_FIXED_A:  		def_ant = 1; -		tx_ant = 0; +		tx_ant = 1;  		use_def_for_tx = true;  		update_def_on_tx = false;  		use_def_for_rts = true; @@ -1882,7 +1884,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)  		break;  	case AR5K_ANTMODE_FIXED_B:  		def_ant = 2; -		tx_ant = 0; +		tx_ant = 2;  		use_def_for_tx = true;  		update_def_on_tx = false;  		use_def_for_rts = true;  |