ath5k_phy.c File Reference

#include <unistd.h>
#include <stdlib.h>
#include "ath5k.h"
#include "reg.h"
#include "base.h"
#include "rfbuffer.h"
#include "rfgain.h"

Go to the source code of this file.

Defines

#define _ATH5K_PHY

Functions

 FILE_LICENCE (MIT)
static int min (int x, int y)
static int max (int x, int y)
static unsigned int ath5k_hw_rfb_op (struct ath5k_hw *ah, const struct ath5k_rf_reg *rf_regs, u32 val, u8 reg_id, int set)
int ath5k_hw_rfgain_opt_init (struct ath5k_hw *ah)
static void ath5k_hw_request_rfgain_probe (struct ath5k_hw *ah)
static u32 ath5k_hw_rf_gainf_corr (struct ath5k_hw *ah)
static int ath5k_hw_rf_check_gainf_readback (struct ath5k_hw *ah)
static s8 ath5k_hw_rf_gainf_adjust (struct ath5k_hw *ah)
enum ath5k_rfgain ath5k_hw_gainf_calibrate (struct ath5k_hw *ah)
int ath5k_hw_rfgain_init (struct ath5k_hw *ah, unsigned int freq)
int ath5k_hw_rfregs_init (struct ath5k_hw *ah, struct net80211_channel *channel, unsigned int mode)
int ath5k_channel_ok (struct ath5k_hw *ah, u16 freq, unsigned int flags)
static u32 ath5k_hw_rf5110_chan2athchan (struct net80211_channel *channel)
static int ath5k_hw_rf5110_channel (struct ath5k_hw *ah, struct net80211_channel *channel)
static int ath5k_hw_rf5111_chan2athchan (unsigned int ieee, struct ath5k_athchan_2ghz *athchan)
static int ath5k_hw_rf5111_channel (struct ath5k_hw *ah, struct net80211_channel *channel)
static int ath5k_hw_rf5112_channel (struct ath5k_hw *ah, struct net80211_channel *channel)
static int ath5k_hw_rf2425_channel (struct ath5k_hw *ah, struct net80211_channel *channel)
int ath5k_hw_channel (struct ath5k_hw *ah, struct net80211_channel *channel)
int ath5k_hw_noise_floor_calibration (struct ath5k_hw *ah, short freq)
 ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
static int ath5k_hw_rf5110_calibrate (struct ath5k_hw *ah, struct net80211_channel *channel)
static int ath5k_hw_rf511x_calibrate (struct ath5k_hw *ah, struct net80211_channel *channel)
int ath5k_hw_phy_calibrate (struct ath5k_hw *ah, struct net80211_channel *channel)
int ath5k_hw_phy_disable (struct ath5k_hw *ah)
u16 ath5k_hw_radio_revision (struct ath5k_hw *ah, unsigned int chan)
void ath5k_hw_set_def_antenna (struct ath5k_hw *ah, unsigned int ant)
unsigned int ath5k_hw_get_def_antenna (struct ath5k_hw *ah)
static s16 ath5k_get_interpolated_value (s16 target, s16 x_left, s16 x_right, s16 y_left, s16 y_right)
static s16 ath5k_get_linear_pcdac_min (const u8 *stepL, const u8 *stepR, const s16 *pwrL, const s16 *pwrR)
static void ath5k_create_power_curve (s16 pmin, s16 pmax, const s16 *pwr, const u8 *vpd, u8 num_points, u8 *vpd_table, u8 type)
static void ath5k_get_chan_pcal_surrounding_piers (struct ath5k_hw *ah, struct net80211_channel *channel, struct ath5k_chan_pcal_info **pcinfo_l, struct ath5k_chan_pcal_info **pcinfo_r)
static void ath5k_get_rate_pcal_data (struct ath5k_hw *ah, struct net80211_channel *channel, struct ath5k_rate_pcal_info *rates)
static void ath5k_get_max_ctl_power (struct ath5k_hw *ah, struct net80211_channel *channel)
static void ath5k_fill_pwr_to_pcdac_table (struct ath5k_hw *ah, s16 *table_min, s16 *table_max)
static void ath5k_combine_linear_pcdac_curves (struct ath5k_hw *ah, s16 *table_min, s16 *table_max, u8 pdcurves)
static void ath5k_setup_pcdac_table (struct ath5k_hw *ah)
static void ath5k_combine_pwr_to_pdadc_curves (struct ath5k_hw *ah, s16 *pwr_min, s16 *pwr_max, u8 pdcurves)
static void ath5k_setup_pwr_to_pdadc_table (struct ath5k_hw *ah, u8 pdcurves, u8 *pdg_to_idx)
static int ath5k_setup_channel_powertable (struct ath5k_hw *ah, struct net80211_channel *channel, u8 ee_mode, u8 type)
static void ath5k_setup_rate_powertable (struct ath5k_hw *ah, u16 max_pwr, struct ath5k_rate_pcal_info *rate_info, u8 ee_mode)
int ath5k_hw_txpower (struct ath5k_hw *ah, struct net80211_channel *channel, u8 ee_mode, u8 txpower)
int ath5k_hw_set_txpower_limit (struct ath5k_hw *ah, u8 mode, u8 txpower)


Define Documentation

#define _ATH5K_PHY

Definition at line 27 of file ath5k_phy.c.


Function Documentation

FILE_LICENCE ( MIT   ) 

static int min ( int  x,
int  y 
) [inline, static]

Definition at line 38 of file ath5k_phy.c.

References min.

00039 {
00040         return (x < y) ? x : y;
00041 }

static int max ( int  x,
int  y 
) [inline, static]

Definition at line 43 of file ath5k_phy.c.

00044 {
00045         return (x > y) ? x : y;
00046 }

static unsigned int ath5k_hw_rfb_op ( struct ath5k_hw ah,
const struct ath5k_rf_reg rf_regs,
u32  val,
u8  reg_id,
int  set 
) [static]

Definition at line 51 of file ath5k_phy.c.

References ath5k_hw::ah_offset, ath5k_hw::ah_rf_banks, ath5k_hw::ah_rf_regs_count, ath5k_hw_bitswap(), ath5k_rf_reg::bank, ath5k_rfb_field::col, DBG, entry, ath5k_rf_reg::field, index, ath5k_rfb_field::len, NULL, offset, ath5k_rfb_field::pos, u16, u32, and u8.

Referenced by ath5k_hw_rf_check_gainf_readback(), ath5k_hw_rf_gainf_corr(), and ath5k_hw_rfregs_init().

00054 {
00055         const struct ath5k_rf_reg *rfreg = NULL;
00056         u8 offset, bank, num_bits, col, position;
00057         u16 entry;
00058         u32 mask, data, last_bit, bits_shifted, first_bit;
00059         u32 *rfb;
00060         s32 bits_left;
00061         unsigned i;
00062 
00063         data = 0;
00064         rfb = ah->ah_rf_banks;
00065 
00066         for (i = 0; i < ah->ah_rf_regs_count; i++) {
00067                 if (rf_regs[i].index == reg_id) {
00068                         rfreg = &rf_regs[i];
00069                         break;
00070                 }
00071         }
00072 
00073         if (rfb == NULL || rfreg == NULL) {
00074                 DBG("ath5k: RF register not found!\n");
00075                 /* should not happen */
00076                 return 0;
00077         }
00078 
00079         bank = rfreg->bank;
00080         num_bits = rfreg->field.len;
00081         first_bit = rfreg->field.pos;
00082         col = rfreg->field.col;
00083 
00084         /* first_bit is an offset from bank's
00085          * start. Since we have all banks on
00086          * the same array, we use this offset
00087          * to mark each bank's start */
00088         offset = ah->ah_offset[bank];
00089 
00090         /* Boundary check */
00091         if (!(col <= 3 && num_bits <= 32 && first_bit + num_bits <= 319)) {
00092                 DBG("ath5k: RF invalid values at offset %d\n", offset);
00093                 return 0;
00094         }
00095 
00096         entry = ((first_bit - 1) / 8) + offset;
00097         position = (first_bit - 1) % 8;
00098 
00099         if (set)
00100                 data = ath5k_hw_bitswap(val, num_bits);
00101 
00102         for (bits_shifted = 0, bits_left = num_bits; bits_left > 0;
00103         position = 0, entry++) {
00104 
00105                 last_bit = (position + bits_left > 8) ? 8 :
00106                                         position + bits_left;
00107 
00108                 mask = (((1 << last_bit) - 1) ^ ((1 << position) - 1)) <<
00109                                                                 (col * 8);
00110 
00111                 if (set) {
00112                         rfb[entry] &= ~mask;
00113                         rfb[entry] |= ((data << position) << (col * 8)) & mask;
00114                         data >>= (8 - position);
00115                 } else {
00116                         data |= (((rfb[entry] & mask) >> (col * 8)) >> position)
00117                                 << bits_shifted;
00118                         bits_shifted += last_bit - position;
00119                 }
00120 
00121                 bits_left -= 8 - position;
00122         }
00123 
00124         data = set ? 1 : ath5k_hw_bitswap(data, num_bits);
00125 
00126         return data;
00127 }

int ath5k_hw_rfgain_opt_init ( struct ath5k_hw ah  ) 

Definition at line 158 of file ath5k_phy.c.

References ath5k_hw::ah_gain, ath5k_hw::ah_radio, AR5K_RF5111, AR5K_RF5112, AR5K_RFGAIN_ACTIVE, EINVAL, ath5k_gain::g_high, ath5k_gain::g_low, ath5k_gain::g_state, ath5k_gain::g_step_idx, ath5k_gain_opt::go_default, rfgain_opt_5111, and rfgain_opt_5112.

Referenced by ath5k_hw_attach().

00159 {
00160         /* Initialize the gain optimization values */
00161         switch (ah->ah_radio) {
00162         case AR5K_RF5111:
00163                 ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default;
00164                 ah->ah_gain.g_low = 20;
00165                 ah->ah_gain.g_high = 35;
00166                 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00167                 break;
00168         case AR5K_RF5112:
00169                 ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default;
00170                 ah->ah_gain.g_low = 20;
00171                 ah->ah_gain.g_high = 85;
00172                 ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00173                 break;
00174         default:
00175                 return -EINVAL;
00176         }
00177 
00178         return 0;
00179 }

static void ath5k_hw_request_rfgain_probe ( struct ath5k_hw ah  )  [static]

Definition at line 194 of file ath5k_phy.c.

References ath5k_hw::ah_gain, ath5k_hw::ah_txpower, AR5K_PHY_PAPD_PROBE, AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE_TXPOWER, AR5K_REG_SM, AR5K_RFGAIN_ACTIVE, AR5K_RFGAIN_READ_REQUESTED, ath5k_hw_reg_write(), ath5k_gain::g_state, and ath5k_hw::txp_max_pwr.

Referenced by ath5k_hw_rf511x_calibrate().

00195 {
00196 
00197         /* Skip if gain calibration is inactive or
00198          * we already handle a probe request */
00199         if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE)
00200                 return;
00201 
00202         /* Send the packet with 2dB below max power as
00203          * patent doc suggest */
00204         ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max_pwr - 4,
00205                         AR5K_PHY_PAPD_PROBE_TXPOWER) |
00206                         AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE);
00207 
00208         ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED;
00209 
00210 }

static u32 ath5k_hw_rf_gainf_corr ( struct ath5k_hw ah  )  [static]

Definition at line 214 of file ath5k_phy.c.

References ath5k_hw::ah_gain, ath5k_hw::ah_radio, ath5k_hw::ah_radio_5ghz_revision, ath5k_hw::ah_rf_banks, ath5k_hw::ah_rf_regs_count, AR5K_RF5112, AR5K_RF_MIXGAIN_STEP, AR5K_RF_MIXVGA_OVR, AR5K_SREV_RAD_5112A, ARRAY_SIZE, ath5k_hw_rfb_op(), ath5k_gain::g_f_corr, ath5k_gain::g_step_idx, ath5k_gain_opt::go_step, ath5k_gain_opt_step::gos_param, NULL, rf_regs_5112a, rfgain_opt_5112, step(), and u32.

Referenced by ath5k_hw_gainf_calibrate().

00215 {
00216         u32 mix, step;
00217         u32 *rf;
00218         const struct ath5k_gain_opt *go;
00219         const struct ath5k_gain_opt_step *g_step;
00220         const struct ath5k_rf_reg *rf_regs;
00221 
00222         /* Only RF5112 Rev. 2 supports it */
00223         if ((ah->ah_radio != AR5K_RF5112) ||
00224         (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A))
00225                 return 0;
00226 
00227         go = &rfgain_opt_5112;
00228         rf_regs = rf_regs_5112a;
00229         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
00230 
00231         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00232 
00233         if (ah->ah_rf_banks == NULL)
00234                 return 0;
00235 
00236         rf = ah->ah_rf_banks;
00237         ah->ah_gain.g_f_corr = 0;
00238 
00239         /* No VGA (Variable Gain Amplifier) override, skip */
00240         if (ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR, 0) != 1)
00241                 return 0;
00242 
00243         /* Mix gain stepping */
00244         step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXGAIN_STEP, 0);
00245 
00246         /* Mix gain override */
00247         mix = g_step->gos_param[0];
00248 
00249         switch (mix) {
00250         case 3:
00251                 ah->ah_gain.g_f_corr = step * 2;
00252                 break;
00253         case 2:
00254                 ah->ah_gain.g_f_corr = (step - 5) * 2;
00255                 break;
00256         case 1:
00257                 ah->ah_gain.g_f_corr = step;
00258                 break;
00259         default:
00260                 ah->ah_gain.g_f_corr = 0;
00261                 break;
00262         }
00263 
00264         return ah->ah_gain.g_f_corr;
00265 }

static int ath5k_hw_rf_check_gainf_readback ( struct ath5k_hw ah  )  [static]

Definition at line 271 of file ath5k_phy.c.

References ath5k_hw::ah_gain, ath5k_hw::ah_radio, ath5k_hw::ah_rf_banks, ath5k_hw::ah_rf_regs_count, AR5K_GAIN_DYN_ADJUST_HI_MARGIN, AR5K_GAIN_DYN_ADJUST_LO_MARGIN, AR5K_RF5111, AR5K_RF_MIXVGA_OVR, AR5K_RF_RFGAIN_STEP, ARRAY_SIZE, ath5k_hw_rfb_op(), ath5k_gain::g_current, ath5k_gain::g_high, ath5k_gain::g_low, NULL, rf_regs_5111, rf_regs_5112, step(), and u32.

