1800 lines · c
1/*2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>3 * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com>4 * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org>5 *6 * Permission to use, copy, modify, and distribute this software for any7 * purpose with or without fee is hereby granted, provided that the above8 * copyright notice and this permission notice appear in all copies.9 *10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17 *18 */19 20/*************************************\21* EEPROM access functions and helpers *22\*************************************/23 24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt25 26#include <linux/slab.h>27 28#include "ath5k.h"29#include "reg.h"30#include "debug.h"31 32 33/******************\34* Helper functions *35\******************/36 37/*38 * Translate binary channel representation in EEPROM to frequency39 */40static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,41 unsigned int mode)42{43 u16 val;44 45 if (bin == AR5K_EEPROM_CHANNEL_DIS)46 return bin;47 48 if (mode == AR5K_EEPROM_MODE_11A) {49 if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)50 val = (5 * bin) + 4800;51 else52 val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :53 (bin * 10) + 5100;54 } else {55 if (ee->ee_version > AR5K_EEPROM_VERSION_3_2)56 val = bin + 2300;57 else58 val = bin + 2400;59 }60 61 return val;62}63 64 65/*********\66* Parsers *67\*********/68 69/*70 * Initialize eeprom & capabilities structs71 */72static int73ath5k_eeprom_init_header(struct ath5k_hw *ah)74{75 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;76 u16 val;77 u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX;78 79 /*80 * Read values from EEPROM and store them in the capability structure81 */82 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);83 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);84 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);85 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);86 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);87 88 /* Return if we have an old EEPROM */89 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)90 return 0;91 92 /*93 * Validate the checksum of the EEPROM date. There are some94 * devices with invalid EEPROMs.95 */96 AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val);97 if (val) {98 eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<99 AR5K_EEPROM_SIZE_ENDLOC_SHIFT;100 AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val);101 eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE;102 103 /*104 * Fail safe check to prevent stupid loops due105 * to busted EEPROMs. XXX: This value is likely too106 * big still, waiting on a better value.107 */108 if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) {109 ATH5K_ERR(ah, "Invalid max custom EEPROM size: "110 "%d (0x%04x) max expected: %d (0x%04x)\n",111 eep_max, eep_max,112 3 * AR5K_EEPROM_INFO_MAX,113 3 * AR5K_EEPROM_INFO_MAX);114 return -EIO;115 }116 }117 118 for (cksum = 0, offset = 0; offset < eep_max; offset++) {119 AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);120 cksum ^= val;121 }122 if (cksum != AR5K_EEPROM_INFO_CKSUM) {123 ATH5K_ERR(ah, "Invalid EEPROM "124 "checksum: 0x%04x eep_max: 0x%04x (%s)\n",125 cksum, eep_max,126 eep_max == AR5K_EEPROM_INFO_MAX ?127 "default size" : "custom size");128 return -EIO;129 }130 131 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),132 ee_ant_gain);133 134 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {135 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);136 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);137 138 /* XXX: Don't know which versions include these two */139 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2);140 141 if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3)142 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3);143 144 if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) {145 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4);146 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5);147 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6);148 }149 }150 151 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {152 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);153 ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;154 ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;155 156 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);157 ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;158 ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;159 }160 161 AR5K_EEPROM_READ(AR5K_EEPROM_IS_HB63, val);162 163 if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && val)164 ee->ee_is_hb63 = true;165 else166 ee->ee_is_hb63 = false;167 168 AR5K_EEPROM_READ(AR5K_EEPROM_RFKILL, val);169 ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);170 ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false;171 172 /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION173 * and enable serdes programming if needed.174 *175 * XXX: Serdes values seem to be fixed so176 * no need to read them here, we write them177 * during ath5k_hw_init */178 AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);179 ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?180 true : false;181 182 return 0;183}184 185 186/*187 * Read antenna infos from eeprom188 */189static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,190 unsigned int mode)191{192 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;193 u32 o = *offset;194 u16 val;195 int i = 0;196 197 AR5K_EEPROM_READ(o++, val);198 ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;199 ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f;200 ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;201 202 AR5K_EEPROM_READ(o++, val);203 ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;204 ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;205 ee->ee_ant_control[mode][i++] = val & 0x3f;206 207 AR5K_EEPROM_READ(o++, val);208 ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f;209 ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f;210 ee->ee_ant_control[mode][i] = (val << 2) & 0x3f;211 212 AR5K_EEPROM_READ(o++, val);213 ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3;214 ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f;215 ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f;216 ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;217 218 AR5K_EEPROM_READ(o++, val);219 ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;220 ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;221 ee->ee_ant_control[mode][i++] = val & 0x3f;222 223 /* Get antenna switch tables */224 ah->ah_ant_ctl[mode][AR5K_ANT_CTL] =225 (ee->ee_ant_control[mode][0] << 4);226 ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_A] =227 ee->ee_ant_control[mode][1] |228 (ee->ee_ant_control[mode][2] << 6) |229 (ee->ee_ant_control[mode][3] << 12) |230 (ee->ee_ant_control[mode][4] << 18) |231 (ee->ee_ant_control[mode][5] << 24);232 ah->ah_ant_ctl[mode][AR5K_ANT_SWTABLE_B] =233 ee->ee_ant_control[mode][6] |234 (ee->ee_ant_control[mode][7] << 6) |235 (ee->ee_ant_control[mode][8] << 12) |236 (ee->ee_ant_control[mode][9] << 18) |237 (ee->ee_ant_control[mode][10] << 24);238 239 /* return new offset */240 *offset = o;241 242 return 0;243}244 245/*246 * Read supported modes and some mode-specific calibration data247 * from eeprom248 */249static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,250 unsigned int mode)251{252 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;253 u32 o = *offset;254 u16 val;255 256 ee->ee_n_piers[mode] = 0;257 AR5K_EEPROM_READ(o++, val);258 ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);259 switch (mode) {260 case AR5K_EEPROM_MODE_11A:261 ee->ee_ob[mode][3] = (val >> 5) & 0x7;262 ee->ee_db[mode][3] = (val >> 2) & 0x7;263 ee->ee_ob[mode][2] = (val << 1) & 0x7;264 265 AR5K_EEPROM_READ(o++, val);266 ee->ee_ob[mode][2] |= (val >> 15) & 0x1;267 ee->ee_db[mode][2] = (val >> 12) & 0x7;268 ee->ee_ob[mode][1] = (val >> 9) & 0x7;269 ee->ee_db[mode][1] = (val >> 6) & 0x7;270 ee->ee_ob[mode][0] = (val >> 3) & 0x7;271 ee->ee_db[mode][0] = val & 0x7;272 break;273 case AR5K_EEPROM_MODE_11G:274 case AR5K_EEPROM_MODE_11B:275 ee->ee_ob[mode][1] = (val >> 4) & 0x7;276 ee->ee_db[mode][1] = val & 0x7;277 break;278 }279 280 AR5K_EEPROM_READ(o++, val);281 ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;282 ee->ee_thr_62[mode] = val & 0xff;283 284 if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)285 ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;286 287 AR5K_EEPROM_READ(o++, val);288 ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;289 ee->ee_tx_frm2xpa_enable[mode] = val & 0xff;290 291 AR5K_EEPROM_READ(o++, val);292 ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff;293 294 if ((val & 0xff) & 0x80)295 ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);296 else297 ee->ee_noise_floor_thr[mode] = val & 0xff;298 299 if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)300 ee->ee_noise_floor_thr[mode] =301 mode == AR5K_EEPROM_MODE_11A ? -54 : -1;302 303 AR5K_EEPROM_READ(o++, val);304 ee->ee_xlna_gain[mode] = (val >> 5) & 0xff;305 ee->ee_x_gain[mode] = (val >> 1) & 0xf;306 ee->ee_xpd[mode] = val & 0x1;307 308 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&309 mode != AR5K_EEPROM_MODE_11B)310 ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;311 312 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {313 AR5K_EEPROM_READ(o++, val);314 ee->ee_false_detect[mode] = (val >> 6) & 0x7f;315 316 if (mode == AR5K_EEPROM_MODE_11A)317 ee->ee_xr_power[mode] = val & 0x3f;318 else {319 /* b_DB_11[bg] and b_OB_11[bg] */320 ee->ee_ob[mode][0] = val & 0x7;321 ee->ee_db[mode][0] = (val >> 3) & 0x7;322 }323 }324 325 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {326 ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;327 ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;328 } else {329 ee->ee_i_gain[mode] = (val >> 13) & 0x7;330 331 AR5K_EEPROM_READ(o++, val);332 ee->ee_i_gain[mode] |= (val << 3) & 0x38;333 334 if (mode == AR5K_EEPROM_MODE_11G) {335 ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;336 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6)337 ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;338 }339 }340 341 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&342 mode == AR5K_EEPROM_MODE_11A) {343 ee->ee_i_cal[mode] = (val >> 8) & 0x3f;344 ee->ee_q_cal[mode] = (val >> 3) & 0x1f;345 }346 347 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0)348 goto done;349 350 /* Note: >= v5 have bg freq piers on another location351 * so these freq piers are ignored for >= v5 (should be 0xff352 * anyway) */353 switch (mode) {354 case AR5K_EEPROM_MODE_11A:355 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1)356 break;357 358 AR5K_EEPROM_READ(o++, val);359 ee->ee_margin_tx_rx[mode] = val & 0x3f;360 break;361 case AR5K_EEPROM_MODE_11B:362 AR5K_EEPROM_READ(o++, val);363 364 ee->ee_pwr_cal_b[0].freq =365 ath5k_eeprom_bin2freq(ee, val & 0xff, mode);366 if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS)367 ee->ee_n_piers[mode]++;368 369 ee->ee_pwr_cal_b[1].freq =370 ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);371 if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS)372 ee->ee_n_piers[mode]++;373 374 AR5K_EEPROM_READ(o++, val);375 ee->ee_pwr_cal_b[2].freq =376 ath5k_eeprom_bin2freq(ee, val & 0xff, mode);377 if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS)378 ee->ee_n_piers[mode]++;379 380 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)381 ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;382 break;383 case AR5K_EEPROM_MODE_11G:384 AR5K_EEPROM_READ(o++, val);385 386 ee->ee_pwr_cal_g[0].freq =387 ath5k_eeprom_bin2freq(ee, val & 0xff, mode);388 if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS)389 ee->ee_n_piers[mode]++;390 391 ee->ee_pwr_cal_g[1].freq =392 ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);393 if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS)394 ee->ee_n_piers[mode]++;395 396 AR5K_EEPROM_READ(o++, val);397 ee->ee_turbo_max_power[mode] = val & 0x7f;398 ee->ee_xr_power[mode] = (val >> 7) & 0x3f;399 400 AR5K_EEPROM_READ(o++, val);401 ee->ee_pwr_cal_g[2].freq =402 ath5k_eeprom_bin2freq(ee, val & 0xff, mode);403 if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS)404 ee->ee_n_piers[mode]++;405 406 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)407 ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;408 409 AR5K_EEPROM_READ(o++, val);410 ee->ee_i_cal[mode] = (val >> 5) & 0x3f;411 ee->ee_q_cal[mode] = val & 0x1f;412 413 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {414 AR5K_EEPROM_READ(o++, val);415 ee->ee_cck_ofdm_gain_delta = val & 0xff;416 }417 break;418 }419 420 /*421 * Read turbo mode information on newer EEPROM versions422 */423 if (ee->ee_version < AR5K_EEPROM_VERSION_5_0)424 goto done;425 426 switch (mode) {427 case AR5K_EEPROM_MODE_11A:428 ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f;429 430 ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7;431 AR5K_EEPROM_READ(o++, val);432 ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3;433 ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f;434 435 ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f;436 AR5K_EEPROM_READ(o++, val);437 ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7;438 ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff;439 440 if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >= 2)441 ee->ee_pd_gain_overlap = (val >> 9) & 0xf;442 break;443 case AR5K_EEPROM_MODE_11G:444 ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f;445 446 ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7;447 AR5K_EEPROM_READ(o++, val);448 ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1;449 ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f;450 451 ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f;452 AR5K_EEPROM_READ(o++, val);453 ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5;454 ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff;455 break;456 }457 458done:459 /* return new offset */460 *offset = o;461 462 return 0;463}464 465/* Read mode-specific data (except power calibration data) */466static int467ath5k_eeprom_init_modes(struct ath5k_hw *ah)468{469 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;470 u32 mode_offset[3];471 unsigned int mode;472 u32 offset;473 int ret;474 475 /*476 * Get values for all modes477 */478 mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);479 mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);480 mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);481 482 ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] =483 AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);484 485 for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) {486 offset = mode_offset[mode];487 488 ret = ath5k_eeprom_read_ants(ah, &offset, mode);489 if (ret)490 return ret;491 492 ret = ath5k_eeprom_read_modes(ah, &offset, mode);493 if (ret)494 return ret;495 }496 497 /* override for older eeprom versions for better performance */498 if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) {499 ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15;500 ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28;501 ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28;502 }503 504 return 0;505}506 507/* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff508 * frequency mask) */509static inline int510ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max,511 struct ath5k_chan_pcal_info *pc, unsigned int mode)512{513 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;514 int o = *offset;515 int i = 0;516 u8 freq1, freq2;517 u16 val;518 519 ee->ee_n_piers[mode] = 0;520 while (i < max) {521 AR5K_EEPROM_READ(o++, val);522 523 freq1 = val & 0xff;524 if (!freq1)525 break;526 527 pc[i++].freq = ath5k_eeprom_bin2freq(ee,528 freq1, mode);529 ee->ee_n_piers[mode]++;530 531 freq2 = (val >> 8) & 0xff;532 if (!freq2 || i >= max)533 break;534 535 pc[i++].freq = ath5k_eeprom_bin2freq(ee,536 freq2, mode);537 ee->ee_n_piers[mode]++;538 }539 540 /* return new offset */541 *offset = o;542 543 return 0;544}545 546/* Read frequency piers for 802.11a */547static int548ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset)549{550 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;551 struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a;552 int i;553 u16 val;554 u8 mask;555 556 if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {557 ath5k_eeprom_read_freq_list(ah, &offset,558 AR5K_EEPROM_N_5GHZ_CHAN, pcal,559 AR5K_EEPROM_MODE_11A);560 } else {561 mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version);562 563 AR5K_EEPROM_READ(offset++, val);564 pcal[0].freq = (val >> 9) & mask;565 pcal[1].freq = (val >> 2) & mask;566 pcal[2].freq = (val << 5) & mask;567 568 AR5K_EEPROM_READ(offset++, val);569 pcal[2].freq |= (val >> 11) & 0x1f;570 pcal[3].freq = (val >> 4) & mask;571 pcal[4].freq = (val << 3) & mask;572 573 AR5K_EEPROM_READ(offset++, val);574 pcal[4].freq |= (val >> 13) & 0x7;575 pcal[5].freq = (val >> 6) & mask;576 pcal[6].freq = (val << 1) & mask;577 578 AR5K_EEPROM_READ(offset++, val);579 pcal[6].freq |= (val >> 15) & 0x1;580 pcal[7].freq = (val >> 8) & mask;581 pcal[8].freq = (val >> 1) & mask;582 pcal[9].freq = (val << 6) & mask;583 584 AR5K_EEPROM_READ(offset++, val);585 pcal[9].freq |= (val >> 10) & 0x3f;586 587 /* Fixed number of piers */588 ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10;589 590 for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) {591 pcal[i].freq = ath5k_eeprom_bin2freq(ee,592 pcal[i].freq, AR5K_EEPROM_MODE_11A);593 }594 }595 596 return 0;597}598 599/* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */600static inline int601ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)602{603 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;604 struct ath5k_chan_pcal_info *pcal;605 606 switch (mode) {607 case AR5K_EEPROM_MODE_11B:608 pcal = ee->ee_pwr_cal_b;609 break;610 case AR5K_EEPROM_MODE_11G:611 pcal = ee->ee_pwr_cal_g;612 break;613 default:614 return -EINVAL;615 }616 617 ath5k_eeprom_read_freq_list(ah, &offset,618 AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal,619 mode);620 621 return 0;622}623 624 625/*626 * Read power calibration for RF5111 chips627 *628 * For RF5111 we have an XPD -eXternal Power Detector- curve629 * for each calibrated channel. Each curve has 0,5dB Power steps630 * on x axis and PCDAC steps (offsets) on y axis and looks like an631 * exponential function. To recreate the curve we read 11 points632 * here and interpolate later.633 */634 635/* Used to match PCDAC steps with power values on RF5111 chips636 * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC637 * steps that match with the power values we read from eeprom. On638 * older eeprom versions (< 3.2) these steps are equally spaced at639 * 10% of the pcdac curve -until the curve reaches its maximum-640 * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2)641 * these 11 steps are spaced in a different way. This function returns642 * the pcdac steps based on eeprom version and curve min/max so that we643 * can have pcdac/pwr points.644 */645static inline void646ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)647{648 static const u16 intercepts3[] = {649 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100650 };651 static const u16 intercepts3_2[] = {652 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100653 };654 const u16 *ip;655 int i;656 657 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2)658 ip = intercepts3_2;659 else660 ip = intercepts3;661 662 for (i = 0; i < ARRAY_SIZE(intercepts3); i++)663 vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;664}665 666static int667ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)668{669 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;670 struct ath5k_chan_pcal_info *chinfo;671 u8 pier, pdg;672 673 switch (mode) {674 case AR5K_EEPROM_MODE_11A:675 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))676 return 0;677 chinfo = ee->ee_pwr_cal_a;678 break;679 case AR5K_EEPROM_MODE_11B:680 if (!AR5K_EEPROM_HDR_11B(ee->ee_header))681 return 0;682 chinfo = ee->ee_pwr_cal_b;683 break;684 case AR5K_EEPROM_MODE_11G:685 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))686 return 0;687 chinfo = ee->ee_pwr_cal_g;688 break;689 default:690 return -EINVAL;691 }692 693 for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {694 if (!chinfo[pier].pd_curves)695 continue;696 697 for (pdg = 0; pdg < AR5K_EEPROM_N_PD_CURVES; pdg++) {698 struct ath5k_pdgain_info *pd =699 &chinfo[pier].pd_curves[pdg];700 701 kfree(pd->pd_step);702 kfree(pd->pd_pwr);703 }704 705 kfree(chinfo[pier].pd_curves);706 }707 708 return 0;709}710 711/* Convert RF5111 specific data to generic raw data712 * used by interpolation code */713static int714ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,715 struct ath5k_chan_pcal_info *chinfo)716{717 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;718 struct ath5k_chan_pcal_info_rf5111 *pcinfo;719 struct ath5k_pdgain_info *pd;720 u8 pier, point, idx;721 u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];722 723 /* Fill raw data for each calibration pier */724 for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {725 726 pcinfo = &chinfo[pier].rf5111_info;727 728 /* Allocate pd_curves for this cal pier */729 chinfo[pier].pd_curves =730 kcalloc(AR5K_EEPROM_N_PD_CURVES,731 sizeof(struct ath5k_pdgain_info),732 GFP_KERNEL);733 734 if (!chinfo[pier].pd_curves)735 goto err_out;736 737 /* Only one curve for RF5111738 * find out which one and place739 * in pd_curves.740 * Note: ee_x_gain is reversed here */741 for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {742 743 if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) {744 pdgain_idx[0] = idx;745 break;746 }747 }748 749 if (idx == AR5K_EEPROM_N_PD_CURVES)750 goto err_out;751 752 ee->ee_pd_gains[mode] = 1;753 754 pd = &chinfo[pier].pd_curves[idx];755 756 pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111;757 758 /* Allocate pd points for this curve */759 pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,760 sizeof(u8), GFP_KERNEL);761 if (!pd->pd_step)762 goto err_out;763 764 pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,765 sizeof(s16), GFP_KERNEL);766 if (!pd->pd_pwr)767 goto err_out;768 769 /* Fill raw dataset770 * (convert power to 0.25dB units771 * for RF5112 compatibility) */772 for (point = 0; point < pd->pd_points; point++) {773 774 /* Absolute values */775 pd->pd_pwr[point] = 2 * pcinfo->pwr[point];776 777 /* Already sorted */778 pd->pd_step[point] = pcinfo->pcdac[point];779 }780 781 /* Set min/max pwr */782 chinfo[pier].min_pwr = pd->pd_pwr[0];783 chinfo[pier].max_pwr = pd->pd_pwr[10];784 785 }786 787 return 0;788 789err_out:790 ath5k_eeprom_free_pcal_info(ah, mode);791 return -ENOMEM;792}793 794/* Parse EEPROM data */795static int796ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode)797{798 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;799 struct ath5k_chan_pcal_info *pcal;800 int offset, ret;801 int i;802 u16 val;803 804 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);805 switch (mode) {806 case AR5K_EEPROM_MODE_11A:807 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))808 return 0;809 810 ret = ath5k_eeprom_init_11a_pcal_freq(ah,811 offset + AR5K_EEPROM_GROUP1_OFFSET);812 if (ret < 0)813 return ret;814 815 offset += AR5K_EEPROM_GROUP2_OFFSET;816 pcal = ee->ee_pwr_cal_a;817 break;818 case AR5K_EEPROM_MODE_11B:819 if (!AR5K_EEPROM_HDR_11B(ee->ee_header) &&820 !AR5K_EEPROM_HDR_11G(ee->ee_header))821 return 0;822 823 pcal = ee->ee_pwr_cal_b;824 offset += AR5K_EEPROM_GROUP3_OFFSET;825 826 /* fixed piers */827 pcal[0].freq = 2412;828 pcal[1].freq = 2447;829 pcal[2].freq = 2484;830 ee->ee_n_piers[mode] = 3;831 break;832 case AR5K_EEPROM_MODE_11G:833 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))834 return 0;835 836 pcal = ee->ee_pwr_cal_g;837 offset += AR5K_EEPROM_GROUP4_OFFSET;838 839 /* fixed piers */840 pcal[0].freq = 2312;841 pcal[1].freq = 2412;842 pcal[2].freq = 2484;843 ee->ee_n_piers[mode] = 3;844 break;845 default:846 return -EINVAL;847 }848 849 for (i = 0; i < ee->ee_n_piers[mode]; i++) {850 struct ath5k_chan_pcal_info_rf5111 *cdata =851 &pcal[i].rf5111_info;852 853 AR5K_EEPROM_READ(offset++, val);854 cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M);855 cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M);856 cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M);857 858 AR5K_EEPROM_READ(offset++, val);859 cdata->pwr[0] |= ((val >> 14) & 0x3);860 cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M);861 cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M);862 cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M);863 864 AR5K_EEPROM_READ(offset++, val);865 cdata->pwr[3] |= ((val >> 12) & 0xf);866 cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M);867 cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M);868 869 AR5K_EEPROM_READ(offset++, val);870 cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M);871 cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M);872 cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M);873 874 AR5K_EEPROM_READ(offset++, val);875 cdata->pwr[8] |= ((val >> 14) & 0x3);876 cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M);877 cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M);878 879 ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min,880 cdata->pcdac_max, cdata->pcdac);881 }882 883 return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal);884}885 886 887/*888 * Read power calibration for RF5112 chips889 *890 * For RF5112 we have 4 XPD -eXternal Power Detector- curves891 * for each calibrated channel on 0, -6, -12 and -18dBm but we only892 * use the higher (3) and the lower (0) curves. Each curve has 0.5dB893 * power steps on x axis and PCDAC steps on y axis and looks like a894 * linear function. To recreate the curve and pass the power values895 * on hw, we read 4 points for xpd 0 (lower gain -> max power)896 * and 3 points for xpd 3 (higher gain -> lower power) here and897 * interpolate later.898 *899 * Note: Many vendors just use xpd 0 so xpd 3 is zeroed.900 */901 902/* Convert RF5112 specific data to generic raw data903 * used by interpolation code */904static int905ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,906 struct ath5k_chan_pcal_info *chinfo)907{908 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;909 struct ath5k_chan_pcal_info_rf5112 *pcinfo;910 u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];911 unsigned int pier, pdg, point;912 913 /* Fill raw data for each calibration pier */914 for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {915 916 pcinfo = &chinfo[pier].rf5112_info;917 918 /* Allocate pd_curves for this cal pier */919 chinfo[pier].pd_curves =920 kcalloc(AR5K_EEPROM_N_PD_CURVES,921 sizeof(struct ath5k_pdgain_info),922 GFP_KERNEL);923 924 if (!chinfo[pier].pd_curves)925 goto err_out;926 927 /* Fill pd_curves */928 for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {929 930 u8 idx = pdgain_idx[pdg];931 struct ath5k_pdgain_info *pd =932 &chinfo[pier].pd_curves[idx];933 934 /* Lowest gain curve (max power) */935 if (pdg == 0) {936 /* One more point for better accuracy */937 pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS;938 939 /* Allocate pd points for this curve */940 pd->pd_step = kcalloc(pd->pd_points,941 sizeof(u8), GFP_KERNEL);942 943 if (!pd->pd_step)944 goto err_out;945 946 pd->pd_pwr = kcalloc(pd->pd_points,947 sizeof(s16), GFP_KERNEL);948 949 if (!pd->pd_pwr)950 goto err_out;951 952 /* Fill raw dataset953 * (all power levels are in 0.25dB units) */954 pd->pd_step[0] = pcinfo->pcdac_x0[0];955 pd->pd_pwr[0] = pcinfo->pwr_x0[0];956 957 for (point = 1; point < pd->pd_points;958 point++) {959 /* Absolute values */960 pd->pd_pwr[point] =961 pcinfo->pwr_x0[point];962 963 /* Deltas */964 pd->pd_step[point] =965 pd->pd_step[point - 1] +966 pcinfo->pcdac_x0[point];967 }968 969 /* Set min power for this frequency */970 chinfo[pier].min_pwr = pd->pd_pwr[0];971 972 /* Highest gain curve (min power) */973 } else if (pdg == 1) {974 975 pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS;976 977 /* Allocate pd points for this curve */978 pd->pd_step = kcalloc(pd->pd_points,979 sizeof(u8), GFP_KERNEL);980 981 if (!pd->pd_step)982 goto err_out;983 984 pd->pd_pwr = kcalloc(pd->pd_points,985 sizeof(s16), GFP_KERNEL);986 987 if (!pd->pd_pwr)988 goto err_out;989 990 /* Fill raw dataset991 * (all power levels are in 0.25dB units) */992 for (point = 0; point < pd->pd_points;993 point++) {994 /* Absolute values */995 pd->pd_pwr[point] =996 pcinfo->pwr_x3[point];997 998 /* Fixed points */999 pd->pd_step[point] =1000 pcinfo->pcdac_x3[point];1001 }1002 1003 /* Since we have a higher gain curve1004 * override min power */1005 chinfo[pier].min_pwr = pd->pd_pwr[0];1006 }1007 }1008 }1009 1010 return 0;1011 1012err_out:1013 ath5k_eeprom_free_pcal_info(ah, mode);1014 return -ENOMEM;1015}1016 1017/* Parse EEPROM data */1018static int1019ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode)1020{1021 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1022 struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info;1023 struct ath5k_chan_pcal_info *gen_chan_info;1024 u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];1025 u32 offset;1026 u8 i, c;1027 u16 val;1028 u8 pd_gains = 0;1029 1030 /* Count how many curves we have and1031 * identify them (which one of the 41032 * available curves we have on each count).1033 * Curves are stored from lower (x0) to1034 * higher (x3) gain */1035 for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) {1036 /* ee_x_gain[mode] is x gain mask */1037 if ((ee->ee_x_gain[mode] >> i) & 0x1)1038 pdgain_idx[pd_gains++] = i;1039 }1040 ee->ee_pd_gains[mode] = pd_gains;1041 1042 if (pd_gains == 0 || pd_gains > 2)1043 return -EINVAL;1044 1045 switch (mode) {1046 case AR5K_EEPROM_MODE_11A:1047 /*1048 * Read 5GHz EEPROM channels1049 */1050 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);1051 ath5k_eeprom_init_11a_pcal_freq(ah, offset);1052 1053 offset += AR5K_EEPROM_GROUP2_OFFSET;1054 gen_chan_info = ee->ee_pwr_cal_a;1055 break;1056 case AR5K_EEPROM_MODE_11B:1057 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);1058 if (AR5K_EEPROM_HDR_11A(ee->ee_header))1059 offset += AR5K_EEPROM_GROUP3_OFFSET;1060 1061 /* NB: frequency piers parsed during mode init */1062 gen_chan_info = ee->ee_pwr_cal_b;1063 break;1064 case AR5K_EEPROM_MODE_11G:1065 offset = AR5K_EEPROM_GROUPS_START(ee->ee_version);1066 if (AR5K_EEPROM_HDR_11A(ee->ee_header))1067 offset += AR5K_EEPROM_GROUP4_OFFSET;1068 else if (AR5K_EEPROM_HDR_11B(ee->ee_header))1069 offset += AR5K_EEPROM_GROUP2_OFFSET;1070 1071 /* NB: frequency piers parsed during mode init */1072 gen_chan_info = ee->ee_pwr_cal_g;1073 break;1074 default:1075 return -EINVAL;1076 }1077 1078 for (i = 0; i < ee->ee_n_piers[mode]; i++) {1079 chan_pcal_info = &gen_chan_info[i].rf5112_info;1080 1081 /* Power values in quarter dB1082 * for the lower xpd gain curve1083 * (0 dBm -> higher output power) */1084 for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) {1085 AR5K_EEPROM_READ(offset++, val);1086 chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff);1087 chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff);1088 }1089 1090 /* PCDAC steps1091 * corresponding to the above power1092 * measurements */1093 AR5K_EEPROM_READ(offset++, val);1094 chan_pcal_info->pcdac_x0[1] = (val & 0x1f);1095 chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f);1096 chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f);1097 1098 /* Power values in quarter dB1099 * for the higher xpd gain curve1100 * (18 dBm -> lower output power) */1101 AR5K_EEPROM_READ(offset++, val);1102 chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff);1103 chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff);1104 1105 AR5K_EEPROM_READ(offset++, val);1106 chan_pcal_info->pwr_x3[2] = (val & 0xff);1107 1108 /* PCDAC steps1109 * corresponding to the above power1110 * measurements (fixed) */1111 chan_pcal_info->pcdac_x3[0] = 20;1112 chan_pcal_info->pcdac_x3[1] = 35;1113 chan_pcal_info->pcdac_x3[2] = 63;1114 1115 if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) {1116 chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f);1117 1118 /* Last xpd0 power level is also channel maximum */1119 gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3];1120 } else {1121 chan_pcal_info->pcdac_x0[0] = 1;1122 gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff);1123 }1124 1125 }1126 1127 return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info);1128}1129 1130 1131/*1132 * Read power calibration for RF2413 chips1133 *1134 * For RF2413 we have a Power to PDDAC table (Power Detector)1135 * instead of a PCDAC and 4 pd gain curves for each calibrated channel.1136 * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y1137 * axis and looks like an exponential function like the RF5111 curve.1138 *1139 * To recreate the curves we read here the points and interpolate1140 * later. Note that in most cases only 2 (higher and lower) curves are1141 * used (like RF5112) but vendors have the opportunity to include all1142 * 4 curves on eeprom. The final curve (higher power) has an extra1143 * point for better accuracy like RF5112.1144 */1145 1146/* For RF2413 power calibration data doesn't start on a fixed location and1147 * if a mode is not supported, its section is missing -not zeroed-.1148 * So we need to calculate the starting offset for each section by using1149 * these two functions */1150 1151/* Return the size of each section based on the mode and the number of pd1152 * gains available (maximum 4). */1153static inline unsigned int1154ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode)1155{1156 static const unsigned int pdgains_size[] = { 4, 6, 9, 12 };1157 unsigned int sz;1158 1159 sz = pdgains_size[ee->ee_pd_gains[mode] - 1];1160 sz *= ee->ee_n_piers[mode];1161 1162 return sz;1163}1164 1165/* Return the starting offset for a section based on the modes supported1166 * and each section's size. */1167static unsigned int1168ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode)1169{1170 u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4);1171 1172 switch (mode) {1173 case AR5K_EEPROM_MODE_11G:1174 if (AR5K_EEPROM_HDR_11B(ee->ee_header))1175 offset += ath5k_pdgains_size_2413(ee,1176 AR5K_EEPROM_MODE_11B) +1177 AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;1178 fallthrough;1179 case AR5K_EEPROM_MODE_11B:1180 if (AR5K_EEPROM_HDR_11A(ee->ee_header))1181 offset += ath5k_pdgains_size_2413(ee,1182 AR5K_EEPROM_MODE_11A) +1183 AR5K_EEPROM_N_5GHZ_CHAN / 2;1184 fallthrough;1185 case AR5K_EEPROM_MODE_11A:1186 break;1187 default:1188 break;1189 }1190 1191 return offset;1192}1193 1194/* Convert RF2413 specific data to generic raw data1195 * used by interpolation code */1196static int1197ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,1198 struct ath5k_chan_pcal_info *chinfo)1199{1200 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1201 struct ath5k_chan_pcal_info_rf2413 *pcinfo;1202 u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];1203 unsigned int pier, pdg, point;1204 1205 /* Fill raw data for each calibration pier */1206 for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {1207 1208 pcinfo = &chinfo[pier].rf2413_info;1209 1210 /* Allocate pd_curves for this cal pier */1211 chinfo[pier].pd_curves =1212 kcalloc(AR5K_EEPROM_N_PD_CURVES,1213 sizeof(struct ath5k_pdgain_info),1214 GFP_KERNEL);1215 1216 if (!chinfo[pier].pd_curves)1217 goto err_out;1218 1219 /* Fill pd_curves */1220 for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {1221 1222 u8 idx = pdgain_idx[pdg];1223 struct ath5k_pdgain_info *pd =1224 &chinfo[pier].pd_curves[idx];1225 1226 /* One more point for the highest power1227 * curve (lowest gain) */1228 if (pdg == ee->ee_pd_gains[mode] - 1)1229 pd->pd_points = AR5K_EEPROM_N_PD_POINTS;1230 else1231 pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1;1232 1233 /* Allocate pd points for this curve */1234 pd->pd_step = kcalloc(pd->pd_points,1235 sizeof(u8), GFP_KERNEL);1236 1237 if (!pd->pd_step)1238 goto err_out;1239 1240 pd->pd_pwr = kcalloc(pd->pd_points,1241 sizeof(s16), GFP_KERNEL);1242 1243 if (!pd->pd_pwr)1244 goto err_out;1245 1246 /* Fill raw dataset1247 * convert all pwr levels to1248 * quarter dB for RF5112 compatibility */1249 pd->pd_step[0] = pcinfo->pddac_i[pdg];1250 pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg];1251 1252 for (point = 1; point < pd->pd_points; point++) {1253 1254 pd->pd_pwr[point] = pd->pd_pwr[point - 1] +1255 2 * pcinfo->pwr[pdg][point - 1];1256 1257 pd->pd_step[point] = pd->pd_step[point - 1] +1258 pcinfo->pddac[pdg][point - 1];1259 1260 }1261 1262 /* Highest gain curve -> min power */1263 if (pdg == 0)1264 chinfo[pier].min_pwr = pd->pd_pwr[0];1265 1266 /* Lowest gain curve -> max power */1267 if (pdg == ee->ee_pd_gains[mode] - 1)1268 chinfo[pier].max_pwr =1269 pd->pd_pwr[pd->pd_points - 1];1270 }1271 }1272 1273 return 0;1274 1275err_out:1276 ath5k_eeprom_free_pcal_info(ah, mode);1277 return -ENOMEM;1278}1279 1280/* Parse EEPROM data */1281static int1282ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode)1283{1284 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1285 struct ath5k_chan_pcal_info_rf2413 *pcinfo;1286 struct ath5k_chan_pcal_info *chinfo;1287 u8 *pdgain_idx = ee->ee_pdc_to_idx[mode];1288 u32 offset;1289 int idx, i;1290 u16 val;1291 u8 pd_gains = 0;1292 1293 /* Count how many curves we have and1294 * identify them (which one of the 41295 * available curves we have on each count).1296 * Curves are stored from higher to1297 * lower gain so we go backwards */1298 for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) {1299 /* ee_x_gain[mode] is x gain mask */1300 if ((ee->ee_x_gain[mode] >> idx) & 0x1)1301 pdgain_idx[pd_gains++] = idx;1302 1303 }1304 ee->ee_pd_gains[mode] = pd_gains;1305 1306 if (pd_gains == 0)1307 return -EINVAL;1308 1309 offset = ath5k_cal_data_offset_2413(ee, mode);1310 switch (mode) {1311 case AR5K_EEPROM_MODE_11A:1312 if (!AR5K_EEPROM_HDR_11A(ee->ee_header))1313 return 0;1314 1315 ath5k_eeprom_init_11a_pcal_freq(ah, offset);1316 offset += AR5K_EEPROM_N_5GHZ_CHAN / 2;1317 chinfo = ee->ee_pwr_cal_a;1318 break;1319 case AR5K_EEPROM_MODE_11B:1320 if (!AR5K_EEPROM_HDR_11B(ee->ee_header))1321 return 0;1322 1323 ath5k_eeprom_init_11bg_2413(ah, mode, offset);1324 offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;1325 chinfo = ee->ee_pwr_cal_b;1326 break;1327 case AR5K_EEPROM_MODE_11G:1328 if (!AR5K_EEPROM_HDR_11G(ee->ee_header))1329 return 0;1330 1331 ath5k_eeprom_init_11bg_2413(ah, mode, offset);1332 offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2;1333 chinfo = ee->ee_pwr_cal_g;1334 break;1335 default:1336 return -EINVAL;1337 }1338 1339 for (i = 0; i < ee->ee_n_piers[mode]; i++) {1340 pcinfo = &chinfo[i].rf2413_info;1341 1342 /*1343 * Read pwr_i, pddac_i and the first1344 * 2 pd points (pwr, pddac)1345 */1346 AR5K_EEPROM_READ(offset++, val);1347 pcinfo->pwr_i[0] = val & 0x1f;1348 pcinfo->pddac_i[0] = (val >> 5) & 0x7f;1349 pcinfo->pwr[0][0] = (val >> 12) & 0xf;1350 1351 AR5K_EEPROM_READ(offset++, val);1352 pcinfo->pddac[0][0] = val & 0x3f;1353 pcinfo->pwr[0][1] = (val >> 6) & 0xf;1354 pcinfo->pddac[0][1] = (val >> 10) & 0x3f;1355 1356 AR5K_EEPROM_READ(offset++, val);1357 pcinfo->pwr[0][2] = val & 0xf;1358 pcinfo->pddac[0][2] = (val >> 4) & 0x3f;1359 1360 pcinfo->pwr[0][3] = 0;1361 pcinfo->pddac[0][3] = 0;1362 1363 if (pd_gains > 1) {1364 /*1365 * Pd gain 0 is not the last pd gain1366 * so it only has 2 pd points.1367 * Continue with pd gain 1.1368 */1369 pcinfo->pwr_i[1] = (val >> 10) & 0x1f;1370 1371 pcinfo->pddac_i[1] = (val >> 15) & 0x1;1372 AR5K_EEPROM_READ(offset++, val);1373 pcinfo->pddac_i[1] |= (val & 0x3F) << 1;1374 1375 pcinfo->pwr[1][0] = (val >> 6) & 0xf;1376 pcinfo->pddac[1][0] = (val >> 10) & 0x3f;1377 1378 AR5K_EEPROM_READ(offset++, val);1379 pcinfo->pwr[1][1] = val & 0xf;1380 pcinfo->pddac[1][1] = (val >> 4) & 0x3f;1381 pcinfo->pwr[1][2] = (val >> 10) & 0xf;1382 1383 pcinfo->pddac[1][2] = (val >> 14) & 0x3;1384 AR5K_EEPROM_READ(offset++, val);1385 pcinfo->pddac[1][2] |= (val & 0xF) << 2;1386 1387 pcinfo->pwr[1][3] = 0;1388 pcinfo->pddac[1][3] = 0;1389 } else if (pd_gains == 1) {1390 /*1391 * Pd gain 0 is the last one so1392 * read the extra point.1393 */1394 pcinfo->pwr[0][3] = (val >> 10) & 0xf;1395 1396 pcinfo->pddac[0][3] = (val >> 14) & 0x3;1397 AR5K_EEPROM_READ(offset++, val);1398 pcinfo->pddac[0][3] |= (val & 0xF) << 2;1399 }1400 1401 /*1402 * Proceed with the other pd_gains1403 * as above.1404 */1405 if (pd_gains > 2) {1406 pcinfo->pwr_i[2] = (val >> 4) & 0x1f;1407 pcinfo->pddac_i[2] = (val >> 9) & 0x7f;1408 1409 AR5K_EEPROM_READ(offset++, val);1410 pcinfo->pwr[2][0] = (val >> 0) & 0xf;1411 pcinfo->pddac[2][0] = (val >> 4) & 0x3f;1412 pcinfo->pwr[2][1] = (val >> 10) & 0xf;1413 1414 pcinfo->pddac[2][1] = (val >> 14) & 0x3;1415 AR5K_EEPROM_READ(offset++, val);1416 pcinfo->pddac[2][1] |= (val & 0xF) << 2;1417 1418 pcinfo->pwr[2][2] = (val >> 4) & 0xf;1419 pcinfo->pddac[2][2] = (val >> 8) & 0x3f;1420 1421 pcinfo->pwr[2][3] = 0;1422 pcinfo->pddac[2][3] = 0;1423 } else if (pd_gains == 2) {1424 pcinfo->pwr[1][3] = (val >> 4) & 0xf;1425 pcinfo->pddac[1][3] = (val >> 8) & 0x3f;1426 }1427 1428 if (pd_gains > 3) {1429 pcinfo->pwr_i[3] = (val >> 14) & 0x3;1430 AR5K_EEPROM_READ(offset++, val);1431 pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2;1432 1433 pcinfo->pddac_i[3] = (val >> 3) & 0x7f;1434 pcinfo->pwr[3][0] = (val >> 10) & 0xf;1435 pcinfo->pddac[3][0] = (val >> 14) & 0x3;1436 1437 AR5K_EEPROM_READ(offset++, val);1438 pcinfo->pddac[3][0] |= (val & 0xF) << 2;1439 pcinfo->pwr[3][1] = (val >> 4) & 0xf;1440 pcinfo->pddac[3][1] = (val >> 8) & 0x3f;1441 1442 pcinfo->pwr[3][2] = (val >> 14) & 0x3;1443 AR5K_EEPROM_READ(offset++, val);1444 pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2;1445 1446 pcinfo->pddac[3][2] = (val >> 2) & 0x3f;1447 pcinfo->pwr[3][3] = (val >> 8) & 0xf;1448 1449 pcinfo->pddac[3][3] = (val >> 12) & 0xF;1450 AR5K_EEPROM_READ(offset++, val);1451 pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4;1452 } else if (pd_gains == 3) {1453 pcinfo->pwr[2][3] = (val >> 14) & 0x3;1454 AR5K_EEPROM_READ(offset++, val);1455 pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2;1456 1457 pcinfo->pddac[2][3] = (val >> 2) & 0x3f;1458 }1459 }1460 1461 return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo);1462}1463 1464 1465/*1466 * Read per rate target power (this is the maximum tx power1467 * supported by the card). This info is used when setting1468 * tx power, no matter the channel.1469 *1470 * This also works for v5 EEPROMs.1471 */1472static int1473ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)1474{1475 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1476 struct ath5k_rate_pcal_info *rate_pcal_info;1477 u8 *rate_target_pwr_num;1478 u32 offset;1479 u16 val;1480 int i;1481 1482 offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1);1483 rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode];1484 switch (mode) {1485 case AR5K_EEPROM_MODE_11A:1486 offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);1487 rate_pcal_info = ee->ee_rate_tpwr_a;1488 ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_RATE_CHAN;1489 break;1490 case AR5K_EEPROM_MODE_11B:1491 offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);1492 rate_pcal_info = ee->ee_rate_tpwr_b;1493 ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */1494 break;1495 case AR5K_EEPROM_MODE_11G:1496 offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version);1497 rate_pcal_info = ee->ee_rate_tpwr_g;1498 ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN;1499 break;1500 default:1501 return -EINVAL;1502 }1503 1504 /* Different freq mask for older eeproms (<= v3.2) */1505 if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) {1506 for (i = 0; i < (*rate_target_pwr_num); i++) {1507 AR5K_EEPROM_READ(offset++, val);1508 rate_pcal_info[i].freq =1509 ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode);1510 1511 rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f);1512 rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f;1513 1514 AR5K_EEPROM_READ(offset++, val);1515 1516 if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||1517 val == 0) {1518 (*rate_target_pwr_num) = i;1519 break;1520 }1521 1522 rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7);1523 rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f);1524 rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f);1525 }1526 } else {1527 for (i = 0; i < (*rate_target_pwr_num); i++) {1528 AR5K_EEPROM_READ(offset++, val);1529 rate_pcal_info[i].freq =1530 ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode);1531 1532 rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f);1533 rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f;1534 1535 AR5K_EEPROM_READ(offset++, val);1536 1537 if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS ||1538 val == 0) {1539 (*rate_target_pwr_num) = i;1540 break;1541 }1542 1543 rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf;1544 rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f);1545 rate_pcal_info[i].target_power_54 = (val & 0x3f);1546 }1547 }1548 1549 return 0;1550}1551 1552 1553/*1554 * Read per channel calibration info from EEPROM1555 *1556 * This info is used to calibrate the baseband power table. Imagine1557 * that for each channel there is a power curve that's hw specific1558 * (depends on amplifier etc) and we try to "correct" this curve using1559 * offsets we pass on to phy chip (baseband -> before amplifier) so that1560 * it can use accurate power values when setting tx power (takes amplifier's1561 * performance on each channel into account).1562 *1563 * EEPROM provides us with the offsets for some pre-calibrated channels1564 * and we have to interpolate to create the full table for these channels and1565 * also the table for any channel.1566 */1567static int1568ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)1569{1570 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1571 int (*read_pcal)(struct ath5k_hw *hw, int mode);1572 int mode;1573 int err;1574 1575 if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) &&1576 (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1))1577 read_pcal = ath5k_eeprom_read_pcal_info_5112;1578 else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) &&1579 (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2))1580 read_pcal = ath5k_eeprom_read_pcal_info_2413;1581 else1582 read_pcal = ath5k_eeprom_read_pcal_info_5111;1583 1584 1585 for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G;1586 mode++) {1587 err = read_pcal(ah, mode);1588 if (err)1589 return err;1590 1591 err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode);1592 if (err < 0)1593 return err;1594 }1595 1596 return 0;1597}1598 1599/* Read conformance test limits used for regulatory control */1600static int1601ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)1602{1603 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1604 struct ath5k_edge_power *rep;1605 unsigned int fmask, pmask;1606 unsigned int ctl_mode;1607 int i, j;1608 u32 offset;1609 u16 val;1610 1611 pmask = AR5K_EEPROM_POWER_M;1612 fmask = AR5K_EEPROM_FREQ_M(ee->ee_version);1613 offset = AR5K_EEPROM_CTL(ee->ee_version);1614 ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version);1615 for (i = 0; i < ee->ee_ctls; i += 2) {1616 AR5K_EEPROM_READ(offset++, val);1617 ee->ee_ctl[i] = (val >> 8) & 0xff;1618 ee->ee_ctl[i + 1] = val & 0xff;1619 }1620 1621 offset = AR5K_EEPROM_GROUP8_OFFSET;1622 if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0)1623 offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) -1624 AR5K_EEPROM_GROUP5_OFFSET;1625 else1626 offset += AR5K_EEPROM_GROUPS_START(ee->ee_version);1627 1628 rep = ee->ee_ctl_pwr;1629 for (i = 0; i < ee->ee_ctls; i++) {1630 switch (ee->ee_ctl[i] & AR5K_CTL_MODE_M) {1631 case AR5K_CTL_11A:1632 case AR5K_CTL_TURBO:1633 ctl_mode = AR5K_EEPROM_MODE_11A;1634 break;1635 default:1636 ctl_mode = AR5K_EEPROM_MODE_11G;1637 break;1638 }1639 if (ee->ee_ctl[i] == 0) {1640 if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3)1641 offset += 8;1642 else1643 offset += 7;1644 rep += AR5K_EEPROM_N_EDGES;1645 continue;1646 }1647 if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) {1648 for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {1649 AR5K_EEPROM_READ(offset++, val);1650 rep[j].freq = (val >> 8) & fmask;1651 rep[j + 1].freq = val & fmask;1652 }1653 for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) {1654 AR5K_EEPROM_READ(offset++, val);1655 rep[j].edge = (val >> 8) & pmask;1656 rep[j].flag = (val >> 14) & 1;1657 rep[j + 1].edge = val & pmask;1658 rep[j + 1].flag = (val >> 6) & 1;1659 }1660 } else {1661 AR5K_EEPROM_READ(offset++, val);1662 rep[0].freq = (val >> 9) & fmask;1663 rep[1].freq = (val >> 2) & fmask;1664 rep[2].freq = (val << 5) & fmask;1665 1666 AR5K_EEPROM_READ(offset++, val);1667 rep[2].freq |= (val >> 11) & 0x1f;1668 rep[3].freq = (val >> 4) & fmask;1669 rep[4].freq = (val << 3) & fmask;1670 1671 AR5K_EEPROM_READ(offset++, val);1672 rep[4].freq |= (val >> 13) & 0x7;1673 rep[5].freq = (val >> 6) & fmask;1674 rep[6].freq = (val << 1) & fmask;1675 1676 AR5K_EEPROM_READ(offset++, val);1677 rep[6].freq |= (val >> 15) & 0x1;1678 rep[7].freq = (val >> 8) & fmask;1679 1680 rep[0].edge = (val >> 2) & pmask;1681 rep[1].edge = (val << 4) & pmask;1682 1683 AR5K_EEPROM_READ(offset++, val);1684 rep[1].edge |= (val >> 12) & 0xf;1685 rep[2].edge = (val >> 6) & pmask;1686 rep[3].edge = val & pmask;1687 1688 AR5K_EEPROM_READ(offset++, val);1689 rep[4].edge = (val >> 10) & pmask;1690 rep[5].edge = (val >> 4) & pmask;1691 rep[6].edge = (val << 2) & pmask;1692 1693 AR5K_EEPROM_READ(offset++, val);1694 rep[6].edge |= (val >> 14) & 0x3;1695 rep[7].edge = (val >> 8) & pmask;1696 }1697 for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) {1698 rep[j].freq = ath5k_eeprom_bin2freq(ee,1699 rep[j].freq, ctl_mode);1700 }1701 rep += AR5K_EEPROM_N_EDGES;1702 }1703 1704 return 0;1705}1706 1707static int1708ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)1709{1710 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;1711 u32 offset;1712 u16 val;1713 int i;1714 1715 offset = AR5K_EEPROM_CTL(ee->ee_version) +1716 AR5K_EEPROM_N_CTLS(ee->ee_version);1717 1718 if (ee->ee_version < AR5K_EEPROM_VERSION_5_3) {1719 /* No spur info for 5GHz */1720 ee->ee_spur_chans[0][0] = AR5K_EEPROM_NO_SPUR;1721 /* 2 channels for 2GHz (2464/2420) */1722 ee->ee_spur_chans[0][1] = AR5K_EEPROM_5413_SPUR_CHAN_1;1723 ee->ee_spur_chans[1][1] = AR5K_EEPROM_5413_SPUR_CHAN_2;1724 ee->ee_spur_chans[2][1] = AR5K_EEPROM_NO_SPUR;1725 } else if (ee->ee_version >= AR5K_EEPROM_VERSION_5_3) {1726 for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) {1727 AR5K_EEPROM_READ(offset, val);1728 ee->ee_spur_chans[i][0] = val;1729 AR5K_EEPROM_READ(offset + AR5K_EEPROM_N_SPUR_CHANS,1730 val);1731 ee->ee_spur_chans[i][1] = val;1732 offset++;1733 }1734 }1735 1736 return 0;1737}1738 1739 1740/***********************\1741* Init/Detach functions *1742\***********************/1743 1744/*1745 * Initialize eeprom data structure1746 */1747int1748ath5k_eeprom_init(struct ath5k_hw *ah)1749{1750 int err;1751 1752 err = ath5k_eeprom_init_header(ah);1753 if (err < 0)1754 return err;1755 1756 err = ath5k_eeprom_init_modes(ah);1757 if (err < 0)1758 return err;1759 1760 err = ath5k_eeprom_read_pcal_info(ah);1761 if (err < 0)1762 return err;1763 1764 err = ath5k_eeprom_read_ctl_info(ah);1765 if (err < 0)1766 return err;1767 1768 err = ath5k_eeprom_read_spur_chans(ah);1769 if (err < 0)1770 return err;1771 1772 return 0;1773}1774 1775void1776ath5k_eeprom_detach(struct ath5k_hw *ah)1777{1778 u8 mode;1779 1780 for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)1781 ath5k_eeprom_free_pcal_info(ah, mode);1782}1783 1784int1785ath5k_eeprom_mode_from_channel(struct ath5k_hw *ah,1786 struct ieee80211_channel *channel)1787{1788 switch (channel->hw_value) {1789 case AR5K_MODE_11A:1790 return AR5K_EEPROM_MODE_11A;1791 case AR5K_MODE_11G:1792 return AR5K_EEPROM_MODE_11G;1793 case AR5K_MODE_11B:1794 return AR5K_EEPROM_MODE_11B;1795 default:1796 ATH5K_WARN(ah, "channel is not A/B/G!");1797 return AR5K_EEPROM_MODE_11A;1798 }1799}1800