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_regwrite(struct ath_hw
*ah
, u32 reg
, u32 val
)
29 REG_WRITE(ah
, reg
, val
);
31 if (ah
->config
.analog_shiftreg
)
35 void ath9k_hw_analog_shift_rmw(struct ath_hw
*ah
, u32 reg
, u32 mask
,
40 regVal
= REG_READ(ah
, reg
) & ~mask
;
41 regVal
|= (val
<< shift
) & mask
;
43 REG_WRITE(ah
, reg
, regVal
);
45 if (ah
->config
.analog_shiftreg
)
49 int16_t ath9k_hw_interpolate(u16 target
, u16 srcLeft
, u16 srcRight
,
50 int16_t targetLeft
, int16_t targetRight
)
54 if (srcRight
== srcLeft
) {
57 rv
= (int16_t) (((target
- srcLeft
) * targetRight
+
58 (srcRight
- target
) * targetLeft
) /
59 (srcRight
- srcLeft
));
64 bool ath9k_hw_get_lower_upper_index(u8 target
, u8
*pList
, u16 listSize
,
65 u16
*indexL
, u16
*indexR
)
69 if (target
<= pList
[0]) {
70 *indexL
= *indexR
= 0;
73 if (target
>= pList
[listSize
- 1]) {
74 *indexL
= *indexR
= (u16
) (listSize
- 1);
78 for (i
= 0; i
< listSize
- 1; i
++) {
79 if (pList
[i
] == target
) {
80 *indexL
= *indexR
= i
;
83 if (target
< pList
[i
+ 1]) {
85 *indexR
= (u16
) (i
+ 1);
92 bool ath9k_hw_nvram_read(struct ath_common
*common
, u32 off
, u16
*data
)
94 return common
->bus_ops
->eeprom_read(common
, off
, data
);
97 void ath9k_hw_fill_vpd_table(u8 pwrMin
, u8 pwrMax
, u8
*pPwrList
,
98 u8
*pVpdList
, u16 numIntercepts
,
103 u16 idxL
= 0, idxR
= 0;
105 for (i
= 0; i
<= (pwrMax
- pwrMin
) / 2; i
++) {
106 ath9k_hw_get_lower_upper_index(currPwr
, pPwrList
,
107 numIntercepts
, &(idxL
),
111 if (idxL
== numIntercepts
- 1)
112 idxL
= (u16
) (numIntercepts
- 2);
113 if (pPwrList
[idxL
] == pPwrList
[idxR
])
116 k
= (u16
)(((currPwr
- pPwrList
[idxL
]) * pVpdList
[idxR
] +
117 (pPwrList
[idxR
] - currPwr
) * pVpdList
[idxL
]) /
118 (pPwrList
[idxR
] - pPwrList
[idxL
]));
119 pRetVpdList
[i
] = (u8
) k
;
124 void ath9k_hw_get_legacy_target_powers(struct ath_hw
*ah
,
125 struct ath9k_channel
*chan
,
126 struct cal_target_power_leg
*powInfo
,
128 struct cal_target_power_leg
*pNewPower
,
129 u16 numRates
, bool isExtTarget
)
131 struct chan_centers centers
;
134 int matchIndex
= -1, lowIndex
= -1;
137 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
138 freq
= (isExtTarget
) ? centers
.ext_center
: centers
.ctl_center
;
140 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
,
141 IS_CHAN_2GHZ(chan
))) {
144 for (i
= 0; (i
< numChannels
) &&
145 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
146 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
147 IS_CHAN_2GHZ(chan
))) {
150 } else if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
151 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
152 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
153 IS_CHAN_2GHZ(chan
))) {
158 if ((matchIndex
== -1) && (lowIndex
== -1))
162 if (matchIndex
!= -1) {
163 *pNewPower
= powInfo
[matchIndex
];
165 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
167 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
170 for (i
= 0; i
< numRates
; i
++) {
171 pNewPower
->tPow2x
[i
] =
172 (u8
)ath9k_hw_interpolate(freq
, clo
, chi
,
173 powInfo
[lowIndex
].tPow2x
[i
],
174 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
179 void ath9k_hw_get_target_powers(struct ath_hw
*ah
,
180 struct ath9k_channel
*chan
,
181 struct cal_target_power_ht
*powInfo
,
183 struct cal_target_power_ht
*pNewPower
,
184 u16 numRates
, bool isHt40Target
)
186 struct chan_centers centers
;
189 int matchIndex
= -1, lowIndex
= -1;
192 ath9k_hw_get_channel_centers(ah
, chan
, ¢ers
);
193 freq
= isHt40Target
? centers
.synth_center
: centers
.ctl_center
;
195 if (freq
<= ath9k_hw_fbin2freq(powInfo
[0].bChannel
, IS_CHAN_2GHZ(chan
))) {
198 for (i
= 0; (i
< numChannels
) &&
199 (powInfo
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
200 if (freq
== ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
201 IS_CHAN_2GHZ(chan
))) {
205 if (freq
< ath9k_hw_fbin2freq(powInfo
[i
].bChannel
,
206 IS_CHAN_2GHZ(chan
)) && i
> 0 &&
207 freq
> ath9k_hw_fbin2freq(powInfo
[i
- 1].bChannel
,
208 IS_CHAN_2GHZ(chan
))) {
213 if ((matchIndex
== -1) && (lowIndex
== -1))
217 if (matchIndex
!= -1) {
218 *pNewPower
= powInfo
[matchIndex
];
220 clo
= ath9k_hw_fbin2freq(powInfo
[lowIndex
].bChannel
,
222 chi
= ath9k_hw_fbin2freq(powInfo
[lowIndex
+ 1].bChannel
,
225 for (i
= 0; i
< numRates
; i
++) {
226 pNewPower
->tPow2x
[i
] = (u8
)ath9k_hw_interpolate(freq
,
228 powInfo
[lowIndex
].tPow2x
[i
],
229 powInfo
[lowIndex
+ 1].tPow2x
[i
]);
234 u16
ath9k_hw_get_max_edge_power(u16 freq
, struct cal_ctl_edges
*pRdEdgesPower
,
235 bool is2GHz
, int num_band_edges
)
237 u16 twiceMaxEdgePower
= AR5416_MAX_RATE_POWER
;
240 for (i
= 0; (i
< num_band_edges
) &&
241 (pRdEdgesPower
[i
].bChannel
!= AR5416_BCHAN_UNUSED
); i
++) {
242 if (freq
== ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
, is2GHz
)) {
243 twiceMaxEdgePower
= CTL_EDGE_TPOWER(pRdEdgesPower
[i
].ctl
);
245 } else if ((i
> 0) &&
246 (freq
< ath9k_hw_fbin2freq(pRdEdgesPower
[i
].bChannel
,
248 if (ath9k_hw_fbin2freq(pRdEdgesPower
[i
- 1].bChannel
,
250 CTL_EDGE_FLAGS(pRdEdgesPower
[i
- 1].ctl
)) {
252 CTL_EDGE_TPOWER(pRdEdgesPower
[i
- 1].ctl
);
258 return twiceMaxEdgePower
;
261 void ath9k_hw_update_regulatory_maxpower(struct ath_hw
*ah
)
263 struct ath_common
*common
= ath9k_hw_common(ah
);
264 struct ath_regulatory
*regulatory
= ath9k_hw_regulatory(ah
);
266 switch (ar5416_get_ntxchains(ah
->txchainmask
)) {
270 regulatory
->max_power_level
+= INCREASE_MAXPOW_BY_TWO_CHAIN
;
273 regulatory
->max_power_level
+= INCREASE_MAXPOW_BY_THREE_CHAIN
;
276 ath_print(common
, ATH_DBG_EEPROM
,
277 "Invalid chainmask configuration\n");
282 int ath9k_hw_eeprom_init(struct ath_hw
*ah
)
286 if (AR_SREV_9300_20_OR_LATER(ah
))
287 ah
->eep_ops
= &eep_ar9300_ops
;
288 else if (AR_SREV_9287(ah
)) {
289 ah
->eep_ops
= &eep_ar9287_ops
;
290 } else if (AR_SREV_9285(ah
) || AR_SREV_9271(ah
)) {
291 ah
->eep_ops
= &eep_4k_ops
;
293 ah
->eep_ops
= &eep_def_ops
;
296 if (!ah
->eep_ops
->fill_eeprom(ah
))
299 status
= ah
->eep_ops
->check_eeprom(ah
);