Referenced by ath5k_hw_gainf_calibrate().

00272 {
00273         const struct ath5k_rf_reg *rf_regs;
00274         u32 step, mix_ovr, level[4];
00275         u32 *rf;
00276 
00277         if (ah->ah_rf_banks == NULL)
00278                 return 0;
00279 
00280         rf = ah->ah_rf_banks;
00281 
00282         if (ah->ah_radio == AR5K_RF5111) {
00283 
00284                 rf_regs = rf_regs_5111;
00285                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
00286 
00287                 step = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_RFGAIN_STEP,
00288                         0);
00289 
00290                 level[0] = 0;
00291                 level[1] = (step == 63) ? 50 : step + 4;
00292                 level[2] = (step != 63) ? 64 : level[0];
00293                 level[3] = level[2] + 50 ;
00294 
00295                 ah->ah_gain.g_high = level[3] -
00296                         (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5);
00297                 ah->ah_gain.g_low = level[0] +
00298                         (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0);
00299         } else {
00300 
00301                 rf_regs = rf_regs_5112;
00302                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
00303 
00304                 mix_ovr = ath5k_hw_rfb_op(ah, rf_regs, 0, AR5K_RF_MIXVGA_OVR,
00305                         0);
00306 
00307                 level[0] = level[2] = 0;
00308 
00309                 if (mix_ovr == 1) {
00310                         level[1] = level[3] = 83;
00311                 } else {
00312                         level[1] = level[3] = 107;
00313                         ah->ah_gain.g_high = 55;
00314                 }
00315         }
00316 
00317         return (ah->ah_gain.g_current >= level[0] &&
00318                         ah->ah_gain.g_current <= level[1]) ||
00319                 (ah->ah_gain.g_current >= level[2] &&
00320                         ah->ah_gain.g_current <= level[3]);
00321 }

static s8 ath5k_hw_rf_gainf_adjust ( struct ath5k_hw ah  )  [static]

Definition at line 325 of file ath5k_phy.c.

References ath5k_hw::ah_gain, ath5k_hw::ah_radio, AR5K_RF5111, AR5K_RF5112, DBG2, ath5k_gain::g_current, ath5k_gain::g_high, ath5k_gain::g_low, ath5k_gain::g_step_idx, ath5k_gain::g_target, ath5k_gain_opt::go_step, ath5k_gain_opt::go_steps_count, ath5k_gain_opt_step::gos_gain, rfgain_opt_5111, and rfgain_opt_5112.

Referenced by ath5k_hw_gainf_calibrate().

00326 {
00327         const struct ath5k_gain_opt *go;
00328         const struct ath5k_gain_opt_step *g_step;
00329         int ret = 0;
00330 
00331         switch (ah->ah_radio) {
00332         case AR5K_RF5111:
00333                 go = &rfgain_opt_5111;
00334                 break;
00335         case AR5K_RF5112:
00336                 go = &rfgain_opt_5112;
00337                 break;
00338         default:
00339                 return 0;
00340         }
00341 
00342         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00343 
00344         if (ah->ah_gain.g_current >= ah->ah_gain.g_high) {
00345 
00346                 /* Reached maximum */
00347                 if (ah->ah_gain.g_step_idx == 0)
00348                         return -1;
00349 
00350                 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
00351                                 ah->ah_gain.g_target >=  ah->ah_gain.g_high &&
00352                                 ah->ah_gain.g_step_idx > 0;
00353                                 g_step = &go->go_step[ah->ah_gain.g_step_idx])
00354                         ah->ah_gain.g_target -= 2 *
00355                             (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain -
00356                             g_step->gos_gain);
00357 
00358                 ret = 1;
00359                 goto done;
00360         }
00361 
00362         if (ah->ah_gain.g_current <= ah->ah_gain.g_low) {
00363 
00364                 /* Reached minimum */
00365                 if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1))
00366                         return -2;
00367 
00368                 for (ah->ah_gain.g_target = ah->ah_gain.g_current;
00369                                 ah->ah_gain.g_target <= ah->ah_gain.g_low &&
00370                                 ah->ah_gain.g_step_idx < go->go_steps_count-1;
00371                                 g_step = &go->go_step[ah->ah_gain.g_step_idx])
00372                         ah->ah_gain.g_target -= 2 *
00373                             (go->go_step[++ah->ah_gain.g_step_idx].gos_gain -
00374                             g_step->gos_gain);
00375 
00376                 ret = 2;
00377                 goto done;
00378         }
00379 
00380 done:
00381         DBG2("ath5k RF adjust: ret %d, gain step %d, current gain %d, "
00382              "target gain %d\n", ret, ah->ah_gain.g_step_idx,
00383              ah->ah_gain.g_current, ah->ah_gain.g_target);
00384 
00385         return ret;
00386 }

enum ath5k_rfgain ath5k_hw_gainf_calibrate ( struct ath5k_hw ah  ) 

Definition at line 394 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, ath5k_hw::ah_gain, ath5k_hw::ah_radio_5ghz_revision, ath5k_hw::ah_rf_banks, AR5K_GAIN_CCK_PROBE_CORR, AR5K_GAIN_CHECK_ADJUST, AR5K_PHY_PAPD_PROBE, AR5K_PHY_PAPD_PROBE_GAINF_S, AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE_TYPE, AR5K_PHY_PAPD_PROBE_TYPE_CCK, AR5K_REG_MS, AR5K_RFGAIN_ACTIVE, AR5K_RFGAIN_INACTIVE, AR5K_RFGAIN_NEED_CHANGE, AR5K_RFGAIN_READ_REQUESTED, AR5K_SREV_RAD_5112A, ath5k_hw_reg_read(), ath5k_hw_rf_check_gainf_readback(), ath5k_hw_rf_gainf_adjust(), ath5k_hw_rf_gainf_corr(), ath5k_capabilities::cap_eeprom, ath5k_eeprom_info::ee_cck_ofdm_gain_delta, ath5k_gain::g_current, ath5k_gain::g_f_corr, ath5k_gain::g_state, NULL, and u32.

Referenced by ath5k_calibrate(), and ath5k_hw_reset().

00395 {
00396         u32 data, type;
00397         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00398 
00399         if (ah->ah_rf_banks == NULL ||
00400         ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
00401                 return AR5K_RFGAIN_INACTIVE;
00402 
00403         /* No check requested, either engine is inactive
00404          * or an adjustment is already requested */
00405         if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED)
00406                 goto done;
00407 
00408         /* Read the PAPD (Peak to Average Power Detector)
00409          * register */
00410         data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE);
00411 
00412         /* No probe is scheduled, read gain_F measurement */
00413         if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) {
00414                 ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S;
00415                 type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE);
00416 
00417                 /* If tx packet is CCK correct the gain_F measurement
00418                  * by cck ofdm gain delta */
00419                 if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) {
00420                         if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A)
00421                                 ah->ah_gain.g_current +=
00422                                         ee->ee_cck_ofdm_gain_delta;
00423                         else
00424                                 ah->ah_gain.g_current +=
00425                                         AR5K_GAIN_CCK_PROBE_CORR;
00426                 }
00427 
00428                 /* Further correct gain_F measurement for
00429                  * RF5112A radios */
00430                 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
00431                         ath5k_hw_rf_gainf_corr(ah);
00432                         ah->ah_gain.g_current =
00433                                 ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ?
00434                                 (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) :
00435                                 0;
00436                 }
00437 
00438                 /* Check if measurement is ok and if we need
00439                  * to adjust gain, schedule a gain adjustment,
00440                  * else switch back to the acive state */
00441                 if (ath5k_hw_rf_check_gainf_readback(ah) &&
00442                 AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) &&
00443                 ath5k_hw_rf_gainf_adjust(ah)) {
00444                         ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE;
00445                 } else {
00446                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00447                 }
00448         }
00449 
00450 done:
00451         return ah->ah_gain.g_state;
00452 }

int ath5k_hw_rfgain_init ( struct ath5k_hw ah,
unsigned int  freq 
)

Definition at line 457 of file ath5k_phy.c.

References ath5k_hw::ah_radio, AR5K_INI_RFGAIN_2GHZ, AR5K_INI_RFGAIN_5GHZ, AR5K_REG_WAIT, AR5K_RF2316, AR5K_RF2317, AR5K_RF2413, AR5K_RF2425, AR5K_RF5111, AR5K_RF5112, AR5K_RF5413, ARRAY_SIZE, ath5k_hw_reg_write(), EINVAL, ath5k_ini_rfgain::rfg_register, ath5k_ini_rfgain::rfg_value, rfgain_2316, rfgain_2413, rfgain_2425, rfgain_5111, rfgain_5112, rfgain_5413, size, and u32.

Referenced by ath5k_hw_reset().

00458 {
00459         const struct ath5k_ini_rfgain *ath5k_rfg;
00460         unsigned int i, size;
00461 
00462         switch (ah->ah_radio) {
00463         case AR5K_RF5111:
00464                 ath5k_rfg = rfgain_5111;
00465                 size = ARRAY_SIZE(rfgain_5111);
00466                 break;
00467         case AR5K_RF5112:
00468                 ath5k_rfg = rfgain_5112;
00469                 size = ARRAY_SIZE(rfgain_5112);
00470                 break;
00471         case AR5K_RF2413:
00472                 ath5k_rfg = rfgain_2413;
00473                 size = ARRAY_SIZE(rfgain_2413);
00474                 break;
00475         case AR5K_RF2316:
00476                 ath5k_rfg = rfgain_2316;
00477                 size = ARRAY_SIZE(rfgain_2316);
00478                 break;
00479         case AR5K_RF5413:
00480                 ath5k_rfg = rfgain_5413;
00481                 size = ARRAY_SIZE(rfgain_5413);
00482                 break;
00483         case AR5K_RF2317:
00484         case AR5K_RF2425:
00485                 ath5k_rfg = rfgain_2425;
00486                 size = ARRAY_SIZE(rfgain_2425);
00487                 break;
00488         default:
00489                 return -EINVAL;
00490         }
00491 
00492         switch (freq) {
00493         case AR5K_INI_RFGAIN_2GHZ:
00494         case AR5K_INI_RFGAIN_5GHZ:
00495                 break;
00496         default:
00497                 return -EINVAL;
00498         }
00499 
00500         for (i = 0; i < size; i++) {
00501                 AR5K_REG_WAIT(i);
00502                 ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq],
00503                         (u32)ath5k_rfg[i].rfg_register);
00504         }
00505 
00506         return 0;
00507 }

int ath5k_hw_rfregs_init ( struct ath5k_hw ah,
struct net80211_channel channel,
unsigned int  mode 
)

Definition at line 519 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, ath5k_hw::ah_gain, ath5k_hw::ah_mac_srev, ath5k_hw::ah_offset, ath5k_hw::ah_phy_revision, ath5k_hw::ah_radio, ath5k_hw::ah_radio_5ghz_revision, ath5k_hw::ah_rf_banks, ath5k_hw::ah_rf_banks_size, ath5k_hw::ah_rf_regs_count, AR5K_EEPROM_MODE_11A, AR5K_EEPROM_MODE_11B, AR5K_EEPROM_MODE_11G, AR5K_MAX_RF_BANKS, AR5K_PHY_FRAME_CTL, AR5K_PHY_FRAME_CTL_TX_CLIP, AR5K_REG_WAIT, AR5K_REG_WRITE_BITS, AR5K_RF2316, AR5K_RF2317, AR5K_RF2413, AR5K_RF2425, AR5K_RF5111, AR5K_RF5112, AR5K_RF5413, AR5K_RF_DB_2GHZ, AR5K_RF_DB_5GHZ, AR5K_RF_DERBY_CHAN_SEL_MODE, AR5K_RF_GAIN_I, AR5K_RF_HIGH_VC_CP, AR5K_RF_LOW_VC_CP, AR5K_RF_MID_VC_CP, AR5K_RF_MIXGAIN_OVR, AR5K_RF_OB_2GHZ, AR5K_RF_OB_5GHZ, AR5K_RF_PAD2GND, AR5K_RF_PD_GAIN_HI, AR5K_RF_PD_GAIN_LO, AR5K_RF_PLO_SEL, AR5K_RF_PUSH_UP, AR5K_RF_PWD_130, AR5K_RF_PWD_131, AR5K_RF_PWD_132, AR5K_RF_PWD_136, AR5K_RF_PWD_137, AR5K_RF_PWD_138, AR5K_RF_PWD_166, AR5K_RF_PWD_167, AR5K_RF_PWD_84, AR5K_RF_PWD_90, AR5K_RF_PWD_ICLOBUF_2G, AR5K_RF_PWD_XPD, AR5K_RF_RFGAIN_SEL, AR5K_RF_XB2_LVL, AR5K_RF_XB5_LVL, AR5K_RF_XPD_GAIN, AR5K_RF_XPD_SEL, AR5K_RFGAIN_ACTIVE, AR5K_SREV_AR2417, AR5K_SREV_AR5413, AR5K_SREV_AR5424, AR5K_SREV_PHY_5212A, AR5K_SREV_RAD_5112A, ARRAY_SIZE, ath5k_hw_bitswap(), ath5k_hw_reg_write(), ath5k_hw_rfb_op(), ath5k_capabilities::cap_eeprom, net80211_channel::center_freq, CHANNEL_2GHZ, CHANNEL_5GHZ, CHANNEL_CCK, CHANNEL_OFDM, DBG, ath5k_eeprom_info::ee_db, ath5k_eeprom_info::ee_i_gain, ath5k_eeprom_info::ee_ob, ath5k_eeprom_info::ee_x_gain, ath5k_eeprom_info::ee_xpd, EINVAL, ENOMEM, ath5k_gain::g_state, ath5k_gain::g_step_idx, ath5k_gain_opt::go_step, ath5k_gain_opt_step::gos_param, net80211_channel::hw_value, malloc(), NULL, rf_regs_2316, rf_regs_2413, rf_regs_2425, rf_regs_5111, rf_regs_5112, rf_regs_5112a, rf_regs_5413, rfb_2316, rfb_2317, rfb_2413, rfb_2417, rfb_2425, rfb_5111, rfb_5112, rfb_5112a, rfb_5413, ath5k_ini_rfbuffer::rfb_bank, ath5k_ini_rfbuffer::rfb_mode_data, rfgain_opt_5111, rfgain_opt_5112, u32, and u8.

