2 * Copyright (c) 2008-2009 Atheros Communications Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 static inline u16
ath9k_hw_fbin2freq(u8 fbin
, bool is2GHz
)
21 if (fbin
== AR5416_BCHAN_UNUSED
)
24 return (u16
) ((is2GHz
) ? (2300 + fbin
) : (4800 + 5 * fbin
));
27 void ath9k_hw_analog_shift_rmw(struct ath_hw
*ah
, u32 reg
, u32 mask
,
32 regVal
= REG_READ(ah
, reg
) & ~mask
;
33 regVal
|= (val
<< shift
) & mask
;
35 REG_WRITE(ah
, reg
, regVal
);
37 if (ah
->config
.analog_shiftreg
)
43 int16_t ath9k_hw_interpolate(u16 target
, u16 srcLeft
, u16 srcRight
,
44 int16_t targetLeft
, int16_t targetRight
)
48 if (srcRight
== srcLeft
) {
51 rv
= (int16_t) (((target
- srcLeft
) * targetRight
+
52 (srcRight
- target
) * targetLeft
) /
53 (srcRight
- srcLeft
));
58 bool ath9k_hw_get_lower_upper_index(u8 target
, u8
*pList
, u16 listSize
,
59 u16
*indexL
, u16
*indexR
)
63 if (target
<= pList
[0]) {
64 *indexL
= *indexR
= 0;
67 if (target
>= pList
[listSize
- 1]) {
68 *indexL
= *indexR
= (u16
) (listSize
- 1);
72 for (i
= 0; i
< listSize
- 1; i
++) {
73 if (pList
[i
] == target
) {
74 *indexL
= *indexR
= i
;
77 if (target
< pList
[i
+ 1]) {
79 *indexR
= (u16
) (i
+ 1);
86 bool ath9k_hw_nvram_read(struct ath_hw
*ah
, u32 off
, u16
*data
)
88 struct ath_softc
*sc
= ah
->ah_sc
;
90 return sc
->bus_ops
->eeprom_read(ah
, off
, data
);
93 void ath9k_hw_fill_vpd_table(u8 pwrMin
, u8 pwrMax
, u8
*pPwrList
,
94 u8
*pVpdList
, u16 numIntercepts
,
99 u16 idxL
= 0, idxR
= 0;
101 for (i
= 0; i
<= (pwrMax
- pwrMin
) / 2; i
++) {
102 ath9k_hw_get_lower_upper_index(currPwr
, pPwrList
,
103 numIntercepts
, &(idxL
),
107 if (idxL
== numIntercepts
- 1)
108 idxL
= (u16
) (numIntercepts
- 2);
109 if (pPwrList
[idxL
] == pPwrList
[idxR
])
112 k
= (u16
)(((currPwr
- pPwrList
[idxL
]) * pVpdList
[idxR
] +
113 (pPwrList
[idxR
] - currPwr
) * pVpdList
[idxL
]) /
114 (pPwrList
[idxR
] - pPwrList
[idxL
]));
115 pRetVpdList
[i
] = (u8
) k
;
120 void ath9k_hw_get_legacy_target_powers(struct ath_hw
*ah
,
121 struct ath9k_channel
*chan
,
122 struct cal_target_power_leg
*powInfo
,
124 struct cal_target_power_leg
*pNewPower
,
125 u16 numRates
, bool isExtTarget
)
127 struct chan_centers centers
;
130 int matchIndex
= -1, lowIndex
= -1;
133 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
134 freq
= (isExtTarget
) ? centers
.ext_center
: centers
.ctl_center
;
136 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
,
137 IS_CHAN_2GHZ(chan
))) {
140 for (i
= 0; (i
< numChannels
) &&
141 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
142 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
143 IS_CHAN_2GHZ(chan
))) {
146 } else if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
147 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
148 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
149 IS_CHAN_2GHZ(chan
))) {
154 if ((matchIndex
== -1) && (lowIndex
== -1))
158 if (matchIndex
!= -1) {
159 *pNewPower
= powInfo
[matchIndex
];
161 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
163 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
166 for (i
= 0; i
< numRates
; i
++) {
167 pNewPower
->tPow2x
[i
] =
168 (u8
)ath9k_hw_interpolate(freq
, clo
, chi
,
169 powInfo
[lowIndex
].tPow2x
[i
],
170 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
175 void ath9k_hw_get_target_powers(struct ath_hw
*ah
,
176 struct ath9k_channel
*chan
,
177 struct cal_target_power_ht
*powInfo
,
179 struct cal_target_power_ht
*pNewPower
,
180 u16 numRates
, bool isHt40Target
)
182 struct chan_centers centers
;
185 int matchIndex
= -1, lowIndex
= -1;
188 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
189 freq
= isHt40Target
? centers
.synth_center
: centers
.ctl_center
;
191 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
, IS_CHAN_2GHZ(chan
))) {
194 for (i
= 0; (i
< numChannels
) &&
195 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
196 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
197 IS_CHAN_2GHZ(chan
))) {
201 if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
202 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
203 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
204 IS_CHAN_2GHZ(chan
))) {
209 if ((matchIndex
== -1) && (lowIndex
== -1))
213 if (matchIndex
!= -1) {
214 *pNewPower
= powInfo
[matchIndex
];
216 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
218 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
221 for (i
= 0; i
< numRates
; i
++) {
222 pNewPower
->tPow2x
[i
] = (u8
)ath9k_hw_interpolate(freq
,
224 powInfo
[lowIndex
].tPow2x
[i
],
225 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
230 u16
ath9k_hw_get_max_edge_power(u16 freq
, struct cal_ctl_edges
*pRdEdgesPower
,
231 bool is2GHz
, int num_band_edges
)
233 u16 twiceMaxEdgePower
= AR5416_MAX_RATE_POWER
;
236 for (i
= 0; (i
< num_band_edges
) &&
237 (pRdEdgesPower
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
238 if (freq
== ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
, is2GHz
)) {
239 twiceMaxEdgePower
= pRdEdgesPower
[i
].tPower
;
241 } else if ((i
> 0) &&
242 (freq
< ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
,
244 if (ath9k_hw_fbin2freq(pRdEdgesPower
[i
- 1].bChannel
,
246 pRdEdgesPower
[i
- 1].flag
) {
248 pRdEdgesPower
[i
- 1].tPower
;
254 return twiceMaxEdgePower
;
257 int ath9k_hw_eeprom_init(struct ath_hw
*ah
)
261 if (AR_SREV_9287(ah
)) {
262 ah
->eep_map
= EEP_MAP_AR9287
;
263 ah
->eep_ops
= &eep_AR9287_ops
;
264 } else if (AR_SREV_9285(ah
) || AR_SREV_9271(ah
)) {
265 ah
->eep_map
= EEP_MAP_4KBITS
;
266 ah
->eep_ops
= &eep_4k_ops
;
268 ah
->eep_map
= EEP_MAP_DEFAULT
;
269 ah
->eep_ops
= &eep_def_ops
;
272 if (!ah
->eep_ops
->fill_eeprom(ah
))
275 status
= ah
->eep_ops
->check_eeprom(ah
);