2010-04-15 17:39:00 -04:00
/*
* Copyright ( c ) 2010 Atheros Communications Inc .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*/
# include "hw.h"
# include "hw-ops.h"
# include "ar9003_phy.h"
static void ar9003_hw_setup_calibration ( struct ath_hw * ah ,
struct ath9k_cal_list * currCal )
{
2010-04-15 17:39:10 -04:00
struct ath_common * common = ath9k_hw_common ( ah ) ;
/* Select calibration to run */
switch ( currCal - > calData - > calType ) {
case IQ_MISMATCH_CAL :
/*
* Start calibration with
* 2 ^ ( INIT_IQCAL_LOG_COUNT_MAX + 1 ) samples
*/
REG_RMW_FIELD ( ah , AR_PHY_TIMING4 ,
AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX ,
currCal - > calData - > calCountMax ) ;
REG_WRITE ( ah , AR_PHY_CALMODE , AR_PHY_CALMODE_IQ ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" starting IQ Mismatch Calibration \n " ) ;
/* Kick-off cal */
REG_SET_BIT ( ah , AR_PHY_TIMING4 , AR_PHY_TIMING4_DO_CAL ) ;
break ;
case TEMP_COMP_CAL :
REG_RMW_FIELD ( ah , AR_PHY_65NM_CH0_THERM ,
AR_PHY_65NM_CH0_THERM_LOCAL , 1 ) ;
REG_RMW_FIELD ( ah , AR_PHY_65NM_CH0_THERM ,
AR_PHY_65NM_CH0_THERM_START , 1 ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" starting Temperature Compensation Calibration \n " ) ;
break ;
case ADC_DC_INIT_CAL :
case ADC_GAIN_CAL :
case ADC_DC_CAL :
/* Not yet */
break ;
}
2010-04-15 17:39:00 -04:00
}
static bool ar9003_hw_calibrate ( struct ath_hw * ah ,
struct ath9k_channel * chan ,
u8 rxchainmask ,
bool longcal )
{
/* TODO */
return false ;
}
static bool ar9003_hw_init_cal ( struct ath_hw * ah ,
struct ath9k_channel * chan )
{
/* TODO */
return false ;
}
2010-04-15 17:39:01 -04:00
static void ar9003_hw_iqcal_collect ( struct ath_hw * ah )
{
int i ;
/* Accumulate IQ cal measures for active chains */
for ( i = 0 ; i < AR5416_MAX_CHAINS ; i + + ) {
ah - > totalPowerMeasI [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_0 ( i ) ) ;
ah - > totalPowerMeasQ [ i ] + =
REG_READ ( ah , AR_PHY_CAL_MEAS_1 ( i ) ) ;
ah - > totalIqCorrMeas [ i ] + =
( int32_t ) REG_READ ( ah , AR_PHY_CAL_MEAS_2 ( i ) ) ;
ath_print ( ath9k_hw_common ( ah ) , ATH_DBG_CALIBRATE ,
" %d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x; \n " ,
ah - > cal_samples , i , ah - > totalPowerMeasI [ i ] ,
ah - > totalPowerMeasQ [ i ] ,
ah - > totalIqCorrMeas [ i ] ) ;
}
}
static void ar9003_hw_iqcalibrate ( struct ath_hw * ah , u8 numChains )
{
struct ath_common * common = ath9k_hw_common ( ah ) ;
u32 powerMeasQ , powerMeasI , iqCorrMeas ;
u32 qCoffDenom , iCoffDenom ;
int32_t qCoff , iCoff ;
int iqCorrNeg , i ;
const u_int32_t offset_array [ 3 ] = {
AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_B1 ,
AR_PHY_RX_IQCAL_CORR_B2 ,
} ;
for ( i = 0 ; i < numChains ; i + + ) {
powerMeasI = ah - > totalPowerMeasI [ i ] ;
powerMeasQ = ah - > totalPowerMeasQ [ i ] ;
iqCorrMeas = ah - > totalIqCorrMeas [ i ] ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Starting IQ Cal and Correction for Chain %d \n " ,
i ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Orignal: Chn %diq_corr_meas = 0x%08x \n " ,
i , ah - > totalIqCorrMeas [ i ] ) ;
iqCorrNeg = 0 ;
if ( iqCorrMeas > 0x80000000 ) {
iqCorrMeas = ( 0xffffffff - iqCorrMeas ) + 1 ;
iqCorrNeg = 1 ;
}
ath_print ( common , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_i = 0x%08x \n " , i , powerMeasI ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Chn %d pwr_meas_q = 0x%08x \n " , i , powerMeasQ ) ;
ath_print ( common , ATH_DBG_CALIBRATE , " iqCorrNeg is 0x%08x \n " ,
iqCorrNeg ) ;
iCoffDenom = ( powerMeasI / 2 + powerMeasQ / 2 ) / 256 ;
qCoffDenom = powerMeasQ / 64 ;
if ( ( iCoffDenom ! = 0 ) & & ( qCoffDenom ! = 0 ) ) {
iCoff = iqCorrMeas / iCoffDenom ;
qCoff = powerMeasI / qCoffDenom - 64 ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Chn %d iCoff = 0x%08x \n " , i , iCoff ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Chn %d qCoff = 0x%08x \n " , i , qCoff ) ;
/* Force bounds on iCoff */
if ( iCoff > = 63 )
iCoff = 63 ;
else if ( iCoff < = - 63 )
iCoff = - 63 ;
/* Negate iCoff if iqCorrNeg == 0 */
if ( iqCorrNeg = = 0x0 )
iCoff = - iCoff ;
/* Force bounds on qCoff */
if ( qCoff > = 63 )
qCoff = 63 ;
else if ( qCoff < = - 63 )
qCoff = - 63 ;
iCoff = iCoff & 0x7f ;
qCoff = qCoff & 0x7f ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Chn %d : iCoff = 0x%x qCoff = 0x%x \n " ,
i , iCoff , qCoff ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Register offset (0x%04x) "
" before update = 0x%x \n " ,
offset_array [ i ] ,
REG_READ ( ah , offset_array [ i ] ) ) ;
REG_RMW_FIELD ( ah , offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF ,
iCoff ) ;
REG_RMW_FIELD ( ah , offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF ,
qCoff ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Register offset (0x%04x) QI COFF "
" (bitfields 0x%08x) after update = 0x%x \n " ,
offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF ,
REG_READ ( ah , offset_array [ i ] ) ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" Register offset (0x%04x) QQ COFF "
" (bitfields 0x%08x) after update = 0x%x \n " ,
offset_array [ i ] ,
AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF ,
REG_READ ( ah , offset_array [ i ] ) ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" IQ Cal and Correction done for Chain %d \n " ,
i ) ;
}
}
REG_SET_BIT ( ah , AR_PHY_RX_IQCAL_CORR_B0 ,
AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE ) ;
ath_print ( common , ATH_DBG_CALIBRATE ,
" IQ Cal and Correction (offset 0x%04x) enabled "
" (bit position 0x%08x). New Value 0x%08x \n " ,
( unsigned ) ( AR_PHY_RX_IQCAL_CORR_B0 ) ,
AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE ,
REG_READ ( ah , AR_PHY_RX_IQCAL_CORR_B0 ) ) ;
}
static const struct ath9k_percal_data iq_cal_single_sample = {
IQ_MISMATCH_CAL ,
MIN_CAL_SAMPLES ,
PER_MAX_LOG_COUNT ,
ar9003_hw_iqcal_collect ,
ar9003_hw_iqcalibrate
} ;
2010-04-15 17:39:00 -04:00
static void ar9003_hw_init_cal_settings ( struct ath_hw * ah )
{
2010-04-15 17:39:01 -04:00
ah - > iq_caldata . calData = & iq_cal_single_sample ;
ah - > supp_cals = IQ_MISMATCH_CAL ;
2010-04-15 17:39:00 -04:00
}
static bool ar9003_hw_iscal_supported ( struct ath_hw * ah ,
enum ath9k_cal_types calType )
{
/* TODO */
return false ;
}
2010-04-15 17:39:09 -04:00
static void ar9003_hw_loadnf ( struct ath_hw * ah , struct ath9k_channel * chan )
{
/* TODO */
}
2010-04-15 17:39:00 -04:00
void ar9003_hw_attach_calib_ops ( struct ath_hw * ah )
{
struct ath_hw_private_ops * priv_ops = ath9k_hw_private_ops ( ah ) ;
struct ath_hw_ops * ops = ath9k_hw_ops ( ah ) ;
priv_ops - > init_cal_settings = ar9003_hw_init_cal_settings ;
priv_ops - > init_cal = ar9003_hw_init_cal ;
priv_ops - > setup_calibration = ar9003_hw_setup_calibration ;
priv_ops - > iscal_supported = ar9003_hw_iscal_supported ;
2010-04-15 17:39:09 -04:00
priv_ops - > loadnf = ar9003_hw_loadnf ;
2010-04-15 17:39:00 -04:00
ops - > calibrate = ar9003_hw_calibrate ;
}