Referenced by ath5k_hw_reset().

00521 {
00522         const struct ath5k_rf_reg *rf_regs;
00523         const struct ath5k_ini_rfbuffer *ini_rfb;
00524         const struct ath5k_gain_opt *go = NULL;
00525         const struct ath5k_gain_opt_step *g_step;
00526         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
00527         u8 ee_mode = 0;
00528         u32 *rfb;
00529         int obdb = -1, bank = -1;
00530         unsigned i;
00531 
00532         switch (ah->ah_radio) {
00533         case AR5K_RF5111:
00534                 rf_regs = rf_regs_5111;
00535                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5111);
00536                 ini_rfb = rfb_5111;
00537                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5111);
00538                 go = &rfgain_opt_5111;
00539                 break;
00540         case AR5K_RF5112:
00541                 if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) {
00542                         rf_regs = rf_regs_5112a;
00543                         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112a);
00544                         ini_rfb = rfb_5112a;
00545                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112a);
00546                 } else {
00547                         rf_regs = rf_regs_5112;
00548                         ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5112);
00549                         ini_rfb = rfb_5112;
00550                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5112);
00551                 }
00552                 go = &rfgain_opt_5112;
00553                 break;
00554         case AR5K_RF2413:
00555                 rf_regs = rf_regs_2413;
00556                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2413);
00557                 ini_rfb = rfb_2413;
00558                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2413);
00559                 break;
00560         case AR5K_RF2316:
00561                 rf_regs = rf_regs_2316;
00562                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2316);
00563                 ini_rfb = rfb_2316;
00564                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2316);
00565                 break;
00566         case AR5K_RF5413:
00567                 rf_regs = rf_regs_5413;
00568                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_5413);
00569                 ini_rfb = rfb_5413;
00570                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_5413);
00571                 break;
00572         case AR5K_RF2317:
00573                 rf_regs = rf_regs_2425;
00574                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
00575                 ini_rfb = rfb_2317;
00576                 ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2317);
00577                 break;
00578         case AR5K_RF2425:
00579                 rf_regs = rf_regs_2425;
00580                 ah->ah_rf_regs_count = ARRAY_SIZE(rf_regs_2425);
00581                 if (ah->ah_mac_srev < AR5K_SREV_AR2417) {
00582                         ini_rfb = rfb_2425;
00583                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2425);
00584                 } else {
00585                         ini_rfb = rfb_2417;
00586                         ah->ah_rf_banks_size = ARRAY_SIZE(rfb_2417);
00587                 }
00588                 break;
00589         default:
00590                 return -EINVAL;
00591         }
00592 
00593         /* If it's the first time we set rf buffer, allocate
00594          * ah->ah_rf_banks based on ah->ah_rf_banks_size
00595          * we set above */
00596         if (ah->ah_rf_banks == NULL) {
00597                 ah->ah_rf_banks = malloc(sizeof(u32) * ah->ah_rf_banks_size);
00598                 if (ah->ah_rf_banks == NULL) {
00599                         return -ENOMEM;
00600                 }
00601         }
00602 
00603         /* Copy values to modify them */
00604         rfb = ah->ah_rf_banks;
00605 
00606         for (i = 0; i < ah->ah_rf_banks_size; i++) {
00607                 if (ini_rfb[i].rfb_bank >= AR5K_MAX_RF_BANKS) {
00608                         DBG("ath5k: invalid RF register bank\n");
00609                         return -EINVAL;
00610                 }
00611 
00612                 /* Bank changed, write down the offset */
00613                 if (bank != ini_rfb[i].rfb_bank) {
00614                         bank = ini_rfb[i].rfb_bank;
00615                         ah->ah_offset[bank] = i;
00616                 }
00617 
00618                 rfb[i] = ini_rfb[i].rfb_mode_data[mode];
00619         }
00620 
00621         /* Set Output and Driver bias current (OB/DB) */
00622         if (channel->hw_value & CHANNEL_2GHZ) {
00623 
00624                 if (channel->hw_value & CHANNEL_CCK)
00625                         ee_mode = AR5K_EEPROM_MODE_11B;
00626                 else
00627                         ee_mode = AR5K_EEPROM_MODE_11G;
00628 
00629                 /* For RF511X/RF211X combination we
00630                  * use b_OB and b_DB parameters stored
00631                  * in eeprom on ee->ee_ob[ee_mode][0]
00632                  *
00633                  * For all other chips we use OB/DB for 2Ghz
00634                  * stored in the b/g modal section just like
00635                  * 802.11a on ee->ee_ob[ee_mode][1] */
00636                 if ((ah->ah_radio == AR5K_RF5111) ||
00637                 (ah->ah_radio == AR5K_RF5112))
00638                         obdb = 0;
00639                 else
00640                         obdb = 1;
00641 
00642                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
00643                                                 AR5K_RF_OB_2GHZ, 1);
00644 
00645                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
00646                                                 AR5K_RF_DB_2GHZ, 1);
00647 
00648         /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */
00649         } else if ((channel->hw_value & CHANNEL_5GHZ) ||
00650                         (ah->ah_radio == AR5K_RF5111)) {
00651 
00652                 /* For 11a, Turbo and XR we need to choose
00653                  * OB/DB based on frequency range */
00654                 ee_mode = AR5K_EEPROM_MODE_11A;
00655                 obdb =   channel->center_freq >= 5725 ? 3 :
00656                         (channel->center_freq >= 5500 ? 2 :
00657                         (channel->center_freq >= 5260 ? 1 :
00658                          (channel->center_freq > 4000 ? 0 : -1)));
00659 
00660                 if (obdb < 0)
00661                         return -EINVAL;
00662 
00663                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_ob[ee_mode][obdb],
00664                                                 AR5K_RF_OB_5GHZ, 1);
00665 
00666                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_db[ee_mode][obdb],
00667                                                 AR5K_RF_DB_5GHZ, 1);
00668         }
00669 
00670         g_step = &go->go_step[ah->ah_gain.g_step_idx];
00671 
00672         /* Bank Modifications (chip-specific) */
00673         if (ah->ah_radio == AR5K_RF5111) {
00674 
00675                 /* Set gain_F settings according to current step */
00676                 if (channel->hw_value & CHANNEL_OFDM) {
00677 
00678                         AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL,
00679                                         AR5K_PHY_FRAME_CTL_TX_CLIP,
00680                                         g_step->gos_param[0]);
00681 
00682                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
00683                                                         AR5K_RF_PWD_90, 1);
00684 
00685                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
00686                                                         AR5K_RF_PWD_84, 1);
00687 
00688                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
00689                                                 AR5K_RF_RFGAIN_SEL, 1);
00690 
00691                         /* We programmed gain_F parameters, switch back
00692                          * to active state */
00693                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00694 
00695                 }
00696 
00697                 /* Bank 6/7 setup */
00698 
00699                 ath5k_hw_rfb_op(ah, rf_regs, !ee->ee_xpd[ee_mode],
00700                                                 AR5K_RF_PWD_XPD, 1);
00701 
00702                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_x_gain[ee_mode],
00703                                                 AR5K_RF_XPD_GAIN, 1);
00704 
00705                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
00706                                                 AR5K_RF_GAIN_I, 1);
00707 
00708                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
00709                                                 AR5K_RF_PLO_SEL, 1);
00710 
00711                 /* TODO: Half/quarter channel support */
00712         }
00713 
00714         if (ah->ah_radio == AR5K_RF5112) {
00715 
00716                 /* Set gain_F settings according to current step */
00717                 if (channel->hw_value & CHANNEL_OFDM) {
00718 
00719                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0],
00720                                                 AR5K_RF_MIXGAIN_OVR, 1);
00721 
00722                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[1],
00723                                                 AR5K_RF_PWD_138, 1);
00724 
00725                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[2],
00726                                                 AR5K_RF_PWD_137, 1);
00727 
00728                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[3],
00729                                                 AR5K_RF_PWD_136, 1);
00730 
00731                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[4],
00732                                                 AR5K_RF_PWD_132, 1);
00733 
00734                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[5],
00735                                                 AR5K_RF_PWD_131, 1);
00736 
00737                         ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[6],
00738                                                 AR5K_RF_PWD_130, 1);
00739 
00740                         /* We programmed gain_F parameters, switch back
00741                          * to active state */
00742                         ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE;
00743                 }
00744 
00745                 /* Bank 6/7 setup */
00746 
00747                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
00748                                                 AR5K_RF_XPD_SEL, 1);
00749 
00750                 if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
00751                         /* Rev. 1 supports only one xpd */
00752                         ath5k_hw_rfb_op(ah, rf_regs,
00753                                                 ee->ee_x_gain[ee_mode],
00754                                                 AR5K_RF_XPD_GAIN, 1);
00755 
00756                 } else {
00757                         /* TODO: Set high and low gain bits */
00758                         ath5k_hw_rfb_op(ah, rf_regs,
00759                                                 ee->ee_x_gain[ee_mode],
00760                                                 AR5K_RF_PD_GAIN_LO, 1);
00761                         ath5k_hw_rfb_op(ah, rf_regs,
00762                                                 ee->ee_x_gain[ee_mode],
00763                                                 AR5K_RF_PD_GAIN_HI, 1);
00764 
00765                         /* Lower synth voltage on Rev 2 */
00766                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00767                                         AR5K_RF_HIGH_VC_CP, 1);
00768 
00769                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00770                                         AR5K_RF_MID_VC_CP, 1);
00771 
00772                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00773                                         AR5K_RF_LOW_VC_CP, 1);
00774 
00775                         ath5k_hw_rfb_op(ah, rf_regs, 2,
00776                                         AR5K_RF_PUSH_UP, 1);
00777 
00778                         /* Decrease power consumption on 5213+ BaseBand */
00779                         if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) {
00780                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00781                                                 AR5K_RF_PAD2GND, 1);
00782 
00783                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00784                                                 AR5K_RF_XB2_LVL, 1);
00785 
00786                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00787                                                 AR5K_RF_XB5_LVL, 1);
00788 
00789                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00790                                                 AR5K_RF_PWD_167, 1);
00791 
00792                                 ath5k_hw_rfb_op(ah, rf_regs, 1,
00793                                                 AR5K_RF_PWD_166, 1);
00794                         }
00795                 }
00796 
00797                 ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
00798                                                 AR5K_RF_GAIN_I, 1);
00799 
00800                 /* TODO: Half/quarter channel support */
00801 
00802         }
00803 
00804         if (ah->ah_radio == AR5K_RF5413 &&
00805         channel->hw_value & CHANNEL_2GHZ) {
00806 
00807                 ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE,
00808                                                                         1);
00809 
00810                 /* Set optimum value for early revisions (on pci-e chips) */
00811                 if (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
00812                 ah->ah_mac_srev < AR5K_SREV_AR5413)
00813                         ath5k_hw_rfb_op(ah, rf_regs, ath5k_hw_bitswap(6, 3),
00814                                                 AR5K_RF_PWD_ICLOBUF_2G, 1);
00815 
00816         }
00817 
00818         /* Write RF banks on hw */
00819         for (i = 0; i < ah->ah_rf_banks_size; i++) {
00820                 AR5K_REG_WAIT(i);
00821                 ath5k_hw_reg_write(ah, rfb[i], ini_rfb[i].rfb_ctrl_register);
00822         }
00823 
00824         return 0;
00825 }

int ath5k_channel_ok ( struct ath5k_hw ah,
u16  freq,
unsigned int  flags 
)

Definition at line 835 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, ath5k_capabilities::cap_range, CHANNEL_2GHZ, CHANNEL_5GHZ, ath5k_capabilities::range_2ghz_min, and ath5k_capabilities::range_5ghz_min.

Referenced by ath5k_copy_channels(), and ath5k_hw_channel().

00836 {
00837         /* Check if the channel is in our supported range */
00838         if (flags & CHANNEL_2GHZ) {
00839                 if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
00840                     (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
00841                         return 1;
00842         } else if (flags & CHANNEL_5GHZ)
00843                 if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
00844                     (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
00845                         return 1;
00846 
00847         return 0;
00848 }

static u32 ath5k_hw_rf5110_chan2athchan ( struct net80211_channel channel  )  [static]

Definition at line 853 of file ath5k_phy.c.

References ath5k_hw_bitswap(), net80211_channel::center_freq, and u32.

Referenced by ath5k_hw_rf5110_channel().

00854 {
00855         u32 athchan;
00856 
00857         /*
00858          * Convert IEEE channel/MHz to an internal channel value used
00859          * by the AR5210 chipset. This has not been verified with
00860          * newer chipsets like the AR5212A who have a completely
00861          * different RF/PHY part.
00862          */
00863         athchan = (ath5k_hw_bitswap((ath5k_freq_to_channel(channel->center_freq)
00864                                      - 24) / 2, 5) << 1)
00865                 | (1 << 6) | 0x1;
00866         return athchan;
00867 }

static int ath5k_hw_rf5110_channel ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 872 of file ath5k_phy.c.

References AR5K_RF_BUFFER, AR5K_RF_BUFFER_CONTROL_0, ath5k_hw_reg_write(), ath5k_hw_rf5110_chan2athchan(), mdelay(), and u32.

Referenced by ath5k_hw_channel().

00874 {
00875         u32 data;
00876 
00877         /*
00878          * Set the channel and wait
00879          */
00880         data = ath5k_hw_rf5110_chan2athchan(channel);
00881         ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER);
00882         ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0);
00883         mdelay(1);
00884 
00885         return 0;
00886 }

static int ath5k_hw_rf5111_chan2athchan ( unsigned int  ieee,
struct ath5k_athchan_2ghz athchan 
) [static]

Definition at line 891 of file ath5k_phy.c.

References ath5k_athchan_2ghz::a2_athchan, ath5k_athchan_2ghz::a2_flags, and EINVAL.

