Commit 33fd5033 authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by John W. Linville

iwlwifi-5000: add run time calibrations for 5000

This patch adds support for run time calibrations for the 5000 family HW.
Those calibrations are sensitivity calibration, and chain noise calibration.
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent c031bf80
...@@ -119,6 +119,15 @@ config IWL5000 ...@@ -119,6 +119,15 @@ config IWL5000
This option enables support for Intel Wireless WiFi Link 5000AGN Family This option enables support for Intel Wireless WiFi Link 5000AGN Family
Dependency on 4965 is temporary Dependency on 4965 is temporary
config IWL5000_RUN_TIME_CALIB
bool "Enable run time Calibration for 5000 NIC"
select IWLWIFI_RUN_TIME_CALIB
depends on IWL5000
default y
---help---
This option will enable run time calibration for the iwl5000 driver.
These calibrations are Sensitivity and Chain Noise. If unsure, say yes
config IWLWIFI_DEBUGFS config IWLWIFI_DEBUGFS
bool "Iwlwifi debugfs support" bool "Iwlwifi debugfs support"
......
...@@ -2671,6 +2671,37 @@ struct iwl4965_calibration_cmd { ...@@ -2671,6 +2671,37 @@ struct iwl4965_calibration_cmd {
u8 reserved1; u8 reserved1;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Phy calibration command for 5000 series */
enum {
IWL5000_PHY_CALIBRATE_DC_CMD = 8,
IWL5000_PHY_CALIBRATE_LO_CMD = 9,
IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10,
IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11,
IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12,
IWL5000_PHY_CALIBRATION_NOISE_CMD = 13,
IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14,
IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15,
IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18,
IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19,
};
struct iwl5000_calibration_chain_noise_reset_cmd {
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
u8 flags; /* not used */
__le16 reserved;
} __attribute__ ((packed));
struct iwl5000_calibration_chain_noise_gain_cmd {
u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */
u8 flags; /* not used */
__le16 reserved;
u8 delta_gain_1;
u8 delta_gain_2;
__le16 reserved1;
} __attribute__ ((packed));
/****************************************************************************** /******************************************************************************
* (12) * (12)
* Miscellaneous Commands: * Miscellaneous Commands:
......
...@@ -125,6 +125,100 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) ...@@ -125,6 +125,100 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
return (address & ADDRESS_MSK) + (offset << 1); return (address & ADDRESS_MSK) + (offset << 1);
} }
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
static void iwl5000_gain_computation(struct iwl_priv *priv,
u32 average_noise[NUM_RX_CHAINS],
u16 min_average_noise_antenna_i,
u32 min_average_noise)
{
int i;
s32 delta_g;
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
/* Find Gain Code for the antennas B and C */
for (i = 1; i < NUM_RX_CHAINS; i++) {
if ((data->disconn_array[i])) {
data->delta_gain_code[i] = 0;
continue;
}
delta_g = (1000 * ((s32)average_noise[0] -
(s32)average_noise[i])) / 1500;
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
if (delta_g < 0)
/* set negative sign */
data->delta_gain_code[i] |= (1 << 2);
}
IWL_DEBUG_CALIB("Delta gains: ANT_B = %d ANT_C = %d\n",
data->delta_gain_code[1], data->delta_gain_code[2]);
if (!data->radio_write) {
struct iwl5000_calibration_chain_noise_gain_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
cmd.delta_gain_1 = data->delta_gain_code[1];
cmd.delta_gain_2 = data->delta_gain_code[2];
iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
sizeof(cmd), &cmd, NULL);
data->radio_write = 1;
data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
data->chain_noise_a = 0;
data->chain_noise_b = 0;
data->chain_noise_c = 0;
data->chain_signal_a = 0;
data->chain_signal_b = 0;
data->chain_signal_c = 0;
data->beacon_count = 0;
}
static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
{
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
struct iwl5000_calibration_chain_noise_reset_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
sizeof(cmd), &cmd))
IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n");
data->state = IWL_CHAIN_NOISE_ACCUMULATE;
IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
}
}
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
.max_nrg_cck = 0,
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
.auto_corr_min_ofdm_x1 = 120,
.auto_corr_min_ofdm_mrc_x1 = 240,
.auto_corr_max_ofdm = 120,
.auto_corr_max_ofdm_mrc = 210,
.auto_corr_max_ofdm_x1 = 155,
.auto_corr_max_ofdm_mrc_x1 = 290,
.auto_corr_min_cck = 125,
.auto_corr_max_cck = 200,
.auto_corr_min_cck_mrc = 170,
.auto_corr_max_cck_mrc = 400,
.nrg_th_cck = 95,
.nrg_th_ofdm = 95,
};
#endif /* CONFIG_IWL5000_RUN_TIME_CALIB */
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset) size_t offset)
{ {
...@@ -159,6 +253,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) ...@@ -159,6 +253,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_bsm_size = BSM_SRAM_SIZE; priv->hw_params.max_bsm_size = BSM_SRAM_SIZE;
priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) | priv->hw_params.fat_channel = BIT(IEEE80211_BAND_2GHZ) |
BIT(IEEE80211_BAND_5GHZ); BIT(IEEE80211_BAND_5GHZ);
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
priv->hw_params.sens = &iwl5000_sensitivity;
#endif
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5100: case CSR_HW_REV_TYPE_5100:
...@@ -202,6 +299,10 @@ static struct iwl_hcmd_ops iwl5000_hcmd = { ...@@ -202,6 +299,10 @@ static struct iwl_hcmd_ops iwl5000_hcmd = {
}; };
static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
#ifdef CONFIG_IWL5000_RUN_TIME_CALIB
.gain_computation = iwl5000_gain_computation,
.chain_noise_reset = iwl5000_chain_noise_reset,
#endif
}; };
static struct iwl_lib_ops iwl5000_lib = { static struct iwl_lib_ops iwl5000_lib = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment