1185377Ssam/*
2187831Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3185377Ssam * Copyright (c) 2002-2008 Atheros Communications, Inc.
4185377Ssam *
5185377Ssam * Permission to use, copy, modify, and/or distribute this software for any
6185377Ssam * purpose with or without fee is hereby granted, provided that the above
7185377Ssam * copyright notice and this permission notice appear in all copies.
8185377Ssam *
9185377Ssam * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10185377Ssam * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11185377Ssam * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12185377Ssam * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13185377Ssam * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14185377Ssam * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15185377Ssam * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16185377Ssam *
17187831Ssam * $FreeBSD$
18185377Ssam */
19185377Ssam#include "opt_ah.h"
20185377Ssam
21185377Ssam#include "ah.h"
22185377Ssam#include "ah_internal.h"
23185377Ssam
24185377Ssam#include "ah_eeprom_v3.h"
25185377Ssam
26185377Ssam#include "ar5212/ar5212.h"
27185377Ssam#include "ar5212/ar5212reg.h"
28185377Ssam#include "ar5212/ar5212phy.h"
29185377Ssam
30185377Ssam#define AH_5212_5413
31185377Ssam#include "ar5212/ar5212.ini"
32185377Ssam
33185377Ssam#define	N(a)	(sizeof(a)/sizeof(a[0]))
34185377Ssam
35185377Ssamstruct ar5413State {
36185377Ssam	RF_HAL_FUNCS	base;		/* public state, must be first */
37185377Ssam	uint16_t	pcdacTable[PWR_TABLE_SIZE_2413];
38185377Ssam
39185377Ssam	uint32_t	Bank1Data[N(ar5212Bank1_5413)];
40185377Ssam	uint32_t	Bank2Data[N(ar5212Bank2_5413)];
41185377Ssam	uint32_t	Bank3Data[N(ar5212Bank3_5413)];
42185377Ssam	uint32_t	Bank6Data[N(ar5212Bank6_5413)];
43185377Ssam	uint32_t	Bank7Data[N(ar5212Bank7_5413)];
44185377Ssam
45185377Ssam	/*
46185377Ssam	 * Private state for reduced stack usage.
47185377Ssam	 */
48185377Ssam	/* filled out Vpd table for all pdGains (chanL) */
49185377Ssam	uint16_t vpdTable_L[MAX_NUM_PDGAINS_PER_CHANNEL]
50185377Ssam			    [MAX_PWR_RANGE_IN_HALF_DB];
51185377Ssam	/* filled out Vpd table for all pdGains (chanR) */
52185377Ssam	uint16_t vpdTable_R[MAX_NUM_PDGAINS_PER_CHANNEL]
53185377Ssam			    [MAX_PWR_RANGE_IN_HALF_DB];
54185377Ssam	/* filled out Vpd table for all pdGains (interpolated) */
55185377Ssam	uint16_t vpdTable_I[MAX_NUM_PDGAINS_PER_CHANNEL]
56185377Ssam			    [MAX_PWR_RANGE_IN_HALF_DB];
57185377Ssam};
58185377Ssam#define	AR5413(ah)	((struct ar5413State *) AH5212(ah)->ah_rfHal)
59185377Ssam
60185377Ssamextern	void ar5212ModifyRfBuffer(uint32_t *rfBuf, uint32_t reg32,
61185377Ssam		uint32_t numBits, uint32_t firstBit, uint32_t column);
62185377Ssam
63185377Ssamstatic void
64185377Ssamar5413WriteRegs(struct ath_hal *ah, u_int modesIndex, u_int freqIndex,
65185377Ssam	int writes)
66185377Ssam{
67185377Ssam	HAL_INI_WRITE_ARRAY(ah, ar5212Modes_5413, modesIndex, writes);
68185377Ssam	HAL_INI_WRITE_ARRAY(ah, ar5212Common_5413, 1, writes);
69185377Ssam	HAL_INI_WRITE_ARRAY(ah, ar5212BB_RfGain_5413, freqIndex, writes);
70185377Ssam}
71185377Ssam
72185377Ssam/*
73185377Ssam * Take the MHz channel value and set the Channel value
74185377Ssam *
75185377Ssam * ASSUMES: Writes enabled to analog bus
76185377Ssam */
77185377Ssamstatic HAL_BOOL
78187831Ssamar5413SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan)
79185377Ssam{
80187831Ssam	uint16_t freq = ath_hal_gethwchannel(ah, chan);
81185377Ssam	uint32_t channelSel  = 0;
82185377Ssam	uint32_t bModeSynth  = 0;
83185377Ssam	uint32_t aModeRefSel = 0;
84185377Ssam	uint32_t reg32       = 0;
85185377Ssam
86187831Ssam	OS_MARK(ah, AH_MARK_SETCHANNEL, freq);
87185377Ssam
88187831Ssam	if (freq < 4800) {
89185377Ssam		uint32_t txctl;
90185377Ssam
91187831Ssam		if (((freq - 2192) % 5) == 0) {
92187831Ssam			channelSel = ((freq - 672) * 2 - 3040)/10;
93185377Ssam			bModeSynth = 0;
94187831Ssam		} else if (((freq - 2224) % 5) == 0) {
95187831Ssam			channelSel = ((freq - 704) * 2 - 3040) / 10;
96185377Ssam			bModeSynth = 1;
97185377Ssam		} else {
98185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
99185377Ssam			    "%s: invalid channel %u MHz\n",
100187831Ssam			    __func__, freq);
101185377Ssam			return AH_FALSE;
102185377Ssam		}
103185377Ssam
104185377Ssam		channelSel = (channelSel << 2) & 0xff;
105185377Ssam		channelSel = ath_hal_reverseBits(channelSel, 8);
106185377Ssam
107185377Ssam		txctl = OS_REG_READ(ah, AR_PHY_CCK_TX_CTRL);
108187831Ssam		if (freq == 2484) {
109185377Ssam			/* Enable channel spreading for channel 14 */
110185377Ssam			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
111185377Ssam				txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
112185377Ssam		} else {
113185377Ssam			OS_REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
114185377Ssam				txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
115185377Ssam		}
116187831Ssam	} else if (((freq % 5) == 2) && (freq <= 5435)) {
117187831Ssam		freq = freq - 2; /* Align to even 5MHz raster */
118185377Ssam		channelSel = ath_hal_reverseBits(
119185377Ssam			(uint32_t)(((freq - 4800)*10)/25 + 1), 8);
120185377Ssam            	aModeRefSel = ath_hal_reverseBits(0, 2);
121187831Ssam	} else if ((freq % 20) == 0 && freq >= 5120) {
122185377Ssam		channelSel = ath_hal_reverseBits(
123187831Ssam			((freq - 4800) / 20 << 2), 8);
124185377Ssam		aModeRefSel = ath_hal_reverseBits(1, 2);
125187831Ssam	} else if ((freq % 10) == 0) {
126185377Ssam		channelSel = ath_hal_reverseBits(
127187831Ssam			((freq - 4800) / 10 << 1), 8);
128185377Ssam		aModeRefSel = ath_hal_reverseBits(1, 2);
129187831Ssam	} else if ((freq % 5) == 0) {
130185377Ssam		channelSel = ath_hal_reverseBits(
131187831Ssam			(freq - 4800) / 5, 8);
132185377Ssam		aModeRefSel = ath_hal_reverseBits(1, 2);
133185377Ssam	} else {
134185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u MHz\n",
135187831Ssam		    __func__, freq);
136185377Ssam		return AH_FALSE;
137185377Ssam	}
138185377Ssam
139185377Ssam	reg32 = (channelSel << 4) | (aModeRefSel << 2) | (bModeSynth << 1) |
140185377Ssam			(1 << 12) | 0x1;
141185377Ssam	OS_REG_WRITE(ah, AR_PHY(0x27), reg32 & 0xff);
142185377Ssam
143185377Ssam	reg32 >>= 8;
144185377Ssam	OS_REG_WRITE(ah, AR_PHY(0x36), reg32 & 0x7f);
145185377Ssam
146185377Ssam	AH_PRIVATE(ah)->ah_curchan = chan;
147185377Ssam	return AH_TRUE;
148185377Ssam}
149185377Ssam
150185377Ssam/*
151185377Ssam * Reads EEPROM header info from device structure and programs
152185377Ssam * all rf registers
153185377Ssam *
154185377Ssam * REQUIRES: Access to the analog rf device
155185377Ssam */
156185377Ssamstatic HAL_BOOL
157187831Ssamar5413SetRfRegs(struct ath_hal *ah,
158187831Ssam	const struct ieee80211_channel *chan,
159187831Ssam	uint16_t modesIndex, uint16_t *rfXpdGain)
160185377Ssam{
161185377Ssam#define	RF_BANK_SETUP(_priv, _ix, _col) do {				    \
162185377Ssam	int i;								    \
163185377Ssam	for (i = 0; i < N(ar5212Bank##_ix##_5413); i++)			    \
164185377Ssam		(_priv)->Bank##_ix##Data[i] = ar5212Bank##_ix##_5413[i][_col];\
165185377Ssam} while (0)
166185377Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
167187831Ssam	uint16_t freq = ath_hal_gethwchannel(ah, chan);
168185377Ssam	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
169185377Ssam	uint16_t ob5GHz = 0, db5GHz = 0;
170185377Ssam	uint16_t ob2GHz = 0, db2GHz = 0;
171185377Ssam	struct ar5413State *priv = AR5413(ah);
172185377Ssam	int regWrites = 0;
173185377Ssam
174187831Ssam	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan %u/0x%x modesIndex %u\n",
175187831Ssam	    __func__, chan->ic_freq, chan->ic_flags, modesIndex);
176185377Ssam
177185377Ssam	HALASSERT(priv != AH_NULL);
178185377Ssam
179185377Ssam	/* Setup rf parameters */
180187831Ssam	switch (chan->ic_flags & IEEE80211_CHAN_ALLFULL) {
181187831Ssam	case IEEE80211_CHAN_A:
182187831Ssam		if (freq > 4000 && freq < 5260) {
183185377Ssam			ob5GHz = ee->ee_ob1;
184185377Ssam			db5GHz = ee->ee_db1;
185187831Ssam		} else if (freq >= 5260 && freq < 5500) {
186185377Ssam			ob5GHz = ee->ee_ob2;
187185377Ssam			db5GHz = ee->ee_db2;
188187831Ssam		} else if (freq >= 5500 && freq < 5725) {
189185377Ssam			ob5GHz = ee->ee_ob3;
190185377Ssam			db5GHz = ee->ee_db3;
191187831Ssam		} else if (freq >= 5725) {
192185377Ssam			ob5GHz = ee->ee_ob4;
193185377Ssam			db5GHz = ee->ee_db4;
194185377Ssam		} else {
195185377Ssam			/* XXX else */
196185377Ssam		}
197185377Ssam		break;
198187831Ssam	case IEEE80211_CHAN_B:
199185377Ssam		ob2GHz = ee->ee_obFor24;
200185377Ssam		db2GHz = ee->ee_dbFor24;
201185377Ssam		break;
202187831Ssam	case IEEE80211_CHAN_G:
203187831Ssam	case IEEE80211_CHAN_PUREG:	/* NB: really 108G */
204185377Ssam		ob2GHz = ee->ee_obFor24g;
205185377Ssam		db2GHz = ee->ee_dbFor24g;
206185377Ssam		break;
207185377Ssam	default:
208185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel flags 0x%x\n",
209187831Ssam		    __func__, chan->ic_flags);
210185377Ssam		return AH_FALSE;
211185377Ssam	}
212185377Ssam
213185377Ssam	/* Bank 1 Write */
214185377Ssam	RF_BANK_SETUP(priv, 1, 1);
215185377Ssam
216185377Ssam	/* Bank 2 Write */
217185377Ssam	RF_BANK_SETUP(priv, 2, modesIndex);
218185377Ssam
219185377Ssam	/* Bank 3 Write */
220185377Ssam	RF_BANK_SETUP(priv, 3, modesIndex);
221185377Ssam
222185377Ssam	/* Bank 6 Write */
223185377Ssam	RF_BANK_SETUP(priv, 6, modesIndex);
224185377Ssam
225185377Ssam    	/* Only the 5 or 2 GHz OB/DB need to be set for a mode */
226187831Ssam	if (IEEE80211_IS_CHAN_2GHZ(chan)) {
227185377Ssam        	ar5212ModifyRfBuffer(priv->Bank6Data, ob2GHz, 3, 241, 0);
228185377Ssam        	ar5212ModifyRfBuffer(priv->Bank6Data, db2GHz, 3, 238, 0);
229185377Ssam
230185377Ssam			/* TODO - only for Eagle 1.0 2GHz - remove for production */
231185377Ssam			/* XXX: but without this bit G doesn't work. */
232185377Ssam			ar5212ModifyRfBuffer(priv->Bank6Data, 1 , 1, 291, 2);
233185377Ssam
234185377Ssam			/* Optimum value for rf_pwd_iclobuf2G for PCIe chips only */
235188979Ssam			if (AH_PRIVATE(ah)->ah_ispcie) {
236185377Ssam				ar5212ModifyRfBuffer(priv->Bank6Data, ath_hal_reverseBits(6, 3),
237185377Ssam						 3, 131, 3);
238185377Ssam			}
239185377Ssam	} else {
240185377Ssam        	ar5212ModifyRfBuffer(priv->Bank6Data, ob5GHz, 3, 247, 0);
241185377Ssam        	ar5212ModifyRfBuffer(priv->Bank6Data, db5GHz, 3, 244, 0);
242185377Ssam
243185377Ssam	}
244185377Ssam
245185377Ssam	/* Bank 7 Setup */
246185377Ssam	RF_BANK_SETUP(priv, 7, modesIndex);
247185377Ssam
248185377Ssam	/* Write Analog registers */
249185377Ssam	HAL_INI_WRITE_BANK(ah, ar5212Bank1_5413, priv->Bank1Data, regWrites);
250185377Ssam	HAL_INI_WRITE_BANK(ah, ar5212Bank2_5413, priv->Bank2Data, regWrites);
251185377Ssam	HAL_INI_WRITE_BANK(ah, ar5212Bank3_5413, priv->Bank3Data, regWrites);
252185377Ssam	HAL_INI_WRITE_BANK(ah, ar5212Bank6_5413, priv->Bank6Data, regWrites);
253185377Ssam	HAL_INI_WRITE_BANK(ah, ar5212Bank7_5413, priv->Bank7Data, regWrites);
254185377Ssam
255185377Ssam	/* Now that we have reprogrammed rfgain value, clear the flag. */
256185377Ssam	ahp->ah_rfgainState = HAL_RFGAIN_INACTIVE;
257185377Ssam
258185377Ssam	return AH_TRUE;
259185377Ssam#undef	RF_BANK_SETUP
260185377Ssam}
261185377Ssam
262185377Ssam/*
263185377Ssam * Return a reference to the requested RF Bank.
264185377Ssam */
265185377Ssamstatic uint32_t *
266185377Ssamar5413GetRfBank(struct ath_hal *ah, int bank)
267185377Ssam{
268185377Ssam	struct ar5413State *priv = AR5413(ah);
269185377Ssam
270185377Ssam	HALASSERT(priv != AH_NULL);
271185377Ssam	switch (bank) {
272185377Ssam	case 1: return priv->Bank1Data;
273185377Ssam	case 2: return priv->Bank2Data;
274185377Ssam	case 3: return priv->Bank3Data;
275185377Ssam	case 6: return priv->Bank6Data;
276185377Ssam	case 7: return priv->Bank7Data;
277185377Ssam	}
278185377Ssam	HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unknown RF Bank %d requested\n",
279185377Ssam	    __func__, bank);
280185377Ssam	return AH_NULL;
281185377Ssam}
282185377Ssam
283185377Ssam/*
284185377Ssam * Return indices surrounding the value in sorted integer lists.
285185377Ssam *
286185377Ssam * NB: the input list is assumed to be sorted in ascending order
287185377Ssam */
288185377Ssamstatic void
289185377SsamGetLowerUpperIndex(int16_t v, const uint16_t *lp, uint16_t listSize,
290185377Ssam                          uint32_t *vlo, uint32_t *vhi)
291185377Ssam{
292185377Ssam	int16_t target = v;
293185377Ssam	const uint16_t *ep = lp+listSize;
294185377Ssam	const uint16_t *tp;
295185377Ssam
296185377Ssam	/*
297185377Ssam	 * Check first and last elements for out-of-bounds conditions.
298185377Ssam	 */
299185377Ssam	if (target < lp[0]) {
300185377Ssam		*vlo = *vhi = 0;
301185377Ssam		return;
302185377Ssam	}
303185377Ssam	if (target >= ep[-1]) {
304185377Ssam		*vlo = *vhi = listSize - 1;
305185377Ssam		return;
306185377Ssam	}
307185377Ssam
308185377Ssam	/* look for value being near or between 2 values in list */
309185377Ssam	for (tp = lp; tp < ep; tp++) {
310185377Ssam		/*
311185377Ssam		 * If value is close to the current value of the list
312185377Ssam		 * then target is not between values, it is one of the values
313185377Ssam		 */
314185377Ssam		if (*tp == target) {
315185377Ssam			*vlo = *vhi = tp - (const uint16_t *) lp;
316185377Ssam			return;
317185377Ssam		}
318185377Ssam		/*
319185377Ssam		 * Look for value being between current value and next value
320185377Ssam		 * if so return these 2 values
321185377Ssam		 */
322185377Ssam		if (target < tp[1]) {
323185377Ssam			*vlo = tp - (const uint16_t *) lp;
324185377Ssam			*vhi = *vlo + 1;
325185377Ssam			return;
326185377Ssam		}
327185377Ssam	}
328185377Ssam}
329185377Ssam
330185377Ssam/*
331185377Ssam * Fill the Vpdlist for indices Pmax-Pmin
332185377Ssam */
333185377Ssamstatic HAL_BOOL
334185377Ssamar5413FillVpdTable(uint32_t pdGainIdx, int16_t Pmin, int16_t  Pmax,
335185377Ssam		   const int16_t *pwrList, const uint16_t *VpdList,
336185377Ssam		   uint16_t numIntercepts,
337185377Ssam		   uint16_t retVpdList[][64])
338185377Ssam{
339185377Ssam	uint16_t ii, jj, kk;
340185377Ssam	int16_t currPwr = (int16_t)(2*Pmin);
341185377Ssam	/* since Pmin is pwr*2 and pwrList is 4*pwr */
342185377Ssam	uint32_t  idxL, idxR;
343185377Ssam
344185377Ssam	ii = 0;
345185377Ssam	jj = 0;
346185377Ssam
347185377Ssam	if (numIntercepts < 2)
348185377Ssam		return AH_FALSE;
349185377Ssam
350185377Ssam	while (ii <= (uint16_t)(Pmax - Pmin)) {
351185377Ssam		GetLowerUpperIndex(currPwr, (const uint16_t *) pwrList,
352185377Ssam				   numIntercepts, &(idxL), &(idxR));
353185377Ssam		if (idxR < 1)
354185377Ssam			idxR = 1;			/* extrapolate below */
355185377Ssam		if (idxL == (uint32_t)(numIntercepts - 1))
356185377Ssam			idxL = numIntercepts - 2;	/* extrapolate above */
357185377Ssam		if (pwrList[idxL] == pwrList[idxR])
358185377Ssam			kk = VpdList[idxL];
359185377Ssam		else
360185377Ssam			kk = (uint16_t)
361185377Ssam				(((currPwr - pwrList[idxL])*VpdList[idxR]+
362185377Ssam				  (pwrList[idxR] - currPwr)*VpdList[idxL])/
363185377Ssam				 (pwrList[idxR] - pwrList[idxL]));
364185377Ssam		retVpdList[pdGainIdx][ii] = kk;
365185377Ssam		ii++;
366185377Ssam		currPwr += 2;				/* half dB steps */
367185377Ssam	}
368185377Ssam
369185377Ssam	return AH_TRUE;
370185377Ssam}
371185377Ssam
372185377Ssam/*
373185377Ssam * Returns interpolated or the scaled up interpolated value
374185377Ssam */
375185377Ssamstatic int16_t
376185377Ssaminterpolate_signed(uint16_t target, uint16_t srcLeft, uint16_t srcRight,
377185377Ssam	int16_t targetLeft, int16_t targetRight)
378185377Ssam{
379185377Ssam	int16_t rv;
380185377Ssam
381185377Ssam	if (srcRight != srcLeft) {
382185377Ssam		rv = ((target - srcLeft)*targetRight +
383185377Ssam		      (srcRight - target)*targetLeft) / (srcRight - srcLeft);
384185377Ssam	} else {
385185377Ssam		rv = targetLeft;
386185377Ssam	}
387185377Ssam	return rv;
388185377Ssam}
389185377Ssam
390185377Ssam/*
391185377Ssam * Uses the data points read from EEPROM to reconstruct the pdadc power table
392185377Ssam * Called by ar5413SetPowerTable()
393185377Ssam */
394185377Ssamstatic int
395185377Ssamar5413getGainBoundariesAndPdadcsForPowers(struct ath_hal *ah, uint16_t channel,
396185377Ssam		const RAW_DATA_STRUCT_2413 *pRawDataset,
397185377Ssam		uint16_t pdGainOverlap_t2,
398185377Ssam		int16_t  *pMinCalPower, uint16_t pPdGainBoundaries[],
399185377Ssam		uint16_t pPdGainValues[], uint16_t pPDADCValues[])
400185377Ssam{
401185377Ssam	struct ar5413State *priv = AR5413(ah);
402185377Ssam#define	VpdTable_L	priv->vpdTable_L
403185377Ssam#define	VpdTable_R	priv->vpdTable_R
404185377Ssam#define	VpdTable_I	priv->vpdTable_I
405185377Ssam	uint32_t ii, jj, kk;
406185377Ssam	int32_t ss;/* potentially -ve index for taking care of pdGainOverlap */
407185377Ssam	uint32_t idxL, idxR;
408185377Ssam	uint32_t numPdGainsUsed = 0;
409185377Ssam	/*
410185377Ssam	 * If desired to support -ve power levels in future, just
411185377Ssam	 * change pwr_I_0 to signed 5-bits.
412185377Ssam	 */
413185377Ssam	int16_t Pmin_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
414185377Ssam	/* to accomodate -ve power levels later on. */
415185377Ssam	int16_t Pmax_t2[MAX_NUM_PDGAINS_PER_CHANNEL];
416185377Ssam	/* to accomodate -ve power levels later on */
417185377Ssam	uint16_t numVpd = 0;
418185377Ssam	uint16_t Vpd_step;
419185377Ssam	int16_t tmpVal ;
420185377Ssam	uint32_t sizeCurrVpdTable, maxIndex, tgtIndex;
421185377Ssam
422185377Ssam	/* Get upper lower index */
423185377Ssam	GetLowerUpperIndex(channel, pRawDataset->pChannels,
424185377Ssam				 pRawDataset->numChannels, &(idxL), &(idxR));
425185377Ssam
426185377Ssam	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
427185377Ssam		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
428185377Ssam		/* work backwards 'cause highest pdGain for lowest power */
429185377Ssam		numVpd = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].numVpd;
430185377Ssam		if (numVpd > 0) {
431185377Ssam			pPdGainValues[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pd_gain;
432185377Ssam			Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0];
433185377Ssam			if (Pmin_t2[numPdGainsUsed] >pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]) {
434185377Ssam				Pmin_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0];
435185377Ssam			}
436185377Ssam			Pmin_t2[numPdGainsUsed] = (int16_t)
437185377Ssam				(Pmin_t2[numPdGainsUsed] / 2);
438185377Ssam			Pmax_t2[numPdGainsUsed] = pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[numVpd-1];
439185377Ssam			if (Pmax_t2[numPdGainsUsed] > pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1])
440185377Ssam				Pmax_t2[numPdGainsUsed] =
441185377Ssam					pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[numVpd-1];
442185377Ssam			Pmax_t2[numPdGainsUsed] = (int16_t)(Pmax_t2[numPdGainsUsed] / 2);
443185377Ssam			ar5413FillVpdTable(
444185377Ssam					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
445185377Ssam					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].pwr_t4[0]),
446185377Ssam					   &(pRawDataset->pDataPerChannel[idxL].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_L
447185377Ssam					   );
448185377Ssam			ar5413FillVpdTable(
449185377Ssam					   numPdGainsUsed, Pmin_t2[numPdGainsUsed], Pmax_t2[numPdGainsUsed],
450185377Ssam					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].pwr_t4[0]),
451185377Ssam					   &(pRawDataset->pDataPerChannel[idxR].pDataPerPDGain[jj].Vpd[0]), numVpd, VpdTable_R
452185377Ssam					   );
453185377Ssam			for (kk = 0; kk < (uint16_t)(Pmax_t2[numPdGainsUsed] - Pmin_t2[numPdGainsUsed]); kk++) {
454185377Ssam				VpdTable_I[numPdGainsUsed][kk] =
455185377Ssam					interpolate_signed(
456185377Ssam							   channel, pRawDataset->pChannels[idxL], pRawDataset->pChannels[idxR],
457185377Ssam							   (int16_t)VpdTable_L[numPdGainsUsed][kk], (int16_t)VpdTable_R[numPdGainsUsed][kk]);
458185377Ssam			}
459185377Ssam			/* fill VpdTable_I for this pdGain */
460185377Ssam			numPdGainsUsed++;
461185377Ssam		}
462185377Ssam		/* if this pdGain is used */
463185377Ssam	}
464185377Ssam
465185377Ssam	*pMinCalPower = Pmin_t2[0];
466185377Ssam	kk = 0; /* index for the final table */
467185377Ssam	for (ii = 0; ii < numPdGainsUsed; ii++) {
468185377Ssam		if (ii == (numPdGainsUsed - 1))
469185377Ssam			pPdGainBoundaries[ii] = Pmax_t2[ii] +
470185377Ssam				PD_GAIN_BOUNDARY_STRETCH_IN_HALF_DB;
471185377Ssam		else
472185377Ssam			pPdGainBoundaries[ii] = (uint16_t)
473185377Ssam				((Pmax_t2[ii] + Pmin_t2[ii+1]) / 2 );
474185377Ssam		if (pPdGainBoundaries[ii] > 63) {
475185377Ssam			HALDEBUG(ah, HAL_DEBUG_ANY,
476185377Ssam			    "%s: clamp pPdGainBoundaries[%d] %d\n",
477185377Ssam			    __func__, ii, pPdGainBoundaries[ii]);/*XXX*/
478185377Ssam			pPdGainBoundaries[ii] = 63;
479185377Ssam		}
480185377Ssam
481185377Ssam		/* Find starting index for this pdGain */
482185377Ssam		if (ii == 0)
483185377Ssam			ss = 0; /* for the first pdGain, start from index 0 */
484185377Ssam		else
485185377Ssam			ss = (pPdGainBoundaries[ii-1] - Pmin_t2[ii]) -
486185377Ssam				pdGainOverlap_t2;
487185377Ssam		Vpd_step = (uint16_t)(VpdTable_I[ii][1] - VpdTable_I[ii][0]);
488185377Ssam		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
489185377Ssam		/*
490185377Ssam		 *-ve ss indicates need to extrapolate data below for this pdGain
491185377Ssam		 */
492185377Ssam		while (ss < 0) {
493185377Ssam			tmpVal = (int16_t)(VpdTable_I[ii][0] + ss*Vpd_step);
494185377Ssam			pPDADCValues[kk++] = (uint16_t)((tmpVal < 0) ? 0 : tmpVal);
495185377Ssam			ss++;
496185377Ssam		}
497185377Ssam
498185377Ssam		sizeCurrVpdTable = Pmax_t2[ii] - Pmin_t2[ii];
499185377Ssam		tgtIndex = pPdGainBoundaries[ii] + pdGainOverlap_t2 - Pmin_t2[ii];
500185377Ssam		maxIndex = (tgtIndex < sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable;
501185377Ssam
502185377Ssam		while (ss < (int16_t)maxIndex)
503185377Ssam			pPDADCValues[kk++] = VpdTable_I[ii][ss++];
504185377Ssam
505185377Ssam		Vpd_step = (uint16_t)(VpdTable_I[ii][sizeCurrVpdTable-1] -
506185377Ssam				       VpdTable_I[ii][sizeCurrVpdTable-2]);
507185377Ssam		Vpd_step = (uint16_t)((Vpd_step < 1) ? 1 : Vpd_step);
508185377Ssam		/*
509185377Ssam		 * for last gain, pdGainBoundary == Pmax_t2, so will
510185377Ssam		 * have to extrapolate
511185377Ssam		 */
512185377Ssam		if (tgtIndex > maxIndex) {	/* need to extrapolate above */
513185377Ssam			while(ss < (int16_t)tgtIndex) {
514185377Ssam				tmpVal = (uint16_t)
515185377Ssam					(VpdTable_I[ii][sizeCurrVpdTable-1] +
516185377Ssam					 (ss-maxIndex)*Vpd_step);
517185377Ssam				pPDADCValues[kk++] = (tmpVal > 127) ?
518185377Ssam					127 : tmpVal;
519185377Ssam				ss++;
520185377Ssam			}
521185377Ssam		}				/* extrapolated above */
522185377Ssam	}					/* for all pdGainUsed */
523185377Ssam
524185377Ssam	while (ii < MAX_NUM_PDGAINS_PER_CHANNEL) {
525185377Ssam		pPdGainBoundaries[ii] = pPdGainBoundaries[ii-1];
526185377Ssam		ii++;
527185377Ssam	}
528185377Ssam	while (kk < 128) {
529185377Ssam		pPDADCValues[kk] = pPDADCValues[kk-1];
530185377Ssam		kk++;
531185377Ssam	}
532185377Ssam
533185377Ssam	return numPdGainsUsed;
534185377Ssam#undef VpdTable_L
535185377Ssam#undef VpdTable_R
536185377Ssam#undef VpdTable_I
537185377Ssam}
538185377Ssam
539185377Ssamstatic HAL_BOOL
540185377Ssamar5413SetPowerTable(struct ath_hal *ah,
541187831Ssam	int16_t *minPower, int16_t *maxPower,
542187831Ssam	const struct ieee80211_channel *chan,
543185377Ssam	uint16_t *rfXpdGain)
544185377Ssam{
545185377Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
546187831Ssam	uint16_t freq = ath_hal_gethwchannel(ah, chan);
547185377Ssam	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
548185377Ssam	const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
549185377Ssam	uint16_t pdGainOverlap_t2;
550185377Ssam	int16_t minCalPower5413_t2;
551185377Ssam	uint16_t *pdadcValues = ahp->ah_pcdacTable;
552185377Ssam	uint16_t gainBoundaries[4];
553185380Ssam	uint32_t reg32, regoffset;
554185380Ssam	int i, numPdGainsUsed;
555185380Ssam#ifndef AH_USE_INIPDGAIN
556185380Ssam	uint32_t tpcrg1;
557185380Ssam#endif
558185377Ssam
559185377Ssam	HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: chan 0x%x flag 0x%x\n",
560187831Ssam	    __func__, chan->ic_freq, chan->ic_flags);
561185377Ssam
562187831Ssam	if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
563185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
564187831Ssam	else if (IEEE80211_IS_CHAN_B(chan))
565185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
566185377Ssam	else {
567187831Ssam		HALASSERT(IEEE80211_IS_CHAN_5GHZ(chan));
568185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11A];
569185377Ssam	}
570185377Ssam
571185377Ssam	pdGainOverlap_t2 = (uint16_t) SM(OS_REG_READ(ah, AR_PHY_TPCRG5),
572185377Ssam					  AR_PHY_TPCRG5_PD_GAIN_OVERLAP);
573185377Ssam
574185377Ssam	numPdGainsUsed = ar5413getGainBoundariesAndPdadcsForPowers(ah,
575187831Ssam		freq, pRawDataset, pdGainOverlap_t2,
576185377Ssam		&minCalPower5413_t2,gainBoundaries, rfXpdGain, pdadcValues);
577185377Ssam	HALASSERT(1 <= numPdGainsUsed && numPdGainsUsed <= 3);
578185377Ssam
579185380Ssam#ifdef AH_USE_INIPDGAIN
580185380Ssam	/*
581185380Ssam	 * Use pd_gains curve from eeprom; Atheros always uses
582185380Ssam	 * the default curve from the ini file but some vendors
583185380Ssam	 * (e.g. Zcomax) want to override this curve and not
584185380Ssam	 * honoring their settings results in tx power 5dBm low.
585185380Ssam	 */
586185377Ssam	OS_REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN,
587185377Ssam			 (pRawDataset->pDataPerChannel[0].numPdGains - 1));
588185380Ssam#else
589185377Ssam	tpcrg1 = OS_REG_READ(ah, AR_PHY_TPCRG1);
590185377Ssam	tpcrg1 = (tpcrg1 &~ AR_PHY_TPCRG1_NUM_PD_GAIN)
591185377Ssam		  | SM(numPdGainsUsed-1, AR_PHY_TPCRG1_NUM_PD_GAIN);
592185377Ssam	switch (numPdGainsUsed) {
593185377Ssam	case 3:
594185377Ssam		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING3;
595185377Ssam		tpcrg1 |= SM(rfXpdGain[2], AR_PHY_TPCRG1_PDGAIN_SETTING3);
596185377Ssam		/* fall thru... */
597185377Ssam	case 2:
598185377Ssam		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING2;
599185377Ssam		tpcrg1 |= SM(rfXpdGain[1], AR_PHY_TPCRG1_PDGAIN_SETTING2);
600185377Ssam		/* fall thru... */
601185377Ssam	case 1:
602185377Ssam		tpcrg1 &= ~AR_PHY_TPCRG1_PDGAIN_SETTING1;
603185377Ssam		tpcrg1 |= SM(rfXpdGain[0], AR_PHY_TPCRG1_PDGAIN_SETTING1);
604185377Ssam		break;
605185377Ssam	}
606185377Ssam#ifdef AH_DEBUG
607185377Ssam	if (tpcrg1 != OS_REG_READ(ah, AR_PHY_TPCRG1))
608185377Ssam		HALDEBUG(ah, HAL_DEBUG_RFPARAM, "%s: using non-default "
609185377Ssam		    "pd_gains (default 0x%x, calculated 0x%x)\n",
610185377Ssam		    __func__, OS_REG_READ(ah, AR_PHY_TPCRG1), tpcrg1);
611185377Ssam#endif
612185377Ssam	OS_REG_WRITE(ah, AR_PHY_TPCRG1, tpcrg1);
613185380Ssam#endif
614185377Ssam
615185377Ssam	/*
616185377Ssam	 * Note the pdadc table may not start at 0 dBm power, could be
617185377Ssam	 * negative or greater than 0.  Need to offset the power
618185377Ssam	 * values by the amount of minPower for griffin
619185377Ssam	 */
620185377Ssam	if (minCalPower5413_t2 != 0)
621185377Ssam		ahp->ah_txPowerIndexOffset = (int16_t)(0 - minCalPower5413_t2);
622185377Ssam	else
623185377Ssam		ahp->ah_txPowerIndexOffset = 0;
624185377Ssam
625185377Ssam	/* Finally, write the power values into the baseband power table */
626185377Ssam	regoffset = 0x9800 + (672 <<2); /* beginning of pdadc table in griffin */
627185377Ssam	for (i = 0; i < 32; i++) {
628185377Ssam		reg32 = ((pdadcValues[4*i + 0] & 0xFF) << 0)  |
629185377Ssam			((pdadcValues[4*i + 1] & 0xFF) << 8)  |
630185377Ssam			((pdadcValues[4*i + 2] & 0xFF) << 16) |
631185377Ssam			((pdadcValues[4*i + 3] & 0xFF) << 24) ;
632185377Ssam		OS_REG_WRITE(ah, regoffset, reg32);
633185377Ssam		regoffset += 4;
634185377Ssam	}
635185377Ssam
636185377Ssam	OS_REG_WRITE(ah, AR_PHY_TPCRG5,
637185377Ssam		     SM(pdGainOverlap_t2, AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
638185377Ssam		     SM(gainBoundaries[0], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) |
639185377Ssam		     SM(gainBoundaries[1], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) |
640185377Ssam		     SM(gainBoundaries[2], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) |
641185377Ssam		     SM(gainBoundaries[3], AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
642185377Ssam
643185377Ssam	return AH_TRUE;
644185377Ssam}
645185377Ssam
646185377Ssamstatic int16_t
647185377Ssamar5413GetMinPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
648185377Ssam{
649185377Ssam	uint32_t ii,jj;
650185377Ssam	uint16_t Pmin=0,numVpd;
651185377Ssam
652185377Ssam	for (ii = 0; ii < MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
653185377Ssam		jj = MAX_NUM_PDGAINS_PER_CHANNEL - ii - 1;
654185377Ssam		/* work backwards 'cause highest pdGain for lowest power */
655185377Ssam		numVpd = data->pDataPerPDGain[jj].numVpd;
656185377Ssam		if (numVpd > 0) {
657185377Ssam			Pmin = data->pDataPerPDGain[jj].pwr_t4[0];
658185377Ssam			return(Pmin);
659185377Ssam		}
660185377Ssam	}
661185377Ssam	return(Pmin);
662185377Ssam}
663185377Ssam
664185377Ssamstatic int16_t
665185377Ssamar5413GetMaxPower(struct ath_hal *ah, const RAW_DATA_PER_CHANNEL_2413 *data)
666185377Ssam{
667185377Ssam	uint32_t ii;
668185377Ssam	uint16_t Pmax=0,numVpd;
669185377Ssam
670185377Ssam	for (ii=0; ii< MAX_NUM_PDGAINS_PER_CHANNEL; ii++) {
671185377Ssam		/* work forwards cuase lowest pdGain for highest power */
672185377Ssam		numVpd = data->pDataPerPDGain[ii].numVpd;
673185377Ssam		if (numVpd > 0) {
674185377Ssam			Pmax = data->pDataPerPDGain[ii].pwr_t4[numVpd-1];
675185377Ssam			return(Pmax);
676185377Ssam		}
677185377Ssam	}
678185377Ssam	return(Pmax);
679185377Ssam}
680185377Ssam
681185377Ssamstatic HAL_BOOL
682187831Ssamar5413GetChannelMaxMinPower(struct ath_hal *ah,
683187831Ssam	const struct ieee80211_channel *chan,
684185377Ssam	int16_t *maxPow, int16_t *minPow)
685185377Ssam{
686187831Ssam	uint16_t freq = chan->ic_freq;		/* NB: never mapped */
687185377Ssam	const HAL_EEPROM *ee = AH_PRIVATE(ah)->ah_eeprom;
688185377Ssam	const RAW_DATA_STRUCT_2413 *pRawDataset = AH_NULL;
689185377Ssam	const RAW_DATA_PER_CHANNEL_2413 *data=AH_NULL;
690185377Ssam	uint16_t numChannels;
691185377Ssam	int totalD,totalF, totalMin,last, i;
692185377Ssam
693185377Ssam	*maxPow = 0;
694185377Ssam
695187831Ssam	if (IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_108G(chan))
696185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11G];
697187831Ssam	else if (IEEE80211_IS_CHAN_B(chan))
698185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11B];
699185377Ssam	else {
700187831Ssam		HALASSERT(IEEE80211_IS_CHAN_5GHZ(chan));
701185377Ssam		pRawDataset = &ee->ee_rawDataset2413[headerInfo11A];
702185377Ssam	}
703185377Ssam
704185377Ssam	numChannels = pRawDataset->numChannels;
705185377Ssam	data = pRawDataset->pDataPerChannel;
706185377Ssam
707185377Ssam	/* Make sure the channel is in the range of the TP values
708185377Ssam	 *  (freq piers)
709185377Ssam	 */
710185377Ssam	if (numChannels < 1)
711185377Ssam		return(AH_FALSE);
712185377Ssam
713187831Ssam	if ((freq < data[0].channelValue) ||
714187831Ssam	    (freq > data[numChannels-1].channelValue)) {
715187831Ssam		if (freq < data[0].channelValue) {
716185377Ssam			*maxPow = ar5413GetMaxPower(ah, &data[0]);
717185377Ssam			*minPow = ar5413GetMinPower(ah, &data[0]);
718185377Ssam			return(AH_TRUE);
719185377Ssam		} else {
720185377Ssam			*maxPow = ar5413GetMaxPower(ah, &data[numChannels - 1]);
721185377Ssam			*minPow = ar5413GetMinPower(ah, &data[numChannels - 1]);
722185377Ssam			return(AH_TRUE);
723185377Ssam		}
724185377Ssam	}
725185377Ssam
726185377Ssam	/* Linearly interpolate the power value now */
727187831Ssam	for (last=0,i=0; (i<numChannels) && (freq > data[i].channelValue);
728185377Ssam	     last = i++);
729185377Ssam	totalD = data[i].channelValue - data[last].channelValue;
730185377Ssam	if (totalD > 0) {
731185377Ssam		totalF = ar5413GetMaxPower(ah, &data[i]) - ar5413GetMaxPower(ah, &data[last]);
732187831Ssam		*maxPow = (int8_t) ((totalF*(freq-data[last].channelValue) +
733185377Ssam				     ar5413GetMaxPower(ah, &data[last])*totalD)/totalD);
734185377Ssam		totalMin = ar5413GetMinPower(ah, &data[i]) - ar5413GetMinPower(ah, &data[last]);
735187831Ssam		*minPow = (int8_t) ((totalMin*(freq-data[last].channelValue) +
736185377Ssam				     ar5413GetMinPower(ah, &data[last])*totalD)/totalD);
737185377Ssam		return(AH_TRUE);
738185377Ssam	} else {
739187831Ssam		if (freq == data[i].channelValue) {
740185377Ssam			*maxPow = ar5413GetMaxPower(ah, &data[i]);
741185377Ssam			*minPow = ar5413GetMinPower(ah, &data[i]);
742185377Ssam			return(AH_TRUE);
743185377Ssam		} else
744185377Ssam			return(AH_FALSE);
745185377Ssam	}
746185377Ssam}
747185377Ssam
748185377Ssam/*
749185377Ssam * Free memory for analog bank scratch buffers
750185377Ssam */
751185377Ssamstatic void
752185377Ssamar5413RfDetach(struct ath_hal *ah)
753185377Ssam{
754185377Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
755185377Ssam
756185377Ssam	HALASSERT(ahp->ah_rfHal != AH_NULL);
757185377Ssam	ath_hal_free(ahp->ah_rfHal);
758185377Ssam	ahp->ah_rfHal = AH_NULL;
759185377Ssam}
760185377Ssam
761185377Ssam/*
762185377Ssam * Allocate memory for analog bank scratch buffers
763185377Ssam * Scratch Buffer will be reinitialized every reset so no need to zero now
764185377Ssam */
765185406Ssamstatic HAL_BOOL
766185377Ssamar5413RfAttach(struct ath_hal *ah, HAL_STATUS *status)
767185377Ssam{
768185377Ssam	struct ath_hal_5212 *ahp = AH5212(ah);
769185377Ssam	struct ar5413State *priv;
770185377Ssam
771185377Ssam	HALASSERT(ah->ah_magic == AR5212_MAGIC);
772185377Ssam
773185377Ssam	HALASSERT(ahp->ah_rfHal == AH_NULL);
774185377Ssam	priv = ath_hal_malloc(sizeof(struct ar5413State));
775185377Ssam	if (priv == AH_NULL) {
776185377Ssam		HALDEBUG(ah, HAL_DEBUG_ANY,
777185377Ssam		    "%s: cannot allocate private state\n", __func__);
778185377Ssam		*status = HAL_ENOMEM;		/* XXX */
779185377Ssam		return AH_FALSE;
780185377Ssam	}
781185377Ssam	priv->base.rfDetach		= ar5413RfDetach;
782185377Ssam	priv->base.writeRegs		= ar5413WriteRegs;
783185377Ssam	priv->base.getRfBank		= ar5413GetRfBank;
784185377Ssam	priv->base.setChannel		= ar5413SetChannel;
785185377Ssam	priv->base.setRfRegs		= ar5413SetRfRegs;
786185377Ssam	priv->base.setPowerTable	= ar5413SetPowerTable;
787185377Ssam	priv->base.getChannelMaxMinPower = ar5413GetChannelMaxMinPower;
788185377Ssam	priv->base.getNfAdjust		= ar5212GetNfAdjust;
789185377Ssam
790185377Ssam	ahp->ah_pcdacTable = priv->pcdacTable;
791185377Ssam	ahp->ah_pcdacTableSize = sizeof(priv->pcdacTable);
792185377Ssam	ahp->ah_rfHal = &priv->base;
793185377Ssam
794185377Ssam	return AH_TRUE;
795185377Ssam}
796185406Ssam
797185406Ssamstatic HAL_BOOL
798185406Ssamar5413Probe(struct ath_hal *ah)
799185406Ssam{
800185406Ssam	return IS_5413(ah);
801185406Ssam}
802185418SsamAH_RF(RF5413, ar5413Probe, ar5413RfAttach);
803