Referenced by ath5k_hw_rf5111_channel().

00893 {
00894         int channel;
00895 
00896         /* Cast this value to catch negative channel numbers (>= -19) */
00897         channel = (int)ieee;
00898 
00899         /*
00900          * Map 2GHz IEEE channel to 5GHz Atheros channel
00901          */
00902         if (channel <= 13) {
00903                 athchan->a2_athchan = 115 + channel;
00904                 athchan->a2_flags = 0x46;
00905         } else if (channel == 14) {
00906                 athchan->a2_athchan = 124;
00907                 athchan->a2_flags = 0x44;
00908         } else if (channel >= 15 && channel <= 26) {
00909                 athchan->a2_athchan = ((channel - 14) * 4) + 132;
00910                 athchan->a2_flags = 0x46;
00911         } else
00912                 return -EINVAL;
00913 
00914         return 0;
00915 }

static int ath5k_hw_rf5111_channel ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 920 of file ath5k_phy.c.

References ath5k_athchan_2ghz::a2_athchan, ath5k_athchan_2ghz::a2_flags, AR5K_RF_BUFFER, AR5K_RF_BUFFER_CONTROL_3, ath5k_hw_bitswap(), ath5k_hw_reg_write(), ath5k_hw_rf5111_chan2athchan(), net80211_channel::center_freq, CHANNEL_2GHZ, data1, net80211_channel::hw_value, and u32.

Referenced by ath5k_hw_channel().

00922 {
00923         struct ath5k_athchan_2ghz ath5k_channel_2ghz;
00924         unsigned int ath5k_channel = ath5k_freq_to_channel(channel->center_freq);
00925         u32 data0, data1, clock;
00926         int ret;
00927 
00928         /*
00929          * Set the channel on the RF5111 radio
00930          */
00931         data0 = data1 = 0;
00932 
00933         if (channel->hw_value & CHANNEL_2GHZ) {
00934                 /* Map 2GHz channel to 5GHz Atheros channel ID */
00935                 ret = ath5k_hw_rf5111_chan2athchan(ath5k_channel,
00936                                                    &ath5k_channel_2ghz);
00937                 if (ret)
00938                         return ret;
00939 
00940                 ath5k_channel = ath5k_channel_2ghz.a2_athchan;
00941                 data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff)
00942                     << 5) | (1 << 4);
00943         }
00944 
00945         if (ath5k_channel < 145 || !(ath5k_channel & 1)) {
00946                 clock = 1;
00947                 data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) |
00948                         (clock << 1) | (1 << 10) | 1;
00949         } else {
00950                 clock = 0;
00951                 data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff)
00952                         << 2) | (clock << 1) | (1 << 10) | 1;
00953         }
00954 
00955         ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8),
00956                         AR5K_RF_BUFFER);
00957         ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00),
00958                         AR5K_RF_BUFFER_CONTROL_3);
00959 
00960         return 0;
00961 }

static int ath5k_hw_rf5112_channel ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 966 of file ath5k_phy.c.

References AR5K_RF_BUFFER, AR5K_RF_BUFFER_CONTROL_5, ath5k_hw_bitswap(), ath5k_hw_reg_write(), net80211_channel::center_freq, data1, EINVAL, u16, and u32.

Referenced by ath5k_hw_channel().

00968 {
00969         u32 data, data0, data1, data2;
00970         u16 c;
00971 
00972         data = data0 = data1 = data2 = 0;
00973         c = channel->center_freq;
00974 
00975         if (c < 4800) {
00976                 if (!((c - 2224) % 5)) {
00977                         data0 = ((2 * (c - 704)) - 3040) / 10;
00978                         data1 = 1;
00979                 } else if (!((c - 2192) % 5)) {
00980                         data0 = ((2 * (c - 672)) - 3040) / 10;
00981                         data1 = 0;
00982                 } else
00983                         return -EINVAL;
00984 
00985                 data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
00986         } else if ((c - (c % 5)) != 2 || c > 5435) {
00987                 if (!(c % 20) && c >= 5120) {
00988                         data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
00989                         data2 = ath5k_hw_bitswap(3, 2);
00990                 } else if (!(c % 10)) {
00991                         data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
00992                         data2 = ath5k_hw_bitswap(2, 2);
00993                 } else if (!(c % 5)) {
00994                         data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
00995                         data2 = ath5k_hw_bitswap(1, 2);
00996                 } else
00997                         return -EINVAL;
00998         } else {
00999                 data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
01000                 data2 = ath5k_hw_bitswap(0, 2);
01001         }
01002 
01003         data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
01004 
01005         ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
01006         ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
01007 
01008         return 0;
01009 }

static int ath5k_hw_rf2425_channel ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 1014 of file ath5k_phy.c.

References AR5K_RF_BUFFER, AR5K_RF_BUFFER_CONTROL_5, ath5k_hw_bitswap(), ath5k_hw_reg_write(), net80211_channel::center_freq, EINVAL, u16, and u32.

Referenced by ath5k_hw_channel().

01016 {
01017         u32 data, data0, data2;
01018         u16 c;
01019 
01020         data = data0 = data2 = 0;
01021         c = channel->center_freq;
01022 
01023         if (c < 4800) {
01024                 data0 = ath5k_hw_bitswap((c - 2272), 8);
01025                 data2 = 0;
01026         /* ? 5GHz ? */
01027         } else if ((c - (c % 5)) != 2 || c > 5435) {
01028                 if (!(c % 20) && c < 5120)
01029                         data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
01030                 else if (!(c % 10))
01031                         data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
01032                 else if (!(c % 5))
01033                         data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
01034                 else
01035                         return -EINVAL;
01036                 data2 = ath5k_hw_bitswap(1, 2);
01037         } else {
01038                 data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
01039                 data2 = ath5k_hw_bitswap(0, 2);
01040         }
01041 
01042         data = (data0 << 4) | data2 << 2 | 0x1001;
01043 
01044         ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
01045         ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
01046 
01047         return 0;
01048 }

int ath5k_hw_channel ( struct ath5k_hw ah,
struct net80211_channel channel 
)

Definition at line 1053 of file ath5k_phy.c.

References ath5k_hw::ah_current_channel, ath5k_hw::ah_radio, ath5k_hw::ah_turbo, AR5K_PHY_CCKTXCTL, AR5K_PHY_CCKTXCTL_JAPAN, AR5K_PHY_CCKTXCTL_WORLD, AR5K_REG_ENABLE_BITS, AR5K_RF2425, AR5K_RF5110, AR5K_RF5111, ath5k_channel_ok(), ath5k_hw_rf2425_channel(), ath5k_hw_rf5110_channel(), ath5k_hw_rf5111_channel(), ath5k_hw_rf5112_channel(), net80211_channel::center_freq, CHANNEL_T, DBG, EINVAL, net80211_channel::hw_value, and strerror().

Referenced by ath5k_hw_reset(), and ath5k_hw_rf5110_calibrate().

01054 {
01055         int ret;
01056         /*
01057          * Check bounds supported by the PHY (we don't care about regultory
01058          * restrictions at this point). Note: hw_value already has the band
01059          * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok()
01060          * of the band by that */
01061         if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) {
01062                 DBG("ath5k: channel frequency (%d MHz) out of supported "
01063                     "range\n", channel->center_freq);
01064                 return -EINVAL;
01065         }
01066 
01067         /*
01068          * Set the channel and wait
01069          */
01070         switch (ah->ah_radio) {
01071         case AR5K_RF5110:
01072                 ret = ath5k_hw_rf5110_channel(ah, channel);
01073                 break;
01074         case AR5K_RF5111:
01075                 ret = ath5k_hw_rf5111_channel(ah, channel);
01076                 break;
01077         case AR5K_RF2425:
01078                 ret = ath5k_hw_rf2425_channel(ah, channel);
01079                 break;
01080         default:
01081                 ret = ath5k_hw_rf5112_channel(ah, channel);
01082                 break;
01083         }
01084 
01085         if (ret) {
01086                 DBG("ath5k: setting channel failed: %s\n", strerror(ret));
01087                 return ret;
01088         }
01089 
01090         /* Set JAPAN setting for channel 14 */
01091         if (channel->center_freq == 2484) {
01092                 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
01093                                 AR5K_PHY_CCKTXCTL_JAPAN);
01094         } else {
01095                 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
01096                                 AR5K_PHY_CCKTXCTL_WORLD);
01097         }
01098 
01099         ah->ah_current_channel = channel;
01100         ah->ah_turbo = (channel->hw_value == CHANNEL_T ? 1 : 0);
01101 
01102         return 0;
01103 }

int ath5k_hw_noise_floor_calibration ( struct ath5k_hw ah,
short  freq 
)

ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration

: struct ath5k_hw pointer we are operating on : the channel frequency, just used for error logging

This function performs a noise floor calibration of the PHY and waits for it to complete. Then the noise floor value is compared to some maximum noise floor we consider valid.

Note that this is different from what the madwifi HAL does: it reads the noise floor and afterwards initiates the calibration. Since the noise floor calibration can take some time to finish, depending on the current channel use, that avoids the occasional timeout warnings we are seeing now.

See the following link for an Atheros patent on noise floor calibration: http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ &p=1&u=2Fnetahtml2FPTO2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7

XXX: Since during noise floor calibration antennas are detached according to the patent, we should stop tx queues here.

Definition at line 1132 of file ath5k_phy.c.

References ath5k_hw::ah_noise_floor, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF, AR5K_PHY_NF, AR5K_PHY_NF_ACTIVE, AR5K_PHY_NF_AVAL, AR5K_PHY_NF_RVAL, AR5K_REG_ENABLE_BITS, AR5K_TUNE_NOISE_FLOOR, ath5k_hw_reg_read(), DBG, DBG2, EAGAIN, and mdelay().

Referenced by ath5k_hw_reset(), ath5k_hw_rf5110_calibrate(), and ath5k_hw_rf511x_calibrate().

01133 {
01134         int ret;
01135         unsigned int i;
01136         s32 noise_floor;
01137 
01138         /*
01139          * Enable noise floor calibration
01140          */
01141         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
01142                                 AR5K_PHY_AGCCTL_NF);
01143 
01144         ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
01145                         AR5K_PHY_AGCCTL_NF, 0, 0);
01146 
01147         if (ret) {
01148                 DBG("ath5k: noise floor calibration timeout (%d MHz)\n", freq);
01149                 return -EAGAIN;
01150         }
01151 
01152         /* Wait until the noise floor is calibrated and read the value */
01153         for (i = 20; i > 0; i--) {
01154                 mdelay(1);
01155                 noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
01156                 noise_floor = AR5K_PHY_NF_RVAL(noise_floor);
01157                 if (noise_floor & AR5K_PHY_NF_ACTIVE) {
01158                         noise_floor = AR5K_PHY_NF_AVAL(noise_floor);
01159 
01160                         if (noise_floor <= AR5K_TUNE_NOISE_FLOOR)
01161                                 break;
01162                 }
01163         }
01164 
01165         DBG2("ath5k: noise floor %d\n", noise_floor);
01166 
01167         if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
01168                 DBG("ath5k: noise floor calibration failed (%d MHz)\n", freq);
01169                 return -EAGAIN;
01170         }
01171 
01172         ah->ah_noise_floor = noise_floor;
01173 
01174         return 0;
01175 }

static int ath5k_hw_rf5110_calibrate ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 1182 of file ath5k_phy.c.

References AR5K_BEACON_5210, AR5K_BEACON_ENABLE, AR5K_DIAG_SW_5210, AR5K_DIAG_SW_DIS_RX_5210, AR5K_DIAG_SW_DIS_TX, AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ADCSAT, AR5K_PHY_ADCSAT_ICNT, AR5K_PHY_ADCSAT_THR, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, AR5K_PHY_AGCCOARSE_LO, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL, AR5K_PHY_RFSTG, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, AR5K_REG_DISABLE_BITS, AR5K_REG_ENABLE_BITS, AR5K_REG_SM, ath5k_hw_channel(), ath5k_hw_noise_floor_calibration(), ath5k_hw_reg_read(), ath5k_hw_reg_write(), net80211_channel::center_freq, DBG, mdelay(), u32, and udelay().

Referenced by ath5k_hw_phy_calibrate().

01184 {
01185         u32 phy_sig, phy_agc, phy_sat, beacon;
01186         int ret;
01187 
01188         /*
01189          * Disable beacons and RX/TX queues, wait
01190          */
01191         AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210,
01192                 AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
01193         beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210);
01194         ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210);
01195 
01196         mdelay(2);
01197 
01198         /*
01199          * Set the channel (with AGC turned off)
01200          */
01201         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01202         udelay(10);
01203         ret = ath5k_hw_channel(ah, channel);
01204 
01205         /*
01206          * Activate PHY and wait
01207          */
01208         ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
01209         mdelay(1);
01210 
01211         AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01212 
01213         if (ret)
01214                 return ret;
01215 
01216         /*
01217          * Calibrate the radio chip
01218          */
01219 
01220         /* Remember normal state */
01221         phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG);
01222         phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE);
01223         phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT);
01224 
01225         /* Update radio registers */
01226         ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) |
01227                 AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG);
01228 
01229         ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI |
01230                         AR5K_PHY_AGCCOARSE_LO)) |
01231                 AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) |
01232                 AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE);
01233 
01234         ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT |
01235                         AR5K_PHY_ADCSAT_THR)) |
01236                 AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) |
01237                 AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT);
01238 
01239         udelay(20);
01240 
01241         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01242         udelay(10);
01243         ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG);
01244         AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE);
01245 
01246         mdelay(1);
01247 
01248         /*
01249          * Enable calibration and wait until completion
01250          */
01251         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL);
01252 
01253         ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
01254                         AR5K_PHY_AGCCTL_CAL, 0, 0);
01255 
01256         /* Reset to normal state */
01257         ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG);
01258         ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE);
01259         ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT);
01260 
01261         if (ret) {
01262                 DBG("ath5k: calibration timeout (%d MHz)\n",
01263                     channel->center_freq);
01264                 return ret;
01265         }
01266 
01267         ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
01268 
01269         /*
01270          * Re-enable RX/TX and beacons
01271          */
01272         AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210,
01273                 AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210);
01274         ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210);
01275 
01276         return 0;
01277 }

