#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 _ATH5K_PHY |
Definition at line 27 of file ath5k_phy.c.
| FILE_LICENCE | ( | MIT | ) |
| static int min | ( | int | x, | |
| int | y | |||
| ) | [inline, static] |
| static int max | ( | int | x, | |
| int | y | |||
| ) | [inline, static] |
| 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 }
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 }
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 }
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 }
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 }
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 }
1.5.7.1