diff options
author | Nick Kossifidis <mick@madwifi-project.org> | 2009-02-08 23:03:41 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:44:43 -0500 |
commit | 6f3b414aca060a847e243f676b8601731938eb48 (patch) | |
tree | 51345c9930dbb9281d2f3dd0ebf0268870caa357 /drivers/net/wireless/ath5k/phy.c | |
parent | 33a31826b4fe9f26d6b383bad19b7ae522fda006 (diff) |
ath5k: Update gain_F calibration code and add documentation
* Update and cleanup rf gain optimization code
* Add comments and refferences to docs and use sane function names
* Use only step index on ath5k_gain, no need to have a pointer to
the current step since we can determine te step from it's index,
this also allows us to put all other structs on rfgain.h and cleanup
ath5k.h a little
* No need for ah_rfgain variable, we use ah_gain.g_state for everything
* Tested on RF2112B chip but gain_F calibration is not yet done
(we will finish this on the next patch where we'll rewrite rf-buffer
handling)
* Use initial rf gain settings for 2316 and 2317 SoCs introduced on a previous patch
It seems big but it's mostly cleanup, very few functional changes have been made on phy.c
Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath5k/phy.c')
-rw-r--r-- | drivers/net/wireless/ath5k/phy.c | 403 |
1 files changed, 264 insertions, 139 deletions
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 5021749a439e..2543a718fe3f 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c | |||
@@ -78,10 +78,104 @@ static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, | |||
78 | return data; | 78 | return data; |
79 | } | 79 | } |
80 | 80 | ||
81 | static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) | 81 | /**********************\ |
82 | * RF Gain optimization * | ||
83 | \**********************/ | ||
84 | |||
85 | /* | ||
86 | * This code is used to optimize rf gain on different environments | ||
87 | * (temprature mostly) based on feedback from a power detector. | ||
88 | * | ||
89 | * It's only used on RF5111 and RF5112, later RF chips seem to have | ||
90 | * auto adjustment on hw -notice they have a much smaller BANK 7 and | ||
91 | * no gain optimization ladder-. | ||
92 | * | ||
93 | * For more infos check out this patent doc | ||
94 | * http://www.freepatentsonline.com/7400691.html | ||
95 | * | ||
96 | * This paper describes power drops as seen on the receiver due to | ||
97 | * probe packets | ||
98 | * http://www.cnri.dit.ie/publications/ICT08%20-%20Practical%20Issues | ||
99 | * %20of%20Power%20Control.pdf | ||
100 | * | ||
101 | * And this is the MadWiFi bug entry related to the above | ||
102 | * http://madwifi-project.org/ticket/1659 | ||
103 | * with various measurements and diagrams | ||
104 | * | ||
105 | * TODO: Deal with power drops due to probes by setting an apropriate | ||
106 | * tx power on the probe packets ! Make this part of the calibration process. | ||
107 | */ | ||
108 | |||
109 | /* Initialize ah_gain durring attach */ | ||
110 | int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) | ||
111 | { | ||
112 | /* Initialize the gain optimization values */ | ||
113 | switch (ah->ah_radio) { | ||
114 | case AR5K_RF5111: | ||
115 | ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; | ||
116 | ah->ah_gain.g_low = 20; | ||
117 | ah->ah_gain.g_high = 35; | ||
118 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; | ||
119 | break; | ||
120 | case AR5K_RF5112: | ||
121 | ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; | ||
122 | ah->ah_gain.g_low = 20; | ||
123 | ah->ah_gain.g_high = 85; | ||
124 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; | ||
125 | break; | ||
126 | default: | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* Schedule a gain probe check on the next transmited packet. | ||
134 | * That means our next packet is going to be sent with lower | ||
135 | * tx power and a Peak to Average Power Detector (PAPD) will try | ||
136 | * to measure the gain. | ||
137 | * | ||
138 | * TODO: Use propper tx power setting for the probe packet so | ||
139 | * that we don't observe a serious power drop on the receiver | ||
140 | * | ||
141 | * XXX: How about forcing a tx packet (bypassing PCU arbitrator etc) | ||
142 | * just after we enable the probe so that we don't mess with | ||
143 | * standard traffic ? Maybe it's time to use sw interrupts and | ||
144 | * a probe tasklet !!! | ||
145 | */ | ||
146 | static void ath5k_hw_request_rfgain_probe(struct ath5k_hw *ah) | ||
147 | { | ||
148 | |||
149 | /* Skip if gain calibration is inactive or | ||
150 | * we already handle a probe request */ | ||
151 | if (ah->ah_gain.g_state != AR5K_RFGAIN_ACTIVE) | ||
152 | return; | ||
153 | |||
154 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, | ||
155 | AR5K_PHY_PAPD_PROBE_TXPOWER) | | ||
156 | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); | ||
157 | |||
158 | ah->ah_gain.g_state = AR5K_RFGAIN_READ_REQUESTED; | ||
159 | |||
160 | } | ||
161 | |||
162 | /* Calculate gain_F measurement correction | ||
163 | * based on the current step for RF5112 rev. 2 */ | ||
164 | static u32 ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah) | ||
82 | { | 165 | { |
83 | u32 mix, step; | 166 | u32 mix, step; |
84 | u32 *rf; | 167 | u32 *rf; |
168 | const struct ath5k_gain_opt *go; | ||
169 | const struct ath5k_gain_opt_step *g_step; | ||
170 | |||
171 | /* Only RF5112 Rev. 2 supports it */ | ||
172 | if ((ah->ah_radio != AR5K_RF5112) || | ||
173 | (ah->ah_radio_5ghz_revision <= AR5K_SREV_RAD_5112A)) | ||
174 | return 0; | ||
175 | |||
176 | go = &rfgain_opt_5112; | ||
177 | |||
178 | g_step = &go->go_step[ah->ah_gain.g_step_idx]; | ||
85 | 179 | ||
86 | if (ah->ah_rf_banks == NULL) | 180 | if (ah->ah_rf_banks == NULL) |
87 | return 0; | 181 | return 0; |
@@ -89,11 +183,15 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) | |||
89 | rf = ah->ah_rf_banks; | 183 | rf = ah->ah_rf_banks; |
90 | ah->ah_gain.g_f_corr = 0; | 184 | ah->ah_gain.g_f_corr = 0; |
91 | 185 | ||
186 | /* No VGA (Variable Gain Amplifier) override, skip */ | ||
92 | if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) | 187 | if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) |
93 | return 0; | 188 | return 0; |
94 | 189 | ||
190 | /* Mix gain stepping */ | ||
95 | step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); | 191 | step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); |
96 | mix = ah->ah_gain.g_step->gos_param[0]; | 192 | |
193 | /* Mix gain override */ | ||
194 | mix = g_step->gos_param[0]; | ||
97 | 195 | ||
98 | switch (mix) { | 196 | switch (mix) { |
99 | case 3: | 197 | case 3: |
@@ -113,9 +211,13 @@ static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) | |||
113 | return ah->ah_gain.g_f_corr; | 211 | return ah->ah_gain.g_f_corr; |
114 | } | 212 | } |
115 | 213 | ||
116 | static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) | 214 | /* Check if current gain_F measurement is in the range of our |
215 | * power detector windows. If we get a measurement outside range | ||
216 | * we know it's not accurate (detectors can't measure anything outside | ||
217 | * their detection window) so we must ignore it */ | ||
218 | static bool ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah) | ||
117 | { | 219 | { |
118 | u32 step, mix, level[4]; | 220 | u32 step, mix_ovr, level[4]; |
119 | u32 *rf; | 221 | u32 *rf; |
120 | 222 | ||
121 | if (ah->ah_rf_banks == NULL) | 223 | if (ah->ah_rf_banks == NULL) |
@@ -127,20 +229,20 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) | |||
127 | step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, | 229 | step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, |
128 | false); | 230 | false); |
129 | level[0] = 0; | 231 | level[0] = 0; |
130 | level[1] = (step == 0x3f) ? 0x32 : step + 4; | 232 | level[1] = (step == 63) ? 50 : step + 4; |
131 | level[2] = (step != 0x3f) ? 0x40 : level[0]; | 233 | level[2] = (step != 63) ? 64 : level[0]; |
132 | level[3] = level[2] + 0x32; | 234 | level[3] = level[2] + 50 ; |
133 | 235 | ||
134 | ah->ah_gain.g_high = level[3] - | 236 | ah->ah_gain.g_high = level[3] - |
135 | (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); | 237 | (step == 63 ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); |
136 | ah->ah_gain.g_low = level[0] + | 238 | ah->ah_gain.g_low = level[0] + |
137 | (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); | 239 | (step == 63 ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); |
138 | } else { | 240 | } else { |
139 | mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, | 241 | mix_ovr = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, |
140 | false); | 242 | false); |
141 | level[0] = level[2] = 0; | 243 | level[0] = level[2] = 0; |
142 | 244 | ||
143 | if (mix == 1) { | 245 | if (mix_ovr == 1) { |
144 | level[1] = level[3] = 83; | 246 | level[1] = level[3] = 83; |
145 | } else { | 247 | } else { |
146 | level[1] = level[3] = 107; | 248 | level[1] = level[3] = 107; |
@@ -154,9 +256,12 @@ static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) | |||
154 | ah->ah_gain.g_current <= level[3]); | 256 | ah->ah_gain.g_current <= level[3]); |
155 | } | 257 | } |
156 | 258 | ||
157 | static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) | 259 | /* Perform gain_F adjustment by choosing the right set |
260 | * of parameters from rf gain optimization ladder */ | ||
261 | static s8 ath5k_hw_rf_gainf_adjust(struct ath5k_hw *ah) | ||
158 | { | 262 | { |
159 | const struct ath5k_gain_opt *go; | 263 | const struct ath5k_gain_opt *go; |
264 | const struct ath5k_gain_opt_step *g_step; | ||
160 | int ret = 0; | 265 | int ret = 0; |
161 | 266 | ||
162 | switch (ah->ah_radio) { | 267 | switch (ah->ah_radio) { |
@@ -170,35 +275,39 @@ static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) | |||
170 | return 0; | 275 | return 0; |
171 | } | 276 | } |
172 | 277 | ||
173 | ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx]; | 278 | g_step = &go->go_step[ah->ah_gain.g_step_idx]; |
174 | 279 | ||
175 | if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { | 280 | if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { |
281 | |||
282 | /* Reached maximum */ | ||
176 | if (ah->ah_gain.g_step_idx == 0) | 283 | if (ah->ah_gain.g_step_idx == 0) |
177 | return -1; | 284 | return -1; |
285 | |||
178 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; | 286 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; |
179 | ah->ah_gain.g_target >= ah->ah_gain.g_high && | 287 | ah->ah_gain.g_target >= ah->ah_gain.g_high && |
180 | ah->ah_gain.g_step_idx > 0; | 288 | ah->ah_gain.g_step_idx > 0; |
181 | ah->ah_gain.g_step = | 289 | g_step = &go->go_step[ah->ah_gain.g_step_idx]) |
182 | &go->go_step[ah->ah_gain.g_step_idx]) | ||
183 | ah->ah_gain.g_target -= 2 * | 290 | ah->ah_gain.g_target -= 2 * |
184 | (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - | 291 | (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - |
185 | ah->ah_gain.g_step->gos_gain); | 292 | g_step->gos_gain); |
186 | 293 | ||
187 | ret = 1; | 294 | ret = 1; |
188 | goto done; | 295 | goto done; |
189 | } | 296 | } |
190 | 297 | ||
191 | if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { | 298 | if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { |
299 | |||
300 | /* Reached minimum */ | ||
192 | if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) | 301 | if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) |
193 | return -2; | 302 | return -2; |
303 | |||
194 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; | 304 | for (ah->ah_gain.g_target = ah->ah_gain.g_current; |
195 | ah->ah_gain.g_target <= ah->ah_gain.g_low && | 305 | ah->ah_gain.g_target <= ah->ah_gain.g_low && |
196 | ah->ah_gain.g_step_idx < go->go_steps_count-1; | 306 | ah->ah_gain.g_step_idx < go->go_steps_count-1; |
197 | ah->ah_gain.g_step = | 307 | g_step = &go->go_step[ah->ah_gain.g_step_idx]) |
198 | &go->go_step[ah->ah_gain.g_step_idx]) | ||
199 | ah->ah_gain.g_target -= 2 * | 308 | ah->ah_gain.g_target -= 2 * |
200 | (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - | 309 | (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - |
201 | ah->ah_gain.g_step->gos_gain); | 310 | g_step->gos_gain); |
202 | 311 | ||
203 | ret = 2; | 312 | ret = 2; |
204 | goto done; | 313 | goto done; |
@@ -213,6 +322,135 @@ done: | |||
213 | return ret; | 322 | return ret; |
214 | } | 323 | } |
215 | 324 | ||
325 | /* Main callback for thermal rf gain calibration engine | ||
326 | * Check for a new gain reading and schedule an adjustment | ||
327 | * if needed. | ||
328 | * | ||
329 | * TODO: Use sw interrupt to schedule reset if gain_F needs | ||
330 | * adjustment */ | ||
331 | enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah) | ||
332 | { | ||
333 | u32 data, type; | ||
334 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
335 | |||
336 | ATH5K_TRACE(ah->ah_sc); | ||
337 | |||
338 | if (ah->ah_rf_banks == NULL || | ||
339 | ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE) | ||
340 | return AR5K_RFGAIN_INACTIVE; | ||
341 | |||
342 | /* No check requested, either engine is inactive | ||
343 | * or an adjustment is already requested */ | ||
344 | if (ah->ah_gain.g_state != AR5K_RFGAIN_READ_REQUESTED) | ||
345 | goto done; | ||
346 | |||
347 | /* Read the PAPD (Peak to Average Power Detector) | ||
348 | * register */ | ||
349 | data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); | ||
350 | |||
351 | /* No probe is scheduled, read gain_F measurement */ | ||
352 | if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { | ||
353 | ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; | ||
354 | type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); | ||
355 | |||
356 | /* If tx packet is CCK correct the gain_F measurement | ||
357 | * by cck ofdm gain delta */ | ||
358 | if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) { | ||
359 | if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) | ||
360 | ah->ah_gain.g_current += | ||
361 | ee->ee_cck_ofdm_gain_delta; | ||
362 | else | ||
363 | ah->ah_gain.g_current += | ||
364 | AR5K_GAIN_CCK_PROBE_CORR; | ||
365 | } | ||
366 | |||
367 | /* Further correct gain_F measurement for | ||
368 | * RF5112A radios */ | ||
369 | if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { | ||
370 | ath5k_hw_rf_gainf_corr(ah); | ||
371 | ah->ah_gain.g_current = | ||
372 | ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? | ||
373 | (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : | ||
374 | 0; | ||
375 | } | ||
376 | |||
377 | /* Check if measurement is ok and if we need | ||
378 | * to adjust gain, schedule a gain adjustment, | ||
379 | * else switch back to the acive state */ | ||
380 | if (ath5k_hw_rf_check_gainf_readback(ah) && | ||
381 | AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && | ||
382 | ath5k_hw_rf_gainf_adjust(ah)) { | ||
383 | ah->ah_gain.g_state = AR5K_RFGAIN_NEED_CHANGE; | ||
384 | } else { | ||
385 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | done: | ||
390 | return ah->ah_gain.g_state; | ||
391 | } | ||
392 | |||
393 | /* Write initial rf gain table to set the RF sensitivity | ||
394 | * this one works on all RF chips and has nothing to do | ||
395 | * with gain_F calibration */ | ||
396 | int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq) | ||
397 | { | ||
398 | const struct ath5k_ini_rfgain *ath5k_rfg; | ||
399 | unsigned int i, size; | ||
400 | |||
401 | switch (ah->ah_radio) { | ||
402 | case AR5K_RF5111: | ||
403 | ath5k_rfg = rfgain_5111; | ||
404 | size = ARRAY_SIZE(rfgain_5111); | ||
405 | break; | ||
406 | case AR5K_RF5112: | ||
407 | ath5k_rfg = rfgain_5112; | ||
408 | size = ARRAY_SIZE(rfgain_5112); | ||
409 | break; | ||
410 | case AR5K_RF2413: | ||
411 | ath5k_rfg = rfgain_2413; | ||
412 | size = ARRAY_SIZE(rfgain_2413); | ||
413 | break; | ||
414 | case AR5K_RF2316: | ||
415 | ath5k_rfg = rfgain_2316; | ||
416 | size = ARRAY_SIZE(rfgain_2316); | ||
417 | break; | ||
418 | case AR5K_RF5413: | ||
419 | ath5k_rfg = rfgain_5413; | ||
420 | size = ARRAY_SIZE(rfgain_5413); | ||
421 | break; | ||
422 | case AR5K_RF2317: | ||
423 | case AR5K_RF2425: | ||
424 | ath5k_rfg = rfgain_2425; | ||
425 | size = ARRAY_SIZE(rfgain_2425); | ||
426 | break; | ||
427 | default: | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | switch (freq) { | ||
432 | case AR5K_INI_RFGAIN_2GHZ: | ||
433 | case AR5K_INI_RFGAIN_5GHZ: | ||
434 | break; | ||
435 | default: | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | for (i = 0; i < size; i++) { | ||
440 | AR5K_REG_WAIT(i); | ||
441 | ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], | ||
442 | (u32)ath5k_rfg[i].rfg_register); | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | |||
449 | |||
450 | /********************\ | ||
451 | * RF Registers setup * | ||
452 | \********************/ | ||
453 | |||
216 | /* | 454 | /* |
217 | * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 | 455 | * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 |
218 | */ | 456 | */ |
@@ -311,6 +549,8 @@ static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, | |||
311 | ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register); | 549 | ath5k_hw_reg_write(ah, rf[i], rfb_5111[i].rfb_ctrl_register); |
312 | } | 550 | } |
313 | 551 | ||
552 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; | ||
553 | |||
314 | return 0; | 554 | return 0; |
315 | } | 555 | } |
316 | 556 | ||
@@ -407,6 +647,9 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, | |||
407 | for (i = 0; i < rf_size; i++) | 647 | for (i = 0; i < rf_size; i++) |
408 | ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); | 648 | ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rfb_ctrl_register); |
409 | 649 | ||
650 | |||
651 | ah->ah_gain.g_state = AR5K_RFGAIN_ACTIVE; | ||
652 | |||
410 | return 0; | 653 | return 0; |
411 | } | 654 | } |
412 | 655 | ||
@@ -536,125 +779,12 @@ int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, | |||
536 | } | 779 | } |
537 | 780 | ||
538 | ret = func(ah, channel, mode); | 781 | ret = func(ah, channel, mode); |
539 | if (!ret) | ||
540 | ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE; | ||
541 | 782 | ||
542 | return ret; | 783 | return ret; |
543 | } | 784 | } |
544 | 785 | ||
545 | int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) | ||
546 | { | ||
547 | const struct ath5k_ini_rfgain *ath5k_rfg; | ||
548 | unsigned int i, size; | ||
549 | 786 | ||
550 | switch (ah->ah_radio) { | ||
551 | case AR5K_RF5111: | ||
552 | ath5k_rfg = rfgain_5111; | ||
553 | size = ARRAY_SIZE(rfgain_5111); | ||
554 | break; | ||
555 | case AR5K_RF5112: | ||
556 | ath5k_rfg = rfgain_5112; | ||
557 | size = ARRAY_SIZE(rfgain_5112); | ||
558 | break; | ||
559 | case AR5K_RF5413: | ||
560 | ath5k_rfg = rfgain_5413; | ||
561 | size = ARRAY_SIZE(rfgain_5413); | ||
562 | break; | ||
563 | case AR5K_RF2413: | ||
564 | ath5k_rfg = rfgain_2413; | ||
565 | size = ARRAY_SIZE(rfgain_2413); | ||
566 | break; | ||
567 | case AR5K_RF2425: | ||
568 | ath5k_rfg = rfgain_2425; | ||
569 | size = ARRAY_SIZE(rfgain_2425); | ||
570 | break; | ||
571 | default: | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | 787 | ||
575 | switch (freq) { | ||
576 | case AR5K_INI_RFGAIN_2GHZ: | ||
577 | case AR5K_INI_RFGAIN_5GHZ: | ||
578 | break; | ||
579 | default: | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | |||
583 | for (i = 0; i < size; i++) { | ||
584 | AR5K_REG_WAIT(i); | ||
585 | ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], | ||
586 | (u32)ath5k_rfg[i].rfg_register); | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) | ||
593 | { | ||
594 | u32 data, type; | ||
595 | |||
596 | ATH5K_TRACE(ah->ah_sc); | ||
597 | |||
598 | if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active || | ||
599 | ah->ah_version <= AR5K_AR5211) | ||
600 | return AR5K_RFGAIN_INACTIVE; | ||
601 | |||
602 | if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED) | ||
603 | goto done; | ||
604 | |||
605 | data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); | ||
606 | |||
607 | if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { | ||
608 | ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; | ||
609 | type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); | ||
610 | |||
611 | if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) | ||
612 | ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR; | ||
613 | |||
614 | if (ah->ah_radio >= AR5K_RF5112) { | ||
615 | ath5k_hw_rfregs_gainf_corr(ah); | ||
616 | ah->ah_gain.g_current = | ||
617 | ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? | ||
618 | (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : | ||
619 | 0; | ||
620 | } | ||
621 | |||
622 | if (ath5k_hw_rfregs_gain_readback(ah) && | ||
623 | AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && | ||
624 | ath5k_hw_rfregs_gain_adjust(ah)) | ||
625 | ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE; | ||
626 | } | ||
627 | |||
628 | done: | ||
629 | return ah->ah_rf_gain; | ||
630 | } | ||
631 | |||
632 | int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah) | ||
633 | { | ||
634 | /* Initialize the gain optimization values */ | ||
635 | switch (ah->ah_radio) { | ||
636 | case AR5K_RF5111: | ||
637 | ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; | ||
638 | ah->ah_gain.g_step = | ||
639 | &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx]; | ||
640 | ah->ah_gain.g_low = 20; | ||
641 | ah->ah_gain.g_high = 35; | ||
642 | ah->ah_gain.g_active = 1; | ||
643 | break; | ||
644 | case AR5K_RF5112: | ||
645 | ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; | ||
646 | ah->ah_gain.g_step = | ||
647 | &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; | ||
648 | ah->ah_gain.g_low = 20; | ||
649 | ah->ah_gain.g_high = 85; | ||
650 | ah->ah_gain.g_active = 1; | ||
651 | break; | ||
652 | default: | ||
653 | return -EINVAL; | ||
654 | } | ||
655 | |||
656 | return 0; | ||
657 | } | ||
658 | 788 | ||
659 | /**************************\ | 789 | /**************************\ |
660 | PHY/RF channel functions | 790 | PHY/RF channel functions |
@@ -1176,13 +1306,8 @@ done: | |||
1176 | * as often as I/Q calibration.*/ | 1306 | * as often as I/Q calibration.*/ |
1177 | ath5k_hw_noise_floor_calibration(ah, channel->center_freq); | 1307 | ath5k_hw_noise_floor_calibration(ah, channel->center_freq); |
1178 | 1308 | ||
1179 | /* Request RF gain */ | 1309 | /* Initiate a gain_F calibration */ |
1180 | if (channel->hw_value & CHANNEL_5GHZ) { | 1310 | ath5k_hw_request_rfgain_probe(ah); |
1181 | ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, | ||
1182 | AR5K_PHY_PAPD_PROBE_TXPOWER) | | ||
1183 | AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); | ||
1184 | ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED; | ||
1185 | } | ||
1186 | 1311 | ||
1187 | return 0; | 1312 | return 0; |
1188 | } | 1313 | } |