static int ath5k_hw_rf511x_calibrate ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 1282 of file ath5k_phy.c.

References ath5k_hw::ah_calibration, AR5K_PHY_IQ, AR5K_PHY_IQ_CAL_NUM_LOG_MAX, AR5K_PHY_IQ_CORR_ENABLE, AR5K_PHY_IQ_CORR_Q_I_COFF_S, AR5K_PHY_IQ_RUN, AR5K_PHY_IQRES_CAL_CORR, AR5K_PHY_IQRES_CAL_PWR_I, AR5K_PHY_IQRES_CAL_PWR_Q, AR5K_REG_ENABLE_BITS, AR5K_REG_WRITE_BITS, ath5k_hw_noise_floor_calibration(), ath5k_hw_reg_read(), ath5k_hw_request_rfgain_probe(), net80211_channel::center_freq, and u32.

Referenced by ath5k_hw_phy_calibrate().

01284 {
01285         u32 i_pwr, q_pwr;
01286         s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
01287         int i;
01288 
01289         if (!ah->ah_calibration ||
01290                 ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
01291                 goto done;
01292 
01293         /* Calibration has finished, get the results and re-run */
01294         for (i = 0; i <= 10; i++) {
01295                 iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
01296                 i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
01297                 q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
01298         }
01299 
01300         i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
01301         q_coffd = q_pwr >> 7;
01302 
01303         /* No correction */
01304         if (i_coffd == 0 || q_coffd == 0)
01305                 goto done;
01306 
01307         i_coff = ((-iq_corr) / i_coffd) & 0x3f;
01308 
01309         /* Boundary check */
01310         if (i_coff > 31)
01311                 i_coff = 31;
01312         if (i_coff < -32)
01313                 i_coff = -32;
01314 
01315         q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
01316 
01317         /* Boundary check */
01318         if (q_coff > 15)
01319                 q_coff = 15;
01320         if (q_coff < -16)
01321                 q_coff = -16;
01322 
01323         /* Commit new I/Q value */
01324         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
01325                 ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
01326 
01327         /* Re-enable calibration -if we don't we'll commit
01328          * the same values again and again */
01329         AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
01330                         AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
01331         AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
01332 
01333 done:
01334 
01335         /* TODO: Separate noise floor calibration from I/Q calibration
01336          * since noise floor calibration interrupts rx path while I/Q
01337          * calibration doesn't. We don't need to run noise floor calibration
01338          * as often as I/Q calibration.*/
01339         ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
01340 
01341         /* Initiate a gain_F calibration */
01342         ath5k_hw_request_rfgain_probe(ah);
01343 
01344         return 0;
01345 }

int ath5k_hw_phy_calibrate ( struct ath5k_hw ah,
struct net80211_channel channel 
)

Definition at line 1350 of file ath5k_phy.c.

References ath5k_hw::ah_radio, AR5K_RF5110, ath5k_hw_rf5110_calibrate(), and ath5k_hw_rf511x_calibrate().

Referenced by ath5k_calibrate().

01352 {
01353         int ret;
01354 
01355         if (ah->ah_radio == AR5K_RF5110)
01356                 ret = ath5k_hw_rf5110_calibrate(ah, channel);
01357         else
01358                 ret = ath5k_hw_rf511x_calibrate(ah, channel);
01359 
01360         return ret;
01361 }

int ath5k_hw_phy_disable ( struct ath5k_hw ah  ) 

Definition at line 1363 of file ath5k_phy.c.

References AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE, and ath5k_hw_reg_write().

Referenced by ath5k_stop_hw().

01364 {
01365         ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
01366 
01367         return 0;
01368 }

u16 ath5k_hw_radio_revision ( struct ath5k_hw ah,
unsigned int  chan 
)

Definition at line 1377 of file ath5k_phy.c.

References ath5k_hw::ah_version, AR5K_AR5210, AR5K_PHY, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY_SHIFT_5GHZ, ath5k_hw_bitswap(), ath5k_hw_reg_read(), ath5k_hw_reg_write(), CHANNEL_2GHZ, CHANNEL_5GHZ, mdelay(), u16, and u32.

Referenced by ath5k_hw_attach().

01378 {
01379         unsigned int i;
01380         u32 srev;
01381         u16 ret;
01382 
01383         /*
01384          * Set the radio chip access register
01385          */
01386         switch (chan) {
01387         case CHANNEL_2GHZ:
01388                 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
01389                 break;
01390         case CHANNEL_5GHZ:
01391                 ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
01392                 break;
01393         default:
01394                 return 0;
01395         }
01396 
01397         mdelay(2);
01398 
01399         /* ...wait until PHY is ready and read the selected radio revision */
01400         ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
01401 
01402         for (i = 0; i < 8; i++)
01403                 ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
01404 
01405         if (ah->ah_version == AR5K_AR5210) {
01406                 srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
01407                 ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
01408         } else {
01409                 srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
01410                 ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
01411                                 ((srev & 0x0f) << 4), 8);
01412         }
01413 
01414         /* Reset to the 5GHz mode */
01415         ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
01416 
01417         return ret;
01418 }

void ath5k_hw_set_def_antenna ( struct ath5k_hw ah,
unsigned int  ant 
)

Definition at line 1421 of file ath5k_phy.c.

References ath5k_hw::ah_version, AR5K_AR5210, AR5K_DEFAULT_ANTENNA, and ath5k_hw_reg_write().

01422 {
01423         if (ah->ah_version != AR5K_AR5210)
01424                 ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA);
01425 }

unsigned int ath5k_hw_get_def_antenna ( struct ath5k_hw ah  ) 

Definition at line 1427 of file ath5k_phy.c.

References ath5k_hw::ah_version, AR5K_AR5210, AR5K_DEFAULT_ANTENNA, and ath5k_hw_reg_read().

01428 {
01429         if (ah->ah_version != AR5K_AR5210)
01430                 return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA);
01431 
01432         return 0; /*XXX: What do we return for 5210 ?*/
01433 }

static s16 ath5k_get_interpolated_value ( s16  target,
s16  x_left,
s16  x_right,
s16  y_left,
s16  y_right 
) [static]

Definition at line 1448 of file ath5k_phy.c.

Referenced by ath5k_create_power_curve(), ath5k_get_linear_pcdac_min(), ath5k_get_rate_pcal_data(), and ath5k_setup_channel_powertable().

01450 {
01451         s16 ratio, result;
01452 
01453         /* Avoid divide by zero and skip interpolation
01454          * if we have the same point */
01455         if ((x_left == x_right) || (y_left == y_right))
01456                 return y_left;
01457 
01458         /*
01459          * Since we use ints and not fps, we need to scale up in
01460          * order to get a sane ratio value (or else we 'll eg. get
01461          * always 1 instead of 1.25, 1.75 etc). We scale up by 100
01462          * to have some accuracy both for 0.5 and 0.25 steps.
01463          */
01464         ratio = ((100 * y_right - 100 * y_left)/(x_right - x_left));
01465 
01466         /* Now scale down to be in range */
01467         result = y_left + (ratio * (target - x_left) / 100);
01468 
01469         return result;
01470 }

static s16 ath5k_get_linear_pcdac_min ( const u8 stepL,
const u8 stepR,
const s16 pwrL,
const s16 pwrR 
) [static]

Definition at line 1481 of file ath5k_phy.c.

References ath5k_get_interpolated_value(), and max.

Referenced by ath5k_setup_channel_powertable().

01483 {
01484         s8 tmp;
01485         s16 min_pwrL, min_pwrR;
01486         s16 pwr_i;
01487 
01488         if (pwrL[0] == pwrL[1])
01489                 min_pwrL = pwrL[0];
01490         else {
01491                 pwr_i = pwrL[0];
01492                 do {
01493                         pwr_i--;
01494                         tmp = (s8) ath5k_get_interpolated_value(pwr_i,
01495                                                         pwrL[0], pwrL[1],
01496                                                         stepL[0], stepL[1]);
01497                 } while (tmp > 1);
01498 
01499                 min_pwrL = pwr_i;
01500         }
01501 
01502         if (pwrR[0] == pwrR[1])
01503                 min_pwrR = pwrR[0];
01504         else {
01505                 pwr_i = pwrR[0];
01506                 do {
01507                         pwr_i--;
01508                         tmp = (s8) ath5k_get_interpolated_value(pwr_i,
01509                                                         pwrR[0], pwrR[1],
01510                                                         stepR[0], stepR[1]);
01511                 } while (tmp > 1);
01512 
01513                 min_pwrR = pwr_i;
01514         }
01515 
01516         /* Keep the right boundary so that it works for both curves */
01517         return max(min_pwrL, min_pwrR);
01518 }

static void ath5k_create_power_curve ( s16  pmin,
s16  pmax,
const s16 pwr,
const u8 vpd,
u8  num_points,
u8 vpd_table,
u8  type 
) [static]

Definition at line 1533 of file ath5k_phy.c.

References AR5K_EEPROM_POWER_TABLE_SIZE, AR5K_PWRTABLE_LINEAR_PCDAC, ath5k_get_interpolated_value(), u16, and u8.

Referenced by ath5k_setup_channel_powertable().

01537 {
01538         u8 idx[2] = { 0, 1 };
01539         s16 pwr_i = 2*pmin;
01540         int i;
01541 
01542         if (num_points < 2)
01543                 return;
01544 
01545         /* We want the whole line, so adjust boundaries
01546          * to cover the entire power range. Note that
01547          * power values are already 0.25dB so no need
01548          * to multiply pwr_i by 2 */
01549         if (type == AR5K_PWRTABLE_LINEAR_PCDAC) {
01550                 pwr_i = pmin;
01551                 pmin = 0;
01552                 pmax = 63;
01553         }
01554 
01555         /* Find surrounding turning points (TPs)
01556          * and interpolate between them */
01557         for (i = 0; (i <= (u16) (pmax - pmin)) &&
01558         (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
01559 
01560                 /* We passed the right TP, move to the next set of TPs
01561                  * if we pass the last TP, extrapolate above using the last
01562                  * two TPs for ratio */
01563                 if ((pwr_i > pwr[idx[1]]) && (idx[1] < num_points - 1)) {
01564                         idx[0]++;
01565                         idx[1]++;
01566                 }
01567 
01568                 vpd_table[i] = (u8) ath5k_get_interpolated_value(pwr_i,
01569                                                 pwr[idx[0]], pwr[idx[1]],
01570                                                 vpd[idx[0]], vpd[idx[1]]);
01571 
01572                 /* Increase by 0.5dB
01573                  * (0.25 dB units) */
01574                 pwr_i += 2;
01575         }
01576 }

static void ath5k_get_chan_pcal_surrounding_piers ( struct ath5k_hw ah,
struct net80211_channel channel,
struct ath5k_chan_pcal_info **  pcinfo_l,
struct ath5k_chan_pcal_info **  pcinfo_r 
) [static]

Definition at line 1585 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, AR5K_EEPROM_MODE_11A, AR5K_EEPROM_MODE_11B, AR5K_EEPROM_MODE_11G, ath5k_capabilities::cap_eeprom, net80211_channel::center_freq, CHANNEL_2GHZ, CHANNEL_OFDM, ath5k_eeprom_info::ee_n_piers, ath5k_eeprom_info::ee_pwr_cal_a, ath5k_eeprom_info::ee_pwr_cal_b, ath5k_eeprom_info::ee_pwr_cal_g, ath5k_chan_pcal_info::freq, net80211_channel::hw_value, max, u32, and u8.

Referenced by ath5k_setup_channel_powertable().

01589 {
01590         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01591         struct ath5k_chan_pcal_info *pcinfo;
01592         u8 idx_l, idx_r;
01593         u8 mode, max, i;
01594         u32 target = channel->center_freq;
01595 
01596         idx_l = 0;
01597         idx_r = 0;
01598 
01599         if (!(channel->hw_value & CHANNEL_OFDM)) {
01600                 pcinfo = ee->ee_pwr_cal_b;
01601                 mode = AR5K_EEPROM_MODE_11B;
01602         } else if (channel->hw_value & CHANNEL_2GHZ) {
01603                 pcinfo = ee->ee_pwr_cal_g;
01604                 mode = AR5K_EEPROM_MODE_11G;
01605         } else {
01606                 pcinfo = ee->ee_pwr_cal_a;
01607                 mode = AR5K_EEPROM_MODE_11A;
01608         }
01609         max = ee->ee_n_piers[mode] - 1;
01610 
01611         /* Frequency is below our calibrated
01612          * range. Use the lowest power curve
01613          * we have */
01614         if (target < pcinfo[0].freq) {
01615                 idx_l = idx_r = 0;
01616                 goto done;
01617         }
01618 
01619         /* Frequency is above our calibrated
01620          * range. Use the highest power curve
01621          * we have */
01622         if (target > pcinfo[max].freq) {
01623                 idx_l = idx_r = max;
01624                 goto done;
01625         }
01626 
01627         /* Frequency is inside our calibrated
01628          * channel range. Pick the surrounding
01629          * calibration piers so that we can
01630          * interpolate */
01631         for (i = 0; i <= max; i++) {
01632 
01633                 /* Frequency matches one of our calibration
01634                  * piers, no need to interpolate, just use
01635                  * that calibration pier */
01636                 if (pcinfo[i].freq == target) {
01637                         idx_l = idx_r = i;
01638                         goto done;
01639                 }
01640 
01641                 /* We found a calibration pier that's above
01642                  * frequency, use this pier and the previous
01643                  * one to interpolate */
01644                 if (target < pcinfo[i].freq) {
01645                         idx_r = i;
01646                         idx_l = idx_r - 1;
01647                         goto done;
01648                 }
01649         }
01650 
01651 done:
01652         *pcinfo_l = &pcinfo[idx_l];
01653         *pcinfo_r = &pcinfo[idx_r];
01654 
01655         return;
01656 }

static void ath5k_get_rate_pcal_data ( struct ath5k_hw ah,
struct net80211_channel channel,
struct ath5k_rate_pcal_info rates 
) [static]

Definition at line 1665 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, AR5K_EEPROM_MODE_11A, AR5K_EEPROM_MODE_11B, AR5K_EEPROM_MODE_11G, ath5k_get_interpolated_value(), ath5k_capabilities::cap_eeprom, net80211_channel::center_freq, CHANNEL_2GHZ, CHANNEL_OFDM, ath5k_eeprom_info::ee_rate_target_pwr_num, ath5k_eeprom_info::ee_rate_tpwr_a, ath5k_eeprom_info::ee_rate_tpwr_b, ath5k_eeprom_info::ee_rate_tpwr_g, ath5k_rate_pcal_info::freq, net80211_channel::hw_value, max, ath5k_rate_pcal_info::target_power_36, ath5k_rate_pcal_info::target_power_48, ath5k_rate_pcal_info::target_power_54, ath5k_rate_pcal_info::target_power_6to24, u32, and u8.

Referenced by ath5k_hw_txpower().

01668 {
01669         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01670         struct ath5k_rate_pcal_info *rpinfo;
01671         u8 idx_l, idx_r;
01672         u8 mode, max, i;
01673         u32 target = channel->center_freq;
01674 
01675         idx_l = 0;
01676         idx_r = 0;
01677 
01678         if (!(channel->hw_value & CHANNEL_OFDM)) {
01679                 rpinfo = ee->ee_rate_tpwr_b;
01680                 mode = AR5K_EEPROM_MODE_11B;
01681         } else if (channel->hw_value & CHANNEL_2GHZ) {
01682                 rpinfo = ee->ee_rate_tpwr_g;
01683                 mode = AR5K_EEPROM_MODE_11G;
01684         } else {
01685                 rpinfo = ee->ee_rate_tpwr_a;
01686                 mode = AR5K_EEPROM_MODE_11A;
01687         }
01688         max = ee->ee_rate_target_pwr_num[mode] - 1;
01689 
01690         /* Get the surrounding calibration
01691          * piers - same as above */
01692         if (target < rpinfo[0].freq) {
01693                 idx_l = idx_r = 0;
01694                 goto done;
01695         }
01696 
01697         if (target > rpinfo[max].freq) {
01698                 idx_l = idx_r = max;
01699                 goto done;
01700         }
01701 
01702         for (i = 0; i <= max; i++) {
01703 
01704                 if (rpinfo[i].freq == target) {
01705                         idx_l = idx_r = i;
01706                         goto done;
01707                 }
01708 
01709                 if (target < rpinfo[i].freq) {
01710                         idx_r = i;
01711                         idx_l = idx_r - 1;
01712                         goto done;
01713                 }
01714         }
01715 
01716 done:
01717         /* Now interpolate power value, based on the frequency */
01718         rates->freq = target;
01719 
01720         rates->target_power_6to24 =
01721                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01722                                         rpinfo[idx_r].freq,
01723                                         rpinfo[idx_l].target_power_6to24,
01724                                         rpinfo[idx_r].target_power_6to24);
01725 
01726         rates->target_power_36 =
01727                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01728                                         rpinfo[idx_r].freq,
01729                                         rpinfo[idx_l].target_power_36,
01730                                         rpinfo[idx_r].target_power_36);
01731 
01732         rates->target_power_48 =
01733                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01734                                         rpinfo[idx_r].freq,
01735                                         rpinfo[idx_l].target_power_48,
01736                                         rpinfo[idx_r].target_power_48);
01737 
01738         rates->target_power_54 =
01739                 ath5k_get_interpolated_value(target, rpinfo[idx_l].freq,
01740                                         rpinfo[idx_r].freq,
01741                                         rpinfo[idx_l].target_power_54,
01742                                         rpinfo[idx_r].target_power_54);
01743 }

