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.
21 #ifdef AH_SUPPORT_5111
24 #include "ah_internal.h"
26 #include "ah_eeprom_v3.h"
28 #include "ar5212/ar5212.h"
29 #include "ar5212/ar5212reg.h"
30 #include "ar5212/ar5212phy.h"
33 #include "ar5212/ar5212.ini"
35 #define N(a) (sizeof(a)/sizeof(a[0]))
38 RF_HAL_FUNCS base
; /* public state, must be first */
39 uint16_t pcdacTable
[PWR_TABLE_SIZE
];
41 uint32_t Bank0Data
[N(ar5212Bank0_5111
)];
42 uint32_t Bank1Data
[N(ar5212Bank1_5111
)];
43 uint32_t Bank2Data
[N(ar5212Bank2_5111
)];
44 uint32_t Bank3Data
[N(ar5212Bank3_5111
)];
45 uint32_t Bank6Data
[N(ar5212Bank6_5111
)];
46 uint32_t Bank7Data
[N(ar5212Bank7_5111
)];
48 #define AR5111(ah) ((struct ar5111State *) AH5212(ah)->ah_rfHal)
50 static uint16_t ar5212GetScaledPower(uint16_t channel
, uint16_t pcdacValue
,
51 const PCDACS_EEPROM
*pSrcStruct
);
52 static HAL_BOOL
ar5212FindValueInList(uint16_t channel
, uint16_t pcdacValue
,
53 const PCDACS_EEPROM
*pSrcStruct
, uint16_t *powerValue
);
54 static void ar5212GetLowerUpperPcdacs(uint16_t pcdac
, uint16_t channel
,
55 const PCDACS_EEPROM
*pSrcStruct
,
56 uint16_t *pLowerPcdac
, uint16_t *pUpperPcdac
);
58 extern void ar5212GetLowerUpperValues(uint16_t value
,
59 const uint16_t *pList
, uint16_t listSize
,
60 uint16_t *pLowerValue
, uint16_t *pUpperValue
);
61 extern void ar5212ModifyRfBuffer(uint32_t *rfBuf
, uint32_t reg32
,
62 uint32_t numBits
, uint32_t firstBit
, uint32_t column
);
65 ar5111WriteRegs(struct ath_hal
*ah
, u_int modesIndex
, u_int freqIndex
,
68 HAL_INI_WRITE_ARRAY(ah
, ar5212Modes_5111
, modesIndex
, writes
);
69 HAL_INI_WRITE_ARRAY(ah
, ar5212Common_5111
, 1, writes
);
70 HAL_INI_WRITE_ARRAY(ah
, ar5212BB_RfGain_5111
, freqIndex
, writes
);
74 * Take the MHz channel value and set the Channel value
76 * ASSUMES: Writes enabled to analog bus
79 ar5111SetChannel(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
)
81 #define CI_2GHZ_INDEX_CORRECTION 19
82 uint32_t refClk
, reg32
, data2111
;
83 int16_t chan5111
, chanIEEE
;
86 * Structure to hold 11b tuning information for 5111/2111
87 * 16 MHz mode, divider ratio = 198 = NP+S. N=16, S=4 or 6, P=12
90 uint32_t refClkSel
; /* reference clock, 1 for 16 MHz */
91 uint32_t channelSelect
; /* P[7:4]S[3:0] bits */
92 uint16_t channel5111
; /* 11a channel for 5111 */
95 const static CHAN_INFO_2GHZ chan2GHzData
[] = {
96 { 1, 0x46, 96 }, /* 2312 -19 */
97 { 1, 0x46, 97 }, /* 2317 -18 */
98 { 1, 0x46, 98 }, /* 2322 -17 */
99 { 1, 0x46, 99 }, /* 2327 -16 */
100 { 1, 0x46, 100 }, /* 2332 -15 */
101 { 1, 0x46, 101 }, /* 2337 -14 */
102 { 1, 0x46, 102 }, /* 2342 -13 */
103 { 1, 0x46, 103 }, /* 2347 -12 */
104 { 1, 0x46, 104 }, /* 2352 -11 */
105 { 1, 0x46, 105 }, /* 2357 -10 */
106 { 1, 0x46, 106 }, /* 2362 -9 */
107 { 1, 0x46, 107 }, /* 2367 -8 */
108 { 1, 0x46, 108 }, /* 2372 -7 */
109 /* index -6 to 0 are pad to make this a nolookup table */
110 { 1, 0x46, 116 }, /* -6 */
111 { 1, 0x46, 116 }, /* -5 */
112 { 1, 0x46, 116 }, /* -4 */
113 { 1, 0x46, 116 }, /* -3 */
114 { 1, 0x46, 116 }, /* -2 */
115 { 1, 0x46, 116 }, /* -1 */
116 { 1, 0x46, 116 }, /* 0 */
117 { 1, 0x46, 116 }, /* 2412 1 */
118 { 1, 0x46, 117 }, /* 2417 2 */
119 { 1, 0x46, 118 }, /* 2422 3 */
120 { 1, 0x46, 119 }, /* 2427 4 */
121 { 1, 0x46, 120 }, /* 2432 5 */
122 { 1, 0x46, 121 }, /* 2437 6 */
123 { 1, 0x46, 122 }, /* 2442 7 */
124 { 1, 0x46, 123 }, /* 2447 8 */
125 { 1, 0x46, 124 }, /* 2452 9 */
126 { 1, 0x46, 125 }, /* 2457 10 */
127 { 1, 0x46, 126 }, /* 2462 11 */
128 { 1, 0x46, 127 }, /* 2467 12 */
129 { 1, 0x46, 128 }, /* 2472 13 */
130 { 1, 0x44, 124 }, /* 2484 14 */
131 { 1, 0x46, 136 }, /* 2512 15 */
132 { 1, 0x46, 140 }, /* 2532 16 */
133 { 1, 0x46, 144 }, /* 2552 17 */
134 { 1, 0x46, 148 }, /* 2572 18 */
135 { 1, 0x46, 152 }, /* 2592 19 */
136 { 1, 0x46, 156 }, /* 2612 20 */
137 { 1, 0x46, 160 }, /* 2632 21 */
138 { 1, 0x46, 164 }, /* 2652 22 */
139 { 1, 0x46, 168 }, /* 2672 23 */
140 { 1, 0x46, 172 }, /* 2692 24 */
141 { 1, 0x46, 176 }, /* 2712 25 */
142 { 1, 0x46, 180 } /* 2732 26 */
145 OS_MARK(ah
, AH_MARK_SETCHANNEL
, chan
->channel
);
147 chanIEEE
= ath_hal_mhz2ieee(ah
, chan
->channel
, chan
->channelFlags
);
148 if (IS_CHAN_2GHZ(chan
)) {
149 const CHAN_INFO_2GHZ
* ci
=
150 &chan2GHzData
[chanIEEE
+ CI_2GHZ_INDEX_CORRECTION
];
153 data2111
= ((ath_hal_reverseBits(ci
->channelSelect
, 8) & 0xff)
155 | (ci
->refClkSel
<< 4);
156 chan5111
= ci
->channel5111
;
157 txctl
= OS_REG_READ(ah
, AR_PHY_CCK_TX_CTRL
);
158 if (chan
->channel
== 2484) {
159 /* Enable channel spreading for channel 14 */
160 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
161 txctl
| AR_PHY_CCK_TX_CTRL_JAPAN
);
163 OS_REG_WRITE(ah
, AR_PHY_CCK_TX_CTRL
,
164 txctl
&~ AR_PHY_CCK_TX_CTRL_JAPAN
);
167 chan5111
= chanIEEE
; /* no conversion needed */
171 /* Rest of the code is common for 5 GHz and 2.4 GHz. */
172 if (chan5111
>= 145 || (chan5111
& 0x1)) {
173 reg32
= ath_hal_reverseBits(chan5111
- 24, 8) & 0xff;
176 reg32
= ath_hal_reverseBits(((chan5111
- 24)/2), 8) & 0xff;
180 reg32
= (reg32
<< 2) | (refClk
<< 1) | (1 << 10) | 0x1;
181 OS_REG_WRITE(ah
, AR_PHY(0x27), ((data2111
& 0xff) << 8) | (reg32
& 0xff));
183 OS_REG_WRITE(ah
, AR_PHY(0x34), (data2111
& 0xff00) | (reg32
& 0xff));
185 AH_PRIVATE(ah
)->ah_curchan
= chan
;
187 #undef CI_2GHZ_INDEX_CORRECTION
191 * Return a reference to the requested RF Bank.
194 ar5111GetRfBank(struct ath_hal
*ah
, int bank
)
196 struct ar5111State
*priv
= AR5111(ah
);
198 HALASSERT(priv
!= AH_NULL
);
200 case 0: return priv
->Bank0Data
;
201 case 1: return priv
->Bank1Data
;
202 case 2: return priv
->Bank2Data
;
203 case 3: return priv
->Bank3Data
;
204 case 6: return priv
->Bank6Data
;
205 case 7: return priv
->Bank7Data
;
207 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: unknown RF Bank %d requested\n",
213 * Reads EEPROM header info from device structure and programs
216 * REQUIRES: Access to the analog rf device
219 ar5111SetRfRegs(struct ath_hal
*ah
, HAL_CHANNEL_INTERNAL
*chan
,
220 uint16_t modesIndex
, uint16_t *rfXpdGain
)
222 struct ath_hal_5212
*ahp
= AH5212(ah
);
223 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
224 uint16_t rfXpdGainFixed
, rfPloSel
, rfPwdXpd
, gainI
;
225 uint16_t tempOB
, tempDB
;
226 uint32_t ob2GHz
, db2GHz
, rfReg
[N(ar5212Bank6_5111
)];
227 int i
, regWrites
= 0;
229 /* Setup rf parameters */
230 switch (chan
->channelFlags
& CHANNEL_ALL
) {
233 if (4000 < chan
->channel
&& chan
->channel
< 5260) {
236 } else if (5260 <= chan
->channel
&& chan
->channel
< 5500) {
239 } else if (5500 <= chan
->channel
&& chan
->channel
< 5725) {
242 } else if (chan
->channel
>= 5725) {
246 /* XXX when does this happen??? */
251 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11A
];
252 rfPloSel
= ee
->ee_xpd
[headerInfo11A
];
253 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11A
];
254 gainI
= ee
->ee_gainI
[headerInfo11A
];
257 tempOB
= ee
->ee_obFor24
;
258 tempDB
= ee
->ee_dbFor24
;
259 ob2GHz
= ee
->ee_ob2GHz
[0];
260 db2GHz
= ee
->ee_db2GHz
[0];
262 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11B
];
263 rfPloSel
= ee
->ee_xpd
[headerInfo11B
];
264 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11B
];
265 gainI
= ee
->ee_gainI
[headerInfo11B
];
268 tempOB
= ee
->ee_obFor24g
;
269 tempDB
= ee
->ee_dbFor24g
;
270 ob2GHz
= ee
->ee_ob2GHz
[1];
271 db2GHz
= ee
->ee_db2GHz
[1];
273 rfXpdGainFixed
= ee
->ee_xgain
[headerInfo11G
];
274 rfPloSel
= ee
->ee_xpd
[headerInfo11G
];
275 rfPwdXpd
= !ee
->ee_xpd
[headerInfo11G
];
276 gainI
= ee
->ee_gainI
[headerInfo11G
];
279 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
280 __func__
, chan
->channelFlags
);
284 HALASSERT(1 <= tempOB
&& tempOB
<= 5);
285 HALASSERT(1 <= tempDB
&& tempDB
<= 5);
288 for (i
= 0; i
< N(ar5212Bank0_5111
); i
++)
289 rfReg
[i
] = ar5212Bank0_5111
[i
][modesIndex
];
290 if (IS_CHAN_2GHZ(chan
)) {
291 ar5212ModifyRfBuffer(rfReg
, ob2GHz
, 3, 119, 0);
292 ar5212ModifyRfBuffer(rfReg
, db2GHz
, 3, 122, 0);
294 HAL_INI_WRITE_BANK(ah
, ar5212Bank0_5111
, rfReg
, regWrites
);
297 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank1_5111
, 1, regWrites
);
300 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank2_5111
, modesIndex
, regWrites
);
303 HAL_INI_WRITE_ARRAY(ah
, ar5212Bank3_5111
, modesIndex
, regWrites
);
306 for (i
= 0; i
< N(ar5212Bank6_5111
); i
++)
307 rfReg
[i
] = ar5212Bank6_5111
[i
][modesIndex
];
308 if (IS_CHAN_A(chan
)) { /* NB: CHANNEL_A | CHANNEL_T */
309 ar5212ModifyRfBuffer(rfReg
, ee
->ee_cornerCal
.pd84
, 1, 51, 3);
310 ar5212ModifyRfBuffer(rfReg
, ee
->ee_cornerCal
.pd90
, 1, 45, 3);
312 ar5212ModifyRfBuffer(rfReg
, rfPwdXpd
, 1, 95, 0);
313 ar5212ModifyRfBuffer(rfReg
, rfXpdGainFixed
, 4, 96, 0);
314 /* Set 5212 OB & DB */
315 ar5212ModifyRfBuffer(rfReg
, tempOB
, 3, 104, 0);
316 ar5212ModifyRfBuffer(rfReg
, tempDB
, 3, 107, 0);
317 HAL_INI_WRITE_BANK(ah
, ar5212Bank6_5111
, rfReg
, regWrites
);
320 for (i
= 0; i
< N(ar5212Bank7_5111
); i
++)
321 rfReg
[i
] = ar5212Bank7_5111
[i
][modesIndex
];
322 ar5212ModifyRfBuffer(rfReg
, gainI
, 6, 29, 0);
323 ar5212ModifyRfBuffer(rfReg
, rfPloSel
, 1, 4, 0);
325 if (IS_CHAN_QUARTER_RATE(chan
) || IS_CHAN_HALF_RATE(chan
)) {
326 uint32_t rfWaitI
, rfWaitS
, rfMaxTime
;
329 rfWaitI
= (IS_CHAN_HALF_RATE(chan
)) ? 0x10 : 0x1f;
331 ar5212ModifyRfBuffer(rfReg
, rfWaitS
, 5, 19, 0);
332 ar5212ModifyRfBuffer(rfReg
, rfWaitI
, 5, 24, 0);
333 ar5212ModifyRfBuffer(rfReg
, rfMaxTime
, 2, 49, 0);
337 HAL_INI_WRITE_BANK(ah
, ar5212Bank7_5111
, rfReg
, regWrites
);
339 /* Now that we have reprogrammed rfgain value, clear the flag. */
340 ahp
->ah_rfgainState
= HAL_RFGAIN_INACTIVE
;
346 * Returns interpolated or the scaled up interpolated value
349 interpolate(uint16_t target
, uint16_t srcLeft
, uint16_t srcRight
,
350 uint16_t targetLeft
, uint16_t targetRight
)
355 /* to get an accurate ratio, always scale, if want to scale, then don't scale back down */
356 if ((targetLeft
* targetRight
) == 0)
359 if (srcRight
!= srcLeft
) {
361 * Note the ratio always need to be scaled,
362 * since it will be a fraction.
364 lRatio
= (target
- srcLeft
) * EEP_SCALE
/ (srcRight
- srcLeft
);
366 /* Return as Left target if value would be negative */
368 } else if (lRatio
> EEP_SCALE
) {
369 /* Return as Right target if Ratio is greater than 100% (SCALE) */
372 rv
= (lRatio
* targetRight
+ (EEP_SCALE
- lRatio
) *
373 targetLeft
) / EEP_SCALE
;
382 * Read the transmit power levels from the structures taken from EEPROM
383 * Interpolate read transmit power values for this channel
384 * Organize the transmit power values into a table for writing into the hardware
387 ar5111SetPowerTable(struct ath_hal
*ah
,
388 int16_t *pMinPower
, int16_t *pMaxPower
, HAL_CHANNEL_INTERNAL
*chan
,
391 struct ath_hal_5212
*ahp
= AH5212(ah
);
392 const HAL_EEPROM
*ee
= AH_PRIVATE(ah
)->ah_eeprom
;
393 FULL_PCDAC_STRUCT pcdacStruct
;
396 uint16_t *pPcdacValues
;
397 int16_t *pScaledUpDbm
;
398 int16_t minScaledPwr
;
399 int16_t maxScaledPwr
;
401 uint16_t pcdacMin
= 0;
402 uint16_t pcdacMax
= PCDAC_STOP
;
403 uint16_t pcdacTableIndex
;
404 uint16_t scaledPcdac
;
405 PCDACS_EEPROM
*pSrcStruct
;
406 PCDACS_EEPROM eepromPcdacs
;
408 /* setup the pcdac struct to point to the correct info, based on mode */
409 switch (chan
->channelFlags
& CHANNEL_ALL
) {
412 eepromPcdacs
.numChannels
= ee
->ee_numChannels11a
;
413 eepromPcdacs
.pChannelList
= ee
->ee_channels11a
;
414 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11a
;
417 eepromPcdacs
.numChannels
= ee
->ee_numChannels2_4
;
418 eepromPcdacs
.pChannelList
= ee
->ee_channels11b
;
419 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11b
;
423 eepromPcdacs
.numChannels
= ee
->ee_numChannels2_4
;
424 eepromPcdacs
.pChannelList
= ee
->ee_channels11g
;
425 eepromPcdacs
.pDataPerChannel
= ee
->ee_dataPerChannel11g
;
428 HALDEBUG(ah
, HAL_DEBUG_ANY
, "%s: invalid channel flags 0x%x\n",
429 __func__
, chan
->channelFlags
);
433 pSrcStruct
= &eepromPcdacs
;
435 OS_MEMZERO(&pcdacStruct
, sizeof(pcdacStruct
));
436 pPcdacValues
= pcdacStruct
.PcdacValues
;
437 pScaledUpDbm
= pcdacStruct
.PwrValues
;
439 /* Initialize the pcdacs to dBM structs pcdacs to be 1 to 63 */
440 for (i
= PCDAC_START
, j
= 0; i
<= PCDAC_STOP
; i
+= PCDAC_STEP
, j
++)
443 pcdacStruct
.numPcdacValues
= j
;
444 pcdacStruct
.pcdacMin
= PCDAC_START
;
445 pcdacStruct
.pcdacMax
= PCDAC_STOP
;
447 /* Fill out the power values for this channel */
448 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++ )
449 pScaledUpDbm
[j
] = ar5212GetScaledPower(chan
->channel
,
450 pPcdacValues
[j
], pSrcStruct
);
452 /* Now scale the pcdac values to fit in the 64 entry power table */
453 minScaledPwr
= pScaledUpDbm
[0];
454 maxScaledPwr
= pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1];
456 /* find minimum and make monotonic */
457 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++) {
458 if (minScaledPwr
>= pScaledUpDbm
[j
]) {
459 minScaledPwr
= pScaledUpDbm
[j
];
463 * Make the full_hsh monotonically increasing otherwise
464 * interpolation algorithm will get fooled gotta start
465 * working from the top, hence i = 63 - j.
467 i
= (uint16_t)(pcdacStruct
.numPcdacValues
- 1 - j
);
470 if (pScaledUpDbm
[i
-1] > pScaledUpDbm
[i
]) {
472 * It could be a glitch, so make the power for
473 * this pcdac the same as the power from the
474 * next highest pcdac.
476 pScaledUpDbm
[i
- 1] = pScaledUpDbm
[i
];
480 for (j
= 0; j
< pcdacStruct
.numPcdacValues
; j
++)
481 if (maxScaledPwr
< pScaledUpDbm
[j
]) {
482 maxScaledPwr
= pScaledUpDbm
[j
];
486 /* Find the first power level with a pcdac */
487 pwr
= (uint16_t)(PWR_STEP
*
488 ((minScaledPwr
- PWR_MIN
+ PWR_STEP
/ 2) / PWR_STEP
) + PWR_MIN
);
490 /* Write all the first pcdac entries based off the pcdacMin */
492 for (i
= 0; i
< (2 * (pwr
- PWR_MIN
) / EEP_SCALE
+ 1); i
++) {
493 HALASSERT(pcdacTableIndex
< PWR_TABLE_SIZE
);
494 ahp
->ah_pcdacTable
[pcdacTableIndex
++] = pcdacMin
;
498 while (pwr
< pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1] &&
499 pcdacTableIndex
< PWR_TABLE_SIZE
) {
501 /* stop if dbM > max_power_possible */
502 while (pwr
< pScaledUpDbm
[pcdacStruct
.numPcdacValues
- 1] &&
503 (pwr
- pScaledUpDbm
[i
])*(pwr
- pScaledUpDbm
[i
+1]) > 0)
505 /* scale by 2 and add 1 to enable round up or down as needed */
506 scaledPcdac
= (uint16_t)(interpolate(pwr
,
507 pScaledUpDbm
[i
], pScaledUpDbm
[i
+ 1],
508 (uint16_t)(pPcdacValues
[i
] * 2),
509 (uint16_t)(pPcdacValues
[i
+ 1] * 2)) + 1);
511 HALASSERT(pcdacTableIndex
< PWR_TABLE_SIZE
);
512 ahp
->ah_pcdacTable
[pcdacTableIndex
] = scaledPcdac
/ 2;
513 if (ahp
->ah_pcdacTable
[pcdacTableIndex
] > pcdacMax
)
514 ahp
->ah_pcdacTable
[pcdacTableIndex
] = pcdacMax
;
518 /* Write all the last pcdac entries based off the last valid pcdac */
519 while (pcdacTableIndex
< PWR_TABLE_SIZE
) {
520 ahp
->ah_pcdacTable
[pcdacTableIndex
] =
521 ahp
->ah_pcdacTable
[pcdacTableIndex
- 1];
525 /* No power table adjustment for 5111 */
526 ahp
->ah_txPowerIndexOffset
= 0;
532 * Get or interpolate the pcdac value from the calibrated data.
535 ar5212GetScaledPower(uint16_t channel
, uint16_t pcdacValue
,
536 const PCDACS_EEPROM
*pSrcStruct
)
539 uint16_t lFreq
, rFreq
; /* left and right frequency values */
540 uint16_t llPcdac
, ulPcdac
; /* lower and upper left pcdac values */
541 uint16_t lrPcdac
, urPcdac
; /* lower and upper right pcdac values */
542 uint16_t lPwr
, uPwr
; /* lower and upper temp pwr values */
543 uint16_t lScaledPwr
, rScaledPwr
; /* left and right scaled power */
545 if (ar5212FindValueInList(channel
, pcdacValue
, pSrcStruct
, &powerValue
)) {
546 /* value was copied from srcStruct */
550 ar5212GetLowerUpperValues(channel
,
551 pSrcStruct
->pChannelList
, pSrcStruct
->numChannels
,
553 ar5212GetLowerUpperPcdacs(pcdacValue
,
554 lFreq
, pSrcStruct
, &llPcdac
, &ulPcdac
);
555 ar5212GetLowerUpperPcdacs(pcdacValue
,
556 rFreq
, pSrcStruct
, &lrPcdac
, &urPcdac
);
558 /* get the power index for the pcdac value */
559 ar5212FindValueInList(lFreq
, llPcdac
, pSrcStruct
, &lPwr
);
560 ar5212FindValueInList(lFreq
, ulPcdac
, pSrcStruct
, &uPwr
);
561 lScaledPwr
= interpolate(pcdacValue
, llPcdac
, ulPcdac
, lPwr
, uPwr
);
563 ar5212FindValueInList(rFreq
, lrPcdac
, pSrcStruct
, &lPwr
);
564 ar5212FindValueInList(rFreq
, urPcdac
, pSrcStruct
, &uPwr
);
565 rScaledPwr
= interpolate(pcdacValue
, lrPcdac
, urPcdac
, lPwr
, uPwr
);
567 return interpolate(channel
, lFreq
, rFreq
, lScaledPwr
, rScaledPwr
);
571 * Find the value from the calibrated source data struct
574 ar5212FindValueInList(uint16_t channel
, uint16_t pcdacValue
,
575 const PCDACS_EEPROM
*pSrcStruct
, uint16_t *powerValue
)
577 const DATA_PER_CHANNEL
*pChannelData
= pSrcStruct
->pDataPerChannel
;
580 for (i
= 0; i
< pSrcStruct
->numChannels
; i
++ ) {
581 if (pChannelData
->channelValue
== channel
) {
582 const uint16_t* pPcdac
= pChannelData
->PcdacValues
;
585 for (j
= 0; j
< pChannelData
->numPcdacValues
; j
++ ) {
586 if (*pPcdac
== pcdacValue
) {
587 *powerValue
= pChannelData
->PwrValues
[j
];
599 * Get the upper and lower pcdac given the channel and the pcdac
603 ar5212GetLowerUpperPcdacs(uint16_t pcdac
, uint16_t channel
,
604 const PCDACS_EEPROM
*pSrcStruct
,
605 uint16_t *pLowerPcdac
, uint16_t *pUpperPcdac
)
607 const DATA_PER_CHANNEL
*pChannelData
= pSrcStruct
->pDataPerChannel
;
610 /* Find the channel information */
611 for (i
= 0; i
< pSrcStruct
->numChannels
; i
++) {
612 if (pChannelData
->channelValue
== channel
)
616 ar5212GetLowerUpperValues(pcdac
, pChannelData
->PcdacValues
,
617 pChannelData
->numPcdacValues
,
618 pLowerPcdac
, pUpperPcdac
);
622 ar5111GetChannelMaxMinPower(struct ath_hal
*ah
, HAL_CHANNEL
*chan
,
623 int16_t *maxPow
, int16_t *minPow
)
625 /* XXX - Get 5111 power limits! */
626 /* NB: caller will cope */
631 * Adjust NF based on statistical values for 5GHz frequencies.
634 ar5111GetNfAdjust(struct ath_hal
*ah
, const HAL_CHANNEL_INTERNAL
*c
)
636 static const struct {
640 { 5790, 6 }, /* NB: ordered high -> low */
654 for (i
= 0; c
->channel
<= adjust5111
[i
].freqLow
; i
++)
656 return adjust5111
[i
].adjust
;
660 * Free memory for analog bank scratch buffers
663 ar5111RfDetach(struct ath_hal
*ah
)
665 struct ath_hal_5212
*ahp
= AH5212(ah
);
667 HALASSERT(ahp
->ah_rfHal
!= AH_NULL
);
668 ath_hal_free(ahp
->ah_rfHal
);
669 ahp
->ah_rfHal
= AH_NULL
;
673 * Allocate memory for analog bank scratch buffers
674 * Scratch Buffer will be reinitialized every reset so no need to zero now
677 ar5111RfAttach(struct ath_hal
*ah
, HAL_STATUS
*status
)
679 struct ath_hal_5212
*ahp
= AH5212(ah
);
680 struct ar5111State
*priv
;
682 HALASSERT(ah
->ah_magic
== AR5212_MAGIC
);
684 HALASSERT(ahp
->ah_rfHal
== AH_NULL
);
685 priv
= ath_hal_malloc(sizeof(struct ar5111State
));
686 if (priv
== AH_NULL
) {
687 HALDEBUG(ah
, HAL_DEBUG_ANY
,
688 "%s: cannot allocate private state\n", __func__
);
689 *status
= HAL_ENOMEM
; /* XXX */
692 priv
->base
.rfDetach
= ar5111RfDetach
;
693 priv
->base
.writeRegs
= ar5111WriteRegs
;
694 priv
->base
.getRfBank
= ar5111GetRfBank
;
695 priv
->base
.setChannel
= ar5111SetChannel
;
696 priv
->base
.setRfRegs
= ar5111SetRfRegs
;
697 priv
->base
.setPowerTable
= ar5111SetPowerTable
;
698 priv
->base
.getChannelMaxMinPower
= ar5111GetChannelMaxMinPower
;
699 priv
->base
.getNfAdjust
= ar5111GetNfAdjust
;
701 ahp
->ah_pcdacTable
= priv
->pcdacTable
;
702 ahp
->ah_pcdacTableSize
= sizeof(priv
->pcdacTable
);
703 ahp
->ah_rfHal
= &priv
->base
;
707 #endif /* AH_SUPPORT_5111 */