2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3 * Copyright (c) 2002-2008 Atheros Communications, Inc.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * $Id: ar5111.c,v 1.3 2009/01/06 06:03:57 mrg Exp $
22 #include "ah_internal.h"
24 #include "ah_eeprom_v3.h"
26 #include "ar5212/ar5212.h"
27 #include "ar5212/ar5212reg.h"
28 #include "ar5212/ar5212phy.h"
31 #include "ar5212/ar5212.ini"
33 #define N(a) (sizeof(a)/sizeof(a[0]))
36 RF_HAL_FUNCS base
; /* public state, must be first */
37 uint16_t pcdacTable
[PWR_TABLE_SIZE
];
39 uint32_t Bank0Data
[N(ar5212Bank0_5111
)];
40 uint32_t Bank1Data
[N(ar5212Bank1_5111
)];
41 uint32_t Bank2Data
[N(ar5212Bank2_5111
)];
42 uint32_t Bank3Data
[N(ar5212Bank3_5111
)];
43 uint32_t Bank6Data
[N(ar5212Bank6_5111
)];
44 uint32_t Bank7Data
[N(ar5212Bank7_5111
)];
46 #define AR5111(ah) ((struct ar5111State *) AH5212(ah)->ah_rfHal)
48 static uint16_t ar5212GetScaledPower(uint16_t channel
, uint16_t pcdacValue
,
49 const PCDACS_EEPROM
*pSrcStruct
);
50 static HAL_BOOL
ar5212FindValueInList(uint16_t channel
, uint16_t pcdacValue
,
51 const PCDACS_EEPROM
*pSrcStruct
, uint16_t *powerValue
);
52 static void ar5212GetLowerUpperPcdacs(uint16_t pcdac
, uint16_t channel
,
53 const PCDACS_EEPROM
*pSrcStruct
,
54 uint16_t *pLowerPcdac
, uint16_t *pUpperPcdac
);
56 extern void ar5212GetLowerUpperValues(uint16_t value
,
57 const uint16_t *pList
, uint16_t listSize
,
58 uint16_t *pLowerValue
, uint16_t *pUpperValue
);
59 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
60 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
63 ar5111WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
66 HAL_INI_WRITE_ARRAY(ah
, ar5212Modes_5111
, modesIndex
, writes
);
67 HAL_INI_WRITE_ARRAY(ah
, ar5212Common_5111
, 1, writes
);
68 HAL_INI_WRITE_ARRAY(ah
, ar5212BB_RfGain_5111
, freqIndex
, writes
);
72 * Take the MHz channel value and set the Channel value
74 * ASSUMES: Writes enabled to analog bus
77 ar5111SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
79 #define CI_2GHZ_INDEX_CORRECTION 19
80 uint32_t refClk
, reg32
, data2111
;
81 int16_t chan5111
, chanIEEE
;
84 * Structure to hold 11b tuning information for 5111/2111
85 * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12
88 uint32_t refClkSel
; /* reference clock, 1 for 16 MHz */
89 uint32_t channelSelect
; /* P[7:4]S[3:0] bits */
90 uint16_t channel5111
; /* 11a channel for 5111 */
93 static const CHAN_INFO_2GHZ chan2GHzData
[] = {
94 { 1, 0x46, 96 }, /* 2312 -19 */
95 { 1, 0x46, 97 }, /* 2317 -18 */
96 { 1, 0x46, 98 }, /* 2322 -17 */
97 { 1, 0x46, 99 }, /* 2327 -16 */
98 { 1, 0x46, 100 }, /* 2332 -15 */
99 { 1, 0x46, 101 }, /* 2337 -14 */
100 { 1, 0x46, 102 }, /* 2342 -13 */
101 { 1, 0x46, 103 }, /* 2347 -12 */
102 { 1, 0x46, 104 }, /* 2352 -11 */
103 { 1, 0x46, 105 }, /* 2357 -10 */
104 { 1, 0x46, 106 }, /* 2362 -9 */
105 { 1, 0x46, 107 }, /* 2367 -8 */
106 { 1, 0x46, 108 }, /* 2372 -7 */
107 /* index -6 to 0 are pad to make this a nolookup table */
108 { 1, 0x46, 116 }, /* -6 */
109 { 1, 0x46, 116 }, /* -5 */
110 { 1, 0x46, 116 }, /* -4 */
111 { 1, 0x46, 116 }, /* -3 */
112 { 1, 0x46, 116 }, /* -2 */
113 { 1, 0x46, 116 }, /* -1 */
114 { 1, 0x46, 116 }, /* 0 */
115 { 1, 0x46, 116 }, /* 2412 1 */
116 { 1, 0x46, 117 }, /* 2417 2 */
117 { 1, 0x46, 118 }, /* 2422 3 */
118 { 1, 0x46, 119 }, /* 2427 4 */
119 { 1, 0x46, 120 }, /* 2432 5 */
120 { 1, 0x46, 121 }, /* 2437 6 */
121 { 1, 0x46, 122 }, /* 2442 7 */
122 { 1, 0x46, 123 }, /* 2447 8 */
123 { 1, 0x46, 124 }, /* 2452 9 */
124 { 1, 0x46, 125 }, /* 2457 10 */
125 { 1, 0x46, 126 }, /* 2462 11 */
126 { 1, 0x46, 127 }, /* 2467 12 */
127 { 1, 0x46, 128 }, /* 2472 13 */
128 { 1, 0x44, 124 }, /* 2484 14 */
129 { 1, 0x46, 136 }, /* 2512 15 */
130 { 1, 0x46, 140 }, /* 2532 16 */
131 { 1, 0x46, 144 }, /* 2552 17 */
132 { 1, 0x46, 148 }, /* 2572 18 */
133 { 1, 0x46, 152 }, /* 2592 19 */
134 { 1, 0x46, 156 }, /* 2612 20 */
135 { 1, 0x46, 160 }, /* 2632 21 */
136 { 1, 0x46, 164 }, /* 2652 22 */
137 { 1, 0x46, 168 }, /* 2672 23 */
138 { 1, 0x46, 172 }, /* 2692 24 */
139 { 1, 0x46, 176 }, /* 2712 25 */
140 { 1, 0x46, 180 } /* 2732 26 */
143 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
145 chanIEEE
= ath_hal_mhz2ieee(ah
, chan
->channel
, chan
->channelFlags
);
146 if (IS_CHAN_2GHZ(chan
)) {
147 const CHAN_INFO_2GHZ
* ci
=
148 &chan2GHzData
[chanIEEE
+ CI_2GHZ_INDEX_CORRECTION
];
151 data2111
= ((ath_hal_reverseBits(ci
->channelSelect
, 8) & 0xff)
153 | (ci
->refClkSel
<< 4);
154 chan5111
= ci
->channel5111
;
155 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
156 if (chan
->channel
== 2484) {
157 /* Enable channel spreading for channel 14 */
158 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
159 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
161 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
162 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
165 chan5111
= chanIEEE
; /* no conversion needed */
169 /* Rest of the code is common for 5 GHz and 2.4 GHz. */
170 if (chan5111
>= 145 || (chan5111
& 0x1)) {
171 reg32
= ath_hal_reverseBits(chan5111
- 24, 8) & 0xff;
174 reg32
= ath_hal_reverseBits(((chan5111
- 24)/2), 8) & 0xff;
178 reg32
= (reg32
<< 2) | (refClk
<< 1) | (1 << 10) | 0x1;
179 OS_REG_WRITE(ah
, AR_PHY(0x27), ((data2111
& 0xff) << 8) | (reg32
& 0xff));
181 OS_REG_WRITE(ah
, AR_PHY(0x34), (data2111
& 0xff00) | (reg32
& 0xff));
183 AH_PRIVATE(ah
)->ah_curchan
= chan
;
185 #undef CI_2GHZ_INDEX_CORRECTION
189 * Return a reference to the requested RF Bank.
192 ar5111GetRfBank(struct ath_hal
*ah
, int bank
)
194 struct ar5111State
*priv
= AR5111(ah
);
196 HALASSERT(priv
!= AH_NULL
);
198 case 0: return priv
->Bank0Data
;
199 case 1: return priv
->Bank1Data
;
200 case 2: return priv
->Bank2Data
;
201 case 3: return priv
->Bank3Data
;
202 case 6: return priv
->Bank6Data
;
203 case 7: return priv
->Bank7Data
;
205 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
211 * Reads EEPROM header info from device structure and programs
214 * REQUIRES: Access to the analog rf device
217 ar5111SetRfRegs(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
,
218 uint16_t modesIndex
, uint16_t *rfXpdGain
)
220 struct ath_hal_5212
*ahp
= AH5212(ah
);
221 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
222 uint16_t rfXpdGainFixed
, rfPloSel
, rfPwdXpd
, gainI
;
223 uint16_t tempOB
, tempDB
;
224 uint32_t ob2GHz
, db2GHz
, rfReg
[N(ar5212Bank6_5111
)];
225 int i
, regWrites
= 0;
227 /* Setup rf parameters */
228 switch (chan
->channelFlags
& CHANNEL_ALL
) {
231 if (4000 < chan
->channel
&& chan
->channel
< 5260) {
234 } else if (5260 <= chan
->channel
&& chan
->channel
< 5500) {
237 } else if (5500 <= chan
->channel
&& chan
->channel
< 5725) {
240 } else if (chan
->channel
>= 5725) {
244 /* XXX when does this happen??? */
249 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11A
];
250 rfPloSel
= ee
->ee_xpd
[headerInfo11A
];
251 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11A
];
252 gainI
= ee
->ee_gainI
[headerInfo11A
];
255 tempOB
= ee
->ee_obFor24
;
256 tempDB
= ee
->ee_dbFor24
;
257 ob2GHz
= ee
->ee_ob2GHz
[0];
258 db2GHz
= ee
->ee_db2GHz
[0];
260 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11B
];
261 rfPloSel
= ee
->ee_xpd
[headerInfo11B
];
262 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11B
];
263 gainI
= ee
->ee_gainI
[headerInfo11B
];
266 tempOB
= ee
->ee_obFor24g
;
267 tempDB
= ee
->ee_dbFor24g
;
268 ob2GHz
= ee
->ee_ob2GHz
[1];
269 db2GHz
= ee
->ee_db2GHz
[1];
271 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11G
];
272 rfPloSel
= ee
->ee_xpd
[headerInfo11G
];
273 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11G
];
274 gainI
= ee
->ee_gainI
[headerInfo11G
];
277 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
278 __func__
, chan
->channelFlags
);
282 HALASSERT(1 <= tempOB
&& tempOB
<= 5);
283 HALASSERT(1 <= tempDB
&& tempDB
<= 5);
286 for (i
= 0; i
< N(ar5212Bank0_5111
); i
++)
287 rfReg
[i
] = ar5212Bank0_5111
[i
][modesIndex
];
288 if (IS_CHAN_2GHZ(chan
)) {
289 ar5212ModifyRfBuffer(rfReg
, ob2GHz
, 3, 119, 0);
290 ar5212ModifyRfBuffer(rfReg
, db2GHz
, 3, 122, 0);
292 HAL_INI_WRITE_BANK(ah
, ar5212Bank0_5111
, rfReg
, regWrites
);
295 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank1_5111
, 1, regWrites
);
298 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank2_5111
, modesIndex
, regWrites
);
301 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank3_5111
, modesIndex
, regWrites
);
304 for (i
= 0; i
< N(ar5212Bank6_5111
); i
++)
305 rfReg
[i
] = ar5212Bank6_5111
[i
][modesIndex
];
306 if (IS_CHAN_A(chan
)) { /* NB: CHANNEL_A | CHANNEL_T */
307 ar5212ModifyRfBuffer(rfReg
, ee
->ee_cornerCal
.pd84
, 1, 51, 3);
308 ar5212ModifyRfBuffer(rfReg
, ee
->ee_cornerCal
.pd90
, 1, 45, 3);
310 ar5212ModifyRfBuffer(rfReg
, rfPwdXpd
, 1, 95, 0);
311 ar5212ModifyRfBuffer(rfReg
, rfXpdGainFixed
, 4, 96, 0);
312 /* Set 5212 OB & DB */
313 ar5212ModifyRfBuffer(rfReg
, tempOB
, 3, 104, 0);
314 ar5212ModifyRfBuffer(rfReg
, tempDB
, 3, 107, 0);
315 HAL_INI_WRITE_BANK(ah
, ar5212Bank6_5111
, rfReg
, regWrites
);
318 for (i
= 0; i
< N(ar5212Bank7_5111
); i
++)
319 rfReg
[i
] = ar5212Bank7_5111
[i
][modesIndex
];
320 ar5212ModifyRfBuffer(rfReg
, gainI
, 6, 29, 0);
321 ar5212ModifyRfBuffer(rfReg
, rfPloSel
, 1, 4, 0);
323 if (IS_CHAN_QUARTER_RATE(chan
) || IS_CHAN_HALF_RATE(chan
)) {
324 uint32_t rfWaitI
, rfWaitS
, rfMaxTime
;
327 rfWaitI
= (IS_CHAN_HALF_RATE(chan
)) ? 0x10 : 0x1f;
329 ar5212ModifyRfBuffer(rfReg
, rfWaitS
, 5, 19, 0);
330 ar5212ModifyRfBuffer(rfReg
, rfWaitI
, 5, 24, 0);
331 ar5212ModifyRfBuffer(rfReg
, rfMaxTime
, 2, 49, 0);
335 HAL_INI_WRITE_BANK(ah
, ar5212Bank7_5111
, rfReg
, regWrites
);
337 /* Now that we have reprogrammed rfgain value, clear the flag. */
338 ahp
->ah_rfgainState
= HAL_RFGAIN_INACTIVE
;
344 * Returns interpolated or the scaled up interpolated value
347 interpolate(uint16_t target
, uint16_t srcLeft
, uint16_t srcRight
,
348 uint16_t targetLeft
, uint16_t targetRight
)
353 /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */
354 if ((targetLeft
* targetRight
) == 0)
357 if (srcRight
!= srcLeft
) {
359 * Note the ratio always need to be scaled,
360 * since it will be a fraction.
362 lRatio
= (target
- srcLeft
) * EEP_SCALE
/ (srcRight
- srcLeft
);
364 /* Return as Left target if value would be negative */
366 } else if (lRatio
> EEP_SCALE
) {
367 /* Return as Right target if Ratio is greater than 100% (SCALE) */
370 rv
= (lRatio
* targetRight
+ (EEP_SCALE
- lRatio
) *
371 targetLeft
) / EEP_SCALE
;
380 * Read the transmit power levels from the structures taken from EEPROM
381 * Interpolate read transmit power values for this channel
382 * Organize the transmit power values into a table for writing into the hardware
385 ar5111SetPowerTable(struct ath_hal
*ah
,
386 int16_t *pMinPower
, int16_t *pMaxPower
, HAL_CHANNEL_INTERNAL
*chan
,
389 struct ath_hal_5212
*ahp
= AH5212(ah
);
390 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
391 FULL_PCDAC_STRUCT pcdacStruct
;
394 uint16_t *pPcdacValues
;
395 int16_t *pScaledUpDbm
;
396 int16_t minScaledPwr
;
397 int16_t maxScaledPwr
;
399 uint16_t pcdacMin
= 0;
400 uint16_t pcdacMax
= PCDAC_STOP
;
401 uint16_t pcdacTableIndex
;
402 uint16_t scaledPcdac
;
403 PCDACS_EEPROM
*pSrcStruct
;
404 PCDACS_EEPROM eepromPcdacs
;
406 /* setup the pcdac struct to point to the correct info, based on mode */
407 switch (chan
->channelFlags
& CHANNEL_ALL
) {
410 eepromPcdacs
.numChannels
= ee
->ee_numChannels11a
;
411 eepromPcdacs
.pChannelList
= ee
->ee_channels11a
;
412 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11a
;
415 eepromPcdacs
.numChannels
= ee
->ee_numChannels2_4
;
416 eepromPcdacs
.pChannelList
= ee
->ee_channels11b
;
417 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11b
;
421 eepromPcdacs
.numChannels
= ee
->ee_numChannels2_4
;
422 eepromPcdacs
.pChannelList
= ee
->ee_channels11g
;
423 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11g
;
426 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
427 __func__
, chan
->channelFlags
);
431 pSrcStruct
= &eepromPcdacs
;
433 OS_MEMZERO(&pcdacStruct
, sizeof(pcdacStruct
));
434 pPcdacValues
= pcdacStruct
.PcdacValues
;
435 pScaledUpDbm
= pcdacStruct
.PwrValues
;
437 /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */
438 for (i
= PCDAC_START
, j
= 0; i
<= PCDAC_STOP
; i
+= PCDAC_STEP
, j
++)
441 pcdacStruct
.numPcdacValues
= j
;
442 pcdacStruct
.pcdacMin
= PCDAC_START
;
443 pcdacStruct
.pcdacMax
= PCDAC_STOP
;
445 /* Fill out the power values for this channel */
446 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++ )
447 pScaledUpDbm
[j
] = ar5212GetScaledPower(chan
->channel
,
448 pPcdacValues
[j
], pSrcStruct
);
450 /* Now scale the pcdac values to fit in the 64 entry power table */
451 minScaledPwr
= pScaledUpDbm
[0];
452 maxScaledPwr
= pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1];
454 /* find minimum and make monotonic */
455 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++) {
456 if (minScaledPwr
>= pScaledUpDbm
[j
]) {
457 minScaledPwr
= pScaledUpDbm
[j
];
461 * Make the full_hsh monotonically increasing otherwise
462 * interpolation algorithm will get fooled gotta start
463 * working from the top, hence i = 63 - j.
465 i
= (uint16_t)(pcdacStruct
.numPcdacValues
- 1 - j
);
468 if (pScaledUpDbm
[i
-1] > pScaledUpDbm
[i
]) {
470 * It could be a glitch, so make the power for
471 * this pcdac the same as the power from the
472 * next highest pcdac.
474 pScaledUpDbm
[i
- 1] = pScaledUpDbm
[i
];
478 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++)
479 if (maxScaledPwr
< pScaledUpDbm
[j
]) {
480 maxScaledPwr
= pScaledUpDbm
[j
];
484 /* Find the first power level with a pcdac */
485 pwr
= (uint16_t)(PWR_STEP
*
486 ((minScaledPwr
- PWR_MIN
+ PWR_STEP
/ 2) / PWR_STEP
) + PWR_MIN
);
488 /* Write all the first pcdac entries based off the pcdacMin */
490 for (i
= 0; i
< (2 * (pwr
- PWR_MIN
) / EEP_SCALE
+ 1); i
++) {
491 HALASSERT(pcdacTableIndex
< PWR_TABLE_SIZE
);
492 ahp
->ah_pcdacTable
[pcdacTableIndex
++] = pcdacMin
;
496 while (pwr
< pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1] &&
497 pcdacTableIndex
< PWR_TABLE_SIZE
) {
499 /* stop if dbM > max_power_possible */
500 while (pwr
< pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1] &&
501 (pwr
- pScaledUpDbm
[i
])*(pwr
- pScaledUpDbm
[i
+1]) > 0)
503 /* scale by 2 and add 1 to enable round up or down as needed */
504 scaledPcdac
= (uint16_t)(interpolate(pwr
,
505 pScaledUpDbm
[i
], pScaledUpDbm
[i
+ 1],
506 (uint16_t)(pPcdacValues
[i
] * 2),
507 (uint16_t)(pPcdacValues
[i
+ 1] * 2)) + 1);
509 HALASSERT(pcdacTableIndex
< PWR_TABLE_SIZE
);
510 ahp
->ah_pcdacTable
[pcdacTableIndex
] = scaledPcdac
/ 2;
511 if (ahp
->ah_pcdacTable
[pcdacTableIndex
] > pcdacMax
)
512 ahp
->ah_pcdacTable
[pcdacTableIndex
] = pcdacMax
;
516 /* Write all the last pcdac entries based off the last valid pcdac */
517 while (pcdacTableIndex
< PWR_TABLE_SIZE
) {
518 ahp
->ah_pcdacTable
[pcdacTableIndex
] =
519 ahp
->ah_pcdacTable
[pcdacTableIndex
- 1];
523 /* No power table adjustment for 5111 */
524 ahp
->ah_txPowerIndexOffset
= 0;
530 * Get or interpolate the pcdac value from the calibrated data.
533 ar5212GetScaledPower(uint16_t channel
, uint16_t pcdacValue
,
534 const PCDACS_EEPROM
*pSrcStruct
)
537 uint16_t lFreq
, rFreq
; /* left and right frequency values */
538 uint16_t llPcdac
, ulPcdac
; /* lower and upper left pcdac values */
539 uint16_t lrPcdac
, urPcdac
; /* lower and upper right pcdac values */
540 uint16_t lPwr
= 0, uPwr
= 0; /* lower and upper temp pwr values */
541 uint16_t lScaledPwr
, rScaledPwr
; /* left and right scaled power */
543 if (ar5212FindValueInList(channel
, pcdacValue
, pSrcStruct
, &powerValue
)) {
544 /* value was copied from srcStruct */
548 ar5212GetLowerUpperValues(channel
,
549 pSrcStruct
->pChannelList
, pSrcStruct
->numChannels
,
551 ar5212GetLowerUpperPcdacs(pcdacValue
,
552 lFreq
, pSrcStruct
, &llPcdac
, &ulPcdac
);
553 ar5212GetLowerUpperPcdacs(pcdacValue
,
554 rFreq
, pSrcStruct
, &lrPcdac
, &urPcdac
);
556 /* get the power index for the pcdac value */
557 ar5212FindValueInList(lFreq
, llPcdac
, pSrcStruct
, &lPwr
);
558 ar5212FindValueInList(lFreq
, ulPcdac
, pSrcStruct
, &uPwr
);
559 lScaledPwr
= interpolate(pcdacValue
, llPcdac
, ulPcdac
, lPwr
, uPwr
);
561 ar5212FindValueInList(rFreq
, lrPcdac
, pSrcStruct
, &lPwr
);
562 ar5212FindValueInList(rFreq
, urPcdac
, pSrcStruct
, &uPwr
);
563 rScaledPwr
= interpolate(pcdacValue
, lrPcdac
, urPcdac
, lPwr
, uPwr
);
565 return interpolate(channel
, lFreq
, rFreq
, lScaledPwr
, rScaledPwr
);
569 * Find the value from the calibrated source data struct
572 ar5212FindValueInList(uint16_t channel
, uint16_t pcdacValue
,
573 const PCDACS_EEPROM
*pSrcStruct
, uint16_t *powerValue
)
575 const DATA_PER_CHANNEL
*pChannelData
= pSrcStruct
->pDataPerChannel
;
578 for (i
= 0; i
< pSrcStruct
->numChannels
; i
++ ) {
579 if (pChannelData
->channelValue
== channel
) {
580 const uint16_t* pPcdac
= pChannelData
->PcdacValues
;
583 for (j
= 0; j
< pChannelData
->numPcdacValues
; j
++ ) {
584 if (*pPcdac
== pcdacValue
) {
585 *powerValue
= pChannelData
->PwrValues
[j
];
597 * Get the upper and lower pcdac given the channel and the pcdac
601 ar5212GetLowerUpperPcdacs(uint16_t pcdac
, uint16_t channel
,
602 const PCDACS_EEPROM
*pSrcStruct
,
603 uint16_t *pLowerPcdac
, uint16_t *pUpperPcdac
)
605 const DATA_PER_CHANNEL
*pChannelData
= pSrcStruct
->pDataPerChannel
;
608 /* Find the channel information */
609 for (i
= 0; i
< pSrcStruct
->numChannels
; i
++) {
610 if (pChannelData
->channelValue
== channel
)
614 ar5212GetLowerUpperValues(pcdac
, pChannelData
->PcdacValues
,
615 pChannelData
->numPcdacValues
,
616 pLowerPcdac
, pUpperPcdac
);
620 ar5111GetChannelMaxMinPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
,
621 int16_t *maxPow
, int16_t *minPow
)
623 /* XXX - Get 5111 power limits! */
624 /* NB: caller will cope */
629 * Adjust NF based on statistical values for 5GHz frequencies.
632 ar5111GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
634 static const struct {
638 { 5790, 6 }, /* NB: ordered high -> low */
652 for (i
= 0; c
->channel
<= adjust5111
[i
].freqLow
; i
++)
654 return adjust5111
[i
].adjust
;
658 * Free memory for analog bank scratch buffers
661 ar5111RfDetach(struct ath_hal
*ah
)
663 struct ath_hal_5212
*ahp
= AH5212(ah
);
665 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
666 ath_hal_free(ahp
->ah_rfHal
);
667 ahp
->ah_rfHal
= AH_NULL
;
671 * Allocate memory for analog bank scratch buffers
672 * Scratch Buffer will be reinitialized every reset so no need to zero now
675 ar5111RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
677 struct ath_hal_5212
*ahp
= AH5212(ah
);
678 struct ar5111State
*priv
;
680 HALASSERT(ah
->ah_magic
== AR5212_MAGIC
);
682 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
683 priv
= ath_hal_malloc(sizeof(struct ar5111State
));
684 if (priv
== AH_NULL
) {
685 HALDEBUG(ah
, HAL_DEBUG_ANY
,
686 "%s: cannot allocate private state\n", __func__
);
687 *status
= HAL_ENOMEM
; /* XXX */
690 priv
->base
.rfDetach
= ar5111RfDetach
;
691 priv
->base
.writeRegs
= ar5111WriteRegs
;
692 priv
->base
.getRfBank
= ar5111GetRfBank
;
693 priv
->base
.setChannel
= ar5111SetChannel
;
694 priv
->base
.setRfRegs
= ar5111SetRfRegs
;
695 priv
->base
.setPowerTable
= ar5111SetPowerTable
;
696 priv
->base
.getChannelMaxMinPower
= ar5111GetChannelMaxMinPower
;
697 priv
->base
.getNfAdjust
= ar5111GetNfAdjust
;
699 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
700 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
701 ahp
->ah_rfHal
= &priv
->base
;
707 ar5111Probe(struct ath_hal
*ah
)
709 return IS_RAD5111(ah
);
711 AH_RF(RF5111
, ar5111Probe
, ar5111RfAttach
);