static void ath5k_get_max_ctl_power ( struct ath5k_hw ah,
struct net80211_channel channel 
) [static]

Definition at line 1753 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, ath5k_hw::ah_txpower, AR5K_CTL_11A, AR5K_CTL_11B, AR5K_CTL_11G, AR5K_CTL_NO_REGDOMAIN, AR5K_CTL_TURBO, AR5K_CTL_TURBOG, AR5K_EEPROM_N_EDGES, ath5k_capabilities::cap_eeprom, net80211_channel::center_freq, CHANNEL_A, CHANNEL_B, CHANNEL_G, CHANNEL_MODES, CHANNEL_T, CHANNEL_TG, CHANNEL_XR, ath5k_edge_power::edge, ath5k_eeprom_info::ee_ctl, ath5k_eeprom_info::ee_ctl_pwr, ath5k_eeprom_info::ee_ctls, ath5k_edge_power::freq, net80211_channel::hw_value, min, ath5k_hw::txp_max_pwr, u32, and u8.

Referenced by ath5k_hw_txpower().

01755 {
01756         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
01757         struct ath5k_edge_power *rep = ee->ee_ctl_pwr;
01758         u8 *ctl_val = ee->ee_ctl;
01759         s16 max_chan_pwr = ah->ah_txpower.txp_max_pwr / 4;
01760         s16 edge_pwr = 0;
01761         u8 rep_idx;
01762         u8 i, ctl_mode;
01763         u8 ctl_idx = 0xFF;
01764         u32 target = channel->center_freq;
01765 
01766         /* Find out a CTL for our mode that's not mapped
01767          * on a specific reg domain.
01768          *
01769          * TODO: Map our current reg domain to one of the 3 available
01770          * reg domain ids so that we can support more CTLs. */
01771         switch (channel->hw_value & CHANNEL_MODES) {
01772         case CHANNEL_A:
01773                 ctl_mode = AR5K_CTL_11A | AR5K_CTL_NO_REGDOMAIN;
01774                 break;
01775         case CHANNEL_G:
01776                 ctl_mode = AR5K_CTL_11G | AR5K_CTL_NO_REGDOMAIN;
01777                 break;
01778         case CHANNEL_B:
01779                 ctl_mode = AR5K_CTL_11B | AR5K_CTL_NO_REGDOMAIN;
01780                 break;
01781         case CHANNEL_T:
01782                 ctl_mode = AR5K_CTL_TURBO | AR5K_CTL_NO_REGDOMAIN;
01783                 break;
01784         case CHANNEL_TG:
01785                 ctl_mode = AR5K_CTL_TURBOG | AR5K_CTL_NO_REGDOMAIN;
01786                 break;
01787         case CHANNEL_XR:
01788                 /* Fall through */
01789         default:
01790                 return;
01791         }
01792 
01793         for (i = 0; i < ee->ee_ctls; i++) {
01794                 if (ctl_val[i] == ctl_mode) {
01795                         ctl_idx = i;
01796                         break;
01797                 }
01798         }
01799 
01800         /* If we have a CTL dataset available grab it and find the
01801          * edge power for our frequency */
01802         if (ctl_idx == 0xFF)
01803                 return;
01804 
01805         /* Edge powers are sorted by frequency from lower
01806          * to higher. Each CTL corresponds to 8 edge power
01807          * measurements. */
01808         rep_idx = ctl_idx * AR5K_EEPROM_N_EDGES;
01809 
01810         /* Don't do boundaries check because we
01811          * might have more that one bands defined
01812          * for this mode */
01813 
01814         /* Get the edge power that's closer to our
01815          * frequency */
01816         for (i = 0; i < AR5K_EEPROM_N_EDGES; i++) {
01817                 rep_idx += i;
01818                 if (target <= rep[rep_idx].freq)
01819                         edge_pwr = (s16) rep[rep_idx].edge;
01820         }
01821 
01822         if (edge_pwr) {
01823                 ah->ah_txpower.txp_max_pwr = 4*min(edge_pwr, max_chan_pwr);
01824         }
01825 }

static void ath5k_fill_pwr_to_pcdac_table ( struct ath5k_hw ah,
s16 table_min,
s16 table_max 
) [static]

Definition at line 1840 of file ath5k_phy.c.

References ath5k_hw::ah_txpower, AR5K_EEPROM_POWER_TABLE_SIZE, ath5k_hw::tmpL, ath5k_hw::txp_pd_table, and u8.

Referenced by ath5k_setup_channel_powertable().

01842 {
01843         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01844         u8      *pcdac_tmp = ah->ah_txpower.tmpL[0];
01845         u8      pcdac_0, pcdac_n, pcdac_i, pwr_idx, i;
01846         s16     min_pwr, max_pwr;
01847 
01848         /* Get table boundaries */
01849         min_pwr = table_min[0];
01850         pcdac_0 = pcdac_tmp[0];
01851 
01852         max_pwr = table_max[0];
01853         pcdac_n = pcdac_tmp[table_max[0] - table_min[0]];
01854 
01855         /* Extrapolate below minimum using pcdac_0 */
01856         pcdac_i = 0;
01857         for (i = 0; i < min_pwr; i++)
01858                 pcdac_out[pcdac_i++] = pcdac_0;
01859 
01860         /* Copy values from pcdac_tmp */
01861         pwr_idx = min_pwr;
01862         for (i = 0 ; pwr_idx <= max_pwr &&
01863         pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE; i++) {
01864                 pcdac_out[pcdac_i++] = pcdac_tmp[i];
01865                 pwr_idx++;
01866         }
01867 
01868         /* Extrapolate above maximum */
01869         while (pcdac_i < AR5K_EEPROM_POWER_TABLE_SIZE)
01870                 pcdac_out[pcdac_i++] = pcdac_n;
01871 
01872 }

static void ath5k_combine_linear_pcdac_curves ( struct ath5k_hw ah,
s16 table_min,
s16 table_max,
u8  pdcurves 
) [static]

Definition at line 1886 of file ath5k_phy.c.

References ath5k_hw::ah_txpower, ath5k_hw::tmpL, ath5k_hw::txp_min_idx, ath5k_hw::txp_pd_table, and u8.

Referenced by ath5k_setup_channel_powertable().

01888 {
01889         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01890         u8      *pcdac_low_pwr;
01891         u8      *pcdac_high_pwr;
01892         u8      *pcdac_tmp;
01893         u8      pwr;
01894         s16     max_pwr_idx;
01895         s16     min_pwr_idx;
01896         s16     mid_pwr_idx = 0;
01897         /* Edge flag turs on the 7nth bit on the PCDAC
01898          * to delcare the higher power curve (force values
01899          * to be greater than 64). If we only have one curve
01900          * we don't need to set this, if we have 2 curves and
01901          * fill the table backwards this can also be used to
01902          * switch from higher power curve to lower power curve */
01903         u8      edge_flag;
01904         int     i;
01905 
01906         /* When we have only one curve available
01907          * that's the higher power curve. If we have
01908          * two curves the first is the high power curve
01909          * and the next is the low power curve. */
01910         if (pdcurves > 1) {
01911                 pcdac_low_pwr = ah->ah_txpower.tmpL[1];
01912                 pcdac_high_pwr = ah->ah_txpower.tmpL[0];
01913                 mid_pwr_idx = table_max[1] - table_min[1] - 1;
01914                 max_pwr_idx = (table_max[0] - table_min[0]) / 2;
01915 
01916                 /* If table size goes beyond 31.5dB, keep the
01917                  * upper 31.5dB range when setting tx power.
01918                  * Note: 126 = 31.5 dB in quarter dB steps */
01919                 if (table_max[0] - table_min[1] > 126)
01920                         min_pwr_idx = table_max[0] - 126;
01921                 else
01922                         min_pwr_idx = table_min[1];
01923 
01924                 /* Since we fill table backwards
01925                  * start from high power curve */
01926                 pcdac_tmp = pcdac_high_pwr;
01927 
01928                 edge_flag = 0x40;
01929         } else {
01930                 pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
01931                 pcdac_high_pwr = ah->ah_txpower.tmpL[0];
01932                 min_pwr_idx = table_min[0];
01933                 max_pwr_idx = (table_max[0] - table_min[0]) / 2;
01934                 pcdac_tmp = pcdac_high_pwr;
01935                 edge_flag = 0;
01936         }
01937 
01938         /* This is used when setting tx power*/
01939         ah->ah_txpower.txp_min_idx = min_pwr_idx/2;
01940 
01941         /* Fill Power to PCDAC table backwards */
01942         pwr = max_pwr_idx;
01943         for (i = 63; i >= 0; i--) {
01944                 /* Entering lower power range, reset
01945                  * edge flag and set pcdac_tmp to lower
01946                  * power curve.*/
01947                 if (edge_flag == 0x40 &&
01948                 (2*pwr <= (table_max[1] - table_min[0]) || pwr == 0)) {
01949                         edge_flag = 0x00;
01950                         pcdac_tmp = pcdac_low_pwr;
01951                         pwr = mid_pwr_idx/2;
01952                 }
01953 
01954                 /* Don't go below 1, extrapolate below if we have
01955                  * already swithced to the lower power curve -or
01956                  * we only have one curve and edge_flag is zero
01957                  * anyway */
01958                 if (pcdac_tmp[pwr] < 1 && (edge_flag == 0x00)) {
01959                         while (i >= 0) {
01960                                 pcdac_out[i] = pcdac_out[i + 1];
01961                                 i--;
01962                         }
01963                         break;
01964                 }
01965 
01966                 pcdac_out[i] = pcdac_tmp[pwr] | edge_flag;
01967 
01968                 /* Extrapolate above if pcdac is greater than
01969                  * 126 -this can happen because we OR pcdac_out
01970                  * value with edge_flag on high power curve */
01971                 if (pcdac_out[i] > 126)
01972                         pcdac_out[i] = 126;
01973 
01974                 /* Decrease by a 0.5dB step */
01975                 pwr--;
01976         }
01977 }

static void ath5k_setup_pcdac_table ( struct ath5k_hw ah  )  [static]

Definition at line 1981 of file ath5k_phy.c.

References ath5k_hw::ah_txpower, AR5K_EEPROM_POWER_TABLE_SIZE, AR5K_PHY_PCDAC_TXPOWER, ath5k_hw_reg_write(), ath5k_hw::txp_pd_table, and u8.

Referenced by ath5k_setup_channel_powertable().

01982 {
01983         u8      *pcdac_out = ah->ah_txpower.txp_pd_table;
01984         int     i;
01985 
01986         /*
01987          * Write TX power values
01988          */
01989         for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
01990                 ath5k_hw_reg_write(ah,
01991                         (((pcdac_out[2*i + 0] << 8 | 0xff) & 0xffff) << 0) |
01992                         (((pcdac_out[2*i + 1] << 8 | 0xff) & 0xffff) << 16),
01993                         AR5K_PHY_PCDAC_TXPOWER(i));
01994         }
01995 }

