brintos

brintos / linux-shallow public Read only

0
0
Text · 48.1 KiB · 58d3e86 Raw
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