162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
562306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
662306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
962306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1062306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1162306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1262306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1362306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1462306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "hw.h"
1862306a36Sopenharmony_ci#include <linux/ath9k_platform.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_civoid ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci        REG_WRITE(ah, reg, val);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci        if (ah->config.analog_shiftreg)
2562306a36Sopenharmony_ci		udelay(100);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_civoid ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
2962306a36Sopenharmony_ci			       u32 shift, u32 val)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	REG_RMW(ah, reg, ((val << shift) & mask), mask);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (ah->config.analog_shiftreg)
3462306a36Sopenharmony_ci		udelay(100);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciint16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
3862306a36Sopenharmony_ci			     int16_t targetLeft, int16_t targetRight)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	int16_t rv;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (srcRight == srcLeft) {
4362306a36Sopenharmony_ci		rv = targetLeft;
4462306a36Sopenharmony_ci	} else {
4562306a36Sopenharmony_ci		rv = (int16_t) (((target - srcLeft) * targetRight +
4662306a36Sopenharmony_ci				 (srcRight - target) * targetLeft) /
4762306a36Sopenharmony_ci				(srcRight - srcLeft));
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci	return rv;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cibool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize,
5362306a36Sopenharmony_ci				    u16 *indexL, u16 *indexR)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	u16 i;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (target <= pList[0]) {
5862306a36Sopenharmony_ci		*indexL = *indexR = 0;
5962306a36Sopenharmony_ci		return true;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	if (target >= pList[listSize - 1]) {
6262306a36Sopenharmony_ci		*indexL = *indexR = (u16) (listSize - 1);
6362306a36Sopenharmony_ci		return true;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	for (i = 0; i < listSize - 1; i++) {
6762306a36Sopenharmony_ci		if (pList[i] == target) {
6862306a36Sopenharmony_ci			*indexL = *indexR = i;
6962306a36Sopenharmony_ci			return true;
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci		if (target < pList[i + 1]) {
7262306a36Sopenharmony_ci			*indexL = i;
7362306a36Sopenharmony_ci			*indexR = (u16) (i + 1);
7462306a36Sopenharmony_ci			return false;
7562306a36Sopenharmony_ci		}
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci	return false;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_civoid ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
8162306a36Sopenharmony_ci				  int eep_start_loc, int size)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	int i = 0, j, addr;
8462306a36Sopenharmony_ci	u32 addrdata[8];
8562306a36Sopenharmony_ci	u32 data[8];
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	for (addr = 0; addr < size; addr++) {
8862306a36Sopenharmony_ci		addrdata[i] = AR5416_EEPROM_OFFSET +
8962306a36Sopenharmony_ci			((addr + eep_start_loc) << AR5416_EEPROM_S);
9062306a36Sopenharmony_ci		i++;
9162306a36Sopenharmony_ci		if (i == 8) {
9262306a36Sopenharmony_ci			REG_READ_MULTI(ah, addrdata, data, i);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci			for (j = 0; j < i; j++) {
9562306a36Sopenharmony_ci				*eep_data = data[j];
9662306a36Sopenharmony_ci				eep_data++;
9762306a36Sopenharmony_ci			}
9862306a36Sopenharmony_ci			i = 0;
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (i != 0) {
10362306a36Sopenharmony_ci		REG_READ_MULTI(ah, addrdata, data, i);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		for (j = 0; j < i; j++) {
10662306a36Sopenharmony_ci			*eep_data = data[j];
10762306a36Sopenharmony_ci			eep_data++;
10862306a36Sopenharmony_ci		}
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic bool ath9k_hw_nvram_read_array(u16 *blob, size_t blob_size,
11362306a36Sopenharmony_ci				      off_t offset, u16 *data)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	if (offset >= blob_size)
11662306a36Sopenharmony_ci		return false;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	*data =  blob[offset];
11962306a36Sopenharmony_ci	return true;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic bool ath9k_hw_nvram_read_pdata(struct ath9k_platform_data *pdata,
12362306a36Sopenharmony_ci				      off_t offset, u16 *data)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return ath9k_hw_nvram_read_array(pdata->eeprom_data,
12662306a36Sopenharmony_ci					 ARRAY_SIZE(pdata->eeprom_data),
12762306a36Sopenharmony_ci					 offset, data);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic bool ath9k_hw_nvram_read_firmware(const struct firmware *eeprom_blob,
13162306a36Sopenharmony_ci					 off_t offset, u16 *data)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return ath9k_hw_nvram_read_array((u16 *) eeprom_blob->data,
13462306a36Sopenharmony_ci					 eeprom_blob->size / sizeof(u16),
13562306a36Sopenharmony_ci					 offset, data);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
13962306a36Sopenharmony_ci				      u16 *data)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	return ath9k_hw_nvram_read_array(ah->nvmem_blob,
14262306a36Sopenharmony_ci					 ah->nvmem_blob_len / sizeof(u16),
14362306a36Sopenharmony_ci					 offset, data);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cibool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
14962306a36Sopenharmony_ci	struct ath9k_platform_data *pdata = ah->dev->platform_data;
15062306a36Sopenharmony_ci	bool ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (ah->nvmem_blob)
15362306a36Sopenharmony_ci		ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
15462306a36Sopenharmony_ci	else if (ah->eeprom_blob)
15562306a36Sopenharmony_ci		ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
15662306a36Sopenharmony_ci	else if (pdata && !pdata->use_eeprom)
15762306a36Sopenharmony_ci		ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
15862306a36Sopenharmony_ci	else
15962306a36Sopenharmony_ci		ret = common->bus_ops->eeprom_read(common, off, data);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!ret)
16262306a36Sopenharmony_ci		ath_dbg(common, EEPROM,
16362306a36Sopenharmony_ci			"unable to read eeprom region at offset %u\n", off);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return ret;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ciint ath9k_hw_nvram_swap_data(struct ath_hw *ah, bool *swap_needed, int size)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	u16 magic;
17162306a36Sopenharmony_ci	u16 *eepdata;
17262306a36Sopenharmony_ci	int i;
17362306a36Sopenharmony_ci	bool needs_byteswap = false;
17462306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
17762306a36Sopenharmony_ci		ath_err(common, "Reading Magic # failed\n");
17862306a36Sopenharmony_ci		return -EIO;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (swab16(magic) == AR5416_EEPROM_MAGIC) {
18262306a36Sopenharmony_ci		needs_byteswap = true;
18362306a36Sopenharmony_ci		ath_dbg(common, EEPROM,
18462306a36Sopenharmony_ci			"EEPROM needs byte-swapping to correct endianness.\n");
18562306a36Sopenharmony_ci	} else if (magic != AR5416_EEPROM_MAGIC) {
18662306a36Sopenharmony_ci		if (ath9k_hw_use_flash(ah)) {
18762306a36Sopenharmony_ci			ath_dbg(common, EEPROM,
18862306a36Sopenharmony_ci				"Ignoring invalid EEPROM magic (0x%04x).\n",
18962306a36Sopenharmony_ci				magic);
19062306a36Sopenharmony_ci		} else {
19162306a36Sopenharmony_ci			ath_err(common,
19262306a36Sopenharmony_ci				"Invalid EEPROM magic (0x%04x).\n", magic);
19362306a36Sopenharmony_ci			return -EINVAL;
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (needs_byteswap) {
19862306a36Sopenharmony_ci		if (ah->ah_flags & AH_NO_EEP_SWAP) {
19962306a36Sopenharmony_ci			ath_info(common,
20062306a36Sopenharmony_ci				 "Ignoring endianness difference in EEPROM magic bytes.\n");
20162306a36Sopenharmony_ci		} else {
20262306a36Sopenharmony_ci			eepdata = (u16 *)(&ah->eeprom);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci			for (i = 0; i < size; i++)
20562306a36Sopenharmony_ci				eepdata[i] = swab16(eepdata[i]);
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (ah->eep_ops->get_eepmisc(ah) & AR5416_EEPMISC_BIG_ENDIAN) {
21062306a36Sopenharmony_ci		*swap_needed = true;
21162306a36Sopenharmony_ci		ath_dbg(common, EEPROM,
21262306a36Sopenharmony_ci			"Big Endian EEPROM detected according to EEPMISC register.\n");
21362306a36Sopenharmony_ci	} else {
21462306a36Sopenharmony_ci		*swap_needed = false;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return 0;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cibool ath9k_hw_nvram_validate_checksum(struct ath_hw *ah, int size)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	u32 i, sum = 0;
22362306a36Sopenharmony_ci	u16 *eepdata = (u16 *)(&ah->eeprom);
22462306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	for (i = 0; i < size; i++)
22762306a36Sopenharmony_ci		sum ^= eepdata[i];
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (sum != 0xffff) {
23062306a36Sopenharmony_ci		ath_err(common, "Bad EEPROM checksum 0x%x\n", sum);
23162306a36Sopenharmony_ci		return false;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	return true;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cibool ath9k_hw_nvram_check_version(struct ath_hw *ah, int version, int minrev)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (ah->eep_ops->get_eeprom_ver(ah) != version ||
24262306a36Sopenharmony_ci	    ah->eep_ops->get_eeprom_rev(ah) < minrev) {
24362306a36Sopenharmony_ci		ath_err(common, "Bad EEPROM VER 0x%04x or REV 0x%04x\n",
24462306a36Sopenharmony_ci			ah->eep_ops->get_eeprom_ver(ah),
24562306a36Sopenharmony_ci			ah->eep_ops->get_eeprom_rev(ah));
24662306a36Sopenharmony_ci		return false;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return true;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_civoid ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList,
25362306a36Sopenharmony_ci			     u8 *pVpdList, u16 numIntercepts,
25462306a36Sopenharmony_ci			     u8 *pRetVpdList)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	u16 i, k;
25762306a36Sopenharmony_ci	u8 currPwr = pwrMin;
25862306a36Sopenharmony_ci	u16 idxL = 0, idxR = 0;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) {
26162306a36Sopenharmony_ci		ath9k_hw_get_lower_upper_index(currPwr, pPwrList,
26262306a36Sopenharmony_ci					       numIntercepts, &(idxL),
26362306a36Sopenharmony_ci					       &(idxR));
26462306a36Sopenharmony_ci		if (idxR < 1)
26562306a36Sopenharmony_ci			idxR = 1;
26662306a36Sopenharmony_ci		if (idxL == numIntercepts - 1)
26762306a36Sopenharmony_ci			idxL = (u16) (numIntercepts - 2);
26862306a36Sopenharmony_ci		if (pPwrList[idxL] == pPwrList[idxR])
26962306a36Sopenharmony_ci			k = pVpdList[idxL];
27062306a36Sopenharmony_ci		else
27162306a36Sopenharmony_ci			k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] +
27262306a36Sopenharmony_ci				   (pPwrList[idxR] - currPwr) * pVpdList[idxL]) /
27362306a36Sopenharmony_ci				  (pPwrList[idxR] - pPwrList[idxL]));
27462306a36Sopenharmony_ci		pRetVpdList[i] = (u8) k;
27562306a36Sopenharmony_ci		currPwr += 2;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_civoid ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
28062306a36Sopenharmony_ci				       struct ath9k_channel *chan,
28162306a36Sopenharmony_ci				       struct cal_target_power_leg *powInfo,
28262306a36Sopenharmony_ci				       u16 numChannels,
28362306a36Sopenharmony_ci				       struct cal_target_power_leg *pNewPower,
28462306a36Sopenharmony_ci				       u16 numRates, bool isExtTarget)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct chan_centers centers;
28762306a36Sopenharmony_ci	u16 clo, chi;
28862306a36Sopenharmony_ci	int i;
28962306a36Sopenharmony_ci	int matchIndex = -1, lowIndex = -1;
29062306a36Sopenharmony_ci	u16 freq;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	ath9k_hw_get_channel_centers(ah, chan, &centers);
29362306a36Sopenharmony_ci	freq = (isExtTarget) ? centers.ext_center : centers.ctl_center;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel,
29662306a36Sopenharmony_ci				       IS_CHAN_2GHZ(chan))) {
29762306a36Sopenharmony_ci		matchIndex = 0;
29862306a36Sopenharmony_ci	} else {
29962306a36Sopenharmony_ci		for (i = 0; (i < numChannels) &&
30062306a36Sopenharmony_ci			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
30162306a36Sopenharmony_ci			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
30262306a36Sopenharmony_ci						       IS_CHAN_2GHZ(chan))) {
30362306a36Sopenharmony_ci				matchIndex = i;
30462306a36Sopenharmony_ci				break;
30562306a36Sopenharmony_ci			} else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
30662306a36Sopenharmony_ci						IS_CHAN_2GHZ(chan)) && i > 0 &&
30762306a36Sopenharmony_ci				   freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
30862306a36Sopenharmony_ci						IS_CHAN_2GHZ(chan))) {
30962306a36Sopenharmony_ci				lowIndex = i - 1;
31062306a36Sopenharmony_ci				break;
31162306a36Sopenharmony_ci			}
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci		if ((matchIndex == -1) && (lowIndex == -1))
31462306a36Sopenharmony_ci			matchIndex = i - 1;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (matchIndex != -1) {
31862306a36Sopenharmony_ci		*pNewPower = powInfo[matchIndex];
31962306a36Sopenharmony_ci	} else {
32062306a36Sopenharmony_ci		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
32162306a36Sopenharmony_ci					 IS_CHAN_2GHZ(chan));
32262306a36Sopenharmony_ci		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
32362306a36Sopenharmony_ci					 IS_CHAN_2GHZ(chan));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		for (i = 0; i < numRates; i++) {
32662306a36Sopenharmony_ci			pNewPower->tPow2x[i] =
32762306a36Sopenharmony_ci				(u8)ath9k_hw_interpolate(freq, clo, chi,
32862306a36Sopenharmony_ci						powInfo[lowIndex].tPow2x[i],
32962306a36Sopenharmony_ci						powInfo[lowIndex + 1].tPow2x[i]);
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_civoid ath9k_hw_get_target_powers(struct ath_hw *ah,
33562306a36Sopenharmony_ci				struct ath9k_channel *chan,
33662306a36Sopenharmony_ci				struct cal_target_power_ht *powInfo,
33762306a36Sopenharmony_ci				u16 numChannels,
33862306a36Sopenharmony_ci				struct cal_target_power_ht *pNewPower,
33962306a36Sopenharmony_ci				u16 numRates, bool isHt40Target)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct chan_centers centers;
34262306a36Sopenharmony_ci	u16 clo, chi;
34362306a36Sopenharmony_ci	int i;
34462306a36Sopenharmony_ci	int matchIndex = -1, lowIndex = -1;
34562306a36Sopenharmony_ci	u16 freq;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	ath9k_hw_get_channel_centers(ah, chan, &centers);
34862306a36Sopenharmony_ci	freq = isHt40Target ? centers.synth_center : centers.ctl_center;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) {
35162306a36Sopenharmony_ci		matchIndex = 0;
35262306a36Sopenharmony_ci	} else {
35362306a36Sopenharmony_ci		for (i = 0; (i < numChannels) &&
35462306a36Sopenharmony_ci			     (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
35562306a36Sopenharmony_ci			if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel,
35662306a36Sopenharmony_ci						       IS_CHAN_2GHZ(chan))) {
35762306a36Sopenharmony_ci				matchIndex = i;
35862306a36Sopenharmony_ci				break;
35962306a36Sopenharmony_ci			} else
36062306a36Sopenharmony_ci				if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel,
36162306a36Sopenharmony_ci						IS_CHAN_2GHZ(chan)) && i > 0 &&
36262306a36Sopenharmony_ci				    freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel,
36362306a36Sopenharmony_ci						IS_CHAN_2GHZ(chan))) {
36462306a36Sopenharmony_ci					lowIndex = i - 1;
36562306a36Sopenharmony_ci					break;
36662306a36Sopenharmony_ci				}
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci		if ((matchIndex == -1) && (lowIndex == -1))
36962306a36Sopenharmony_ci			matchIndex = i - 1;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (matchIndex != -1) {
37362306a36Sopenharmony_ci		*pNewPower = powInfo[matchIndex];
37462306a36Sopenharmony_ci	} else {
37562306a36Sopenharmony_ci		clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel,
37662306a36Sopenharmony_ci					 IS_CHAN_2GHZ(chan));
37762306a36Sopenharmony_ci		chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel,
37862306a36Sopenharmony_ci					 IS_CHAN_2GHZ(chan));
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		for (i = 0; i < numRates; i++) {
38162306a36Sopenharmony_ci			pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq,
38262306a36Sopenharmony_ci						clo, chi,
38362306a36Sopenharmony_ci						powInfo[lowIndex].tPow2x[i],
38462306a36Sopenharmony_ci						powInfo[lowIndex + 1].tPow2x[i]);
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciu16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
39062306a36Sopenharmony_ci				bool is2GHz, int num_band_edges)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	u16 twiceMaxEdgePower = MAX_RATE_POWER;
39362306a36Sopenharmony_ci	int i;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	for (i = 0; (i < num_band_edges) &&
39662306a36Sopenharmony_ci		     (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) {
39762306a36Sopenharmony_ci		if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) {
39862306a36Sopenharmony_ci			twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
39962306a36Sopenharmony_ci			break;
40062306a36Sopenharmony_ci		} else if ((i > 0) &&
40162306a36Sopenharmony_ci			   (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel,
40262306a36Sopenharmony_ci						      is2GHz))) {
40362306a36Sopenharmony_ci			if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel,
40462306a36Sopenharmony_ci					       is2GHz) < freq &&
40562306a36Sopenharmony_ci			    CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
40662306a36Sopenharmony_ci				twiceMaxEdgePower =
40762306a36Sopenharmony_ci					CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
40862306a36Sopenharmony_ci			}
40962306a36Sopenharmony_ci			break;
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return twiceMaxEdgePower;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ciu16 ath9k_hw_get_scaled_power(struct ath_hw *ah, u16 power_limit,
41762306a36Sopenharmony_ci			      u8 antenna_reduction)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	u16 reduction = antenna_reduction;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/*
42262306a36Sopenharmony_ci	 * Reduce scaled Power by number of chains active
42362306a36Sopenharmony_ci	 * to get the per chain tx power level.
42462306a36Sopenharmony_ci	 */
42562306a36Sopenharmony_ci	switch (ar5416_get_ntxchains(ah->txchainmask)) {
42662306a36Sopenharmony_ci	case 1:
42762306a36Sopenharmony_ci		break;
42862306a36Sopenharmony_ci	case 2:
42962306a36Sopenharmony_ci		reduction += POWER_CORRECTION_FOR_TWO_CHAIN;
43062306a36Sopenharmony_ci		break;
43162306a36Sopenharmony_ci	case 3:
43262306a36Sopenharmony_ci		reduction += POWER_CORRECTION_FOR_THREE_CHAIN;
43362306a36Sopenharmony_ci		break;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (power_limit > reduction)
43762306a36Sopenharmony_ci		power_limit -= reduction;
43862306a36Sopenharmony_ci	else
43962306a36Sopenharmony_ci		power_limit = 0;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	return min_t(u16, power_limit, MAX_RATE_POWER);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_civoid ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct ath_common *common = ath9k_hw_common(ah);
44762306a36Sopenharmony_ci	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	switch (ar5416_get_ntxchains(ah->txchainmask)) {
45062306a36Sopenharmony_ci	case 1:
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci	case 2:
45362306a36Sopenharmony_ci		regulatory->max_power_level += POWER_CORRECTION_FOR_TWO_CHAIN;
45462306a36Sopenharmony_ci		break;
45562306a36Sopenharmony_ci	case 3:
45662306a36Sopenharmony_ci		regulatory->max_power_level += POWER_CORRECTION_FOR_THREE_CHAIN;
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	default:
45962306a36Sopenharmony_ci		ath_dbg(common, EEPROM, "Invalid chainmask configuration\n");
46062306a36Sopenharmony_ci		break;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_civoid ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
46562306a36Sopenharmony_ci				struct ath9k_channel *chan,
46662306a36Sopenharmony_ci				void *pRawDataSet,
46762306a36Sopenharmony_ci				u8 *bChans, u16 availPiers,
46862306a36Sopenharmony_ci				u16 tPdGainOverlap,
46962306a36Sopenharmony_ci				u16 *pPdGainBoundaries, u8 *pPDADCValues,
47062306a36Sopenharmony_ci				u16 numXpdGains)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	int i, j, k;
47362306a36Sopenharmony_ci	int16_t ss;
47462306a36Sopenharmony_ci	u16 idxL = 0, idxR = 0, numPiers;
47562306a36Sopenharmony_ci	static u8 vpdTableL[AR5416_NUM_PD_GAINS]
47662306a36Sopenharmony_ci		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
47762306a36Sopenharmony_ci	static u8 vpdTableR[AR5416_NUM_PD_GAINS]
47862306a36Sopenharmony_ci		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
47962306a36Sopenharmony_ci	static u8 vpdTableI[AR5416_NUM_PD_GAINS]
48062306a36Sopenharmony_ci		[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
48362306a36Sopenharmony_ci	u8 minPwrT4[AR5416_NUM_PD_GAINS];
48462306a36Sopenharmony_ci	u8 maxPwrT4[AR5416_NUM_PD_GAINS];
48562306a36Sopenharmony_ci	int16_t vpdStep;
48662306a36Sopenharmony_ci	int16_t tmpVal;
48762306a36Sopenharmony_ci	u16 sizeCurrVpdTable, maxIndex, tgtIndex;
48862306a36Sopenharmony_ci	bool match;
48962306a36Sopenharmony_ci	int16_t minDelta = 0;
49062306a36Sopenharmony_ci	struct chan_centers centers;
49162306a36Sopenharmony_ci	int pdgain_boundary_default;
49262306a36Sopenharmony_ci	struct cal_data_per_freq *data_def = pRawDataSet;
49362306a36Sopenharmony_ci	struct cal_data_per_freq_4k *data_4k = pRawDataSet;
49462306a36Sopenharmony_ci	struct cal_data_per_freq_ar9287 *data_9287 = pRawDataSet;
49562306a36Sopenharmony_ci	bool eeprom_4k = AR_SREV_9285(ah) || AR_SREV_9271(ah);
49662306a36Sopenharmony_ci	int intercepts;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (AR_SREV_9287(ah))
49962306a36Sopenharmony_ci		intercepts = AR9287_PD_GAIN_ICEPTS;
50062306a36Sopenharmony_ci	else
50162306a36Sopenharmony_ci		intercepts = AR5416_PD_GAIN_ICEPTS;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	memset(&minPwrT4, 0, AR5416_NUM_PD_GAINS);
50462306a36Sopenharmony_ci	ath9k_hw_get_channel_centers(ah, chan, &centers);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	for (numPiers = 0; numPiers < availPiers; numPiers++) {
50762306a36Sopenharmony_ci		if (bChans[numPiers] == AR5416_BCHAN_UNUSED)
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center,
51262306a36Sopenharmony_ci							     IS_CHAN_2GHZ(chan)),
51362306a36Sopenharmony_ci					       bChans, numPiers, &idxL, &idxR);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (match) {
51662306a36Sopenharmony_ci		if (AR_SREV_9287(ah)) {
51762306a36Sopenharmony_ci			for (i = 0; i < numXpdGains; i++) {
51862306a36Sopenharmony_ci				minPwrT4[i] = data_9287[idxL].pwrPdg[i][0];
51962306a36Sopenharmony_ci				maxPwrT4[i] = data_9287[idxL].pwrPdg[i][intercepts - 1];
52062306a36Sopenharmony_ci				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
52162306a36Sopenharmony_ci						data_9287[idxL].pwrPdg[i],
52262306a36Sopenharmony_ci						data_9287[idxL].vpdPdg[i],
52362306a36Sopenharmony_ci						intercepts,
52462306a36Sopenharmony_ci						vpdTableI[i]);
52562306a36Sopenharmony_ci			}
52662306a36Sopenharmony_ci		} else if (eeprom_4k) {
52762306a36Sopenharmony_ci			for (i = 0; i < numXpdGains; i++) {
52862306a36Sopenharmony_ci				minPwrT4[i] = data_4k[idxL].pwrPdg[i][0];
52962306a36Sopenharmony_ci				maxPwrT4[i] = data_4k[idxL].pwrPdg[i][intercepts - 1];
53062306a36Sopenharmony_ci				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
53162306a36Sopenharmony_ci						data_4k[idxL].pwrPdg[i],
53262306a36Sopenharmony_ci						data_4k[idxL].vpdPdg[i],
53362306a36Sopenharmony_ci						intercepts,
53462306a36Sopenharmony_ci						vpdTableI[i]);
53562306a36Sopenharmony_ci			}
53662306a36Sopenharmony_ci		} else {
53762306a36Sopenharmony_ci			for (i = 0; i < numXpdGains; i++) {
53862306a36Sopenharmony_ci				minPwrT4[i] = data_def[idxL].pwrPdg[i][0];
53962306a36Sopenharmony_ci				maxPwrT4[i] = data_def[idxL].pwrPdg[i][intercepts - 1];
54062306a36Sopenharmony_ci				ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
54162306a36Sopenharmony_ci						data_def[idxL].pwrPdg[i],
54262306a36Sopenharmony_ci						data_def[idxL].vpdPdg[i],
54362306a36Sopenharmony_ci						intercepts,
54462306a36Sopenharmony_ci						vpdTableI[i]);
54562306a36Sopenharmony_ci			}
54662306a36Sopenharmony_ci		}
54762306a36Sopenharmony_ci	} else {
54862306a36Sopenharmony_ci		for (i = 0; i < numXpdGains; i++) {
54962306a36Sopenharmony_ci			if (AR_SREV_9287(ah)) {
55062306a36Sopenharmony_ci				pVpdL = data_9287[idxL].vpdPdg[i];
55162306a36Sopenharmony_ci				pPwrL = data_9287[idxL].pwrPdg[i];
55262306a36Sopenharmony_ci				pVpdR = data_9287[idxR].vpdPdg[i];
55362306a36Sopenharmony_ci				pPwrR = data_9287[idxR].pwrPdg[i];
55462306a36Sopenharmony_ci			} else if (eeprom_4k) {
55562306a36Sopenharmony_ci				pVpdL = data_4k[idxL].vpdPdg[i];
55662306a36Sopenharmony_ci				pPwrL = data_4k[idxL].pwrPdg[i];
55762306a36Sopenharmony_ci				pVpdR = data_4k[idxR].vpdPdg[i];
55862306a36Sopenharmony_ci				pPwrR = data_4k[idxR].pwrPdg[i];
55962306a36Sopenharmony_ci			} else {
56062306a36Sopenharmony_ci				pVpdL = data_def[idxL].vpdPdg[i];
56162306a36Sopenharmony_ci				pPwrL = data_def[idxL].pwrPdg[i];
56262306a36Sopenharmony_ci				pVpdR = data_def[idxR].vpdPdg[i];
56362306a36Sopenharmony_ci				pPwrR = data_def[idxR].pwrPdg[i];
56462306a36Sopenharmony_ci			}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci			maxPwrT4[i] =
56962306a36Sopenharmony_ci				min(pPwrL[intercepts - 1],
57062306a36Sopenharmony_ci				    pPwrR[intercepts - 1]);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
57462306a36Sopenharmony_ci						pPwrL, pVpdL,
57562306a36Sopenharmony_ci						intercepts,
57662306a36Sopenharmony_ci						vpdTableL[i]);
57762306a36Sopenharmony_ci			ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
57862306a36Sopenharmony_ci						pPwrR, pVpdR,
57962306a36Sopenharmony_ci						intercepts,
58062306a36Sopenharmony_ci						vpdTableR[i]);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci			for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
58362306a36Sopenharmony_ci				vpdTableI[i][j] =
58462306a36Sopenharmony_ci					(u8)(ath9k_hw_interpolate((u16)
58562306a36Sopenharmony_ci					     FREQ2FBIN(centers.
58662306a36Sopenharmony_ci						       synth_center,
58762306a36Sopenharmony_ci						       IS_CHAN_2GHZ
58862306a36Sopenharmony_ci						       (chan)),
58962306a36Sopenharmony_ci					     bChans[idxL], bChans[idxR],
59062306a36Sopenharmony_ci					     vpdTableL[i][j], vpdTableR[i][j]));
59162306a36Sopenharmony_ci			}
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	k = 0;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	for (i = 0; i < numXpdGains; i++) {
59862306a36Sopenharmony_ci		if (i == (numXpdGains - 1))
59962306a36Sopenharmony_ci			pPdGainBoundaries[i] =
60062306a36Sopenharmony_ci				(u16)(maxPwrT4[i] / 2);
60162306a36Sopenharmony_ci		else
60262306a36Sopenharmony_ci			pPdGainBoundaries[i] =
60362306a36Sopenharmony_ci				(u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci		pPdGainBoundaries[i] =
60662306a36Sopenharmony_ci			min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		minDelta = 0;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		if (i == 0) {
61162306a36Sopenharmony_ci			if (AR_SREV_9280_20_OR_LATER(ah))
61262306a36Sopenharmony_ci				ss = (int16_t)(0 - (minPwrT4[i] / 2));
61362306a36Sopenharmony_ci			else
61462306a36Sopenharmony_ci				ss = 0;
61562306a36Sopenharmony_ci		} else {
61662306a36Sopenharmony_ci			ss = (int16_t)((pPdGainBoundaries[i - 1] -
61762306a36Sopenharmony_ci					(minPwrT4[i] / 2)) -
61862306a36Sopenharmony_ci				       tPdGainOverlap + 1 + minDelta);
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci		vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
62162306a36Sopenharmony_ci		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
62462306a36Sopenharmony_ci			tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
62562306a36Sopenharmony_ci			pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
62662306a36Sopenharmony_ci			ss++;
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1);
63062306a36Sopenharmony_ci		tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap -
63162306a36Sopenharmony_ci				(minPwrT4[i] / 2));
63262306a36Sopenharmony_ci		maxIndex = (tgtIndex < sizeCurrVpdTable) ?
63362306a36Sopenharmony_ci			tgtIndex : sizeCurrVpdTable;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) {
63662306a36Sopenharmony_ci			pPDADCValues[k++] = vpdTableI[i][ss++];
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
64062306a36Sopenharmony_ci				    vpdTableI[i][sizeCurrVpdTable - 2]);
64162306a36Sopenharmony_ci		vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		if (tgtIndex >= maxIndex) {
64462306a36Sopenharmony_ci			while ((ss <= tgtIndex) &&
64562306a36Sopenharmony_ci			       (k < (AR5416_NUM_PDADC_VALUES - 1))) {
64662306a36Sopenharmony_ci				tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] +
64762306a36Sopenharmony_ci						    (ss - maxIndex + 1) * vpdStep));
64862306a36Sopenharmony_ci				pPDADCValues[k++] = (u8)((tmpVal > 255) ?
64962306a36Sopenharmony_ci							 255 : tmpVal);
65062306a36Sopenharmony_ci				ss++;
65162306a36Sopenharmony_ci			}
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	if (eeprom_4k)
65662306a36Sopenharmony_ci		pdgain_boundary_default = 58;
65762306a36Sopenharmony_ci	else
65862306a36Sopenharmony_ci		pdgain_boundary_default = pPdGainBoundaries[i - 1];
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	while (i < AR5416_PD_GAINS_IN_MASK) {
66162306a36Sopenharmony_ci		pPdGainBoundaries[i] = pdgain_boundary_default;
66262306a36Sopenharmony_ci		i++;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	while (k < AR5416_NUM_PDADC_VALUES) {
66662306a36Sopenharmony_ci		pPDADCValues[k] = pPDADCValues[k - 1];
66762306a36Sopenharmony_ci		k++;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ciint ath9k_hw_eeprom_init(struct ath_hw *ah)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	if (AR_SREV_9300_20_OR_LATER(ah))
67462306a36Sopenharmony_ci		ah->eep_ops = &eep_ar9300_ops;
67562306a36Sopenharmony_ci	else if (AR_SREV_9287(ah)) {
67662306a36Sopenharmony_ci		ah->eep_ops = &eep_ar9287_ops;
67762306a36Sopenharmony_ci	} else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
67862306a36Sopenharmony_ci		ah->eep_ops = &eep_4k_ops;
67962306a36Sopenharmony_ci	} else {
68062306a36Sopenharmony_ci		ah->eep_ops = &eep_def_ops;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (!ah->eep_ops->fill_eeprom(ah))
68462306a36Sopenharmony_ci		return -EIO;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return ah->eep_ops->check_eeprom(ah);
68762306a36Sopenharmony_ci}
688