static void ath5k_combine_pwr_to_pdadc_curves ( struct ath5k_hw ah,
s16 pwr_min,
s16 pwr_max,
u8  pdcurves 
) [static]

Definition at line 2010 of file ath5k_phy.c.

References ath5k_hw::ah_txpower, AR5K_EEPROM_N_PD_GAINS, AR5K_EEPROM_POWER_TABLE_SIZE, AR5K_PHY_TPC_RG5, AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1, AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2, AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3, AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4, AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP, AR5K_REG_SM, AR5K_TUNE_MAX_TXPOWER, ath5k_hw_reg_read(), ath5k_hw_reg_write(), ath5k_hw::tmpL, ath5k_hw::txp_min_idx, ath5k_hw::txp_pd_table, and u8.

Referenced by ath5k_setup_channel_powertable().

02012 {
02013         u8 gain_boundaries[AR5K_EEPROM_N_PD_GAINS];
02014         u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
02015         u8 *pdadc_tmp;
02016         s16 pdadc_0;
02017         u8 pdadc_i, pdadc_n, pwr_step, pdg, max_idx, table_size;
02018         u8 pd_gain_overlap;
02019 
02020         /* Note: Register value is initialized on initvals
02021          * there is no feedback from hw.
02022          * XXX: What about pd_gain_overlap from EEPROM ? */
02023         pd_gain_overlap = (u8) ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG5) &
02024                 AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP;
02025 
02026         /* Create final PDADC table */
02027         for (pdg = 0, pdadc_i = 0; pdg < pdcurves; pdg++) {
02028                 pdadc_tmp = ah->ah_txpower.tmpL[pdg];
02029 
02030                 if (pdg == pdcurves - 1)
02031                         /* 2 dB boundary stretch for last
02032                          * (higher power) curve */
02033                         gain_boundaries[pdg] = pwr_max[pdg] + 4;
02034                 else
02035                         /* Set gain boundary in the middle
02036                          * between this curve and the next one */
02037                         gain_boundaries[pdg] =
02038                                 (pwr_max[pdg] + pwr_min[pdg + 1]) / 2;
02039 
02040                 /* Sanity check in case our 2 db stretch got out of
02041                  * range. */
02042                 if (gain_boundaries[pdg] > AR5K_TUNE_MAX_TXPOWER)
02043                         gain_boundaries[pdg] = AR5K_TUNE_MAX_TXPOWER;
02044 
02045                 /* For the first curve (lower power)
02046                  * start from 0 dB */
02047                 if (pdg == 0)
02048                         pdadc_0 = 0;
02049                 else
02050                         /* For the other curves use the gain overlap */
02051                         pdadc_0 = (gain_boundaries[pdg - 1] - pwr_min[pdg]) -
02052                                                         pd_gain_overlap;
02053 
02054                 /* Force each power step to be at least 0.5 dB */
02055                 if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1)
02056                         pwr_step = pdadc_tmp[1] - pdadc_tmp[0];
02057                 else
02058                         pwr_step = 1;
02059 
02060                 /* If pdadc_0 is negative, we need to extrapolate
02061                  * below this pdgain by a number of pwr_steps */
02062                 while ((pdadc_0 < 0) && (pdadc_i < 128)) {
02063                         s16 tmp = pdadc_tmp[0] + pdadc_0 * pwr_step;
02064                         pdadc_out[pdadc_i++] = (tmp < 0) ? 0 : (u8) tmp;
02065                         pdadc_0++;
02066                 }
02067 
02068                 /* Set last pwr level, using gain boundaries */
02069                 pdadc_n = gain_boundaries[pdg] + pd_gain_overlap - pwr_min[pdg];
02070                 /* Limit it to be inside pwr range */
02071                 table_size = pwr_max[pdg] - pwr_min[pdg];
02072                 max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
02073 
02074                 /* Fill pdadc_out table */
02075                 while (pdadc_0 < max_idx)
02076                         pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
02077 
02078                 /* Need to extrapolate above this pdgain? */
02079                 if (pdadc_n <= max_idx)
02080                         continue;
02081 
02082                 /* Force each power step to be at least 0.5 dB */
02083                 if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1)
02084                         pwr_step = pdadc_tmp[table_size - 1] -
02085                                                 pdadc_tmp[table_size - 2];
02086                 else
02087                         pwr_step = 1;
02088 
02089                 /* Extrapolate above */
02090                 while ((pdadc_0 < (s16) pdadc_n) &&
02091                 (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2)) {
02092                         s16 tmp = pdadc_tmp[table_size - 1] +
02093                                         (pdadc_0 - max_idx) * pwr_step;
02094                         pdadc_out[pdadc_i++] = (tmp > 127) ? 127 : (u8) tmp;
02095                         pdadc_0++;
02096                 }
02097         }
02098 
02099         while (pdg < AR5K_EEPROM_N_PD_GAINS) {
02100                 gain_boundaries[pdg] = gain_boundaries[pdg - 1];
02101                 pdg++;
02102         }
02103 
02104         while (pdadc_i < AR5K_EEPROM_POWER_TABLE_SIZE * 2) {
02105                 pdadc_out[pdadc_i] = pdadc_out[pdadc_i - 1];
02106                 pdadc_i++;
02107         }
02108 
02109         /* Set gain boundaries */
02110         ath5k_hw_reg_write(ah,
02111                 AR5K_REG_SM(pd_gain_overlap,
02112                         AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP) |
02113                 AR5K_REG_SM(gain_boundaries[0],
02114                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_1) |
02115                 AR5K_REG_SM(gain_boundaries[1],
02116                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_2) |
02117                 AR5K_REG_SM(gain_boundaries[2],
02118                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_3) |
02119                 AR5K_REG_SM(gain_boundaries[3],
02120                         AR5K_PHY_TPC_RG5_PD_GAIN_BOUNDARY_4),
02121                 AR5K_PHY_TPC_RG5);
02122 
02123         /* Used for setting rate power table */
02124         ah->ah_txpower.txp_min_idx = pwr_min[0];
02125 
02126 }

static void ath5k_setup_pwr_to_pdadc_table ( struct ath5k_hw ah,
u8  pdcurves,
u8 pdg_to_idx 
) [static]

Definition at line 2130 of file ath5k_phy.c.

References ath5k_hw::ah_txpower, AR5K_EEPROM_POWER_TABLE_SIZE, AR5K_PHY_PDADC_TXPOWER, AR5K_PHY_TPC_RG1, AR5K_PHY_TPC_RG1_NUM_PD_GAIN, AR5K_PHY_TPC_RG1_PDGAIN_1, AR5K_PHY_TPC_RG1_PDGAIN_2, AR5K_PHY_TPC_RG1_PDGAIN_3, AR5K_REG_SM, ath5k_hw_reg_read(), ath5k_hw_reg_write(), ath5k_hw::txp_pd_table, u32, and u8.

Referenced by ath5k_setup_channel_powertable().

02132 {
02133         u8 *pdadc_out = ah->ah_txpower.txp_pd_table;
02134         u32 reg;
02135         u8 i;
02136 
02137         /* Select the right pdgain curves */
02138 
02139         /* Clear current settings */
02140         reg = ath5k_hw_reg_read(ah, AR5K_PHY_TPC_RG1);
02141         reg &= ~(AR5K_PHY_TPC_RG1_PDGAIN_1 |
02142                 AR5K_PHY_TPC_RG1_PDGAIN_2 |
02143                 AR5K_PHY_TPC_RG1_PDGAIN_3 |
02144                 AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
02145 
02146         /*
02147          * Use pd_gains curve from eeprom
02148          *
02149          * This overrides the default setting from initvals
02150          * in case some vendors (e.g. Zcomax) don't use the default
02151          * curves. If we don't honor their settings we 'll get a
02152          * 5dB (1 * gain overlap ?) drop.
02153          */
02154         reg |= AR5K_REG_SM(pdcurves, AR5K_PHY_TPC_RG1_NUM_PD_GAIN);
02155 
02156         switch (pdcurves) {
02157         case 3:
02158                 reg |= AR5K_REG_SM(pdg_to_idx[2], AR5K_PHY_TPC_RG1_PDGAIN_3);
02159                 /* Fall through */
02160         case 2:
02161                 reg |= AR5K_REG_SM(pdg_to_idx[1], AR5K_PHY_TPC_RG1_PDGAIN_2);
02162                 /* Fall through */
02163         case 1:
02164                 reg |= AR5K_REG_SM(pdg_to_idx[0], AR5K_PHY_TPC_RG1_PDGAIN_1);
02165                 break;
02166         }
02167         ath5k_hw_reg_write(ah, reg, AR5K_PHY_TPC_RG1);
02168 
02169         /*
02170          * Write TX power values
02171          */
02172         for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) {
02173                 ath5k_hw_reg_write(ah,
02174                         ((pdadc_out[4*i + 0] & 0xff) << 0) |
02175                         ((pdadc_out[4*i + 1] & 0xff) << 8) |
02176                         ((pdadc_out[4*i + 2] & 0xff) << 16) |
02177                         ((pdadc_out[4*i + 3] & 0xff) << 24),
02178                         AR5K_PHY_PDADC_TXPOWER(i));
02179         }
02180 }

static int ath5k_setup_channel_powertable ( struct ath5k_hw ah,
struct net80211_channel channel,
u8  ee_mode,
u8  type 
) [static]

Definition at line 2195 of file ath5k_phy.c.

References ath5k_hw::ah_capabilities, ath5k_hw::ah_txpower, AR5K_EEPROM_N_PD_GAINS, AR5K_EEPROM_POWER_TABLE_SIZE, AR5K_PWRTABLE_LINEAR_PCDAC, AR5K_PWRTABLE_PWR_TO_PCDAC, AR5K_PWRTABLE_PWR_TO_PDADC, ath5k_combine_linear_pcdac_curves(), ath5k_combine_pwr_to_pdadc_curves(), ath5k_create_power_curve(), ath5k_fill_pwr_to_pcdac_table(), ath5k_get_chan_pcal_surrounding_piers(), ath5k_get_interpolated_value(), ath5k_get_linear_pcdac_min(), ath5k_setup_pcdac_table(), ath5k_setup_pwr_to_pdadc_table(), ath5k_capabilities::cap_eeprom, net80211_channel::center_freq, ath5k_eeprom_info::ee_pd_gains, ath5k_eeprom_info::ee_pdc_to_idx, EINVAL, ath5k_chan_pcal_info::freq, max, ath5k_chan_pcal_info::max_pwr, min, ath5k_chan_pcal_info::min_pwr, ath5k_chan_pcal_info::pd_curves, ath5k_pdgain_info::pd_points, ath5k_pdgain_info::pd_pwr, ath5k_pdgain_info::pd_step, ath5k_hw::tmpL, ath5k_hw::tmpR, ath5k_hw::txp_max_pwr, ath5k_hw::txp_min_idx, ath5k_hw::txp_min_pwr, ath5k_hw::txp_offset, u16, u32, and u8.

Referenced by ath5k_hw_txpower().

02198 {
02199         struct ath5k_pdgain_info *pdg_L, *pdg_R;
02200         struct ath5k_chan_pcal_info *pcinfo_L;
02201         struct ath5k_chan_pcal_info *pcinfo_R;
02202         struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
02203         u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
02204         s16 table_min[AR5K_EEPROM_N_PD_GAINS];
02205         s16 table_max[AR5K_EEPROM_N_PD_GAINS];
02206         u8 *tmpL;
02207         u8 *tmpR;
02208         u32 target = channel->center_freq;
02209         int pdg, i;
02210 
02211         /* Get surounding freq piers for this channel */
02212         ath5k_get_chan_pcal_surrounding_piers(ah, channel,
02213                                                 &pcinfo_L,
02214                                                 &pcinfo_R);
02215 
02216         /* Loop over pd gain curves on
02217          * surounding freq piers by index */
02218         for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) {
02219 
02220                 /* Fill curves in reverse order
02221                  * from lower power (max gain)
02222                  * to higher power. Use curve -> idx
02223                  * backmaping we did on eeprom init */
02224                 u8 idx = pdg_curve_to_idx[pdg];
02225 
02226                 /* Grab the needed curves by index */
02227                 pdg_L = &pcinfo_L->pd_curves[idx];
02228                 pdg_R = &pcinfo_R->pd_curves[idx];
02229 
02230                 /* Initialize the temp tables */
02231                 tmpL = ah->ah_txpower.tmpL[pdg];
02232                 tmpR = ah->ah_txpower.tmpR[pdg];
02233 
02234                 /* Set curve's x boundaries and create
02235                  * curves so that they cover the same
02236                  * range (if we don't do that one table
02237                  * will have values on some range and the
02238                  * other one won't have any so interpolation
02239                  * will fail) */
02240                 table_min[pdg] = min(pdg_L->pd_pwr[0],
02241                                         pdg_R->pd_pwr[0]) / 2;
02242 
02243                 table_max[pdg] = max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
02244                                 pdg_R->pd_pwr[pdg_R->pd_points - 1]) / 2;
02245 
02246                 /* Now create the curves on surrounding channels
02247                  * and interpolate if needed to get the final
02248                  * curve for this gain on this channel */
02249                 switch (type) {
02250                 case AR5K_PWRTABLE_LINEAR_PCDAC:
02251                         /* Override min/max so that we don't loose
02252                          * accuracy (don't divide by 2) */
02253                         table_min[pdg] = min(pdg_L->pd_pwr[0],
02254                                                 pdg_R->pd_pwr[0]);
02255 
02256                         table_max[pdg] =
02257                                 max(pdg_L->pd_pwr[pdg_L->pd_points - 1],
02258                                         pdg_R->pd_pwr[pdg_R->pd_points - 1]);
02259 
02260                         /* Override minimum so that we don't get
02261                          * out of bounds while extrapolating
02262                          * below. Don't do this when we have 2
02263                          * curves and we are on the high power curve
02264                          * because table_min is ok in this case */
02265                         if (!(ee->ee_pd_gains[ee_mode] > 1 && pdg == 0)) {
02266 
02267                                 table_min[pdg] =
02268                                         ath5k_get_linear_pcdac_min(pdg_L->pd_step,
02269                                                                 pdg_R->pd_step,
02270                                                                 pdg_L->pd_pwr,
02271                                                                 pdg_R->pd_pwr);
02272 
02273                                 /* Don't go too low because we will
02274                                  * miss the upper part of the curve.
02275                                  * Note: 126 = 31.5dB (max power supported)
02276                                  * in 0.25dB units */
02277                                 if (table_max[pdg] - table_min[pdg] > 126)
02278                                         table_min[pdg] = table_max[pdg] - 126;
02279                         }
02280 
02281                         /* Fall through */
02282                 case AR5K_PWRTABLE_PWR_TO_PCDAC:
02283                 case AR5K_PWRTABLE_PWR_TO_PDADC:
02284 
02285                         ath5k_create_power_curve(table_min[pdg],
02286                                                 table_max[pdg],
02287                                                 pdg_L->pd_pwr,
02288                                                 pdg_L->pd_step,
02289                                                 pdg_L->pd_points, tmpL, type);
02290 
02291                         /* We are in a calibration
02292                          * pier, no need to interpolate
02293                          * between freq piers */
02294                         if (pcinfo_L == pcinfo_R)
02295                                 continue;
02296 
02297                         ath5k_create_power_curve(table_min[pdg],
02298                                                 table_max[pdg],
02299                                                 pdg_R->pd_pwr,
02300                                                 pdg_R->pd_step,
02301                                                 pdg_R->pd_points, tmpR, type);
02302                         break;
02303                 default:
02304                         return -EINVAL;
02305                 }
02306 
02307                 /* Interpolate between curves
02308                  * of surounding freq piers to
02309                  * get the final curve for this
02310                  * pd gain. Re-use tmpL for interpolation
02311                  * output */
02312                 for (i = 0; (i < (u16) (table_max[pdg] - table_min[pdg])) &&
02313                 (i < AR5K_EEPROM_POWER_TABLE_SIZE); i++) {
02314                         tmpL[i] = (u8) ath5k_get_interpolated_value(target,
02315                                                         (s16) pcinfo_L->freq,
02316                                                         (s16) pcinfo_R->freq,
02317                                                         (s16) tmpL[i],
02318                                                         (s16) tmpR[i]);
02319                 }
02320         }
02321 
02322         /* Now we have a set of curves for this
02323          * channel on tmpL (x range is table_max - table_min
02324          * and y values are tmpL[pdg][]) sorted in the same
02325          * order as EEPROM (because we've used the backmaping).
02326          * So for RF5112 it's from higher power to lower power
02327          * and for RF2413 it's from lower power to higher power.
02328          * For RF5111 we only have one curve. */
02329 
02330         /* Fill min and max power levels for this
02331          * channel by interpolating the values on
02332          * surounding channels to complete the dataset */
02333         ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target,
02334                                         (s16) pcinfo_L->freq,
02335                                         (s16) pcinfo_R->freq,
02336                                         pcinfo_L->min_pwr, pcinfo_R->min_pwr);
02337 
02338         ah->ah_txpower.txp_max_pwr = ath5k_get_interpolated_value(target,
02339                                         (s16) pcinfo_L->freq,
02340                                         (s16) pcinfo_R->freq,
02341                                         pcinfo_L->max_pwr, pcinfo_R->max_pwr);
02342 
02343         /* We are ready to go, fill PCDAC/PDADC
02344          * table and write settings on hardware */
02345         switch (type) {
02346         case AR5K_PWRTABLE_LINEAR_PCDAC:
02347                 /* For RF5112 we can have one or two curves
02348                  * and each curve covers a certain power lvl
02349                  * range so we need to do some more processing */
02350                 ath5k_combine_linear_pcdac_curves(ah, table_min, table_max,
02351                                                 ee->ee_pd_gains[ee_mode]);
02352 
02353                 /* Set txp.offset so that we can
02354                  * match max power value with max
02355                  * table index */
02356                 ah->ah_txpower.txp_offset = 64 - (table_max[0] / 2);
02357 
02358                 /* Write settings on hw */
02359                 ath5k_setup_pcdac_table(ah);
02360                 break;
02361         case AR5K_PWRTABLE_PWR_TO_PCDAC:
02362                 /* We are done for RF5111 since it has only
02363                  * one curve, just fit the curve on the table */
02364                 ath5k_fill_pwr_to_pcdac_table(ah, table_min, table_max);
02365 
02366                 /* No rate powertable adjustment for RF5111 */
02367                 ah->ah_txpower.txp_min_idx = 0;
02368                 ah->ah_txpower.txp_offset = 0;
02369 
02370                 /* Write settings on hw */
02371                 ath5k_setup_pcdac_table(ah);
02372                 break;
02373         case AR5K_PWRTABLE_PWR_TO_PDADC:
02374                 /* Set PDADC boundaries and fill
02375                  * final PDADC table */
02376                 ath5k_combine_pwr_to_pdadc_curves(ah, table_min, table_max,
02377                                                 ee->ee_pd_gains[ee_mode]);
02378 
02379                 /* Write settings on hw */
02380                 ath5k_setup_pwr_to_pdadc_table(ah, pdg, pdg_curve_to_idx);
02381 
02382                 /* Set txp.offset, note that table_min
02383                  * can be negative */
02384                 ah->ah_txpower.txp_offset = table_min[0];
02385                 break;
02386         default:
02387                 return -EINVAL;
02388         }
02389 
02390         return 0;
02391 }

static void ath5k_setup_rate_powertable ( struct ath5k_hw ah,
u16  max_pwr,
struct ath5k_rate_pcal_info rate_info,
u8  ee_mode 
) [static]

Definition at line 2417 of file ath5k_phy.c.

References ath5k_hw::ah_phy_revision, ath5k_hw::ah_txpower, AR5K_EEPROM_MODE_11G, AR5K_SREV_PHY_5212A, min, ath5k_rate_pcal_info::target_power_36, ath5k_rate_pcal_info::target_power_48, ath5k_rate_pcal_info::target_power_54, ath5k_rate_pcal_info::target_power_6to24, ath5k_hw::txp_cck_ofdm_gainf_delta, ath5k_hw::txp_max_pwr, ath5k_hw::txp_min_pwr, ath5k_hw::txp_ofdm, ath5k_hw::txp_rates_power_table, and u16.

Referenced by ath5k_hw_txpower().

02420 {
02421         unsigned int i;
02422         u16 *rates;
02423 
02424         /* max_pwr is power level we got from driver/user in 0.5dB
02425          * units, switch to 0.25dB units so we can compare */
02426         max_pwr *= 2;
02427         max_pwr = min(max_pwr, (u16) ah->ah_txpower.txp_max_pwr) / 2;
02428 
02429         /* apply rate limits */
02430         rates = ah->ah_txpower.txp_rates_power_table;
02431 
02432         /* OFDM rates 6 to 24Mb/s */
02433         for (i = 0; i < 5; i++)
02434                 rates[i] = min(max_pwr, rate_info->target_power_6to24);
02435 
02436         /* Rest OFDM rates */
02437         rates[5] = min(rates[0], rate_info->target_power_36);
02438         rates[6] = min(rates[0], rate_info->target_power_48);
02439         rates[7] = min(rates[0], rate_info->target_power_54);
02440 
02441         /* CCK rates */
02442         /* 1L */
02443         rates[8] = min(rates[0], rate_info->target_power_6to24);
02444         /* 2L */
02445         rates[9] = min(rates[0], rate_info->target_power_36);
02446         /* 2S */
02447         rates[10] = min(rates[0], rate_info->target_power_36);
02448         /* 5L */
02449         rates[11] = min(rates[0], rate_info->target_power_48);
02450         /* 5S */
02451         rates[12] = min(rates[0], rate_info->target_power_48);
02452         /* 11L */
02453         rates[13] = min(rates[0], rate_info->target_power_54);
02454         /* 11S */
02455         rates[14] = min(rates[0], rate_info->target_power_54);
02456 
02457         /* XR rates */
02458         rates[15] = min(rates[0], rate_info->target_power_6to24);
02459 
02460         /* CCK rates have different peak to average ratio
02461          * so we have to tweak their power so that gainf
02462          * correction works ok. For this we use OFDM to
02463          * CCK delta from eeprom */
02464         if ((ee_mode == AR5K_EEPROM_MODE_11G) &&
02465         (ah->ah_phy_revision < AR5K_SREV_PHY_5212A))
02466                 for (i = 8; i <= 15; i++)
02467                         rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
02468 
02469         ah->ah_txpower.txp_min_pwr = rates[7];
02470         ah->ah_txpower.txp_max_pwr = rates[0];
02471         ah->ah_txpower.txp_ofdm = rates[7];
02472 }

int ath5k_hw_txpower ( struct ath5k_hw ah,
struct net80211_channel channel,
u8  ee_mode,
u8  txpower 
)

Definition at line 2479 of file ath5k_phy.c.

References ath5k_hw::ah_radio, ath5k_hw::ah_txpower, AR5K_PHY_TXPOWER_RATE1, AR5K_PHY_TXPOWER_RATE2, AR5K_PHY_TXPOWER_RATE3, AR5K_PHY_TXPOWER_RATE4, AR5K_PHY_TXPOWER_RATE_MAX, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE, AR5K_PWRTABLE_LINEAR_PCDAC, AR5K_PWRTABLE_PWR_TO_PCDAC, AR5K_PWRTABLE_PWR_TO_PDADC, AR5K_REG_MS, AR5K_RF2316, AR5K_RF2317, AR5K_RF2413, AR5K_RF2425, AR5K_RF5111, AR5K_RF5112, AR5K_RF5413, AR5K_TPC, AR5K_TPC_ACK, AR5K_TPC_CHIRP, AR5K_TPC_CTS, AR5K_TUNE_DEFAULT_TXPOWER, AR5K_TUNE_MAX_TXPOWER, AR5K_TUNE_TPC_TXPOWER, AR5K_TXPOWER_CCK, AR5K_TXPOWER_OFDM, ath5k_get_max_ctl_power(), ath5k_get_rate_pcal_data(), ath5k_hw_reg_write(), ath5k_setup_channel_powertable(), ath5k_setup_rate_powertable(), DBG, EINVAL, memset(), ath5k_hw::txp_max_pwr, ath5k_hw::txp_min_pwr, ath5k_hw::txp_tpc, and u8.

Referenced by ath5k_hw_reset(), and ath5k_hw_set_txpower_limit().

02481 {
02482         struct ath5k_rate_pcal_info rate_info;
02483         u8 type;
02484         int ret;
02485 
02486         if (txpower > AR5K_TUNE_MAX_TXPOWER) {
02487                 DBG("ath5k: invalid tx power %d\n", txpower);
02488                 return -EINVAL;
02489         }
02490         if (txpower == 0)
02491                 txpower = AR5K_TUNE_DEFAULT_TXPOWER;
02492 
02493         /* Reset TX power values */
02494         memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
02495         ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
02496         ah->ah_txpower.txp_min_pwr = 0;
02497         ah->ah_txpower.txp_max_pwr = AR5K_TUNE_MAX_TXPOWER;
02498 
02499         /* Initialize TX power table */
02500         switch (ah->ah_radio) {
02501         case AR5K_RF5111:
02502                 type = AR5K_PWRTABLE_PWR_TO_PCDAC;
02503                 break;
02504         case AR5K_RF5112:
02505                 type = AR5K_PWRTABLE_LINEAR_PCDAC;
02506                 break;
02507         case AR5K_RF2413:
02508         case AR5K_RF5413:
02509         case AR5K_RF2316:
02510         case AR5K_RF2317:
02511         case AR5K_RF2425:
02512                 type = AR5K_PWRTABLE_PWR_TO_PDADC;
02513                 break;
02514         default:
02515                 return -EINVAL;
02516         }
02517 
02518         /* FIXME: Only on channel/mode change */
02519         ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
02520         if (ret)
02521                 return ret;
02522 
02523         /* Limit max power if we have a CTL available */
02524         ath5k_get_max_ctl_power(ah, channel);
02525 
02526         /* FIXME: Tx power limit for this regdomain
02527          * XXX: Mac80211/CRDA will do that anyway ? */
02528 
02529         /* FIXME: Antenna reduction stuff */
02530 
02531         /* FIXME: Limit power on turbo modes */
02532 
02533         /* FIXME: TPC scale reduction */
02534 
02535         /* Get surounding channels for per-rate power table
02536          * calibration */
02537         ath5k_get_rate_pcal_data(ah, channel, &rate_info);
02538 
02539         /* Setup rate power table */
02540         ath5k_setup_rate_powertable(ah, txpower, &rate_info, ee_mode);
02541 
02542         /* Write rate power table on hw */
02543         ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) |
02544                 AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) |
02545                 AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1);
02546 
02547         ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) |
02548                 AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) |
02549                 AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2);
02550 
02551         ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) |
02552                 AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) |
02553                 AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3);
02554 
02555         ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) |
02556                 AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) |
02557                 AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4);
02558 
02559         /* FIXME: TPC support */
02560         if (ah->ah_txpower.txp_tpc) {
02561                 ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE |
02562                         AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
02563 
02564                 ath5k_hw_reg_write(ah,
02565                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_ACK) |
02566                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CTS) |
02567                         AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
02568                         AR5K_TPC);
02569         } else {
02570                 ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
02571                         AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
02572         }
02573 
02574         return 0;
02575 }

int ath5k_hw_set_txpower_limit ( struct ath5k_hw ah,
u8  mode,
u8  txpower 
)

Definition at line 2577 of file ath5k_phy.c.

References ath5k_hw::ah_current_channel, ath5k_hw_txpower(), and DBG2.

02578 {
02579         struct net80211_channel *channel = ah->ah_current_channel;
02580 
02581         DBG2("ath5k: changing txpower to %d\n", txpower);
02582 
02583         return ath5k_hw_txpower(ah, channel, mode, txpower);
02584 }


Generated on Tue Apr 6 20:01:20 2010 for gPXE by  doxygen 1.5.7.1